We've got a couple build systems in place that use Qt. Since we wanted to save time on signing tasks and we're required to sign all unsigned binaries that we distribute, we went ahead and signed all the Qt binaries in their installation location, and for some of our package managers using Qt dependencies, the same type of setup, except that it's packages being signed instead of the local Qt directory on the build slaves.
Today I noticed both on Jenkins and TFS build flows where using Qt projects, this little two-liner shows up in the logs:
15:24:19 Updating Qt5Core.dll.
15:24:19 Patching Qt5Core.dll...
Then later on in the build logs for Jenkins, its digital signature was unsuccessfully verified and then signed with a test-cert:
15:24:19
call "C:\Program Files (x86)\Windows Kits\10\bin\x64\signtool.exe" verify /pa C:\BuildFolder\artifacts\qt5611_win32-msvc2015\release\Qt5Core.dll
15:24:19IF NOT "!errorlevel!" == "0" echo Self-Signing C:\BuildFolder\artifacts\qt5611_win32-msvc2015\release\Qt5Core.dll & call signtool sign /f C:\DevOps\test_certificates\cert.pfx /fd SHA512 C:\BuildFolder\artifacts\qt5611_win32-msvc2015\release\Qt5Core.dll && set something_signed=true
15:24:19)
15:24:19 File: C:\BuildFolder\artifacts\qt5611_win32-msvc2015\release\Qt5Core.dll
15:24:19 Index Algorithm Timestamp
15:24:19 ========================================
15:24:19
15:24:19 Number of errors: 1
15:24:19 SignTool Error: No signature found.
15:24:19 Self-Signing C:\BuildFolder\artifacts\qt5611_win32-msvc2015\release\Qt5Core.dll
15:24:19 Done Adding Additional Store 15:24:19 Successfully signed: C:\BuildFolder\artifacts\qt5611_win32-msvc2015\release\Qt5Core.dll
Is something from QMake
or JOM
invalidating the digital signature from this Updating
/Patching
that's happening? If so, is this unavoidable? I'm not well-versed on building Qt projects on other operating systems, but I recall needing to use some tools to change where libs pointed to. The best I can figure is that something like that is happening behind the scenes with WinDeployQt
.
This is what runs right before the first two quoted lines, if you're interested in what WinDeployQt
was reporting:
15:24:18
link /NOLOGO /DYNAMICBASE /NXCOMPAT /INCREMENTAL:NO /SUBSYSTEM:CONSOLE "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='removed-by-OP' language='*' processorArchitecture='*'" /MANIFEST:embed /OUT:C:\BuildFolder\bin\release\qt_test_build.exe @C:\Users\USER~1\AppData\Local\Temp\qt_test_build.exe.4012.485.jom
15:24:19windeployqt -core --no-compiler-runtime --no-quick-import --no-translations
C:\BuildFolder\solution_directory\..\bin\release\qt_test_build.exe
15:24:19 C:\BuildFolder\bin\release\qt_test_build.exe 64 bit, release executable
15:24:19 Direct dependencies: Qt5Core
15:24:19 All dependencies : Qt5Core
15:24:19 To be deployed : Qt5Core
qmake
doesn't modify anything besides its output: its only job is to generate build scripts for another build system.
jom
is a make tool and does what nmake
would do, except in multiple processes in parallel if possible. It merely follows directions in the makefiles. I don't know of any code in qmake
that would generate makefile actions that modify Qt libraries themselves - not unless you put something explicit in the project file that will cause this. I've never seen it happen either.
That leaves windeployqt
, and it does patch Qt binaries after they are copied to the target location, since the binaries contain some embedded paths etc. If you invoke windeployqt
via your makefile/project file, then it will appear as if Qt has been modified from within job
.
Observe that the Qt binaries in original locations that you've signed remain so. In fact, your Qt installation after signing should be made read-only and have the permission set such that the build itself cannot mess it up, unless the Qt installation step is a part of the build itself.
Alas, there's a simple fix: sign stuff right before you build your install package - that'll certainly be after windeployqt
. Works for me (tm). A static build could perhaps be an option as well if your product consists of one executable, or could be made to be that way.