Static OpenSSL *.a libraries not linked target binary (using Statically Compiled Qt with SSL)

Right off the bat, sorry about the length of the question, but it is due to all the additional details I am providing which I hope could help trouble shoot the issue faster

What am I trying to achieve?

I need to create a portable (all-in-one) application, with SSL support.

What is the problem?

So the core problem I am facing is getting SSL support included into my binary/portable app.

A MCVE of the app is simple:

Project .pro file

QT -= gui
QT += network

CONFIG += c++11 console
CONFIG -= app_bundle

SOURCES += \
        main.cpp

INSTALLS += target

Project main.cpp

#include <QCoreApplication>
#include <QSslSocket>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    qDebug() << "Is SSL Enabled? " << QSslSocket::supportsSsl();
    qDebug() << "SSL Library Build Version (Qt compiled against): " << QSslSocket::sslLibraryBuildVersionString();
    qDebug() << "SSL Library Version String (available locally): " << QSslSocket::sslLibraryVersionString();

    return a.exec();
}

  • Output on my DEV machine:

    Is SSL Enabled?  true
    SSL Library Build Version (Qt compiled against):  "OpenSSL 1.1.1d  10 Sep 2019"
    SSL Library Version String (available locally):  "OpenSSL 1.1.1d  10 Sep 2019"

Info of Dev Machine

    C:\Users\cybex>echo %PATH%
    C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Strawberry\c\bin;C:\Strawberry\perl\site\bin;C:\Strawberry\perl\bin

    C:\Users\cybex>openssl
    WARNING: can't open config file: /z/extlib/_openssl_/ssl/openssl.cnf
    OpenSSL> version
    OpenSSL 1.0.2g  1 Mar 2016

  • Running the same binary on a fresh Windows 10 x86 machine results in:

    Is SSL Enabled?  false
    SSL Library Build Version (Qt compiled against):  "OpenSSL 1.1.1d  10 Sep 2019"
    SSL Library Version String (available locally):  ""

Info of Test Machine (Completely fresh install - Windows 10 x86)

    C:\Users\cybex>echo %PATH%
    C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\
    C:\Users\cybex>openssl
    'openssl' is not recognized as an internal or external command,
    operable program or batch file.

  • Running the same binary on a fresh Windows 7 x64 machine results in:

    Is SSL Enabled?  false
    SSL Library Build Version (Qt compiled against):  "OpenSSL 1.1.1d  10 Sep 2019"
    SSL Library Version String (available locally):  ""

Info of Test Machine (Windows 7 x64 laptop with drivers installed)

    C:\Users\Home>echo %PATH%
    C:\Program Files (x86)\OpenSSL\libs;C:\Program Files (x86)\Intel\iCLS Client\;C:\Program Files\Intel\iCLS Client\;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files (x86)\Intel\OpenCL SDK\2.0\bin\x86;C:\Program Files (x86)\Intel\OpenCL SDK\2.0\bin\x64;C:\Program Files\Intel\WiFi\bin\;C:\Program Files\Common Files\Intel\WirelessCommon\;C:\Program Files\Intel\Intel(R) Management Engine Components\DAL;C:\Program Files\Intel\Intel(R) Management Engine Components\IPT;C:\Program Files (x86)\Intel\Intel(R) Management Engine Components\DAL;C:\Program Files (x86)\Intel\Intel(R) Management Engine Components\IPT;C:\Program Files (x86)\Intel\OpenCL SDK\2.0\bin\x86;C:\Program Files (x86)\Intel\OpenCL SDK\2.0\bin\x64;C:\Program Files (x86)\OpenSSL\libs;C:\Program Files\Intel\WiFi\bin\;C:\Program Files\Common Files\Intel\WirelessCommon\
    C:\Users\Home>openssl
    'openssl' is not recognized as an internal or external command, operable program or batch file.

By look at the above results, I conclude that installing OpenSSL solves the problem. Good, but I want need to have it included in my portable app.

In achieving this, I am required to

  1. Compile Qt statically with OpenSSL support

I have done this with the help of this script adapted from ps1 powershell script found here on Qt's wiki. I made additions for:

  • OpenSSL home $OPENSSL_HOME

  • number of threads $threads, and

  • architecture type $arch to be used.

Qt Compiling Details & OpenSSL info

  • Compiler: mingw32 located in C:\Qt\Qt5.13.1\Tools\mingw730_32\bin

  • mkspec: win32-g++ (if that makes any difference).

  • OpenSSL version (32 bit): 1.1.1d

The configuration is as follows:

cmd /C "configure.bat -static -debug-and-release -platform win32-g++ -prefix $QtDir `
        -qt-zlib -qt-pcre -qt-libpng -qt-libjpeg -qt-freetype -opengl desktop -sql-sqlite -ssl -openssl -I $($OPENSSL_HOME)\include -L$($OPENSSL_HOME)\lib\MinGW`
        -opensource -confirm-license `
        -make libs -nomake tools -nomake examples -nomake tests -v"
cmd /C "mingw32-make -k -j$($threads)"

Note 1:

I am using -openssl and not -openssl-linked. I have tried several variations of builing Qt with both -openssl and -openssl-linked. -openssl-linked could never successfully build, see this post I made as to the reason why.

Note 2:

The only successful static Qt compilation I had working was with -ssl -openssl configuration flags enabled

OpenSSL installation (on DEV machine only) is at

`$OPENSSL_HOME = "C:\OpenSSL-Win32"` 

where I am using the statically compiled MinGW libraries for OpenSSL, found in

`$OPENSSL_HOME = "C:\OpenSSL-Win32\lib\MinGW",`

The file contents of C:\OpenSSL-Win32\lib\MinGW is:

Directory: C:\OpenSSL-Win32\lib\MinGW

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       2019/09/11     18:11        3347286 libcrypto.a
-a----       2019/09/11     18:10         109020 libcrypto.def
-a----       2019/09/11     18:11         385126 libssl.a
-a----       2019/09/11     18:10          14033 libssl.def
  1. Add link project .pro to OpenSSL libraries

I added the OpenSSL libraries to the .pro file using 2 methods(libraries are the statically compiled MinGW OpenSSL libraries found at C:\OpenSSL-Win32\lib\MinGW)

Manual Entry of libraries into .pro file

QT -= gui
QT += network

# OpenSSL static .a libraries
INCLUDEPATH += "C:\OpenSSL-Win32\include"
LIBS += -L"C:\OpenSSL-Win32\lib\MinGW\libssl.a"
LIBS += -L"C:\OpenSSL-Win32\lib\MinGW\libcrypto.a"

CONFIG += c++11 console
CONFIG -= app_bundle

SOURCES += \
        main.cpp

INSTALLS += target

Note 3

The binary size with and without the linked libraries above remains the same size

The LDD output of the binary (on my dev machine) with libraries added above is:

Start-Process -PassThru .\SSL-Test.exe | Get-Process -Module

   Size(K) ModuleName                                         FileName
   ------- ----------                                         --------
      6280 SSL-Test.exe                                       C:\Users\cybex\QtProjects\build-SSL-Test-Desktop_Qt_Op...
      1512 ntdll.dll                                          C:\Windows\SYSTEM32\ntdll.dll
       596 KERNEL32.DLL                                       C:\Windows\system32\KERNEL32.DLL
      1500 KERNELBASE.dll                                     C:\Windows\system32\KERNELBASE.dll

The LDD output of the binary (on my Windows 10 x86 test machine) with libraries added above is:

Start-Process -PassThru .\SSL-Test.exe | Get-Process -Module

   Size(K) ModuleName                                         FileName
   ------- ----------                                         --------
      6280 SSL-Test.exe                                       C:\Users\cybex\Desktop\SSL-Test.exe
      1512 ntdll.dll                                          C:\Windows\SYSTEM32\ntdll.dll
       596 KERNEL32.DLL                                       C:\Windows\system32\KERNEL32.DLL
      1500 KERNELBASE.dll                                     C:\Windows\system32\KERNELBASE.dll

Qt Library Import into .pro file

Import using (External Library > Import .a file> Static & Windows only options with no debug suffix)

QT -= gui
QT += network

CONFIG += c++11 console
CONFIG -= app_bundle

SOURCES += \
        main.cpp

INSTALLS += target

win32: LIBS += -L$$PWD/../../../../OpenSSL/OpenSSL-Win32/lib/MinGW/ -lssl

INCLUDEPATH += $$PWD/../../../../OpenSSL/OpenSSL-Win32/lib/MinGW
DEPENDPATH += $$PWD/../../../../OpenSSL/OpenSSL-Win32/lib/MinGW

win32:!win32-g++: PRE_TARGETDEPS += $$PWD/../../../../OpenSSL/OpenSSL-Win32/lib/MinGW/ssl.lib
else:win32-g++: PRE_TARGETDEPS += $$PWD/../../../../OpenSSL/OpenSSL-Win32/lib/MinGW/libssl.a

win32: LIBS += -L$$PWD/../../../../OpenSSL/OpenSSL-Win32/lib/MinGW/ -lcrypto

INCLUDEPATH += $$PWD/../../../../OpenSSL/OpenSSL-Win32/lib/MinGW
DEPENDPATH += $$PWD/../../../../OpenSSL/OpenSSL-Win32/lib/MinGW

win32:!win32-g++: PRE_TARGETDEPS += $$PWD/../../../../OpenSSL/OpenSSL-Win32/lib/MinGW/crypto.lib
else:win32-g++: PRE_TARGETDEPS += $$PWD/../../../../OpenSSL/OpenSSL-Win32/lib/MinGW/libcrypto.a

Using the automatic binary import, the LDD output of the binary (on my dev machine) with libraries added above is:

Start-Process -PassThru .\SSL-Test.exe | Get-Process -Module

   Size(K) ModuleName                                         FileName
   ------- ----------                                         --------
      6280 SSL-Test.exe                                       C:\Users\cybex\QtProjects\build-SSL-Test-Desktop_Qt_Op...
      1512 ntdll.dll                                          C:\Windows\SYSTEM32\ntdll.dll
       596 KERNEL32.DLL                                       C:\Windows\system32\KERNEL32.DLL
      1500 KERNELBASE.dll                                     C:\Windows\system32\KERNELBASE.dll

And using the automatic library import, the LDD output of the binary (on my Windows 10 x86 test machine) with libraries added above is:

Start-Process -PassThru .\SSL-Test.exe | Get-Process -Module

   Size(K) ModuleName                                         FileName
   ------- ----------                                         --------
      6280 SSL-Test.exe                                       C:\Users\cybex\Desktop\SSL-Test.exe
      1512 ntdll.dll                                          C:\Windows\SYSTEM32\ntdll.dll
       596 KERNEL32.DLL                                       C:\Windows\system32\KERNEL32.DLL
      1500 KERNELBASE.dll                                     C:\Windows\system32\KERNELBASE.dll

The application output for the dev machine is SSL enabled as mentioned previously in my post (for both manual and automatic library entry):

Is SSL Enabled?  true
SSL Library Build Version (Qt compiled against):  "OpenSSL 1.1.1d  10 Sep 2019"
SSL Library Version String (available locally):  "OpenSSL 1.1.1d  10 Sep 2019"

The application output for the test machines (w/o OpenSSL installed) is the same as previously too (for both manual and automatic library entry):

Is SSL Enabled?  false
SSL Library Build Version (Qt compiled against):  "OpenSSL 1.1.1d  10 Sep 2019"
SSL Library Version String (available locally):  ""

So with OpenSSL library not being present, it causes the below error when requesting a SSL connection on Non-Dev (fresh / client) machines:

QSslSocket::connectToHostEncrypted: TLS initialization failed

which is the result of the OpenSSL libary not being included in the binary as a dependency. So basically, adding a static OpenSSL library to the project file does not work or I am doing something incorrectly somewhere down the line.

Note 4: Why isn't the question titled: How to Import a static library into Qt?

Importing a static library is straight forward and not complicated. I am assuming I have made a mistake somewhere in the static compilation of Qt with SSL support enabled.

Advice on solving this problem would be greatly appreciated.


Update 1

I have resolved the problem with -openssl-linked. The cause (or fix rather) is to not install OpenSSL to your machine. Rather, extract the .a & include directries into a seperate directory. So everything is the same with exception of you having the libs & include without installing.

Then use the standard configureation (mentioned above), replacing -openssl with -openssl-linked and you should have a successful compile.

Updated Problem

When building & running my application with the new Linked OpenSSL Qt kit, I get a message saying:

The code execution cannot proceed because libcrypto.dll was not found. Reinstalling the program may fix this problem.

Followed by another dialog

The code execution cannot proceed because libssl.dll was not found. Reinstalling the program may fix this problem

LDD requirments:

Start-Process -PassThru .\MyAwesomeApp.exe | Get-Process -Module

   Size(K) ModuleName                                         FileName
   ------- ----------                                         --------
     22708 MyAwesomeApp.exe                                     C:\Users\CybeX\QtProjects\build-MyAwesomeApp-Desktop_Qt_OpenSSL_Linked_5_13_1_MinGW_32bit-Release\release\MyAwesomeApp.exe
      1924 ntdll.dll                                          C:\WINDOWS\SYSTEM32\ntdll.dll
       328 wow64.dll                                          C:\WINDOWS\System32\wow64.dll
       480 wow64win.dll                                       C:\WINDOWS\System32\wow64win.dll
        40 wow64cpu.dll                                       C:\WINDOWS\System32\wow64cpu.dll

Have tested this with and without the .pro LIBS & INCLUDEPATH. Both result in the missing dll's required.

Asked By: CybeX
||

Answer #1:

The -openssl configuration option configures Qt to load libopenssl dynamically using LoadLibrary or another platform equivalent function. Therefore from this point on all your efforts are futile. You need to go back and solve the -openssl-linked problem.

Answered By: CybeX

Answer #2:

If you have built Qt correctly, linking to ssl as static, you no longer need to link the ssl to the application explicitly, just link Qt.

The correct form for gcc is -Lrelative-or-absolute/path (I'm using *nix paths), -L to specify the path where the libraries are located and -lxyz where xyz is the name of the library to link, ssl (without the prefix lib and without the suffix .a)

But in the end an .a file is a collection of .o files, and can be added at linking stage like this: gcc -o target file.o libssl.a (consequently on some occasion simply LIBS += /path/libssl.a could work)

According to the Qt documentation it is not necessary to uninstall system ssl, just pass (export) an OPENSSL_LIBS environment variable to the Qt configure script (OPENSSL_LIBS='-L/opt/ssl/lib -lssl -lcrypto')

If both files (.a, .dll) are present gcc could still prefer the dynamic version, to be sure that you link the static version you can delete the .dll files.

The Qt documentation is not clear (IMHO) on the fact that supports ssl linked statically, I assume that it is so but should be checked

By default, an SSL-enabled Qt library dynamically loads any installed OpenSSL library at run-time. However, it is possible to link to the library at compile-time by configuring Qt with the -openssl-linked option.

Should I do the build for me, I would enable a verbose output, and I would verify in the log that it is actually linked statically, I would verify that it is taken from the right directory, and that the final target Qt contains the ssl symbols.

Answered By: n. 'pronouns' m.

Answer #3:

I' using VS2019 as native win32 compiler, not mingw:

  1. Bukd openSSL as static lib

    "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat"

    SET CL=/MP

    perl Configure VC-WIN64A no-shared --prefix=C:\Build-OpenSSL-VC-64-STATIC

    nmake

    nmake install

  2. build Qt with static SSL:

    ..\configure -static -I C:\Build-OpenSSL-VC-64-STATIC\include -L C:\Build-OpenSSL-VC-64-STATIC\lib OPENSSL_LIBS="-llibcrypto -llibssl -lgdi32 -lWs2_32 -lwsock32 -ladvapi32 -luser32 -lCRYPT32" -openssl-linked -static-runtime ... etc

The same for 32 bits

perl Configure VC-WIN32 no-shared --prefix=C:\Build-OpenSSL-VC-32-STATIC

etc

I have applications with SSL support in a single .exe with no DLLs. --static-runtime is fo no VC_redistributable dependencies.

Then you need to allow relinking of the closed source app to make it compatible with LGPL V3

for example, using this app template:

https://marketplace.qt.io/products/qt-lgpl-app-template

Answered By: Alex

Answer #4:

Just ship the 4 DLL files from OpenSSL with your application (i.e. copy libcrypto-1_1-x64.dll, libssl-1_1-x64.dll, libcrypto-1_1.dll and libssl-1_1.dll to the installation of your application).

Builiding all libraries statically may violate LGPL license if you are using a free version of Qt.

Answered By: Miguel Angel Pons
The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 .



# More Articles