aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIvan Komissarov <abbapoh@gmail.com>2021-04-24 02:20:06 +0300
committerIvan Komissarov <abbapoh@gmail.com>2021-04-24 02:20:06 +0300
commita8bbaf016dc3092f6f6ad0c4a333e595da665983 (patch)
tree6b1b74bbca7850ed75da01cba5a72618f3cfa94b
parent001bf31623c02ba8249dd066777d014d546eb7f9 (diff)
parent2f6eecdc96fcd693cecef8011d8f9500c7872fc7 (diff)
Merge branch '1.19' into master
-rw-r--r--.github/workflows/main.yml6
-rw-r--r--changelogs/changes-1.18.2.md41
-rw-r--r--cmake/QbsBuildConfig.cmake3
-rw-r--r--doc/CMakeLists.txt5
-rw-r--r--doc/reference/modules/codesign-module.qdoc118
-rw-r--r--doc/reference/modules/cpp-module.qdoc27
-rw-r--r--share/CMakeLists.txt5
-rw-r--r--share/qbs/imports/qbs/Probes/ClangClProbe.qbs17
-rw-r--r--share/qbs/imports/qbs/Probes/MsvcProbe.qbs5
-rw-r--r--share/qbs/module-providers/Qt/templates/android_support.qbs80
-rw-r--r--share/qbs/module-providers/Qt/templates/qml.js25
-rw-r--r--share/qbs/module-providers/Qt/templates/qml.qbs2
-rw-r--r--share/qbs/modules/Android/sdk/utils.js3
-rw-r--r--share/qbs/modules/codesign/CodeSignModule.qbs6
-rw-r--r--share/qbs/modules/codesign/apple.qbs16
-rw-r--r--share/qbs/modules/codesign/codesign.js119
-rw-r--r--share/qbs/modules/codesign/signtool.qbs94
-rw-r--r--share/qbs/modules/cpp/CppModule.qbs2
-rw-r--r--share/qbs/modules/cpp/iar.js12
-rw-r--r--share/qbs/modules/cpp/iar.qbs6
-rw-r--r--share/qbs/modules/cpp/keil.js92
-rw-r--r--share/qbs/modules/cpp/keil.qbs6
-rw-r--r--share/qbs/modules/cpp/msvc.js7
-rw-r--r--share/qbs/modules/cpp/sdcc.js156
-rw-r--r--share/qbs/modules/cpp/sdcc.qbs5
-rw-r--r--share/qbs/modules/cpp/windows-clang-cl.qbs1
-rw-r--r--share/qbs/modules/cpp/windows-msvc-base.qbs29
-rw-r--r--share/qbs/modules/cpp/windows-msvc.qbs1
-rw-r--r--src/3rdparty/python/lib/python2.7/site-packages/dmgbuild/core.py79
-rw-r--r--src/app/qbs-setup-toolchains/msvcprobe.cpp15
-rw-r--r--src/lib/corelib/jsextensions/utilitiesextension.cpp32
-rw-r--r--src/lib/corelib/tools/msvcinfo.cpp32
-rw-r--r--src/lib/corelib/tools/msvcinfo.h7
-rw-r--r--src/lib/corelib/tools/set.h4
-rw-r--r--src/lib/corelib/tools/stlutils.h15
-rw-r--r--src/lib/corelib/tools/vsenvironmentdetector.cpp9
-rw-r--r--src/lib/corelib/tools/vsenvironmentdetector.h3
-rw-r--r--src/lib/scriptengine/scriptengine.qbs7
-rw-r--r--tests/auto/auto.qbs3
-rw-r--r--tests/auto/blackbox/CMakeLists.txt9
-rw-r--r--tests/auto/blackbox/blackbox-windows.pro18
-rw-r--r--tests/auto/blackbox/blackbox-windows.qbs21
-rw-r--r--tests/auto/blackbox/testdata-baremetal/compiler-listing/compiler-listing.qbs (renamed from tests/auto/blackbox/testdata-baremetal/generate-compiler-listing/generate-compiler-listing.qbs)4
-rw-r--r--tests/auto/blackbox/testdata-baremetal/compiler-listing/fun.c (renamed from tests/auto/blackbox/testdata-baremetal/do-not-generate-compiler-listing/fun.c)0
-rw-r--r--tests/auto/blackbox/testdata-baremetal/compiler-listing/main.c (renamed from tests/auto/blackbox/testdata-baremetal/do-not-generate-compiler-listing/main.c)0
-rw-r--r--tests/auto/blackbox/testdata-baremetal/do-not-generate-compiler-listing/do-not-generate-compiler-listing.qbs16
-rw-r--r--tests/auto/blackbox/testdata-baremetal/external-static-libraries/external-static-libraries.qbs14
-rw-r--r--tests/auto/blackbox/testdata-baremetal/generate-compiler-listing/fun.c4
-rw-r--r--tests/auto/blackbox/testdata-baremetal/generate-compiler-listing/main.c6
-rw-r--r--tests/auto/blackbox/testdata-baremetal/linker-map/linker-map.qbs6
-rw-r--r--tests/auto/blackbox/testdata-windows/codesign/app.cpp1
-rw-r--r--tests/auto/blackbox/testdata-windows/codesign/codesign.qbs37
-rw-r--r--tests/auto/blackbox/tst_blackboxbaremetal.cpp96
-rw-r--r--tests/auto/blackbox/tst_blackboxwindows.cpp174
-rw-r--r--tests/auto/blackbox/tst_blackboxwindows.h51
-rw-r--r--tests/auto/tools/tst_tools.cpp24
-rw-r--r--tests/auto/tools/tst_tools.h1
57 files changed, 1319 insertions, 258 deletions
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 951ddc1c3..98c1a8b11 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -631,6 +631,12 @@ jobs:
qbs config defaultProfile qt
qbs config --list
shell: bash
+ - name: Setup self-signed certificate
+ run: |
+ New-SelfSignedCertificate -DnsName qbs@community.test -Type CodeSigning -CertStoreLocation cert:\CurrentUser\My
+ Export-Certificate -Cert (Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert)[0] -FilePath qbs-code-signing.crt
+ Import-Certificate -FilePath .\qbs-code-signing.crt -CertStoreLocation Cert:\CurrentUser\TrustedPublisher
+ shell: powershell
- name: Run Tests
run: ${{ matrix.config.script }} ./release/install-root/bin
shell: bash
diff --git a/changelogs/changes-1.18.2.md b/changelogs/changes-1.18.2.md
new file mode 100644
index 000000000..5019e491f
--- /dev/null
+++ b/changelogs/changes-1.18.2.md
@@ -0,0 +1,41 @@
+# C/C++ Support
+
+* qbs-setup-toolchains is now able to detect clang-cl properly
+* The Library and Include probes take more paths into account on Linux to better
+ support containerization systems such as Flatpak.
+* Xcode autodetection now uses xcode-select to find Xcode on the system.
+
+
+# Protocol Buffers Support (Protobuf Module)
+
+* A missing nanopb generator file extension on windows has been added.
+* The problem that property _libraryName was incorrect when protobuf was not
+ found has been fixed.
+
+
+# Android Support
+
+* An assertion when building Android applications using additional java classes
+ with native methods has been fixed (QBS-1628).
+
+
+# Qt Support
+
+* A problem related to handling Qt6EntryPoint in the Qt module provider has been
+ fixed.
+
+
+# Infrastructure
+
+* A Qt4 docker image for basic testing has been added.
+
+
+# Contributors
+
+* Christian Kandeler
+* Eike Ziller
+* Ivan Komissarov
+* Jan Blackquill
+* Kai Dohmen
+* Raphaël Cotty
+* Richard Weickelt
diff --git a/cmake/QbsBuildConfig.cmake b/cmake/QbsBuildConfig.cmake
index 111778dc7..b6614ce3f 100644
--- a/cmake/QbsBuildConfig.cmake
+++ b/cmake/QbsBuildConfig.cmake
@@ -60,7 +60,8 @@ function(get_update_path_command var)
endif()
get_filename_component(_QT_LIBRARY_PATH "${_QTCORE_LIBRARY}" DIRECTORY)
get_target_property(_QBS_LIBRARY_PATH qbscore LIBRARY_OUTPUT_DIRECTORY)
- set(${var} "PATH=${_QT_LIBRARY_PATH}\;${_QBS_LIBRARY_PATH}\;%PATH%" PARENT_SCOPE)
+ file(TO_NATIVE_PATH "${_QT_LIBRARY_PATH}\;${_QBS_LIBRARY_PATH}\;$ENV{PATH}" _NEW_PATH)
+ set(${var} "PATH=${_NEW_PATH}" PARENT_SCOPE)
else()
set(${var} "")
endif()
diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt
index 74d71f4dc..0b5922a1a 100644
--- a/doc/CMakeLists.txt
+++ b/doc/CMakeLists.txt
@@ -46,8 +46,7 @@ if (QBS_INSTALL_HTML_DOCS OR QBS_INSTALL_QCH_DOCS)
get_update_path_command(UPDATE_PATH_COMMAND)
add_custom_target(
BuildQbsDocumentation ALL
- COMMAND ${UPDATE_PATH_COMMAND}
- COMMAND ${_QBS_OUTPUT_DIR}/qbs
+ COMMAND ${CMAKE_COMMAND} -E env "${UPDATE_PATH_COMMAND}" ${_QBS_OUTPUT_DIR}/qbs
resolve
--settings-dir ${PROJECT_BINARY_DIR}/settings
-f ${PROJECT_SOURCE_DIR}/qbs.qbs
@@ -62,7 +61,7 @@ if (QBS_INSTALL_HTML_DOCS OR QBS_INSTALL_QCH_DOCS)
modules.qbsbuildconfig.installHtml:${_INSTALL_HTML_DOCS}
modules.qbsbuildconfig.installQch:${_INSTALL_QCH_DOCS}
moduleProviders.Qt.qmakeFilePaths:${_QT_QMAKE_EXECUTABLE}
- COMMAND ${_QBS_OUTPUT_DIR}/qbs
+ COMMAND ${CMAKE_COMMAND} -E env "${UPDATE_PATH_COMMAND}" ${_QBS_OUTPUT_DIR}/qbs
build
--settings-dir ${PROJECT_BINARY_DIR}/settings
-f ${PROJECT_SOURCE_DIR}/qbs.qbs
diff --git a/doc/reference/modules/codesign-module.qdoc b/doc/reference/modules/codesign-module.qdoc
index 70a37477b..d0aba4688 100644
--- a/doc/reference/modules/codesign-module.qdoc
+++ b/doc/reference/modules/codesign-module.qdoc
@@ -63,15 +63,25 @@
*/
/*!
- \qmlproperty string codesign::codesignFlags
+ \qmlproperty string codesign::signingTimestamp
- Additional flags passed to the \c{codesign} tool.
+ URL of the timestamp authority RFC 3161 server to be contacted to authenticate code signing.
+ \c undefined or \c empty indicates that a system-specific default should be used;
+ \c{"none"} explicitly disables the use of timestamp services on Apple platforms.
\since Qbs 1.19
- \defaultvalue \c{undefined}
+ \defaultvalue \c "none" on Apple, \c undefined otherwise
+*/
+
+/*!
+ \qmlproperty stringList codesign::codesignFlags
- \appleproperty
+ Additional flags passed to the \c{codesign} tool.
+
+ \since Qbs 1.19
+
+ \nodefaultvalue
*/
/*!
@@ -81,9 +91,7 @@
\since Qbs 1.19
- \defaultvalue \c{"codesign"}
-
- \appleproperty
+ \defaultvalue Determined automatically
*/
/*!
@@ -94,8 +102,6 @@
\since Qbs 1.19
\defaultvalue Determined automatically
-
- \appleproperty
*/
/*!
@@ -104,6 +110,7 @@
Whether to actually perform code signing.
\since Qbs 1.19
+
\defaultvalue \c false
*/
@@ -164,21 +171,6 @@
*/
/*!
- \qmlproperty string codesign::signingTimestamp
-
- URL of the timestamp authority server to be contacted to authenticate code signing.
- \c{undefined} indicates that a system-specific default should be used, and the empty
- string indicates the default server provided by Apple. \c{"none"} explicitly disables
- the use of timestamp services and this should not usually need to be changed.
-
- \since Qbs 1.19
-
- \defaultvalue \c{"none"}
-
- \appleproperty
-*/
-
-/*!
\qmlproperty string codesign::signingType
Type of code signing to use. This should generally be used in preference to an explicit
@@ -307,3 +299,81 @@
\androidproperty
*/
+
+/*!
+ \qmlproperty string codesign::subjectName
+
+ Specifies the name of the subject of the signing certificate.
+ This value can be a substring of the entire subject name.
+
+ \since Qbs 1.19
+
+ \defaultvalue \c undefined
+
+ \windowsproperty
+*/
+
+/*!
+ \qmlproperty string codesign::rootSubjectName
+
+ Specifies the name of the subject of the root certificate that
+ the signing certificate must chain to. This value may be a substring
+ of the entire subject name of the root certificate.
+
+ \since Qbs 1.19
+
+ \defaultvalue \c undefined
+
+ \windowsproperty
+*/
+
+/*!
+ \qmlproperty string codesign::hashAlgorithm
+
+ Specifies the default hash algorithm used on the signing certificate.
+ The possible values are \c sha1, \c sha256, \c sha384, and \c sha512.
+
+ \note Only available in Windows 10 kit builds 20236 and later.
+
+ \since Qbs 1.19
+
+ \defaultvalue \c undefined
+
+ \windowsproperty
+*/
+
+/*!
+ \qmlproperty string codesign::certificatePath
+
+ Specifies the full path to the signing certificate file (*.pfx).
+
+ \since Qbs 1.19
+
+ \defaultvalue \c undefined
+
+ \windowsproperty
+*/
+
+/*!
+ \qmlproperty string codesign::certificatePassword
+
+ Specifies the password to use when opening a signing certificate file (*.pfx).
+
+ \since Qbs 1.19
+
+ \defaultvalue \c undefined
+
+ \windowsproperty
+*/
+
+/*!
+ \qmlproperty string codesign::crossCertificatePath
+
+ Specifies the full path to the additional certificate file (*.cer).
+
+ \since Qbs 1.19
+
+ \defaultvalue \c undefined
+
+ \windowsproperty
+*/
diff --git a/doc/reference/modules/cpp-module.qdoc b/doc/reference/modules/cpp-module.qdoc
index 1b09320f0..1628bc80e 100644
--- a/doc/reference/modules/cpp-module.qdoc
+++ b/doc/reference/modules/cpp-module.qdoc
@@ -634,6 +634,22 @@
*/
/*!
+ \qmlproperty string cpp::compilerListingSuffix
+
+ A string to append to the generated compiler listing files.
+
+ \defaultvalue \l{qbs::toolchain}{toolchain}-dependent, typical value is \c ".lst"
+*/
+
+/*!
+ \qmlproperty string cpp::assemblerListingSuffix
+
+ A string to append to the generated assembler listing files.
+
+ \defaultvalue \l{qbs::toolchain}{toolchain}-dependent, typical value is \c ".lst"
+*/
+
+/*!
\qmlproperty pathList cpp::prefixHeaders
\since Qbs 1.0.1
@@ -1898,3 +1914,14 @@
\defaultvalue \c{true}
*/
+
+/*!
+ \qmlproperty string cpp::windowsSdkVersion
+ \since Qbs 1.19
+
+ Which Windows SDK version should be used with MSVC toolchain. By default,
+ the latest SDK is used.
+
+ \windowsproperty
+ \nodefaultvalue
+*/
diff --git a/share/CMakeLists.txt b/share/CMakeLists.txt
index f607e0a85..bde65d450 100644
--- a/share/CMakeLists.txt
+++ b/share/CMakeLists.txt
@@ -36,8 +36,7 @@ get_update_path_command(UPDATE_PATH_COMMAND)
get_target_property(_QBS_OUTPUT_DIR qbs RUNTIME_OUTPUT_DIRECTORY)
add_custom_target(
BuildQbsResources ALL
- COMMAND ${UPDATE_PATH_COMMAND}
- COMMAND ${_QBS_OUTPUT_DIR}/qbs
+ COMMAND ${CMAKE_COMMAND} -E env "${UPDATE_PATH_COMMAND}" ${_QBS_OUTPUT_DIR}/qbs
resolve
--settings-dir ${PROJECT_BINARY_DIR}/settings
-f ${PROJECT_SOURCE_DIR}/qbs.qbs
@@ -47,7 +46,7 @@ add_custom_target(
project.withCode:false
project.withDocumentation:false
profile:none
- COMMAND ${_QBS_OUTPUT_DIR}/qbs
+ COMMAND ${CMAKE_COMMAND} -E env "${UPDATE_PATH_COMMAND}" ${_QBS_OUTPUT_DIR}/qbs
build
--settings-dir ${PROJECT_BINARY_DIR}/settings
-f ${PROJECT_SOURCE_DIR}/qbs.qbs
diff --git a/share/qbs/imports/qbs/Probes/ClangClProbe.qbs b/share/qbs/imports/qbs/Probes/ClangClProbe.qbs
index 8205e92fa..658da8a9f 100644
--- a/share/qbs/imports/qbs/Probes/ClangClProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/ClangClProbe.qbs
@@ -42,6 +42,7 @@ PathProbe {
property string preferredArchitecture
property string _nullDevice: qbs.nullDevice
property string _pathListSeparator: qbs.pathListSeparator
+ property string winSdkVersion
// Outputs
property int versionMajor
@@ -58,9 +59,21 @@ PathProbe {
languages = ["c"];
var info = languages.contains("c")
- ? Utilities.clangClCompilerInfo(compilerFilePath, preferredArchitecture, vcvarsallFilePath, "c") : {};
+ ? Utilities.clangClCompilerInfo(
+ compilerFilePath,
+ preferredArchitecture,
+ vcvarsallFilePath,
+ "c",
+ winSdkVersion)
+ : {};
var infoCpp = languages.contains("cpp")
- ? Utilities.clangClCompilerInfo(compilerFilePath, preferredArchitecture, vcvarsallFilePath, "cpp") : {};
+ ? Utilities.clangClCompilerInfo(
+ compilerFilePath,
+ preferredArchitecture,
+ vcvarsallFilePath,
+ "cpp",
+ winSdkVersion)
+ : {};
found = (!languages.contains("c") ||
(!!info && !!info.macros && !!info.buildEnvironment))
&& (!languages.contains("cpp") ||
diff --git a/share/qbs/imports/qbs/Probes/MsvcProbe.qbs b/share/qbs/imports/qbs/Probes/MsvcProbe.qbs
index 2d5faecdd..d3624e010 100644
--- a/share/qbs/imports/qbs/Probes/MsvcProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/MsvcProbe.qbs
@@ -38,6 +38,7 @@ PathProbe {
property string compilerFilePath
property stringList enableDefinesByLanguage
property string preferredArchitecture
+ property string winSdkVersion
// Outputs
property string architecture
@@ -54,9 +55,9 @@ PathProbe {
languages = ["c"];
var info = languages.contains("c")
- ? Utilities.msvcCompilerInfo(compilerFilePath, "c") : {};
+ ? Utilities.msvcCompilerInfo(compilerFilePath, "c", winSdkVersion) : {};
var infoCpp = languages.contains("cpp")
- ? Utilities.msvcCompilerInfo(compilerFilePath, "cpp") : {};
+ ? Utilities.msvcCompilerInfo(compilerFilePath, "cpp", winSdkVersion) : {};
found = (!languages.contains("c") ||
(!!info && !!info.macros && !!info.buildEnvironment))
&& (!languages.contains("cpp") ||
diff --git a/share/qbs/module-providers/Qt/templates/android_support.qbs b/share/qbs/module-providers/Qt/templates/android_support.qbs
index 87c980448..68a29bb95 100644
--- a/share/qbs/module-providers/Qt/templates/android_support.qbs
+++ b/share/qbs/module-providers/Qt/templates/android_support.qbs
@@ -4,6 +4,7 @@ import qbs.ModUtils
import qbs.TextFile
import qbs.Utilities
import qbs.Process
+import qbs.Xml
Module {
version: @version@
@@ -35,6 +36,10 @@ Module {
property bool _multiAbi: Utilities.versionCompare(version, "5.14") >= 0
+ // QTBUG-87288: correct QtNetwork jar dependencies for 5.15.0 < Qt < 5.15.3
+ property bool _correctQtNetworkDependencies: Utilities.versionCompare(version, "5.15.0") > 0 &&
+ Utilities.versionCompare(version, "5.15.3") < 0
+
Depends { name: "Android.sdk"; condition: _enableSdkSupport }
Depends { name: "Android.ndk"; condition: _enableNdkSupport }
Depends { name: "java"; condition: _enableSdkSupport }
@@ -355,8 +360,6 @@ Module {
var moveCmd = new JavaScriptCommand();
moveCmd.description = "processing androiddeployqt outout";
moveCmd.sourceCode = function() {
- File.move(product.Qt.android_support._deployQtOutDir + "/AndroidManifest.xml",
- outputs["android.manifest_final"][0].filePath);
var libsDir = product.Qt.android_support._deployQtOutDir + "/libs";
var libDir = product.Android.sdk.packageContentsDir + "/lib";
var listFilePath = outputs["android.deployqt_list"][0].filePath;
@@ -400,7 +403,78 @@ Module {
File.remove(oldLibs[i]);
}
};
- return [copyCmd, androidDeployQtCmd, moveCmd];
+
+ var correctingCmd = new JavaScriptCommand();
+ if (product.Qt.android_support._correctQtNetworkDependencies) {
+ correctingCmd.description = "correcting network jar dependency";
+ correctingCmd.sourceCode = function() {
+ var findNetworkLib = function() {
+ var libsDir = product.Android.sdk.packageContentsDir + "/lib";
+ var dirList = File.directoryEntries(libsDir, File.Dirs |
+ File.NoDotAndDotDot);
+ for (var i = 0; i < dirList.length; ++i) {
+ var archDir = FileInfo.joinPaths(libsDir, dirList[i]);
+ var fileList = File.directoryEntries(archDir, File.Files);
+ if (fileList) {
+ for (var j = 0; j < fileList.length; ++j) {
+ if (fileList[j].contains("libQt5Network")) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ if (findNetworkLib()) {
+ var manifestData = new Xml.DomDocument();
+ var manifestFilePath = product.Qt.android_support._deployQtOutDir +
+ "/AndroidManifest.xml"
+ manifestData.load(manifestFilePath);
+
+ var rootElem = manifestData.documentElement();
+ if (!rootElem || !rootElem.isElement() || rootElem.tagName() != "manifest")
+ throw "No manifest tag found in '" + manifestFilePath + "'.";
+ var appElem = rootElem.firstChild("application");
+ if (!appElem || !appElem.isElement() || appElem.tagName() != "application")
+ throw "No application tag found in '" + manifestFilePath + "'.";
+ var activityElem = appElem.firstChild("activity");
+ if (!activityElem || !activityElem.isElement() ||
+ activityElem.tagName() != "activity")
+ throw "No activity tag found in '" + manifestFilePath + "'.";
+ var metaDataElem = activityElem.firstChild("meta-data");
+ while (metaDataElem && metaDataElem.isElement()) {
+ if (metaDataElem.attribute("android:name") ==
+ "android.app.load_local_jars" ) {
+ var value = metaDataElem.attribute("android:value");
+ var fileName = "QtAndroidNetwork.jar";
+ metaDataElem.setAttribute("android:value", value + ":jar/" +
+ fileName);
+ var jarFilePath = FileInfo.joinPaths(
+ product.Qt.android_support._qtInstallDir, "jar",
+ fileName);
+ var targetFilePath = FileInfo.joinPaths(product.java.classFilesDir,
+ fileName);
+ File.copy(jarFilePath, targetFilePath);
+ break;
+ }
+ metaDataElem = metaDataElem.nextSibling("meta-data");
+ }
+ manifestData.save(outputs["android.manifest_final"][0].filePath, 4);
+ } else {
+ File.move(product.Qt.android_support._deployQtOutDir + "/AndroidManifest.xml",
+ outputs["android.manifest_final"][0].filePath);
+ }
+ };
+ } else {
+ correctingCmd.description = "copying manifest";
+ correctingCmd.sourceCode = function() {
+ File.move(product.Qt.android_support._deployQtOutDir + "/AndroidManifest.xml",
+ outputs["android.manifest_final"][0].filePath);
+ }
+ }
+
+ return [copyCmd, androidDeployQtCmd, moveCmd, correctingCmd];
}
}
diff --git a/share/qbs/module-providers/Qt/templates/qml.js b/share/qbs/module-providers/Qt/templates/qml.js
index df69034fe..e48c9230e 100644
--- a/share/qbs/module-providers/Qt/templates/qml.js
+++ b/share/qbs/module-providers/Qt/templates/qml.js
@@ -3,14 +3,31 @@ var FileInfo = require("qbs.FileInfo");
var Process = require("qbs.Process");
var TextFile = require("qbs.TextFile");
-function scannerData(scannerFilePath, qmlFiles, qmlPath)
+function scannerData(scannerFilePath, qmlFiles, qmlPath, targetOS)
{
var p;
try {
p = new Process();
- p.exec(scannerFilePath, ["-qmlFiles"].concat(qmlFiles).concat(["-importPath", qmlPath]),
- true);
- return JSON.parse(p.readStdOut());
+ if (!targetOS.contains("windows")) {
+ p.exec(scannerFilePath, ["-qmlFiles"].concat(qmlFiles).concat(["-importPath", qmlPath]),
+ true);
+ return JSON.parse(p.readStdOut());
+ }
+ var data = [];
+ var nextFileIndex = 0;
+ while (nextFileIndex < qmlFiles.length) {
+ var currentFileList = [];
+ var currentFileListStringLength = 0;
+ while (nextFileIndex < qmlFiles.length && currentFileListStringLength < 30000) {
+ var currentFile = qmlFiles[nextFileIndex++];
+ currentFileList.push(currentFile);
+ currentFileListStringLength += currentFile.length;
+ }
+ p.exec(scannerFilePath, ["-qmlFiles"].concat(currentFileList)
+ .concat(["-importPath", qmlPath]), true);
+ data = data.concat(JSON.parse(p.readStdOut()));
+ }
+ return data;
} finally {
if (p)
p.close();
diff --git a/share/qbs/module-providers/Qt/templates/qml.qbs b/share/qbs/module-providers/Qt/templates/qml.qbs
index f608ba4dd..af7b0fb5f 100644
--- a/share/qbs/module-providers/Qt/templates/qml.qbs
+++ b/share/qbs/module-providers/Qt/templates/qml.qbs
@@ -144,7 +144,7 @@ QtModule {
qmlInputs = [];
var scannerData = Qml.scannerData(product.Qt.qml.qmlImportScannerFilePath,
qmlInputs.map(function(inp) { return inp.filePath; }),
- product.Qt.qml.qmlPath);
+ product.Qt.qml.qmlPath, product.qbs.targetOS);
var cppFile;
var listFile;
try {
diff --git a/share/qbs/modules/Android/sdk/utils.js b/share/qbs/modules/Android/sdk/utils.js
index 9511ae9de..264ad2da7 100644
--- a/share/qbs/modules/Android/sdk/utils.js
+++ b/share/qbs/modules/Android/sdk/utils.js
@@ -174,7 +174,8 @@ function prepareAapt2CompileResource(project, product, inputs, outputs, input, o
throw "Cannot create directory '" + FileInfo.toNativeSeparators(compilesResourcesDir) +
"'.";
}
- var args = ["compile", input.filePath, "-o", compilesResourcesDir];
+ var args = ["compile", FileInfo.toNativeSeparators(input.filePath),
+ "-o", FileInfo.toNativeSeparators(compilesResourcesDir)];
var cmd = new Command(product.Android.sdk.aaptFilePath, args);
var outputFileName = generateAapt2ResourceFileName(input.filePath);
cmd.description = "compiling resource " + input.fileName + " into " + outputFileName;
diff --git a/share/qbs/modules/codesign/CodeSignModule.qbs b/share/qbs/modules/codesign/CodeSignModule.qbs
index 1951ec374..2115baebf 100644
--- a/share/qbs/modules/codesign/CodeSignModule.qbs
+++ b/share/qbs/modules/codesign/CodeSignModule.qbs
@@ -43,5 +43,11 @@ Module {
property string codesignPath: codesignName
property stringList codesignFlags
+ property string signingTimestamp
+ PropertyOptions {
+ name: "signingTimestamp"
+ description: "URL of the RFC 3161 time stamp server."
+ }
+
property bool _canSignArtifacts: false // whether can sign individual actifacts
}
diff --git a/share/qbs/modules/codesign/apple.qbs b/share/qbs/modules/codesign/apple.qbs
index 06f07d72d..565d29080 100644
--- a/share/qbs/modules/codesign/apple.qbs
+++ b/share/qbs/modules/codesign/apple.qbs
@@ -96,7 +96,7 @@ CodeSignModule {
}
}
- property string signingTimestamp: "none"
+ signingTimestamp: "none"
property string provisioningProfile
PropertyOptions {
@@ -125,7 +125,7 @@ CodeSignModule {
var identities = CodeSign.findSigningIdentities(signingIdentity, teamIdentifier);
if (identities && Object.keys(identities).length > 1) {
throw "Multiple codesigning identities (i.e. certificate and private key pairs) " +
- "matching “" + signingIdentity + "” were found." +
+ "matching '" + signingIdentity + "' were found." +
CodeSign.humanReadableIdentitySummary(identities);
}
@@ -240,17 +240,17 @@ CodeSignModule {
}
});
} else if (uuid) {
- throw "Your build settings specify a provisioning profile with the UUID “"
- + uuid + "”, however, no such provisioning profile was found.";
+ throw "Your build settings specify a provisioning profile with the UUID '"
+ + uuid + "', however, no such provisioning profile was found.";
} else if (product._provisioningProfileRequired) {
var hasProfiles = !!((inputs["codesign.provisioningprofile"] || []).length);
var teamIdentifier = product.teamIdentifier;
var codeSignIdentity = product.signingIdentity;
if (hasProfiles) {
if (codeSignIdentity) {
- console.warn("No provisioning profiles matching the bundle identifier “"
+ console.warn("No provisioning profiles matching the bundle identifier '"
+ product.bundle.identifier
- + "” were found.");
+ + "' were found.");
} else {
console.warn("No provisioning profiles matching an applicable signing "
+ "identity were found.");
@@ -260,13 +260,13 @@ CodeSignModule {
if (teamIdentifier) {
console.warn("No provisioning profiles with a valid signing identity "
+ "(i.e. certificate and private key pair) matching the "
- + "team ID “" + teamIdentifier + "” were found.")
+ + "team ID '" + teamIdentifier + "' were found.")
} else {
console.warn("No provisioning profiles with a valid signing identity "
+ "(i.e. certificate and private key pair) were found.");
}
} else {
- console.warn("No non–expired provisioning profiles were found.");
+ console.warn("No non-expired provisioning profiles were found.");
}
}
}
diff --git a/share/qbs/modules/codesign/codesign.js b/share/qbs/modules/codesign/codesign.js
index bf7e95224..5aa303c9c 100644
--- a/share/qbs/modules/codesign/codesign.js
+++ b/share/qbs/modules/codesign/codesign.js
@@ -202,6 +202,75 @@ function findBestProvisioningProfile(product, files) {
}
}
+/**
+ * Finds out the search paths for the `signtool.exe` utility supplied with
+ * the Windows SDK's.
+ */
+function findBestSignToolSearchPaths(arch) {
+ var searchPaths = [];
+ var keys = [
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows",
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Microsoft SDKs\\Windows"
+ ];
+ for (var keyIndex = 0; keyIndex < keys.length; ++keyIndex) {
+ var re = /^v([0-9]+)\.([0-9]+)$/;
+ var groups = Utilities.nativeSettingGroups(keys[keyIndex]).filter(function(version) {
+ return version.match(re);
+ });
+
+ groups.sort(function(a, b) {
+ return Utilities.versionCompare(b.substring(1), a.substring(1));
+ });
+
+ function addSearchPath(searchPath) {
+ if (File.exists(searchPath) && !searchPaths.contains(searchPath)) {
+ searchPaths.push(searchPath);
+ return true;
+ }
+ return false;
+ }
+
+ for (var groupIndex = 0; groupIndex < groups.length; ++groupIndex) {
+ var fullKey = keys[keyIndex] + "\\" + groups[groupIndex];
+ var fullVersion = Utilities.getNativeSetting(fullKey, "ProductVersion");
+ if (fullVersion) {
+ var installRoot = FileInfo.cleanPath(
+ Utilities.getNativeSetting(fullKey, "InstallationFolder"));
+ if (installRoot) {
+ // Try to add the architecture-independent path at first.
+ var searchPath = FileInfo.joinPaths(installRoot, "App Certification Kit");
+ if (!addSearchPath(searchPath)) {
+ // Try to add the architecture-dependent paths at second.
+ var binSearchPath = FileInfo.joinPaths(installRoot, "bin/" + fullVersion);
+ if (!File.exists(binSearchPath)) {
+ binSearchPath += ".0";
+ if (!File.exists(binSearchPath))
+ continue;
+ }
+
+ function kitsArchitectureSubDirectory(arch) {
+ if (arch === "x86")
+ return "x86";
+ else if (arch === "x86_64")
+ return "x64";
+ else if (arch.startsWith("arm64"))
+ return "arm64";
+ else if (arch.startsWith("arm"))
+ return "arm";
+ }
+
+ var archDir = kitsArchitectureSubDirectory(arch);
+ searchPath = FileInfo.joinPaths(binSearchPath, archDir);
+ addSearchPath(searchPath);
+ }
+ }
+ }
+ }
+ }
+
+ return searchPaths;
+}
+
function prepareSign(project, product, inputs, outputs, input, output) {
var cmd, cmds = [];
@@ -243,10 +312,10 @@ function prepareSign(project, product, inputs, outputs, input, output) {
args.push("--force");
args.push("--sign", actualSigningIdentity.SHA1);
- // If signingTimestamp is undefined, do not specify the flag at all -
+ // If signingTimestamp is undefined or empty, do not specify the flag at all -
// this uses the system-specific default behavior
var signingTimestamp = product.codesign.signingTimestamp;
- if (signingTimestamp !== undefined) {
+ if (signingTimestamp) {
// If signingTimestamp is an empty string, specify the flag but do
// not specify a value - this uses a default Apple-provided server
var flag = "--timestamp";
@@ -349,3 +418,49 @@ function createDebugKeyStoreCommandString(keytoolFilePath, keystoreFilePath, key
"CN=Android Debug,O=Android,C=US"];
return Process.shellQuote(keytoolFilePath, args);
}
+
+function prepareSigntool(project, product, inputs, outputs, input, output) {
+ var cmd, cmds = [];
+
+ if (!product.codesign.enableCodeSigning)
+ return cmds;
+
+ var args = ["sign"].concat(product.codesign.codesignFlags || []);
+
+ var subjectName = product.codesign.subjectName;
+ if (subjectName)
+ args.push("/n", subjectName);
+
+ var rootSubjectName = product.codesign.rootSubjectName;
+ if (rootSubjectName)
+ args.push("/r", rootSubjectName);
+
+ var hashAlgorithm = product.codesign.hashAlgorithm;
+ if (hashAlgorithm)
+ args.push("/fd", hashAlgorithm);
+
+ var signingTimestamp = product.codesign.signingTimestamp;
+ if (signingTimestamp)
+ args.push("/tr", signingTimestamp);
+
+ var certificatePath = product.codesign.certificatePath;
+ if (certificatePath)
+ args.push("/f", certificatePath);
+
+ var certificatePassword = product.codesign.certificatePassword;
+ if (certificatePassword)
+ args.push("/p", certificatePassword);
+
+ var crossCertificatePath = product.codesign.crossCertificatePath;
+ if (crossCertificatePath)
+ args.push("/ac", crossCertificatePath);
+
+ var outputArtifact = outputs["codesign.signed_artifact"][0];
+ args.push(outputArtifact.filePath);
+
+ cmd = new Command(product.codesign.codesignPath, args);
+ cmd.description = "signing " + outputArtifact.fileName;
+ cmd.highlight = "linker";
+ cmds.push(cmd);
+ return cmds;
+}
diff --git a/share/qbs/modules/codesign/signtool.qbs b/share/qbs/modules/codesign/signtool.qbs
new file mode 100644
index 000000000..13933c6f6
--- /dev/null
+++ b/share/qbs/modules/codesign/signtool.qbs
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+import qbs
+import qbs.File
+import qbs.ModUtils
+import qbs.Probes
+import "codesign.js" as CODESIGN
+
+CodeSignModule {
+ condition: qbs.targetOS.contains("windows") && qbs.hostOS.contains("windows")
+
+ _canSignArtifacts: true
+
+ Probes.BinaryProbe {
+ id: signtoolProbe
+ names: [codesignName]
+ searchPaths: CODESIGN.findBestSignToolSearchPaths(qbs.hostArchitecture)
+ }
+
+ codesignName: "signtool"
+ codesignPath: signtoolProbe.filePath
+
+ property string subjectName
+ PropertyOptions {
+ name: "subjectName"
+ description: "Name of the subject of the signing certificate."
+ }
+
+ property string rootSubjectName
+ PropertyOptions {
+ name: "rootSubjectName"
+ description: "Name of the subject of the root certificate that the signing " +
+ "certificate must chain to."
+ }
+
+ property string hashAlgorithm
+ PropertyOptions {
+ name: "hashAlgorithm"
+ description: "Name of the hash algorithm used on the signing certificate."
+ allowedValues: ["sha1", "sha256", "sha384", "sha512"]
+ }
+
+ property path certificatePath
+ PropertyOptions {
+ name: "certificatePath"
+ description: "Path to the signing certificate PFX file."
+ }
+
+ property path certificatePassword
+ PropertyOptions {
+ name: "certificatePassword"
+ description: "Password to use when opening a certificate PFX file."
+ }
+
+ property path crossCertificatePath
+ PropertyOptions {
+ name: "crossCertificatePath"
+ description: "Path to the additional certificate CER file."
+ }
+
+ validate: {
+ if (enableCodeSigning && !File.exists(codesignPath)) {
+ throw ModUtils.ModuleError("Could not find 'signtool' utility");
+ }
+ }
+}
diff --git a/share/qbs/modules/cpp/CppModule.qbs b/share/qbs/modules/cpp/CppModule.qbs
index 761e8be85..39077bec8 100644
--- a/share/qbs/modules/cpp/CppModule.qbs
+++ b/share/qbs/modules/cpp/CppModule.qbs
@@ -188,6 +188,8 @@ Module {
property string dynamicLibraryImportSuffix: ".lib"
property string objectSuffix: ".o"
property string linkerMapSuffix: ".map"
+ property string compilerListingSuffix: ".lst"
+ property string assemblerListingSuffix: ".lst"
property bool createSymlinks: true
property stringList dynamicLibraries // list of names, will be linked with -lname
property stringList staticLibraries // list of static library files
diff --git a/share/qbs/modules/cpp/iar.js b/share/qbs/modules/cpp/iar.js
index a1f1a9a88..416de7ee2 100644
--- a/share/qbs/modules/cpp/iar.js
+++ b/share/qbs/modules/cpp/iar.js
@@ -612,18 +612,24 @@ function collectLibraryDependencies(product) {
return result;
}
-function compilerOutputArtifacts(input, useListing) {
+function compilerOutputArtifacts(input, isCompilerArtifacts) {
var artifacts = [];
artifacts.push({
fileTags: ["obj"],
filePath: Utilities.getHash(input.baseDir) + "/"
+ input.fileName + input.cpp.objectSuffix
});
- if (useListing) {
+ if (isCompilerArtifacts && input.cpp.generateCompilerListingFiles) {
artifacts.push({
fileTags: ["lst"],
filePath: Utilities.getHash(input.baseDir) + "/"
- + input.fileName + ".lst"
+ + input.fileName + input.cpp.compilerListingSuffix
+ });
+ } else if (!isCompilerArtifacts && input.cpp.generateAssemblerListingFiles) {
+ artifacts.push({
+ fileTags: ["lst"],
+ filePath: Utilities.getHash(input.baseDir) + "/"
+ + input.fileName + input.cpp.assemblerListingSuffix
});
}
return artifacts;
diff --git a/share/qbs/modules/cpp/iar.qbs b/share/qbs/modules/cpp/iar.qbs
index 6c00f8f36..9709695c1 100644
--- a/share/qbs/modules/cpp/iar.qbs
+++ b/share/qbs/modules/cpp/iar.qbs
@@ -99,8 +99,7 @@ CppModule {
id: assembler
inputs: ["asm"]
outputFileTags: ["obj", "lst"]
- outputArtifacts: IAR.compilerOutputArtifacts(
- input, input.cpp.generateAssemblerListingFiles)
+ outputArtifacts: IAR.compilerOutputArtifacts(input, false)
prepare: IAR.prepareAssembler.apply(IAR, arguments)
}
@@ -114,8 +113,7 @@ CppModule {
inputs: ["cpp", "c"]
auxiliaryInputs: ["hpp"]
outputFileTags: ["obj", "lst"]
- outputArtifacts: IAR.compilerOutputArtifacts(
- input, input.cpp.generateCompilerListingFiles)
+ outputArtifacts: IAR.compilerOutputArtifacts(input, true)
prepare: IAR.prepareCompiler.apply(IAR, arguments)
}
diff --git a/share/qbs/modules/cpp/keil.js b/share/qbs/modules/cpp/keil.js
index 567b0ddd3..27e4e12d7 100644
--- a/share/qbs/modules/cpp/keil.js
+++ b/share/qbs/modules/cpp/keil.js
@@ -582,19 +582,24 @@ function filterC166Output(output) {
return filteredLines.join('\n');
};
-function compilerOutputArtifacts(input, useListing) {
+function compilerOutputArtifacts(input, isCompilerArtifacts) {
var artifacts = [];
artifacts.push({
fileTags: ["obj"],
filePath: Utilities.getHash(input.baseDir) + "/"
+ input.fileName + input.cpp.objectSuffix
});
- if (useListing) {
+ if (isCompilerArtifacts && input.cpp.generateCompilerListingFiles) {
artifacts.push({
fileTags: ["lst"],
filePath: Utilities.getHash(input.baseDir) + "/"
- + (isArmCCCompiler(input.cpp.compilerPath) ? input.baseName : input.fileName)
- + ".lst"
+ + input.fileName + input.cpp.compilerListingSuffix
+ });
+ } else if (!isCompilerArtifacts && input.cpp.generateAssemblerListingFiles) {
+ artifacts.push({
+ fileTags: ["lst"],
+ filePath: Utilities.getHash(input.baseDir) + "/"
+ + input.fileName + input.cpp.assemblerListingSuffix
});
}
return artifacts;
@@ -970,24 +975,37 @@ function disassemblerFlags(project, product, input, outputs, explicitlyDependsOn
function linkerFlags(project, product, inputs, outputs) {
var args = [];
+ // Library paths.
+ var libraryPaths = product.cpp.libraryPaths;
+
var architecture = product.qbs.architecture;
if (isMcsArchitecture(architecture) || isC166Architecture(architecture)) {
- // Note: The C51/256/166 linker does not distinguish an object files and
+ // Note: The C51, C251, or C166 linker does not distinguish an object files and
// a libraries, it interpret all this stuff as an input objects,
// so, we need to pass it together in one string.
-
var allObjectPaths = [];
- function addObjectPath(obj) {
- allObjectPaths.push(obj.filePath);
- }
// Inputs.
if (inputs.obj)
- inputs.obj.map(function(obj) { addObjectPath(obj) });
+ inputs.obj.map(function(obj) { allObjectPaths.push(obj.filePath) });
// Library dependencies.
var libraryObjects = collectLibraryDependencies(product);
- libraryObjects.forEach(function(dep) { addObjectPath(dep); })
+ allObjectPaths = allObjectPaths.concat(libraryObjects.map(function(lib) {
+ // Semi-intelligent handling the library paths.
+ // We need to add the full path prefix to the library file if this
+ // file is not absolute or not relative. Reason is that the C51, C251,
+ // and C166 linkers does not support the library paths.
+ var filePath = lib.filePath;
+ if (FileInfo.isAbsolutePath(filePath))
+ return filePath;
+ for (var i = 0; i < libraryPaths.length; ++i) {
+ var fullPath = FileInfo.joinPaths(libraryPaths[i], filePath);
+ if (File.exists(fullPath))
+ return fullPath;
+ }
+ return filePath;
+ }));
// Add all input objects as arguments (application and library object files).
if (allObjectPaths.length > 0)
@@ -1009,8 +1027,6 @@ function linkerFlags(project, product, inputs, outputs) {
// Output.
args.push("--output", outputs.application[0].filePath);
- // Library paths.
- var libraryPaths = product.cpp.libraryPaths;
if (libraryPaths)
args.push("--userlibpath=" + libraryPaths.join(","));
@@ -1084,6 +1100,38 @@ function archiverFlags(project, product, inputs, outputs) {
return args;
}
+// The ARMCLANG compiler does not support generation
+// for the listing files:
+// * https://www.keil.com/support/docs/4152.htm
+// So, we generate the listing files from the object files
+// using the disassembler.
+function generateClangCompilerListing(project, product, inputs, outputs, input, output) {
+ if (isArmClangCompiler(input.cpp.compilerPath) && input.cpp.generateCompilerListingFiles) {
+ var args = disassemblerFlags(project, product, input, outputs, explicitlyDependsOn);
+ var disassemblerPath = input.cpp.disassemblerPath;
+ var cmd = new Command(disassemblerPath, args);
+ cmd.silent = true;
+ return cmd;
+ }
+}
+
+// The ARMCC compiler generates the listing files only in a short form,
+// e.g. to 'module.lst' instead of 'module.{c|cpp}.lst', that complicates
+// the auto-tests. Therefore we need to rename generated listing files
+// with correct unified names.
+function generateArmccCompilerListing(project, product, inputs, outputs, input, output) {
+ if (isArmCCCompiler(input.cpp.compilerPath) && input.cpp.generateCompilerListingFiles) {
+ var listingPath = FileInfo.path(outputs.lst[0].filePath);
+ var cmd = new JavaScriptCommand();
+ cmd.oldListing = FileInfo.joinPaths(listingPath, input.baseName + ".lst");
+ cmd.newListing = FileInfo.joinPaths(
+ listingPath, input.fileName + input.cpp.compilerListingSuffix);
+ cmd.silent = true;
+ cmd.sourceCode = function() { File.move(oldListing, newListing); };
+ return cmd;
+ }
+}
+
function prepareCompiler(project, product, inputs, outputs, input, output, explicitlyDependsOn) {
var cmds = [];
var args = compilerFlags(project, product, input, outputs, explicitlyDependsOn);
@@ -1101,18 +1149,14 @@ function prepareCompiler(project, product, inputs, outputs, input, output, expli
}
cmds.push(cmd);
- // The ARMCLANG compiler does not support generation
- // for the listing files:
- // * https://www.keil.com/support/docs/4152.htm
- // So, we generate the listing files from the object files
- // using the disassembler.
- if (isArmClangCompiler(compilerPath) && input.cpp.generateCompilerListingFiles) {
- args = disassemblerFlags(project, product, input, outputs, explicitlyDependsOn);
- var disassemblerPath = input.cpp.disassemblerPath;
- cmd = new Command(disassemblerPath, args);
- cmd.silent = true;
+ cmd = generateClangCompilerListing(project, product, inputs, outputs, input, output);
+ if (cmd)
cmds.push(cmd);
- }
+
+ cmd = generateArmccCompilerListing(project, product, inputs, outputs, input, output);
+ if (cmd)
+ cmds.push(cmd);
+
return cmds;
}
diff --git a/share/qbs/modules/cpp/keil.qbs b/share/qbs/modules/cpp/keil.qbs
index f1f3b50e8..ea99b589c 100644
--- a/share/qbs/modules/cpp/keil.qbs
+++ b/share/qbs/modules/cpp/keil.qbs
@@ -103,8 +103,7 @@ CppModule {
id: assembler
inputs: ["asm"]
outputFileTags: ["obj", "lst"]
- outputArtifacts: KEIL.compilerOutputArtifacts(
- input, input.cpp.generateAssemblerListingFiles)
+ outputArtifacts: KEIL.compilerOutputArtifacts(input, false)
prepare: KEIL.prepareAssembler.apply(KEIL, arguments)
}
@@ -118,8 +117,7 @@ CppModule {
inputs: ["cpp", "c"]
auxiliaryInputs: ["hpp"]
outputFileTags: ["obj", "lst"]
- outputArtifacts: KEIL.compilerOutputArtifacts(
- input, input.cpp.generateCompilerListingFiles)
+ outputArtifacts: KEIL.compilerOutputArtifacts(input, true)
prepare: KEIL.prepareCompiler.apply(KEIL, arguments)
}
diff --git a/share/qbs/modules/cpp/msvc.js b/share/qbs/modules/cpp/msvc.js
index 566059610..9f3d20282 100644
--- a/share/qbs/modules/cpp/msvc.js
+++ b/share/qbs/modules/cpp/msvc.js
@@ -28,6 +28,7 @@
**
****************************************************************************/
+var Codesign = require("../codesign/codesign.js");
var Cpp = require("cpp.js");
var File = require("qbs.File");
var FileInfo = require("qbs.FileInfo");
@@ -655,6 +656,12 @@ function prepareLinker(project, product, inputs, outputs, input, output) {
commands.push(cmd);
}
+ if (product.cpp.shouldSignArtifacts) {
+ Array.prototype.push.apply(
+ commands, Codesign.prepareSigntool(
+ project, product, inputs, outputs, input, output));
+ }
+
return commands;
}
diff --git a/share/qbs/modules/cpp/sdcc.js b/share/qbs/modules/cpp/sdcc.js
index a47063401..1904f59fc 100644
--- a/share/qbs/modules/cpp/sdcc.js
+++ b/share/qbs/modules/cpp/sdcc.js
@@ -239,7 +239,7 @@ function collectLibraryDependencies(product) {
return result;
}
-function compilerOutputArtifacts(input, useListing) {
+function compilerOutputArtifacts(input, isCompilerArtifacts) {
var obj = {
fileTags: ["obj"],
filePath: Utilities.getHash(input.baseDir) + "/"
@@ -270,11 +270,17 @@ function compilerOutputArtifacts(input, useListing) {
+ input.fileName + ".rst"
};
var artifacts = [obj, asm_adb, asm_src, asm_sym, rst_data];
- if (useListing) {
+ if (isCompilerArtifacts && input.cpp.generateCompilerListingFiles) {
artifacts.push({
fileTags: ["lst"],
filePath: Utilities.getHash(input.baseDir) + "/"
- + input.fileName + ".lst"
+ + input.fileName + input.cpp.compilerListingSuffix
+ });
+ } else if (!isCompilerArtifacts && input.cpp.generateAssemblerListingFiles) {
+ artifacts.push({
+ fileTags: ["lst"],
+ filePath: Utilities.getHash(input.baseDir) + "/"
+ + input.fileName + input.cpp.assemblerListingSuffix
});
}
return artifacts;
@@ -547,14 +553,19 @@ function archiverFlags(project, product, inputs, outputs) {
return args;
}
+function buildLinkerMapFilePath(target, suffix) {
+ return FileInfo.joinPaths(FileInfo.path(target.filePath),
+ FileInfo.completeBaseName(target.fileName) + suffix);
+}
+
// This is the workaround for the SDCC bug on a Windows host:
// * https://sourceforge.net/p/sdcc/bugs/2970/
// We need to replace the '\r\n\' line endings with the'\n' line
// endings for each generated object file.
-function patchObjectFiles(project, product, inputs, outputs, input, output) {
+function patchObjectFile(project, product, inputs, outputs, input, output) {
var isWindows = input.qbs.hostOS.contains("windows");
if (isWindows && input.cpp.debugInformation) {
- cmd = new JavaScriptCommand();
+ var cmd = new JavaScriptCommand();
cmd.objectPath = outputs.obj[0].filePath;
cmd.silent = true;
cmd.sourceCode = function() {
@@ -576,6 +587,85 @@ function patchObjectFiles(project, product, inputs, outputs, input, output) {
}
}
+// It is a workaround which removes the generated linker map file
+// if it is disabled by cpp.generateLinkerMapFile property.
+// Reason is that the SDCC compiler always generates this file,
+// and does not have an option to disable generation for a linker
+// map file. So, we can to remove a listing files only after the
+// linking completes.
+function removeLinkerMapFile(project, product, inputs, outputs, input, output) {
+ if (!product.cpp.generateLinkerMapFile) {
+ var target = outputs.application[0];
+ var cmd = new JavaScriptCommand();
+ cmd.mapFilePath = buildLinkerMapFilePath(target, product.cpp.linkerMapSuffix)
+ cmd.silent = true;
+ cmd.sourceCode = function() { File.remove(mapFilePath); };
+ return cmd;
+ }
+}
+
+// It is a workaround to rename the extension of the output linker
+// map file to the specified one, since the linker generates only
+// files with the '.map' extension.
+function renameLinkerMapFile(project, product, inputs, outputs, input, output) {
+ if (product.cpp.generateLinkerMapFile && (product.cpp.linkerMapSuffix !== ".map")) {
+ var target = outputs.application[0];
+ var cmd = new JavaScriptCommand();
+ cmd.newMapFilePath = buildLinkerMapFilePath(target, product.cpp.linkerMapSuffix);
+ cmd.oldMapFilePath = buildLinkerMapFilePath(target, ".map");
+ cmd.silent = true;
+ cmd.sourceCode = function() { File.move(oldMapFilePath, newMapFilePath); };
+ return cmd;
+ }
+}
+
+// It is a workaround which removes the generated listing files
+// if it is disabled by cpp.generateCompilerListingFiles property
+// or when the cpp.compilerListingSuffix differs with '.lst'.
+// Reason is that the SDCC compiler does not have an option to
+// disable generation for a listing files. Besides, the SDCC
+// compiler use this files and for the linking. So, we can to
+// remove a listing files only after the linking completes.
+function removeCompilerListingFiles(project, product, inputs, outputs, input, output) {
+ var cmd = new JavaScriptCommand();
+ cmd.objects = inputs.obj.map(function(a) { return a; });
+ cmd.silent = true;
+ cmd.sourceCode = function() {
+ objects.forEach(function(object) {
+ if (!object.filePath.endsWith(".c" + object.cpp.objectSuffix))
+ return; // Skip the assembler generated objects.
+ if (!object.cpp.generateCompilerListingFiles
+ || (object.cpp.compilerListingSuffix !== ".lst")) {
+ var listingPath = FileInfo.joinPaths(FileInfo.path(object.filePath),
+ object.completeBaseName + ".lst");
+ File.remove(listingPath);
+ }
+ })
+ };
+ return cmd;
+}
+
+// It is a workaround that duplicates the generated listing files
+// but with desired names. The problem is that the SDCC compiler does
+// not support an options to specify names for the generated listing
+// files. At the same time, the compiler always generates the listing
+// files in the form of 'module.c.lst', which makes it impossible to
+// change the file suffix to a user-specified one. In addition, these
+// files are also somehow used for linking. Thus, we can not rename them
+// on the compiling stage.
+function duplicateCompilerListingFile(project, product, inputs, outputs, input, output) {
+ if (input.cpp.generateCompilerListingFiles
+ && (input.cpp.compilerListingSuffix !== ".lst")) {
+ var cmd = new JavaScriptCommand();
+ cmd.newListing = outputs.lst[0].filePath;
+ cmd.oldListing = FileInfo.joinPaths(FileInfo.path(outputs.lst[0].filePath),
+ outputs.lst[0].completeBaseName + ".lst");
+ cmd.silent = true;
+ cmd.sourceCode = function() { File.copy(oldListing, newListing); };
+ return cmd;
+ }
+}
+
function prepareCompiler(project, product, inputs, outputs, input, output, explicitlyDependsOn) {
var cmds = [];
var args = compilerFlags(project, product, input, outputs, explicitlyDependsOn);
@@ -585,7 +675,11 @@ function prepareCompiler(project, product, inputs, outputs, input, output, expli
cmd.highlight = "compiler";
cmds.push(cmd);
- cmd = patchObjectFiles(project, product, inputs, outputs, input, output);
+ cmd = patchObjectFile(project, product, inputs, outputs, input, output);
+ if (cmd)
+ cmds.push(cmd);
+
+ cmd = duplicateCompilerListingFile(project, product, inputs, outputs, input, output);
if (cmd)
cmds.push(cmd);
@@ -601,7 +695,7 @@ function prepareAssembler(project, product, inputs, outputs, input, output, expl
cmd.highlight = "compiler";
cmds.push(cmd);
- cmd = patchObjectFiles(project, product, inputs, outputs, input, output);
+ cmd = patchObjectFile(project, product, inputs, outputs, input, output);
if (cmd)
cmds.push(cmd);
@@ -610,52 +704,24 @@ function prepareAssembler(project, product, inputs, outputs, input, output, expl
function prepareLinker(project, product, inputs, outputs, input, output) {
var cmds = [];
- var target = outputs.application[0];
var args = linkerFlags(project, product, inputs, outputs);
var linkerPath = effectiveLinkerPath(product);
var cmd = new Command(linkerPath, args);
- cmd.description = "linking " + target.fileName;
+ cmd.description = "linking " + outputs.application[0].fileName;
cmd.highlight = "linker";
cmds.push(cmd);
- // It is a workaround which removes the generated listing files
- // if it is disabled by cpp.generateCompilerListingFiles property.
- // Reason is that the SDCC compiler does not have an option to
- // disable generation for a listing files. Besides, the SDCC
- // compiler use this files and for the linking. So, we can to
- // remove a listing files only after the linking completes.
- if (!product.cpp.generateCompilerListingFiles) {
- cmd = new JavaScriptCommand();
- cmd.objectPaths = inputs.obj.map(function(a) { return a.filePath; });
- cmd.objectSuffix = product.cpp.objectSuffix;
- cmd.silent = true;
- cmd.sourceCode = function() {
- objectPaths.forEach(function(objectPath) {
- if (!objectPath.endsWith(".c" + objectSuffix))
- return; // Skip the assembler objects.
- var listingPath = FileInfo.joinPaths(
- FileInfo.path(objectPath),
- FileInfo.completeBaseName(objectPath) + ".lst");
- File.remove(listingPath);
- });
- };
+ cmd = removeCompilerListingFiles(project, product, inputs, outputs, input, output);
+ if (cmd)
cmds.push(cmd);
- }
- // It is a workaround which removes the generated linker map file
- // if it is disabled by cpp.generateLinkerMapFile property.
- // Reason is that the SDCC compiler always generates this file,
- // and does not have an option to disable generation for a linker
- // map file. So, we can to remove a listing files only after the
- // linking completes.
- if (!product.cpp.generateLinkerMapFile) {
- cmd = new JavaScriptCommand();
- cmd.mapFilePath = FileInfo.joinPaths(
- FileInfo.path(target.filePath),
- FileInfo.completeBaseName(target.fileName) + product.cpp.linkerMapSuffix);
- cmd.silent = true;
- cmd.sourceCode = function() { File.remove(mapFilePath); };
+
+ cmd = renameLinkerMapFile(project, product, inputs, outputs, input, output);
+ if (cmd)
+ cmds.push(cmd);
+
+ cmd = removeLinkerMapFile(project, product, inputs, outputs, input, output);
+ if (cmd)
cmds.push(cmd);
- }
return cmds;
}
diff --git a/share/qbs/modules/cpp/sdcc.qbs b/share/qbs/modules/cpp/sdcc.qbs
index 8b631d4e5..c5a0893d4 100644
--- a/share/qbs/modules/cpp/sdcc.qbs
+++ b/share/qbs/modules/cpp/sdcc.qbs
@@ -100,7 +100,7 @@ CppModule {
id: assembler
inputs: ["asm"]
outputFileTags: ["obj", "asm_adb", "lst", "asm_src", "asm_sym", "rst_data"]
- outputArtifacts: SDCC.compilerOutputArtifacts(input, true)
+ outputArtifacts: SDCC.compilerOutputArtifacts(input, false)
prepare: SDCC.prepareAssembler.apply(SDCC, arguments)
}
@@ -114,8 +114,7 @@ CppModule {
inputs: ["cpp", "c"]
auxiliaryInputs: ["hpp"]
outputFileTags: ["obj", "asm_adb", "lst", "asm_src", "asm_sym", "rst_data"]
- outputArtifacts: SDCC.compilerOutputArtifacts(
- input, input.cpp.generateCompilerListingFiles)
+ outputArtifacts: SDCC.compilerOutputArtifacts(input, true)
prepare: SDCC.prepareCompiler.apply(SDCC, arguments)
}
diff --git a/share/qbs/modules/cpp/windows-clang-cl.qbs b/share/qbs/modules/cpp/windows-clang-cl.qbs
index a34a67ad2..556efb042 100644
--- a/share/qbs/modules/cpp/windows-clang-cl.qbs
+++ b/share/qbs/modules/cpp/windows-clang-cl.qbs
@@ -53,6 +53,7 @@ MsvcBaseModule {
vcvarsallFilePath: vcvarsallPath
enableDefinesByLanguage: enableCompilerDefinesByLanguage
preferredArchitecture: qbs.architecture
+ winSdkVersion: windowsSdkVersion
}
qbs.architecture: clangClProbe.found ? clangClProbe.architecture : original
diff --git a/share/qbs/modules/cpp/windows-msvc-base.qbs b/share/qbs/modules/cpp/windows-msvc-base.qbs
index b25fdf159..c45ec5ec3 100644
--- a/share/qbs/modules/cpp/windows-msvc-base.qbs
+++ b/share/qbs/modules/cpp/windows-msvc-base.qbs
@@ -40,6 +40,8 @@ import 'msvc.js' as MSVC
CppModule {
condition: false
+ Depends { name: "codesign" }
+
windowsApiCharacterSet: "unicode"
platformDefines: {
var defines = base.concat(WindowsUtils.characterSetDefines(windowsApiCharacterSet))
@@ -100,6 +102,8 @@ CppModule {
property var buildEnv
+ readonly property bool shouldSignArtifacts: codesign.enableCodeSigning
+
setupBuildEnvironment: {
for (var key in product.cpp.buildEnv) {
var v = new ModUtils.EnvironmentVariable(key, ';');
@@ -108,6 +112,8 @@ CppModule {
}
}
+ property string windowsSdkVersion
+
Rule {
condition: useCPrecompiledHeader
inputs: ["c_pch_src"]
@@ -162,7 +168,8 @@ CppModule {
if (input.cpp.generateCompilerListingFiles) {
artifacts.push({
fileTags: ["lst"],
- filePath: Utilities.getHash(input.baseDir) + "/" + input.fileName + ".lst"
+ filePath: Utilities.getHash(input.baseDir)
+ + "/" + input.fileName + input.cpp.compilerListingSuffix
});
}
return artifacts;
@@ -189,10 +196,16 @@ CppModule {
inputs: ['obj', 'native.pe.manifest', 'def']
inputsFromDependencies: ['staticlibrary', 'dynamiclibrary_import', "debuginfo_app"]
- outputFileTags: ["application", "debuginfo_app", "mem_map"]
+ outputFileTags: {
+ var tags = ["application", "debuginfo_app", "mem_map"];
+ if (shouldSignArtifacts)
+ tags.push("codesign.signed_artifact");
+ return tags;
+ }
outputArtifacts: {
var app = {
- fileTags: ["application"],
+ fileTags: ["application"].concat(
+ product.cpp.shouldSignArtifacts ? ["codesign.signed_artifact"] : []),
filePath: FileInfo.joinPaths(
product.destinationDirectory,
PathTools.applicationFilePath(product))
@@ -227,11 +240,17 @@ CppModule {
inputs: ['obj', 'native.pe.manifest', 'def']
inputsFromDependencies: ['staticlibrary', 'dynamiclibrary_import', "debuginfo_dll"]
- outputFileTags: ["dynamiclibrary", "dynamiclibrary_import", "debuginfo_dll"]
+ outputFileTags: {
+ var tags = ["dynamiclibrary", "dynamiclibrary_import", "debuginfo_dll"];
+ if (shouldSignArtifacts)
+ tags.push("codesign.signed_artifact");
+ return tags;
+ }
outputArtifacts: {
var artifacts = [
{
- fileTags: ["dynamiclibrary"],
+ fileTags: ["dynamiclibrary"].concat(
+ product.cpp.shouldSignArtifacts ? ["codesign.signed_artifact"] : []),
filePath: product.destinationDirectory + "/" + PathTools.dynamicLibraryFilePath(product)
},
{
diff --git a/share/qbs/modules/cpp/windows-msvc.qbs b/share/qbs/modules/cpp/windows-msvc.qbs
index d5b5baf92..33c5e74c8 100644
--- a/share/qbs/modules/cpp/windows-msvc.qbs
+++ b/share/qbs/modules/cpp/windows-msvc.qbs
@@ -51,6 +51,7 @@ MsvcBaseModule {
compilerFilePath: compilerPath
enableDefinesByLanguage: enableCompilerDefinesByLanguage
preferredArchitecture: qbs.architecture
+ winSdkVersion: windowsSdkVersion
}
qbs.architecture: msvcProbe.found ? msvcProbe.architecture : original
diff --git a/src/3rdparty/python/lib/python2.7/site-packages/dmgbuild/core.py b/src/3rdparty/python/lib/python2.7/site-packages/dmgbuild/core.py
index efccd0028..d94a06c1f 100644
--- a/src/3rdparty/python/lib/python2.7/site-packages/dmgbuild/core.py
+++ b/src/3rdparty/python/lib/python2.7/site-packages/dmgbuild/core.py
@@ -3,6 +3,7 @@ from __future__ import unicode_literals
import os
import pkg_resources
+import platform
import re
import shutil
import stat
@@ -25,7 +26,19 @@ try:
except NameError:
unicode = str
-import biplist
+if sys.version_info < (3, 4):
+ import biplist
+ def plist_from_bytes(data):
+ return biplist.readPlistFromString(data)
+ def plist_bytes(data):
+ return biplist.Data(data)
+else:
+ import plistlib
+ def plist_from_bytes(data):
+ return plistlib.loads(data)
+ def plist_bytes(data):
+ return data
+
from mac_alias import *
from ds_store import *
@@ -39,6 +52,10 @@ except ImportError:
_hexcolor_re = re.compile(r'#[0-9a-f]{3}(?:[0-9a-f]{3})?')
+# The first element in the platform.mac_ver() tuple is a string containing the
+# macOS version (e.g., '10.15.6'). Parse into an integer tuple.
+MACOS_VERSION = tuple(int(v) for v in platform.mac_ver()[0].split('.'))
+
class DMGError(Exception):
pass
@@ -51,7 +68,7 @@ def hdiutil(cmd, *args, **kwargs):
p = subprocess.Popen(all_args, stdout=subprocess.PIPE, close_fds=True)
output, errors = p.communicate()
if plist:
- results = biplist.readPlistFromString(output)
+ results = plist_from_bytes(output)
else:
results = output
retcode = p.wait()
@@ -103,6 +120,8 @@ def load_json(filename, settings):
settings['compression_level'] = json_data.get('compression-level', None)
settings['license'] = json_data.get('license', None)
files = []
+ hide = []
+ hide_extensions = []
symlinks = {}
icon_locations = {}
for fileinfo in json_data.get('contents', []):
@@ -123,8 +142,16 @@ def load_json(filename, settings):
elif kind == 'position':
pass
icon_locations[name] = (fileinfo['x'], fileinfo['y'])
+ hide_ext = fileinfo.get('hide_extension', False)
+ if hide_ext:
+ hide_extensions.append(name)
+ hidden = fileinfo.get('hidden', False)
+ if hidden:
+ hide.append(name)
settings['files'] = files
+ settings['hide_extensions'] = hide_extensions
+ settings['hide'] = hide
settings['symlinks'] = symlinks
settings['icon_locations'] = icon_locations
@@ -139,6 +166,8 @@ def build_dmg(filename, volume_name, settings_file=None, settings={},
'size': None,
'files': [],
'symlinks': {},
+ 'hide': [],
+ 'hide_extensions': [],
'icon': None,
'badge_icon': None,
'background': None,
@@ -258,7 +287,7 @@ def build_dmg(filename, volume_name, settings_file=None, settings={},
}
background = options['background']
-
+
columns = {
'name': 'name',
'date-modified': 'dateModified',
@@ -297,7 +326,7 @@ def build_dmg(filename, volume_name, settings_file=None, settings={},
'version': 'ascending',
'comments': 'ascending',
}
-
+
lsvp = {
'viewOptionsVersion': 1,
'sortColumn': columns.get(options['list_sort_by'], 'name'),
@@ -319,7 +348,7 @@ def build_dmg(filename, volume_name, settings_file=None, settings={},
default_widths[column])
asc = 'ascending' == options['list_column_sort_directions'].get(column,
default_sort_directions[column])
-
+
lsvp['columns'][columns[column]] = {
'index': n,
'width': width,
@@ -334,7 +363,7 @@ def build_dmg(filename, volume_name, settings_file=None, settings={},
cndx[k] = n
width = default_widths[k]
asc = 'ascending' == default_sort_directions[k]
-
+
lsvp['columns'][columns[column]] = {
'index': n,
'width': width,
@@ -344,7 +373,7 @@ def build_dmg(filename, volume_name, settings_file=None, settings={},
}
n += 1
-
+
default_view = options['default_view']
views = {
'icon-view': b'icnv',
@@ -411,11 +440,19 @@ def build_dmg(filename, volume_name, settings_file=None, settings={},
if ret:
raise DMGError('Unable to create disk image')
- ret, output = hdiutil('attach',
- '-nobrowse',
- '-owners', 'off',
- '-noidme',
- writableFile.name)
+ # IDME was deprecated in macOS 10.15/Catalina; as a result, use of -noidme
+ # started raising a warning.
+ if MACOS_VERSION >= (10, 15):
+ ret, output = hdiutil('attach',
+ '-nobrowse',
+ '-owners', 'off',
+ writableFile.name)
+ else:
+ ret, output = hdiutil('attach',
+ '-nobrowse',
+ '-owners', 'off',
+ '-noidme',
+ writableFile.name)
if ret:
raise DMGError('Unable to attach disk image')
@@ -506,7 +543,7 @@ def build_dmg(filename, volume_name, settings_file=None, settings={},
background_bmk = Bookmark.for_file(path_in_image)
icvp['backgroundType'] = 2
- icvp['backgroundImageAlias'] = biplist.Data(alias.to_bytes())
+ icvp['backgroundImageAlias'] = plist_bytes(alias.to_bytes())
for f in options['files']:
if isinstance(f, tuple):
@@ -523,6 +560,22 @@ def build_dmg(filename, volume_name, settings_file=None, settings={},
name_in_image = os.path.join(mount_point, name)
os.symlink(target, name_in_image)
+ to_hide = []
+ for name in options['hide_extensions']:
+ name_in_image = os.path.join(mount_point, name)
+ to_hide.append(name_in_image)
+
+ if to_hide:
+ subprocess.call(['/usr/bin/SetFile', '-a', 'E'] + to_hide)
+
+ to_hide = []
+ for name in options['hide']:
+ name_in_image = os.path.join(mount_point, name)
+ to_hide.append(name_in_image)
+
+ if to_hide:
+ subprocess.call(['/usr/bin/SetFile', '-a', 'V'] + to_hide)
+
userfn = options.get('create_hook', None)
if callable(userfn):
userfn(mount_point, options)
diff --git a/src/app/qbs-setup-toolchains/msvcprobe.cpp b/src/app/qbs-setup-toolchains/msvcprobe.cpp
index bb54add9f..00aedaaab 100644
--- a/src/app/qbs-setup-toolchains/msvcprobe.cpp
+++ b/src/app/qbs-setup-toolchains/msvcprobe.cpp
@@ -58,6 +58,7 @@
#include <QtCore/qstringlist.h>
#include <algorithm>
+#include <set>
#include <vector>
using namespace qbs;
@@ -182,8 +183,20 @@ void msvcProbe(Settings *settings, std::vector<Profile> &profiles)
}
}
+ // we want the same MSVC version share the same suffix in profiles, thus use
+ // a set to know the number of versions processed so far
+ std::map<QString /*VS*/, std::set<QString /*vcInstallPath*/>> msvcCounters;
for (MSVC &msvc : msvcs) {
- const QString name = QLatin1String("MSVC") + msvc.version + QLatin1Char('-')
+ // each VS needs its own counter
+ auto &msvcVersions = msvcCounters[msvc.version];
+ // vcInstallPath is "Microsoft Visual Studio/2019/Enterprise/VC/Tools/MSVC/14.16.27023/bin"
+ // Since msvcs are sorted by version, when the new vcInstallPath is inserted, we start
+ // a new group of compilers of the same version incrementing the set size
+ msvcVersions.insert(msvc.vcInstallPath);
+ // index is the number of specific vcInstallPaths (e.g. compiler versions) seen so far
+ const qsizetype index = msvcVersions.size() - 1;
+ const QString suffix = index == 0 ? QString() : QStringLiteral("-%1").arg(index);
+ const QString name = QLatin1String("MSVC") + msvc.version + suffix + QLatin1Char('-')
+ msvc.architecture;
try {
msvc.init();
diff --git a/src/lib/corelib/jsextensions/utilitiesextension.cpp b/src/lib/corelib/jsextensions/utilitiesextension.cpp
index 6c693cb61..282362382 100644
--- a/src/lib/corelib/jsextensions/utilitiesextension.cpp
+++ b/src/lib/corelib/jsextensions/utilitiesextension.cpp
@@ -468,9 +468,10 @@ static std::pair<QVariantMap /*result*/, QString /*error*/> msvcCompilerInfoHelp
const QString &compilerFilePath,
MSVC::CompilerLanguage language,
const QString &vcvarsallPath,
- const QString &arch)
+ const QString &arch,
+ const QString &sdkVersion)
{
- MSVC msvc(compilerFilePath, arch);
+ MSVC msvc(compilerFilePath, arch, sdkVersion);
VsEnvironmentDetector envdetector(vcvarsallPath);
if (!envdetector.start(&msvc))
return { {}, QStringLiteral("Detecting the MSVC build environment failed: ")
@@ -501,12 +502,16 @@ QScriptValue UtilitiesExtension::js_msvcCompilerInfo(QScriptContext *context, QS
return context->throwError(QScriptContext::UnknownError,
QStringLiteral("msvcCompilerInfo is not available on this platform"));
#else
- if (Q_UNLIKELY(context->argumentCount() < 2))
+ if (Q_UNLIKELY(context->argumentCount() < 3))
return context->throwError(QScriptContext::SyntaxError,
- QStringLiteral("msvcCompilerInfo expects 2 arguments"));
+ QStringLiteral("msvcCompilerInfo expects 3 arguments"));
const QString compilerFilePath = context->argument(0).toString();
const QString compilerLanguage = context->argument(1).toString();
+ const QString sdkVersion =
+ !context->argument(2).isNull() && !context->argument(2).isUndefined()
+ ? context->argument(2).toString()
+ : QString();
MSVC::CompilerLanguage language;
if (compilerLanguage == QStringLiteral("c"))
language = MSVC::CLanguage;
@@ -517,7 +522,11 @@ QScriptValue UtilitiesExtension::js_msvcCompilerInfo(QScriptContext *context, QS
QStringLiteral("msvcCompilerInfo expects \"c\" or \"cpp\" as its second argument"));
const auto result = msvcCompilerInfoHelper(
- compilerFilePath, language, {}, MSVC::architectureFromClPath(compilerFilePath));
+ compilerFilePath,
+ language,
+ {},
+ MSVC::architectureFromClPath(compilerFilePath),
+ sdkVersion);
if (result.first.isEmpty())
return context->throwError(QScriptContext::UnknownError, result.second);
return engine->toScriptValue(result.first);
@@ -531,9 +540,9 @@ QScriptValue UtilitiesExtension::js_clangClCompilerInfo(QScriptContext *context,
return context->throwError(QScriptContext::UnknownError,
QStringLiteral("clangClCompilerInfo is not available on this platform"));
#else
- if (Q_UNLIKELY(context->argumentCount() < 4))
+ if (Q_UNLIKELY(context->argumentCount() < 5))
return context->throwError(QScriptContext::SyntaxError,
- QStringLiteral("clangClCompilerInfo expects 4 arguments"));
+ QStringLiteral("clangClCompilerInfo expects 5 arguments"));
const QString compilerFilePath = context->argument(0).toString();
// architecture cannot be empty as vcvarsall.bat requires at least 1 arg, so fallback
@@ -542,9 +551,14 @@ QScriptValue UtilitiesExtension::js_clangClCompilerInfo(QScriptContext *context,
? context->argument(1).toString()
: QString::fromStdString(HostOsInfo::hostOSArchitecture());
QString vcvarsallPath = context->argument(2).toString();
- const QString compilerLanguage = context->argumentCount() > 3
+ const QString compilerLanguage =
+ !context->argument(3).isNull() && !context->argument(3).isUndefined()
? context->argument(3).toString()
: QString();
+ const QString sdkVersion =
+ !context->argument(4).isNull() && !context->argument(4).isUndefined()
+ ? context->argument(4).toString()
+ : QString();
MSVC::CompilerLanguage language;
if (compilerLanguage == QStringLiteral("c"))
language = MSVC::CLanguage;
@@ -555,7 +569,7 @@ QScriptValue UtilitiesExtension::js_clangClCompilerInfo(QScriptContext *context,
QStringLiteral("clangClCompilerInfo expects \"c\" or \"cpp\" as its fourth argument"));
const auto result = msvcCompilerInfoHelper(
- compilerFilePath, language, vcvarsallPath, arch);
+ compilerFilePath, language, vcvarsallPath, arch, sdkVersion);
if (result.first.isEmpty())
return context->throwError(QScriptContext::UnknownError, result.second);
return engine->toScriptValue(result.first);
diff --git a/src/lib/corelib/tools/msvcinfo.cpp b/src/lib/corelib/tools/msvcinfo.cpp
index 42cfefe7b..58cd458c3 100644
--- a/src/lib/corelib/tools/msvcinfo.cpp
+++ b/src/lib/corelib/tools/msvcinfo.cpp
@@ -43,6 +43,7 @@
#include <logging/logger.h>
#include <tools/error.h>
#include <tools/profile.h>
+#include <tools/stlutils.h>
#include <tools/stringconstants.h>
#include <QtCore/qbytearray.h>
@@ -471,12 +472,20 @@ static std::vector<MSVC> installedCompilersHelper(Logger &logger)
QDir vcInstallDir = vsInstallDir;
vcInstallDir.cd(QStringLiteral("Tools/MSVC"));
const auto vcVersionStrs = vcInstallDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
+ std::vector<Version> vcVersions;
+ vcVersions.reserve(vcVersionStrs.size());
for (const QString &vcVersionStr : vcVersionStrs) {
const Version vcVersion = Version::fromString(vcVersionStr);
if (!vcVersion.isValid())
continue;
+ vcVersions.push_back(vcVersion);
+ }
+ // sort the versions so the new one comes first
+ std::sort(vcVersions.begin(), vcVersions.end(), std::greater<>());
+
+ for (const Version &vcVersion : vcVersions) {
QDir specificVcInstallDir = vcInstallDir;
- if (!specificVcInstallDir.cd(vcVersionStr)
+ if (!specificVcInstallDir.cd(vcVersion.toString())
|| !specificVcInstallDir.cd(QStringLiteral("bin"))) {
continue;
}
@@ -501,11 +510,32 @@ QString MSVC::architectureFromClPath(const QString &clPath)
{
const auto parentDir = QFileInfo(clPath).absolutePath();
const auto parentDirName = QFileInfo(parentDir).fileName().toLower();
+ // can be the case when cl.exe is present within the Windows SDK installation... but can it?
if (parentDirName == QLatin1String("bin"))
return QStringLiteral("x86");
return parentDirName;
}
+QString MSVC::vcVariablesVersionFromBinPath(const QString &binPath)
+{
+ const auto binDirName = QFileInfo(binPath).fileName().toLower();
+ // the case when cl.exe is present within the Windows SDK installation
+ if (binDirName == QLatin1String("bin"))
+ return {};
+ // binPath is something like
+ // Microsoft Visual Studio 14.0/VC/bin/amd64_x86
+ // or
+ // Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.28.29910/bin/Hostx64/x64
+ QDir dir(binPath);
+ dir.cdUp();
+ // older Visual Studios do not support multiple compiler versions
+ if (dir.dirName().toLower() == QLatin1String("bin"))
+ return {};
+ dir.cdUp();
+ dir.cdUp();
+ return dir.dirName();
+}
+
QString MSVC::canonicalArchitecture(const QString &arch)
{
if (arch == QLatin1String("x64") || arch == QLatin1String("amd64"))
diff --git a/src/lib/corelib/tools/msvcinfo.h b/src/lib/corelib/tools/msvcinfo.h
index de4470bf0..efaf0b6c2 100644
--- a/src/lib/corelib/tools/msvcinfo.h
+++ b/src/lib/corelib/tools/msvcinfo.h
@@ -81,12 +81,14 @@ public:
QString binPath;
QString pathPrefix;
QString architecture;
+ QString sdkVersion;
QProcessEnvironment environment;
MSVC() = default;
- MSVC(const QString &clPath, QString arch):
- architecture(std::move(arch))
+ MSVC(const QString &clPath, QString arch, QString sdkVersion = {}):
+ architecture(std::move(arch)),
+ sdkVersion(std::move(sdkVersion))
{
QDir parentDir = QFileInfo(clPath).dir();
binPath = parentDir.absolutePath();
@@ -98,6 +100,7 @@ public:
QBS_EXPORT void init();
QBS_EXPORT static QString architectureFromClPath(const QString &clPath);
+ QBS_EXPORT static QString vcVariablesVersionFromBinPath(const QString &binPath);
QBS_EXPORT static QString canonicalArchitecture(const QString &arch);
QBS_EXPORT static std::pair<QString, QString> getHostTargetArchPair(const QString &arch);
QBS_EXPORT QString binPathForArchitecture(const QString &arch) const;
diff --git a/src/lib/corelib/tools/set.h b/src/lib/corelib/tools/set.h
index 75db0528b..463d3beb6 100644
--- a/src/lib/corelib/tools/set.h
+++ b/src/lib/corelib/tools/set.h
@@ -112,8 +112,8 @@ public:
Set &operator&=(const Set &other) { return intersect(other); }
Set &operator&=(const T &v) { return intersect(Set{ v }); }
- iterator find(const T &v) { return std::find(m_data.begin(), m_data.end(), v); }
- const_iterator find(const T &v) const { return std::find(m_data.cbegin(), m_data.cend(), v); }
+ iterator find(const T &v) { return binaryFind(m_data.begin(), m_data.end(), v); }
+ const_iterator find(const T &v) const { return binaryFind(m_data.cbegin(), m_data.cend(), v); }
std::pair<iterator, bool> insert(const T &v);
Set &operator+=(const T &v) { insert(v); return *this; }
Set &operator|=(const T &v) { return operator+=(v); }
diff --git a/src/lib/corelib/tools/stlutils.h b/src/lib/corelib/tools/stlutils.h
index 1b6d7278f..d4c569a95 100644
--- a/src/lib/corelib/tools/stlutils.h
+++ b/src/lib/corelib/tools/stlutils.h
@@ -123,6 +123,21 @@ bool none_of(const Container &container, const UnaryPredicate &predicate)
return std::none_of(std::begin(container), std::end(container), predicate);
}
+template <class It, class T, class Compare>
+It binaryFind(It begin, It end, const T &value, Compare comp)
+{
+ const auto it = std::lower_bound(begin, end, value, comp);
+ if (it == end || comp(value, *it))
+ return end;
+ return it;
+}
+
+template <class It, class T>
+It binaryFind(It begin, It end, const T &value)
+{
+ return binaryFind(begin, end, value, std::less<T>());
+}
+
template <class C>
C &operator<<(C &container, const typename C::value_type &v)
{
diff --git a/src/lib/corelib/tools/vsenvironmentdetector.cpp b/src/lib/corelib/tools/vsenvironmentdetector.cpp
index b0788823f..82dff578f 100644
--- a/src/lib/corelib/tools/vsenvironmentdetector.cpp
+++ b/src/lib/corelib/tools/vsenvironmentdetector.cpp
@@ -241,8 +241,13 @@ void VsEnvironmentDetector::writeBatchFile(QIODevice *device, const QString &vcv
<< "setlocal" << endl;
batClearVars(s, varnames);
s << "set PATH=" << m_windowsSystemDirPath << endl; // vcvarsall.bat needs tools from here
- s << "call \"" << vcvarsallbat << "\" " << vcArchitecture(msvc)
- << " || exit /b 1" << endl;
+ s << "call \"" << vcvarsallbat << "\" " << vcArchitecture(msvc);
+ if (!msvc->sdkVersion.isEmpty())
+ s << " " << msvc->sdkVersion;
+ const auto vcVarsVer = MSVC::vcVariablesVersionFromBinPath(msvc->binPath);
+ if (!vcVarsVer.isEmpty())
+ s << " -vcvars_ver=" << vcVarsVer;
+ s << " || exit /b 1" << endl;
batPrintVars(s, varnames);
s << "endlocal" << endl;
}
diff --git a/src/lib/corelib/tools/vsenvironmentdetector.h b/src/lib/corelib/tools/vsenvironmentdetector.h
index 7fa152cb6..39bea07d6 100644
--- a/src/lib/corelib/tools/vsenvironmentdetector.h
+++ b/src/lib/corelib/tools/vsenvironmentdetector.h
@@ -57,7 +57,7 @@ class MSVC;
class QBS_EXPORT VsEnvironmentDetector
{
public:
- explicit VsEnvironmentDetector(QString vcvarsallPath = QString());
+ explicit VsEnvironmentDetector(QString vcvarsallPath = {});
bool start(MSVC *msvc);
bool start(std::vector<MSVC *> msvcs);
@@ -71,6 +71,7 @@ private:
const QString m_windowsSystemDirPath;
const QString m_vcvarsallPath;
+ const QString m_vcVariablesVersion;
QString m_errorString;
};
diff --git a/src/lib/scriptengine/scriptengine.qbs b/src/lib/scriptengine/scriptengine.qbs
index bb9984999..3225ceaac 100644
--- a/src/lib/scriptengine/scriptengine.qbs
+++ b/src/lib/scriptengine/scriptengine.qbs
@@ -383,6 +383,13 @@ Project {
Product {
type: ["hpp"]
name: "QtScriptFwdHeaders"
+ condition: qbsbuildconfig.useBundledQtScript || !Qt.script.present
+ Depends { name: "qbsbuildconfig" }
+ Depends {
+ name: "Qt.script"
+ condition: !qbsbuildconfig.useBundledQtScript
+ required: false
+ }
Depends { name: "Qt.core" }
Group {
files: [
diff --git a/tests/auto/auto.qbs b/tests/auto/auto.qbs
index 8dd301f68..0d87af9fe 100644
--- a/tests/auto/auto.qbs
+++ b/tests/auto/auto.qbs
@@ -4,7 +4,6 @@ Project {
name: "Autotests"
references: [
"api/api.qbs",
- "blackbox/blackbox.qbs",
"blackbox/blackbox-android.qbs",
"blackbox/blackbox-apple.qbs",
"blackbox/blackbox-baremetal.qbs",
@@ -13,6 +12,8 @@ Project {
"blackbox/blackbox-java.qbs",
"blackbox/blackbox-joblimits.qbs",
"blackbox/blackbox-qt.qbs",
+ "blackbox/blackbox-windows.qbs",
+ "blackbox/blackbox.qbs",
"buildgraph/buildgraph.qbs",
"cmdlineparser/cmdlineparser.qbs",
"language/language.qbs",
diff --git a/tests/auto/blackbox/CMakeLists.txt b/tests/auto/blackbox/CMakeLists.txt
index 88eed4b42..0bf79a433 100644
--- a/tests/auto/blackbox/CMakeLists.txt
+++ b/tests/auto/blackbox/CMakeLists.txt
@@ -70,3 +70,12 @@ add_qbs_test(blackbox-qt
tst_blackboxqt.cpp
tst_blackboxqt.h
)
+
+add_qbs_test(blackbox-windows
+ SOURCES
+ ../shared.h
+ tst_blackboxbase.cpp
+ tst_blackboxbase.h
+ tst_blackboxwindows.cpp
+ tst_blackboxwindows.h
+ )
diff --git a/tests/auto/blackbox/blackbox-windows.pro b/tests/auto/blackbox/blackbox-windows.pro
new file mode 100644
index 000000000..a9e8fdbd2
--- /dev/null
+++ b/tests/auto/blackbox/blackbox-windows.pro
@@ -0,0 +1,18 @@
+TARGET = tst_blackbox-windows
+
+HEADERS = tst_blackboxwindows.h tst_blackboxbase.h
+SOURCES = tst_blackboxwindows.cpp tst_blackboxbase.cpp
+OBJECTS_DIR = windows
+MOC_DIR = $${OBJECTS_DIR}-moc
+
+include(../auto.pri)
+
+DATA_DIRS = testdata-windows ../find
+
+for(data_dir, DATA_DIRS) {
+ files = $$files($$PWD/$$data_dir/*, true)
+ win32:files ~= s|\\\\|/|g
+ for(file, files):!exists($$file/*):FILES += $$file
+}
+
+OTHER_FILES += $$FILES
diff --git a/tests/auto/blackbox/blackbox-windows.qbs b/tests/auto/blackbox/blackbox-windows.qbs
new file mode 100644
index 000000000..e32421e3b
--- /dev/null
+++ b/tests/auto/blackbox/blackbox-windows.qbs
@@ -0,0 +1,21 @@
+import qbs.Utilities
+
+QbsAutotest {
+ testName: "blackbox-windows"
+ Depends { name: "qbs_app" }
+ Depends { name: "qbs-setup-toolchains" }
+ Group {
+ name: "testdata"
+ prefix: "testdata-windows/"
+ files: ["**/*"]
+ fileTags: []
+ }
+ files: [
+ "../shared.h",
+ "tst_blackboxbase.cpp",
+ "tst_blackboxbase.h",
+ "tst_blackboxwindows.cpp",
+ "tst_blackboxwindows.h",
+ ]
+ cpp.defines: base.concat(["SRCDIR=" + Utilities.cStringQuote(path)])
+}
diff --git a/tests/auto/blackbox/testdata-baremetal/generate-compiler-listing/generate-compiler-listing.qbs b/tests/auto/blackbox/testdata-baremetal/compiler-listing/compiler-listing.qbs
index a6731d224..bcf983c88 100644
--- a/tests/auto/blackbox/testdata-baremetal/generate-compiler-listing/generate-compiler-listing.qbs
+++ b/tests/auto/blackbox/testdata-baremetal/compiler-listing/compiler-listing.qbs
@@ -3,14 +3,12 @@ import "../BareMetalApplication.qbs" as BareMetalApplication
BareMetalApplication {
condition: {
if (!qbs.toolchain.contains("gcc")) {
- if (cpp.compilerName.startsWith("armcc"))
- console.info("using short listing file names");
+ console.info("compiler listing suffix: %%" + cpp.compilerListingSuffix + "%%");
return true;
}
console.info("unsupported toolset: %%"
+ qbs.toolchainType + "%%, %%" + qbs.architecture + "%%");
return false;
}
- cpp.generateCompilerListingFiles: true
files: ["main.c", "fun.c"]
}
diff --git a/tests/auto/blackbox/testdata-baremetal/do-not-generate-compiler-listing/fun.c b/tests/auto/blackbox/testdata-baremetal/compiler-listing/fun.c
index 3b8c8f2f4..3b8c8f2f4 100644
--- a/tests/auto/blackbox/testdata-baremetal/do-not-generate-compiler-listing/fun.c
+++ b/tests/auto/blackbox/testdata-baremetal/compiler-listing/fun.c
diff --git a/tests/auto/blackbox/testdata-baremetal/do-not-generate-compiler-listing/main.c b/tests/auto/blackbox/testdata-baremetal/compiler-listing/main.c
index 2c3d7726c..2c3d7726c 100644
--- a/tests/auto/blackbox/testdata-baremetal/do-not-generate-compiler-listing/main.c
+++ b/tests/auto/blackbox/testdata-baremetal/compiler-listing/main.c
diff --git a/tests/auto/blackbox/testdata-baremetal/do-not-generate-compiler-listing/do-not-generate-compiler-listing.qbs b/tests/auto/blackbox/testdata-baremetal/do-not-generate-compiler-listing/do-not-generate-compiler-listing.qbs
deleted file mode 100644
index 1bc4ba208..000000000
--- a/tests/auto/blackbox/testdata-baremetal/do-not-generate-compiler-listing/do-not-generate-compiler-listing.qbs
+++ /dev/null
@@ -1,16 +0,0 @@
-import "../BareMetalApplication.qbs" as BareMetalApplication
-
-BareMetalApplication {
- condition: {
- if (!qbs.toolchain.contains("gcc")) {
- if (cpp.compilerName.startsWith("armcc"))
- console.info("using short listing file names");
- return true;
- }
- console.info("unsupported toolset: %%"
- + qbs.toolchainType + "%%, %%" + qbs.architecture + "%%");
- return false;
- }
- cpp.generateCompilerListingFiles: false
- files: ["main.c", "fun.c"]
-}
diff --git a/tests/auto/blackbox/testdata-baremetal/external-static-libraries/external-static-libraries.qbs b/tests/auto/blackbox/testdata-baremetal/external-static-libraries/external-static-libraries.qbs
index 6fbbb8647..fffb6a03d 100644
--- a/tests/auto/blackbox/testdata-baremetal/external-static-libraries/external-static-libraries.qbs
+++ b/tests/auto/blackbox/testdata-baremetal/external-static-libraries/external-static-libraries.qbs
@@ -2,20 +2,6 @@ import "../BareMetalApplication.qbs" as BareMetalApplication
import "../BareMetalStaticLibrary.qbs" as BareMetalStaticLibrary
Project {
- condition: {
- // The KEIL C51/C251/C166 toolchains support only a
- // full paths to the external libraries.
- if (qbs.toolchainType === "keil") {
- if (qbs.architecture === "mcs51"
- || qbs.architecture === "mcs251"
- || qbs.architecture === "c166") {
- console.info("unsupported toolset: %%"
- + qbs.toolchainType + "%%, %%" + qbs.architecture + "%%");
- return false;
- }
- }
- return true;
- }
property string outputLibrariesDirectory: sourceDirectory + "/libs"
BareMetalStaticLibrary {
name: "lib-a"
diff --git a/tests/auto/blackbox/testdata-baremetal/generate-compiler-listing/fun.c b/tests/auto/blackbox/testdata-baremetal/generate-compiler-listing/fun.c
deleted file mode 100644
index 3b8c8f2f4..000000000
--- a/tests/auto/blackbox/testdata-baremetal/generate-compiler-listing/fun.c
+++ /dev/null
@@ -1,4 +0,0 @@
-int f(void)
-{
- return 0;
-}
diff --git a/tests/auto/blackbox/testdata-baremetal/generate-compiler-listing/main.c b/tests/auto/blackbox/testdata-baremetal/generate-compiler-listing/main.c
deleted file mode 100644
index 2c3d7726c..000000000
--- a/tests/auto/blackbox/testdata-baremetal/generate-compiler-listing/main.c
+++ /dev/null
@@ -1,6 +0,0 @@
-extern int f(void);
-
-int main(void)
-{
- return f();
-}
diff --git a/tests/auto/blackbox/testdata-baremetal/linker-map/linker-map.qbs b/tests/auto/blackbox/testdata-baremetal/linker-map/linker-map.qbs
index 676221e11..fe93ac144 100644
--- a/tests/auto/blackbox/testdata-baremetal/linker-map/linker-map.qbs
+++ b/tests/auto/blackbox/testdata-baremetal/linker-map/linker-map.qbs
@@ -1,10 +1,8 @@
import "../BareMetalApplication.qbs" as BareMetalApplication
BareMetalApplication {
- condition: {
- console.info("current toolset: %%"
- + qbs.toolchainType + "%%, %%" + qbs.architecture + "%%");
- return true;
+ property bool dummy: {
+ console.info("linker map suffix: %%" + cpp.linkerMapSuffix + "%%");
}
files: ["main.c"]
}
diff --git a/tests/auto/blackbox/testdata-windows/codesign/app.cpp b/tests/auto/blackbox/testdata-windows/codesign/app.cpp
new file mode 100644
index 000000000..76e819701
--- /dev/null
+++ b/tests/auto/blackbox/testdata-windows/codesign/app.cpp
@@ -0,0 +1 @@
+int main() { return 0; }
diff --git a/tests/auto/blackbox/testdata-windows/codesign/codesign.qbs b/tests/auto/blackbox/testdata-windows/codesign/codesign.qbs
new file mode 100644
index 000000000..2b48c67ff
--- /dev/null
+++ b/tests/auto/blackbox/testdata-windows/codesign/codesign.qbs
@@ -0,0 +1,37 @@
+Project {
+ name: "p"
+
+ property bool enableSigning: true
+ property string hashAlgorithm
+ property string subjectName
+ property string signingTimestamp
+
+ CppApplication {
+ name: "A"
+ files: "app.cpp"
+ codesign.enableCodeSigning: project.enableSigning
+ codesign.hashAlgorithm: project.hashAlgorithm
+ codesign.subjectName: project.subjectName
+ codesign.signingTimestamp: project.signingTimestamp
+ install: true
+ installDir: ""
+ property bool dummy: {
+ console.info("signtool path: %%" + codesign.codesignPath + "%%");
+ }
+ }
+
+ DynamicLibrary {
+ Depends { name: "cpp" }
+ name: "B"
+ files: "app.cpp"
+ codesign.enableCodeSigning: project.enableSigning
+ codesign.hashAlgorithm: project.hashAlgorithm
+ codesign.subjectName: project.subjectName
+ codesign.signingTimestamp: project.signingTimestamp
+ install: true
+ installDir: ""
+ property bool dummy: {
+ console.info("signtool path: %%" + codesign.codesignPath + "%%");
+ }
+ }
+}
diff --git a/tests/auto/blackbox/tst_blackboxbaremetal.cpp b/tests/auto/blackbox/tst_blackboxbaremetal.cpp
index a5feedd48..e0a068bc6 100644
--- a/tests/auto/blackbox/tst_blackboxbaremetal.cpp
+++ b/tests/auto/blackbox/tst_blackboxbaremetal.cpp
@@ -59,6 +59,16 @@ static bool extractCompilerIncludePaths(const QByteArray &output, QStringList &c
return true;
}
+static bool extractQuitedValue(const QByteArray &output, QString &pattern)
+{
+ const QRegularExpression re("%%(.+)%%");
+ const QRegularExpressionMatch match = re.match(output);
+ if (!match.hasMatch())
+ return false;
+ pattern = match.captured(1);
+ return true;
+}
+
static QByteArray unsupportedToolsetMessage(const QByteArray &output)
{
QByteArray toolchain;
@@ -68,17 +78,6 @@ static QByteArray unsupportedToolsetMessage(const QByteArray &output)
+ "' for architecture '" + architecture + "'";
}
-static QString linkerMapFileExtension(const QByteArray &toolchain, const QByteArray &architecture)
-{
- if (toolchain == "keil") {
- if (architecture == "mcs51")
- return QStringLiteral(".m51");
- if (architecture == "c166")
- return QStringLiteral(".m66");
- }
- return QStringLiteral(".map");
-}
-
TestBlackboxBareMetal::TestBlackboxBareMetal()
: TestBlackboxBase (SRCDIR "/testdata-baremetal", "blackbox-baremetal")
{
@@ -187,61 +186,84 @@ void TestBlackboxBareMetal::defines()
void TestBlackboxBareMetal::compilerListingFiles_data()
{
- QTest::addColumn<QString>("testPath");
QTest::addColumn<bool>("generateListing");
- QTest::newRow("do-not-generate-compiler-listing") << "/do-not-generate-compiler-listing" << false;
- QTest::newRow("generate-compiler-listing") << "/generate-compiler-listing" << true;
+ QTest::addColumn<QString>("customListingSuffix");
+ QTest::newRow("do-not-generate-compiler-listing") << false << "";
+ QTest::newRow("generate-default-compiler-listing") << true << "";
+ QTest::newRow("generate-custom-compiler-listing") << true << ".lll";
}
void TestBlackboxBareMetal::compilerListingFiles()
{
- QFETCH(QString, testPath);
QFETCH(bool, generateListing);
- QDir::setCurrent(testDataDir + testPath);
- QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("-n"))), 0);
+ QFETCH(QString, customListingSuffix);
+ QDir::setCurrent(testDataDir + "/compiler-listing");
+
+ rmDirR(relativeBuildDir());
+ QStringList args = {QStringLiteral("modules.cpp.generateCompilerListingFiles:%1")
+ .arg(generateListing ? "true" : "false")};
+ if (!customListingSuffix.isEmpty())
+ args << QStringLiteral("modules.cpp.compilerListingSuffix:%1").arg(customListingSuffix);
+
+ QCOMPARE(runQbs(QbsRunParameters("resolve", args)), 0);
if (m_qbsStdout.contains("unsupported toolset:"))
QSKIP(unsupportedToolsetMessage(m_qbsStdout));
- QCOMPARE(runQbs(), 0);
- const bool isShortListingNames = m_qbsStdout.contains("using short listing file names");
- const QString productName = testPath.mid(1);
- const QString productBuildDir = relativeProductBuildDir(productName);
+ if (!m_qbsStdout.contains("compiler listing suffix:"))
+ QFAIL("No current compiler listing suffix pattern exists");
+
+ QString compilerListingSuffix;
+ if (!extractQuitedValue(m_qbsStdout, compilerListingSuffix))
+ QFAIL("Unable to extract current compiler listing suffix");
+
+ if (!customListingSuffix.isEmpty())
+ QCOMPARE(compilerListingSuffix, customListingSuffix);
+
+ QCOMPARE(runQbs(QbsRunParameters(args)), 0);
+ const QString productBuildDir = relativeProductBuildDir("compiler-listing");
const QString hash = inputDirHash(".");
- const QString mainListing = productBuildDir + "/" + hash + (isShortListingNames ? "/main.lst" : "/main.c.lst");
+ const QString mainListing = productBuildDir + "/" + hash
+ + "/main.c" + compilerListingSuffix;
QCOMPARE(regularFileExists(mainListing), generateListing);
- const QString funListing = productBuildDir + "/" + hash + (isShortListingNames ? "/fun.lst" : "/fun.c.lst");
+ const QString funListing = productBuildDir + "/" + hash
+ + "/fun.c" + compilerListingSuffix;
QCOMPARE(regularFileExists(funListing), generateListing);
}
void TestBlackboxBareMetal::linkerMapFile_data()
{
QTest::addColumn<bool>("generateMap");
- QTest::newRow("do-not-generate-linker-map") << false;
- QTest::newRow("generate-linker-map") << true;
+ QTest::addColumn<QString>("customMapSuffix");
+ QTest::newRow("do-not-generate-linker-map") << false << "";
+ QTest::newRow("generate-default-linker-map") << true << "";
+ QTest::newRow("generate-custom-linker-map") << true << ".mmm";
}
void TestBlackboxBareMetal::linkerMapFile()
{
QFETCH(bool, generateMap);
+ QFETCH(QString, customMapSuffix);
QDir::setCurrent(testDataDir + "/linker-map");
rmDirR(relativeBuildDir());
- const QStringList args = {QStringLiteral("modules.cpp.generateLinkerMapFile:%1")
- .arg(generateMap ? "true" : "false")};
+ QStringList args = {QStringLiteral("modules.cpp.generateLinkerMapFile:%1")
+ .arg(generateMap ? "true" : "false")};
+ if (!customMapSuffix.isEmpty())
+ args << QStringLiteral("modules.cpp.linkerMapSuffix:%1").arg(customMapSuffix);
+
QCOMPARE(runQbs(QbsRunParameters("resolve", args)), 0);
- if (m_qbsStdout.contains("unsupported toolset:"))
- QSKIP(unsupportedToolsetMessage(m_qbsStdout));
- if (!m_qbsStdout.contains("current toolset:"))
- QFAIL("No current toolset pattern exists");
+ if (!m_qbsStdout.contains("linker map suffix:"))
+ QFAIL("No current linker map suffix pattern exists");
- QByteArray toolchain;
- QByteArray architecture;
- if (!extractToolset(m_qbsStdout, toolchain, architecture))
- QFAIL("Unable to extract current toolset");
+ QString linkerMapSuffix;
+ if (!extractQuitedValue(m_qbsStdout, linkerMapSuffix))
+ QFAIL("Unable to extract current linker map suffix");
+
+ if (!customMapSuffix.isEmpty())
+ QCOMPARE(linkerMapSuffix, customMapSuffix);
QCOMPARE(runQbs(QbsRunParameters(args)), 0);
const QString productBuildDir = relativeProductBuildDir("linker-map");
- const auto extension = linkerMapFileExtension(toolchain, architecture);
- const QString linkerMap = productBuildDir + "/linker-map" + extension;
+ const QString linkerMap = productBuildDir + "/linker-map" + linkerMapSuffix;
QCOMPARE(regularFileExists(linkerMap), generateMap);
}
diff --git a/tests/auto/blackbox/tst_blackboxwindows.cpp b/tests/auto/blackbox/tst_blackboxwindows.cpp
new file mode 100644
index 000000000..0c82754fb
--- /dev/null
+++ b/tests/auto/blackbox/tst_blackboxwindows.cpp
@@ -0,0 +1,174 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "tst_blackboxwindows.h"
+
+#include "../shared.h"
+
+#include <tools/hostosinfo.h>
+
+#include <QtCore/qdir.h>
+#include <QtCore/qregularexpression.h>
+
+using qbs::Internal::HostOsInfo;
+
+struct SigntoolInfo
+{
+ enum class CodeSignResult { Failed = 0, Signed, Unsigned };
+ CodeSignResult result = CodeSignResult::Failed;
+ bool timestamped = false;
+ QString hashAlgorithm;
+ QString subjectName;
+};
+
+Q_DECLARE_METATYPE(SigntoolInfo::CodeSignResult)
+
+static SigntoolInfo extractSigntoolInfo(const QString &signtoolPath, const QString &appPath)
+{
+ QProcess signtool;
+ signtool.start(signtoolPath, { QStringLiteral("verify"), QStringLiteral("/v"), appPath });
+ if (!signtool.waitForStarted() || !signtool.waitForFinished())
+ return {};
+ const auto output = signtool.readAllStandardError();
+ SigntoolInfo signtoolInfo;
+ if (output.contains("No signature found")) {
+ signtoolInfo.result = SigntoolInfo::CodeSignResult::Unsigned;
+ } else {
+ signtoolInfo.result = SigntoolInfo::CodeSignResult::Signed;
+ const auto output = signtool.readAllStandardOutput();
+ const auto lines = output.split('\n');
+ for (const auto &line: lines) {
+ {
+ const QRegularExpression re("^Hash of file \\((.+)\\):.+$");
+ const QRegularExpressionMatch match = re.match(line);
+ if (match.hasMatch()) {
+ signtoolInfo.hashAlgorithm = match.captured(1).toLocal8Bit();
+ continue;
+ }
+ }
+ {
+ const QRegularExpression re("Issued to: (.+)");
+ const QRegularExpressionMatch match = re.match(line);
+ if (match.hasMatch()) {
+ signtoolInfo.subjectName = match.captured(1).toLocal8Bit().trimmed();
+ continue;
+ }
+ }
+ if (line.startsWith("The signature is timestamped:")) {
+ signtoolInfo.timestamped = true;
+ break;
+ } else if (line.startsWith("File is not timestamped.")) {
+ break;
+ }
+ }
+ }
+ return signtoolInfo;
+}
+
+static QString extractSigntoolPath(const QByteArray &output)
+{
+ const QRegularExpression re("%%(.+)%%");
+ QRegularExpressionMatchIterator it = re.globalMatch(output);
+ if (!it.hasNext())
+ return {};
+ const QRegularExpressionMatch match = it.next();
+ return match.captured(1).toUtf8();
+}
+
+TestBlackboxWindows::TestBlackboxWindows()
+ : TestBlackboxBase (SRCDIR "/testdata-windows", "blackbox-windows")
+{
+}
+
+void TestBlackboxWindows::initTestCase()
+{
+ if (!HostOsInfo::isWindowsHost()) {
+ QSKIP("only applies on Windows");
+ return;
+ }
+
+ TestBlackboxBase::initTestCase();
+}
+
+void TestBlackboxWindows::standaloneCodesign()
+{
+ QFETCH(SigntoolInfo::CodeSignResult, result);
+ QFETCH(QString, hashAlgorithm);
+ QFETCH(QString, subjectName);
+ QFETCH(QString, signingTimestamp);
+
+ QDir::setCurrent(testDataDir + "/codesign");
+ QbsRunParameters params(QStringList{"qbs.installPrefix:''"});
+ params.arguments << QStringLiteral("project.enableSigning:%1").arg(
+ (result == SigntoolInfo::CodeSignResult::Signed) ? "true" : "false")
+ << QStringLiteral("project.hashAlgorithm:%1").arg(hashAlgorithm)
+ << QStringLiteral("project.subjectName:%1").arg(subjectName)
+ << QStringLiteral("project.signingTimestamp:%1").arg(signingTimestamp);
+
+ rmDirR(relativeBuildDir());
+ QCOMPARE(runQbs(params), 0);
+
+ if (!m_qbsStdout.contains("signtool path:"))
+ QFAIL("No current signtool path pattern exists");
+
+ const auto signtoolPath = extractSigntoolPath(m_qbsStdout);
+ QVERIFY(QFileInfo(signtoolPath).exists());
+
+ const QStringList outputBinaries = {"A.exe", "B.dll"};
+ for (const auto &outputBinary : outputBinaries) {
+ const auto outputBinaryPath = defaultInstallRoot + "/" + outputBinary;
+ QVERIFY(QFileInfo(outputBinaryPath).exists());
+
+ const SigntoolInfo signtoolInfo = extractSigntoolInfo(signtoolPath, outputBinaryPath);
+ QVERIFY(signtoolInfo.result != SigntoolInfo::CodeSignResult::Failed);
+ QCOMPARE(signtoolInfo.result, result);
+ QCOMPARE(signtoolInfo.hashAlgorithm, hashAlgorithm);
+ QCOMPARE(signtoolInfo.subjectName, subjectName);
+ QCOMPARE(signtoolInfo.timestamped, !signingTimestamp.isEmpty());
+ }
+}
+
+void TestBlackboxWindows::standaloneCodesign_data()
+{
+ QTest::addColumn<SigntoolInfo::CodeSignResult>("result");
+ QTest::addColumn<QString>("hashAlgorithm");
+ QTest::addColumn<QString>("subjectName");
+ QTest::addColumn<QString>("signingTimestamp");
+
+ QTest::newRow("standalone, unsigned")
+ << SigntoolInfo::CodeSignResult::Unsigned << "" << "" << "";
+ QTest::newRow("standalone, signed, sha1, qbs@community.test, no timestamp")
+ << SigntoolInfo::CodeSignResult::Signed << "sha1" << "qbs@community.test" << "";
+ QTest::newRow("standalone, signed, sha256, qbs@community.test, RFC3061 timestamp")
+ << SigntoolInfo::CodeSignResult::Signed << "sha256" << "qbs@community.test"
+ << "http://timestamp.digicert.com";
+}
+
+QTEST_MAIN(TestBlackboxWindows)
diff --git a/tests/auto/blackbox/tst_blackboxwindows.h b/tests/auto/blackbox/tst_blackboxwindows.h
new file mode 100644
index 000000000..fbc597313
--- /dev/null
+++ b/tests/auto/blackbox/tst_blackboxwindows.h
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef TST_BLACKBOXWINDOWS_H
+#define TST_BLACKBOXWINDOWS_H
+
+#include "tst_blackboxbase.h"
+
+class TestBlackboxWindows : public TestBlackboxBase
+{
+ Q_OBJECT
+
+public:
+ TestBlackboxWindows();
+
+public slots:
+ void initTestCase() override;
+
+private slots:
+ void standaloneCodesign();
+ void standaloneCodesign_data();
+};
+
+#endif // TST_BLACKBOXWINDOWS_H
diff --git a/tests/auto/tools/tst_tools.cpp b/tests/auto/tools/tst_tools.cpp
index edf5a1308..92e0978b5 100644
--- a/tests/auto/tools/tst_tools.cpp
+++ b/tests/auto/tools/tst_tools.cpp
@@ -673,6 +673,30 @@ void TestTools::set_containsSet()
QVERIFY(set3.contains(set4));
}
+void TestTools::set_find()
+{
+ Set<QString> set1;
+
+ for (int i = 0; i < 500; ++i) {
+ QVERIFY(set1.find(QString::number(i)) == set1.end());
+ set1.insert(QString::number(i));
+ const auto it = set1.find(QString::number(i));
+ QVERIFY(it != set1.end());
+ QVERIFY(*it == QString::number(i));
+ }
+
+ QCOMPARE(set1.size(), size_t { 500 });
+
+ for (int j = 0; j < 500; ++j) {
+ int i = (j * 17) % 500;
+ const auto it = set1.find(QString::number(i));
+ QVERIFY(it != set1.end());
+ QVERIFY(*it == QString::number(i));
+ set1.remove(QString::number(i));
+ QVERIFY(set1.find(QString::number(i)) == set1.end());
+ }
+}
+
void TestTools::set_begin()
{
Set<int> set1;
diff --git a/tests/auto/tools/tst_tools.h b/tests/auto/tools/tst_tools.h
index bd8538be2..d1ba0a57b 100644
--- a/tests/auto/tools/tst_tools.h
+++ b/tests/auto/tools/tst_tools.h
@@ -79,6 +79,7 @@ private slots:
void set_remove();
void set_contains();
void set_containsSet();
+ void set_find();
void set_begin();
void set_end();
void set_insert();