aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--changelogs/changes-1.9.0.md2
-rw-r--r--doc/codeattributions.qdoc201
-rw-r--r--doc/qbs.qdoc13
-rw-r--r--docker/windowsservercore/Dockerfile10
-rw-r--r--share/qbs/modules/cpp/android-gcc.qbs34
-rw-r--r--share/qbs/modules/cpp/msvc.js25
-rw-r--r--share/qbs/modules/cpp/windows-mingw.qbs6
-rw-r--r--src/app/qbs-setup-android/qbs-setup-android.exe.manifest13
-rw-r--r--src/app/qbs-setup-android/qbs-setup-android.qbs5
-rw-r--r--src/app/qbs-setup-android/qbs-setup-android.rc4
-rw-r--r--src/app/qbs-setup-toolchains/qbs-setup-toolchains.qbs5
-rw-r--r--src/lib/corelib/buildgraph/executor.cpp29
-rw-r--r--src/lib/corelib/buildgraph/productinstaller.cpp7
-rw-r--r--src/lib/corelib/buildgraph/rulesapplicator.cpp1
-rw-r--r--src/lib/corelib/buildgraph/transformer.cpp11
-rw-r--r--src/lib/corelib/buildgraph/transformer.h1
-rw-r--r--src/lib/corelib/corelib.pro1
-rw-r--r--src/lib/corelib/corelib.qbs1
-rw-r--r--src/lib/corelib/parser/qmljsastvisitor_p.h2
-rw-r--r--src/lib/corelib/parser/qmljsengine_p.h2
-rw-r--r--src/lib/corelib/parser/qmljsglobal_p.h9
-rw-r--r--src/lib/corelib/parser/qmljslexer_p.h2
-rw-r--r--src/lib/corelib/parser/qmljsparser_p.h2
-rw-r--r--src/lib/corelib/tools/fileinfo.cpp29
-rw-r--r--src/lib/corelib/tools/fileinfo.h3
-rw-r--r--src/packages/chocolatey/qbs.nuspec2
-rw-r--r--tests/auto/blackbox/testdata/check-timestamps/check-timestamps.qbs10
-rw-r--r--tests/auto/blackbox/testdata/check-timestamps/file.cpp3
-rw-r--r--tests/auto/blackbox/testdata/check-timestamps/file.h1
-rw-r--r--tests/auto/blackbox/testdata/check-timestamps/main.cpp1
-rw-r--r--tests/auto/blackbox/testdata/cxx-language-version/cxx-language-version.qbs30
-rw-r--r--tests/auto/blackbox/testdata/cxx-language-version/main.cpp1
-rw-r--r--tests/auto/blackbox/testdata/rescue-transformer-data/main.cpp1
-rw-r--r--tests/auto/blackbox/testdata/rescue-transformer-data/modules/m/m.qbs21
-rw-r--r--tests/auto/blackbox/testdata/rescue-transformer-data/transformer-data-rescue.qbs7
-rw-r--r--tests/auto/blackbox/tst_blackbox.cpp108
-rw-r--r--tests/auto/blackbox/tst_blackbox.h4
-rw-r--r--tests/auto/tools/tst_tools.cpp11
38 files changed, 568 insertions, 50 deletions
diff --git a/changelogs/changes-1.9.0.md b/changelogs/changes-1.9.0.md
index 55345c1cc..2e3cbfa09 100644
--- a/changelogs/changes-1.9.0.md
+++ b/changelogs/changes-1.9.0.md
@@ -41,6 +41,8 @@
upward (see the `ld64` man page for more information).
* The property `cpp.useCxxPrecompiledHeader`, as well as the variants for the
other languages, now defaults to true.
+* The property `cpp.cxxLanguageVersion` now gets mapped to MSVC's `/std` option,
+ if applicable.
# Apple
* Added support for building macOS disk images.
diff --git a/doc/codeattributions.qdoc b/doc/codeattributions.qdoc
new file mode 100644
index 000000000..ee4e4b901
--- /dev/null
+++ b/doc/codeattributions.qdoc
@@ -0,0 +1,201 @@
+/*!
+
+\contentspage attributions.html
+\ingroup attributions-libs
+\ingroup attributions-qbs
+\page qbs-attribution-ds_store.html attribution
+\target ds_store
+
+\title ds_store
+\brief MIT License
+
+Manipulate Finder .DS_Store files from Python
+
+Used in the qbs dmg module for building Apple disk images.
+
+The sources can be found in src/3rdparty/python/lib/python2.7/site-packages/ds_store.
+
+\l{https://github.com/al45tair/ds_store}{Project Homepage}, upstream version: 1.1.2
+
+
+\badcode
+Copyright (c) 2014 Alastair Houghton
+\endcode
+
+\l{https://spdx.org/licenses/MIT.html}{MIT License}.
+
+\badcode
+Copyright (c) 2014 Alastair Houghton
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+\endcode
+*/
+
+/*!
+
+\contentspage attributions.html
+\ingroup attributions-libs
+\ingroup attributions-qbs
+\page qbs-attribution-dmgbuild.html attribution
+\target dmgbuild
+
+\title dmgbuild
+\brief MIT License
+
+macOS command line utility to build disk images
+
+Used in the qbs dmg module for building Apple disk images.
+
+The sources can be found in src/3rdparty/python/lib/python2.7/site-packages/dmgbuild.
+
+\l{https://github.com/al45tair/dmgbuild}{Project Homepage}, upstream version: 1.3.1
+
+
+\badcode
+Copyright (c) 2014 Alastair Houghton
+\endcode
+
+\l{https://spdx.org/licenses/MIT.html}{MIT License}.
+
+\badcode
+Copyright (c) 2014 Alastair Houghton
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+\endcode
+*/
+
+/*!
+
+\contentspage attributions.html
+\ingroup attributions-libs
+\ingroup attributions-qbs
+\page qbs-attribution-mac_alias.html attribution
+\target mac_alias
+
+\title mac_alias
+\brief MIT License
+
+Generate/parse Mac OS Alias records from Python
+
+Used in the qbs dmg module for building Apple disk images.
+
+The sources can be found in src/3rdparty/python/lib/python2.7/site-packages/mac_alias.
+
+\l{https://github.com/al45tair/mac_alias}{Project Homepage}, upstream version: 2.0.6
+
+
+\badcode
+Copyright (c) 2014 Alastair Houghton
+\endcode
+
+\l{https://spdx.org/licenses/MIT.html}{MIT License}.
+
+\badcode
+Copyright (c) 2014 Alastair Houghton
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+\endcode
+*/
+
+/*!
+
+\contentspage attributions.html
+\ingroup attributions-libs
+\ingroup attributions-qbs
+\page qbs-attribution-biplist.html attribution
+\target biplist
+
+\title biplist
+\brief BSD 3-clause "New" or "Revised" License
+
+biplist is a library for reading/writing binary plists.
+
+Used in the qbs dmg module for building Apple disk images.
+
+The sources can be found in src/3rdparty/python/lib/python2.7/site-packages/biplist.
+
+\l{https://bitbucket.org/wooster/biplist}{Project Homepage}, upstream version: 1.0.2
+
+
+\badcode
+Copyright (c) 2010, Andrew Wooster
+\endcode
+
+\l{https://spdx.org/licenses/BSD-3-Clause.html}{BSD 3-clause "New" or "Revised" License}.
+
+\badcode
+Copyright (c) 2010, Andrew Wooster
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of biplist nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\endcode
+*/
diff --git a/doc/qbs.qdoc b/doc/qbs.qdoc
index 3e01e862f..abacf6d71 100644
--- a/doc/qbs.qdoc
+++ b/doc/qbs.qdoc
@@ -85,6 +85,7 @@
\endlist
\li \l{Appendix A: Building Qbs}
+ \li \l{Appendix B: Code Attributions}
\endlist
*/
@@ -123,6 +124,7 @@
\contentspage index.html
\previouspage reference.html
\page building-qbs.html
+ \nextpage attributions.html
\title Appendix A: Building Qbs
@@ -1121,3 +1123,14 @@
\c Product.name), the generator will typically suggest it in the error
message.
*/
+
+/*!
+ \contentspage index.html
+ \previouspage building-qbs.html
+ \page attributions.html
+
+ \title Appendix B: Code Attributions
+
+ \QBS contains third-party code, which we gratefully acknowledge:
+ \generatelist{groupsbymodule attributions-qbs}
+*/
diff --git a/docker/windowsservercore/Dockerfile b/docker/windowsservercore/Dockerfile
index 0e6e78e60..942ecbd2b 100644
--- a/docker/windowsservercore/Dockerfile
+++ b/docker/windowsservercore/Dockerfile
@@ -1,4 +1,4 @@
-FROM microsoft/windowsservercore:10.0.14393.1358
+FROM microsoft/windowsservercore:10.0.14393.1480
LABEL Description="Windows Server Core development environment for Qbs with Qt 5.9, Chocolatey and various dependencies for testing Qbs modules and functionality"
# Disable crash dialog for release-mode runtimes
@@ -22,7 +22,7 @@ RUN @powershell -NoProfile -ExecutionPolicy Bypass -Command \
$Env:chocolateyVersion = '0.10.5' ; \
$Env:chocolateyUseWindowsCompression = 'false' ; \
"iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))" && SET "PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin"
-RUN choco install -y qbs --version 1.8.1
-RUN choco install -y unzip --version 6.0
-RUN choco install -y visualcpp-build-tools --version 14.0.25420.1
-RUN choco install -y zip --version 3.0
+RUN choco install -y qbs --version 1.8.1 && qbs --version
+RUN choco install -y unzip --version 6.0 && unzip -v
+RUN choco install -y visualcpp-build-tools --version 14.0.25420.1 && dir "%PROGRAMFILES(X86)%\Microsoft Visual C++ Build Tools"
+RUN choco install -y zip --version 3.0 && zip -v
diff --git a/share/qbs/modules/cpp/android-gcc.qbs b/share/qbs/modules/cpp/android-gcc.qbs
index 5307c06a4..a21f56f2a 100644
--- a/share/qbs/modules/cpp/android-gcc.qbs
+++ b/share/qbs/modules/cpp/android-gcc.qbs
@@ -85,6 +85,13 @@ LinuxGCC {
? FileInfo.joinPaths(stlLibsDir, staticLibraryPrefix + Android.ndk.appStl + staticLibrarySuffix)
: undefined
+ Group {
+ name: "Android STL"
+ condition: product.cpp.sharedStlFilePath
+ files: product.cpp.sharedStlFilePath ? [product.cpp.sharedStlFilePath] : []
+ fileTags: ["android.unstripped-stl"]
+ }
+
toolchainInstallPath: FileInfo.joinPaths(Android.ndk.ndkDir, "toolchains",
toolchainDir, "prebuilt",
Android.ndk.hostArch, "bin")
@@ -203,7 +210,22 @@ LinuxGCC {
endianness: "little"
Rule {
+ inputs: ["android.unstripped-stl"]
+ Artifact {
+ filePath: FileInfo.joinPaths("stripped-libs", input.fileName);
+ fileTags: ["android.stripped-stl"]
+ }
+ prepare: {
+ var args = ["--strip-unneeded", "-o", output.filePath, input.filePath];
+ var cmd = new Command(product.cpp.stripPath, args);
+ cmd.description = "stripping " + input.fileName;
+ return [cmd];
+ }
+ }
+
+ Rule {
inputs: ["dynamiclibrary"]
+ explicitlyDependsOn: ["android.stripped-stl"];
outputFileTags: ["android.nativelibrary", "android.gdbserver-info", "android.stl-info"]
outputArtifacts: {
var artifacts = [{
@@ -217,17 +239,14 @@ LinuxGCC {
fileTags: ["android.gdbserver-info"]
});
}
- var stlFilePath = product.moduleProperty("cpp", "sharedStlFilePath");
- if (stlFilePath)
+ if (explicitlyDependsOn["android.stripped-stl"])
artifacts.push({filePath: "android.stl-info.txt", fileTags: ["android.stl-info"]});
return artifacts;
}
prepare: {
- var stlFilePath = product.moduleProperty("cpp", "sharedStlFilePath");
var copyCmd = new JavaScriptCommand();
copyCmd.silent = true;
- copyCmd.stlFilePath = stlFilePath;
copyCmd.sourceCode = function() {
File.copy(inputs["dynamiclibrary"][0].filePath,
outputs["android.nativelibrary"][0].filePath);
@@ -246,8 +265,9 @@ LinuxGCC {
infoFile.writeLine(targetPath);
infoFile.close();
}
- if (stlFilePath) {
- var srcPath = stlFilePath;
+ var strippedStlList = explicitlyDependsOn["android.stripped-stl"];
+ if (strippedStlList) {
+ var srcPath = strippedStlList[0].filePath;
var targetPath = FileInfo.joinPaths(destDir, FileInfo.fileName(srcPath));
var infoFile = new TextFile(outputs["android.stl-info"][0].filePath,
TextFile.WriteOnly);
@@ -257,8 +277,6 @@ LinuxGCC {
}
}
var stripArgs = ["--strip-unneeded", outputs["android.nativelibrary"][0].filePath];
- if (stlFilePath)
- stripArgs.push(stlFilePath);
var stripCmd = new Command(product.moduleProperty("cpp", "stripPath"), stripArgs);
stripCmd.description = "Stripping unneeded symbols from "
+ outputs["android.nativelibrary"][0].fileName;
diff --git a/share/qbs/modules/cpp/msvc.js b/share/qbs/modules/cpp/msvc.js
index 4d12ee427..13e5d8821 100644
--- a/share/qbs/modules/cpp/msvc.js
+++ b/share/qbs/modules/cpp/msvc.js
@@ -57,6 +57,25 @@ function handleCpuFeatures(input, flags) {
}
}
+function addLanguageVersionFlag(input, args) {
+ var cxxVersion = input.cpp.cxxLanguageVersion;
+ if (!cxxVersion)
+ return;
+
+ // Visual C++ 2013, Update 3
+ var hasStdOption = Utilities.versionCompare(input.cpp.compilerVersion, "18.00.30723") >= 0;
+ if (!hasStdOption)
+ return;
+
+ var flag;
+ if (cxxVersion === "c++14")
+ flag = "/std:c++14";
+ else if (cxxVersion !== "c++11" && cxxVersion !== "c++98")
+ flag = "/std:c++latest";
+ if (flag)
+ args.push(flag);
+}
+
function prepareCompiler(project, product, inputs, outputs, input, output, explicitlyDependsOn) {
var i;
var debugInformation = input.cpp.debugInformation;
@@ -164,10 +183,12 @@ function prepareCompiler(project, product, inputs, outputs, input, output, expli
args.push("/FI" + FileInfo.toWindowsSeparators(prefixHeaders[i]));
// Language
- if (tag === "cpp")
+ if (tag === "cpp") {
args.push("/TP");
- else if (tag === "c")
+ addLanguageVersionFlag(input, args);
+ } else if (tag === "c") {
args.push("/TC");
+ }
// Whether we're compiling a precompiled header or normal source file
var pchOutput = outputs[tag + "_pch"] ? outputs[tag + "_pch"][0] : undefined;
diff --git a/share/qbs/modules/cpp/windows-mingw.qbs b/share/qbs/modules/cpp/windows-mingw.qbs
index fec31cf3f..2fe96495e 100644
--- a/share/qbs/modules/cpp/windows-mingw.qbs
+++ b/share/qbs/modules/cpp/windows-mingw.qbs
@@ -85,15 +85,17 @@ GenericGCC {
}
prepare: {
+ var inputList = inputs["native.pe.manifest"];
// TODO: Emulate manifest merging like Microsoft's mt.exe tool does
- if (inputs.length !== 1)
+ if (inputList.length !== 1) {
throw("The MinGW toolchain does not support manifest merging; " +
"you may only specify a single manifest file to embed into your assembly.");
+ }
var cmd = new JavaScriptCommand();
cmd.silent = true;
cmd.productType = product.type;
- cmd.inputFilePath = inputs[0].filePath;
+ cmd.inputFilePath = inputList[0].filePath;
cmd.outputFilePath = output.filePath;
cmd.sourceCode = function() {
var tf;
diff --git a/src/app/qbs-setup-android/qbs-setup-android.exe.manifest b/src/app/qbs-setup-android/qbs-setup-android.exe.manifest
new file mode 100644
index 000000000..6b425b152
--- /dev/null
+++ b/src/app/qbs-setup-android/qbs-setup-android.exe.manifest
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+ <!-- Make sure Windows UAC does not believe qbs-setup-android is an installer. -->
+ <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+ <security>
+ <requestedPrivileges>
+ <requestedExecutionLevel
+ level="asInvoker"
+ uiAccess="false"/>
+ </requestedPrivileges>
+ </security>
+ </trustInfo>
+</assembly>
diff --git a/src/app/qbs-setup-android/qbs-setup-android.qbs b/src/app/qbs-setup-android/qbs-setup-android.qbs
index 0eb67f9c5..edadd5dd1 100644
--- a/src/app/qbs-setup-android/qbs-setup-android.qbs
+++ b/src/app/qbs-setup-android/qbs-setup-android.qbs
@@ -9,4 +9,9 @@ QbsApp {
"commandlineparser.h",
"main.cpp",
]
+ Group {
+ name: "MinGW specific files"
+ condition: qbs.toolchain.contains("mingw")
+ files: ["qbs-setup-android.exe.manifest", "qbs-setup-android.rc"]
+ }
}
diff --git a/src/app/qbs-setup-android/qbs-setup-android.rc b/src/app/qbs-setup-android/qbs-setup-android.rc
new file mode 100644
index 000000000..20cd1ab11
--- /dev/null
+++ b/src/app/qbs-setup-android/qbs-setup-android.rc
@@ -0,0 +1,4 @@
+#define RT_MANIFEST 24
+#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1
+
+CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "qbs-setup-android.exe.manifest"
diff --git a/src/app/qbs-setup-toolchains/qbs-setup-toolchains.qbs b/src/app/qbs-setup-toolchains/qbs-setup-toolchains.qbs
index 3536b51db..1b7cb6526 100644
--- a/src/app/qbs-setup-toolchains/qbs-setup-toolchains.qbs
+++ b/src/app/qbs-setup-toolchains/qbs-setup-toolchains.qbs
@@ -14,4 +14,9 @@ QbsApp {
"xcodeprobe.cpp",
"xcodeprobe.h",
]
+ Group {
+ name: "MinGW specific files"
+ condition: qbs.toolchain.contains("mingw")
+ files: ["qbs-setup-toolchains.exe.manifest", "qbs-setup-toolchains.rc"]
+ }
}
diff --git a/src/lib/corelib/buildgraph/executor.cpp b/src/lib/corelib/buildgraph/executor.cpp
index 1c50f7234..c5f652db5 100644
--- a/src/lib/corelib/buildgraph/executor.cpp
+++ b/src/lib/corelib/buildgraph/executor.cpp
@@ -860,24 +860,27 @@ void Executor::potentiallyRunTransformer(const TransformerPtr &transformer)
return;
}
- if (!mustExecuteTransformer(transformer)) {
+ const bool mustExecute = mustExecuteTransformer(transformer);
+ if (mustExecute || m_buildOptions.forceTimestampCheck()) {
+ for (Artifact * const output : qAsConst(transformer->outputs)) {
+ // Scan all input artifacts. If new dependencies were found during scanning, delay
+ // execution of this transformer.
+ InputArtifactScanner scanner(output, m_inputArtifactScanContext, m_logger);
+ AccumulatingTimer scanTimer(m_buildOptions.logElapsedTime()
+ ? &m_elapsedTimeScanners : nullptr);
+ scanner.scan();
+ scanTimer.stop();
+ if (scanner.newDependencyAdded() && checkForUnbuiltDependencies(output))
+ return;
+ }
+ }
+
+ if (!mustExecute) {
qCDebug(lcExec) << "Up to date. Skipping.";
finishTransformer(transformer);
return;
}
- for (Artifact * const output : qAsConst(transformer->outputs)) {
- // Scan all input artifacts. If new dependencies were found during scanning, delay
- // execution of this transformer.
- InputArtifactScanner scanner(output, m_inputArtifactScanContext, m_logger);
- AccumulatingTimer scanTimer(m_buildOptions.logElapsedTime()
- ? &m_elapsedTimeScanners : nullptr);
- scanner.scan();
- scanTimer.stop();
- if (scanner.newDependencyAdded() && checkForUnbuiltDependencies(output))
- return;
- }
-
if (m_buildOptions.executeRulesOnly())
finishTransformer(transformer);
else
diff --git a/src/lib/corelib/buildgraph/productinstaller.cpp b/src/lib/corelib/buildgraph/productinstaller.cpp
index 1688dcc76..1b1e507bb 100644
--- a/src/lib/corelib/buildgraph/productinstaller.cpp
+++ b/src/lib/corelib/buildgraph/productinstaller.cpp
@@ -151,11 +151,14 @@ QString ProductInstaller::targetFilePath(const TopLevelProject *project,
localAbsBasePath));
}
- targetFilePath.remove(0, localAbsBasePath.length() + 1);
+ // Since there is a difference between X: and X:\\ on Windows, absolute paths can sometimes
+ // end with a slash, so only remove an extra character if there is no ending slash
+ targetFilePath.remove(0, localAbsBasePath.length()
+ + (localAbsBasePath.endsWith(QLatin1Char('/')) ? 0 : 1));
}
targetFilePath.prepend(targetDir + QLatin1Char('/'));
- return targetFilePath;
+ return QDir::cleanPath(targetFilePath);
}
void ProductInstaller::initInstallRoot(const TopLevelProject *project,
diff --git a/src/lib/corelib/buildgraph/rulesapplicator.cpp b/src/lib/corelib/buildgraph/rulesapplicator.cpp
index f4f57cb15..4a5954a73 100644
--- a/src/lib/corelib/buildgraph/rulesapplicator.cpp
+++ b/src/lib/corelib/buildgraph/rulesapplicator.cpp
@@ -354,6 +354,7 @@ Artifact *RulesApplicator::createOutputArtifact(const QString &filePath, const F
if (m_rule->declaresInputs() && m_rule->requiresInputs)
outputArtifact->clearTimestamp();
m_invalidatedArtifacts += outputArtifact;
+ m_transformer->rescueChangeTrackingData(outputArtifact->transformer);
} else {
QScopedPointer<Artifact> newArtifact(new Artifact);
newArtifact->artifactType = Artifact::Generated;
diff --git a/src/lib/corelib/buildgraph/transformer.cpp b/src/lib/corelib/buildgraph/transformer.cpp
index 0e5b4a084..b6e02e708 100644
--- a/src/lib/corelib/buildgraph/transformer.cpp
+++ b/src/lib/corelib/buildgraph/transformer.cpp
@@ -260,6 +260,17 @@ void Transformer::createCommands(ScriptEngine *engine, const ScriptFunctionConst
}
}
+void Transformer::rescueChangeTrackingData(const TransformerConstPtr &other)
+{
+ if (!other)
+ return;
+ propertiesRequestedInPrepareScript = other->propertiesRequestedInPrepareScript;
+ propertiesRequestedInCommands = other->propertiesRequestedInCommands;
+ propertiesRequestedFromArtifactInPrepareScript
+ = other->propertiesRequestedFromArtifactInPrepareScript;
+ propertiesRequestedFromArtifactInCommands = other->propertiesRequestedFromArtifactInCommands;
+}
+
void Transformer::load(PersistentPool &pool)
{
pool.load(rule);
diff --git a/src/lib/corelib/buildgraph/transformer.h b/src/lib/corelib/buildgraph/transformer.h
index e4ffcb83b..b83321bda 100644
--- a/src/lib/corelib/buildgraph/transformer.h
+++ b/src/lib/corelib/buildgraph/transformer.h
@@ -82,6 +82,7 @@ public:
void setupExplicitlyDependsOn(QScriptValue targetScriptValue);
void createCommands(ScriptEngine *engine, const ScriptFunctionConstPtr &script,
const QScriptValueList &args);
+ void rescueChangeTrackingData(const TransformerConstPtr &other);
private:
Transformer();
diff --git a/src/lib/corelib/corelib.pro b/src/lib/corelib/corelib.pro
index 8e53891fd..c0026f14b 100644
--- a/src/lib/corelib/corelib.pro
+++ b/src/lib/corelib/corelib.pro
@@ -13,7 +13,6 @@ qbs_enable_project_file_updates: QT += gui
INCLUDEPATH += $$PWD
CONFIG += depend_includepath
-DEFINES += QT_CREATOR QML_BUILD_STATIC_LIB # needed for QmlJS
DEFINES += SRCDIR=\\\"$$PWD\\\"
diff --git a/src/lib/corelib/corelib.qbs b/src/lib/corelib/corelib.qbs
index 43efa24f1..570eb4605 100644
--- a/src/lib/corelib/corelib.qbs
+++ b/src/lib/corelib/corelib.qbs
@@ -18,7 +18,6 @@ QbsLibrary {
cpp.defines: base.concat([
'QBS_RELATIVE_LIBEXEC_PATH="' + qbsbuildconfig.relativeLibexecPath + '"',
"QBS_VERSION=\"" + version + "\"",
- "QT_CREATOR", "QML_BUILD_STATIC_LIB", // needed for QmlJS
]).concat(projectFileUpdateDefines).concat(enableUnitTestsDefines)
Properties {
diff --git a/src/lib/corelib/parser/qmljsastvisitor_p.h b/src/lib/corelib/parser/qmljsastvisitor_p.h
index aa4471c6b..bec174c65 100644
--- a/src/lib/corelib/parser/qmljsastvisitor_p.h
+++ b/src/lib/corelib/parser/qmljsastvisitor_p.h
@@ -58,7 +58,7 @@
namespace QbsQmlJS {
namespace AST {
-class QML_PARSER_EXPORT QBS_AUTOTEST_EXPORT Visitor
+class QBS_AUTOTEST_EXPORT Visitor
{
public:
Visitor();
diff --git a/src/lib/corelib/parser/qmljsengine_p.h b/src/lib/corelib/parser/qmljsengine_p.h
index 2fdd60b30..6ff53a6e9 100644
--- a/src/lib/corelib/parser/qmljsengine_p.h
+++ b/src/lib/corelib/parser/qmljsengine_p.h
@@ -88,7 +88,7 @@ public:
QString message;
};
-class QML_PARSER_EXPORT QBS_AUTOTEST_EXPORT Engine
+class QBS_AUTOTEST_EXPORT Engine
{
Lexer *_lexer;
Directives *_directives;
diff --git a/src/lib/corelib/parser/qmljsglobal_p.h b/src/lib/corelib/parser/qmljsglobal_p.h
index 5a875c01a..c3d198ea5 100644
--- a/src/lib/corelib/parser/qmljsglobal_p.h
+++ b/src/lib/corelib/parser/qmljsglobal_p.h
@@ -41,6 +41,15 @@
#include <QtCore/qglobal.h>
+// Force QML_PARSER_EXPORT to be always empty.
+#ifndef QT_CREATOR
+# define QT_CREATOR
+#endif
+#ifdef QML_BUILD_STATIC_LIB
+# undef QML_BUILD_STATIC_LIB
+#endif
+#define QML_BUILD_STATIC_LIB 1
+
#ifdef QT_CREATOR
# ifdef QMLJS_BUILD_DIR
# define QML_PARSER_EXPORT Q_DECL_EXPORT
diff --git a/src/lib/corelib/parser/qmljslexer_p.h b/src/lib/corelib/parser/qmljslexer_p.h
index e0d61b226..e9dff1dd4 100644
--- a/src/lib/corelib/parser/qmljslexer_p.h
+++ b/src/lib/corelib/parser/qmljslexer_p.h
@@ -82,7 +82,7 @@ public:
}
};
-class QML_PARSER_EXPORT QBS_AUTOTEST_EXPORT Lexer: public QmlJSGrammar
+class QBS_AUTOTEST_EXPORT Lexer: public QmlJSGrammar
{
public:
enum {
diff --git a/src/lib/corelib/parser/qmljsparser_p.h b/src/lib/corelib/parser/qmljsparser_p.h
index 38fc1f5ce..fde61ea11 100644
--- a/src/lib/corelib/parser/qmljsparser_p.h
+++ b/src/lib/corelib/parser/qmljsparser_p.h
@@ -70,7 +70,7 @@ namespace QbsQmlJS {
class Engine;
-class QML_PARSER_EXPORT QBS_AUTOTEST_EXPORT Parser: protected QmlJSGrammar
+class QBS_AUTOTEST_EXPORT Parser: protected QmlJSGrammar
{
public:
union Value {
diff --git a/src/lib/corelib/tools/fileinfo.cpp b/src/lib/corelib/tools/fileinfo.cpp
index 27fe2b9e2..3e2f0d36c 100644
--- a/src/lib/corelib/tools/fileinfo.cpp
+++ b/src/lib/corelib/tools/fileinfo.cpp
@@ -131,6 +131,15 @@ bool FileInfo::exists(const QString &fp)
return FileInfo(fp).exists();
}
+// Whether a path is the special "current drive path" path type,
+// which is neither truly relative nor absolute
+static bool isCurrentDrivePath(const QString &path, HostOsInfo::HostOs hostOs)
+{
+ return hostOs == HostOsInfo::HostOsWindows
+ ? path.size() == 2 && path.at(1) == QLatin1Char(':') && path.at(0).isLetter()
+ : false;
+}
+
// from creator/src/shared/proparser/ioutils.cpp
bool FileInfo::isAbsolute(const QString &path, HostOsInfo::HostOs hostOs)
{
@@ -176,11 +185,12 @@ bool FileInfo::isPattern(const QStringRef &str)
* This function assumes that both paths are clean, that is they don't contain
* double slashes or redundant dot parts.
*/
-QString FileInfo::resolvePath(const QString &base, const QString &rel)
+QString FileInfo::resolvePath(const QString &base, const QString &rel, HostOsInfo::HostOs hostOs)
{
- QBS_ASSERT(isAbsolute(base), qDebug("base: %s, rel: %s", qPrintable(base), qPrintable(rel));
+ QBS_ASSERT(isAbsolute(base, hostOs) && !isCurrentDrivePath(rel, hostOs),
+ qDebug("base: %s, rel: %s", qPrintable(base), qPrintable(rel));
return QString());
- if (isAbsolute(rel))
+ if (isAbsolute(rel, hostOs))
return rel;
if (rel.size() == 1 && rel.at(0) == QLatin1Char('.'))
return base;
@@ -204,12 +214,13 @@ QString FileInfo::resolvePath(const QString &base, const QString &rel)
int idx = r.lastIndexOf(QLatin1Char('/'));
if (idx >= 0)
r.truncate(idx);
- return r;
+ s.clear();
+ }
+ if (!s.isEmpty() || isCurrentDrivePath(r, hostOs)) {
+ r.reserve(r.length() + 1 + s.length());
+ r += QLatin1Char('/');
+ r += s;
}
-
- r.reserve(r.length() + 1 + s.length());
- r += QLatin1Char('/');
- r += s;
return r;
}
@@ -317,7 +328,7 @@ static QString resolveSymlinks(const QString &fileName)
{
QFileInfo fi(fileName);
while (fi.isSymLink())
- fi.setFile(fi.symLinkTarget());
+ fi.setFile(fi.dir(), fi.symLinkTarget());
return fi.absoluteFilePath();
}
diff --git a/src/lib/corelib/tools/fileinfo.h b/src/lib/corelib/tools/fileinfo.h
index 71d178265..2ab250c0a 100644
--- a/src/lib/corelib/tools/fileinfo.h
+++ b/src/lib/corelib/tools/fileinfo.h
@@ -75,7 +75,8 @@ public:
static bool isAbsolute(const QString &fp, HostOsInfo::HostOs hostOs = HostOsInfo::hostOs());
static bool isPattern(const QStringRef &str);
static bool isPattern(const QString &str);
- static QString resolvePath(const QString &base, const QString &rel);
+ static QString resolvePath(const QString &base, const QString &rel,
+ HostOsInfo::HostOs hostOs = HostOsInfo::hostOs());
static bool globMatches(const QRegExp &pattern, const QString &subject);
static bool isFileCaseCorrect(const QString &filePath);
diff --git a/src/packages/chocolatey/qbs.nuspec b/src/packages/chocolatey/qbs.nuspec
index 3926ec7db..42ccbae8b 100644
--- a/src/packages/chocolatey/qbs.nuspec
+++ b/src/packages/chocolatey/qbs.nuspec
@@ -5,7 +5,7 @@
<id>qbs</id>
<title>Qbs</title>
<authors>Qt Project</authors>
- <owners>jakepetroules</owners>
+ <owners>qbs</owners>
<summary>Build tool that helps simplify the build process for developing projects across multiple platforms.</summary>
<description>Qbs is a tool that helps simplify the build process for developing projects across multiple platforms.</description>
<projectUrl>https://wiki.qt.io/Qbs</projectUrl>
diff --git a/tests/auto/blackbox/testdata/check-timestamps/check-timestamps.qbs b/tests/auto/blackbox/testdata/check-timestamps/check-timestamps.qbs
new file mode 100644
index 000000000..32456444c
--- /dev/null
+++ b/tests/auto/blackbox/testdata/check-timestamps/check-timestamps.qbs
@@ -0,0 +1,10 @@
+import qbs
+
+CppApplication {
+ name: "app"
+ files: [
+ "file.cpp",
+ "file.h",
+ "main.cpp",
+ ]
+}
diff --git a/tests/auto/blackbox/testdata/check-timestamps/file.cpp b/tests/auto/blackbox/testdata/check-timestamps/file.cpp
new file mode 100644
index 000000000..4752b89d5
--- /dev/null
+++ b/tests/auto/blackbox/testdata/check-timestamps/file.cpp
@@ -0,0 +1,3 @@
+#include "file.h"
+
+void f() { }
diff --git a/tests/auto/blackbox/testdata/check-timestamps/file.h b/tests/auto/blackbox/testdata/check-timestamps/file.h
new file mode 100644
index 000000000..789447c02
--- /dev/null
+++ b/tests/auto/blackbox/testdata/check-timestamps/file.h
@@ -0,0 +1 @@
+void f();
diff --git a/tests/auto/blackbox/testdata/check-timestamps/main.cpp b/tests/auto/blackbox/testdata/check-timestamps/main.cpp
new file mode 100644
index 000000000..237c8ce18
--- /dev/null
+++ b/tests/auto/blackbox/testdata/check-timestamps/main.cpp
@@ -0,0 +1 @@
+int main() {}
diff --git a/tests/auto/blackbox/testdata/cxx-language-version/cxx-language-version.qbs b/tests/auto/blackbox/testdata/cxx-language-version/cxx-language-version.qbs
new file mode 100644
index 000000000..436c64c5e
--- /dev/null
+++ b/tests/auto/blackbox/testdata/cxx-language-version/cxx-language-version.qbs
@@ -0,0 +1,30 @@
+import qbs
+
+CppApplication {
+ name: "app"
+
+ files: ["main.cpp"]
+
+ Probe {
+ id: compilerProbe
+ property stringList toolchain: qbs.toolchain
+ property string compilerVersion: cpp.compilerVersion
+
+ configure: {
+ var isNewerMsvc;
+ var isOlderMsvc;
+ var isGcc;
+ if (toolchain.contains("msvc")) {
+ if (compilerVersion >= "18.00.30723")
+ isNewerMsvc = true;
+ else
+ isOlderMsvc = true;
+ } else {
+ isGcc = true;
+ }
+ console.info("is newer MSVC: " + isNewerMsvc);
+ console.info("is older MSVC: " + isOlderMsvc);
+ console.info("is GCC: " + isGcc);
+ }
+ }
+}
diff --git a/tests/auto/blackbox/testdata/cxx-language-version/main.cpp b/tests/auto/blackbox/testdata/cxx-language-version/main.cpp
new file mode 100644
index 000000000..237c8ce18
--- /dev/null
+++ b/tests/auto/blackbox/testdata/cxx-language-version/main.cpp
@@ -0,0 +1 @@
+int main() {}
diff --git a/tests/auto/blackbox/testdata/rescue-transformer-data/main.cpp b/tests/auto/blackbox/testdata/rescue-transformer-data/main.cpp
new file mode 100644
index 000000000..237c8ce18
--- /dev/null
+++ b/tests/auto/blackbox/testdata/rescue-transformer-data/main.cpp
@@ -0,0 +1 @@
+int main() {}
diff --git a/tests/auto/blackbox/testdata/rescue-transformer-data/modules/m/m.qbs b/tests/auto/blackbox/testdata/rescue-transformer-data/modules/m/m.qbs
new file mode 100644
index 000000000..03fdf7a6b
--- /dev/null
+++ b/tests/auto/blackbox/testdata/rescue-transformer-data/modules/m/m.qbs
@@ -0,0 +1,21 @@
+import qbs
+
+Module {
+ property bool p
+
+ Rule {
+ multiplex: true
+ Artifact {
+ filePath: "dummy"
+ fileTags: ["out"]
+ }
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.description = "creating dummy";
+ cmd.sourceCode = function() {
+ console.info("m.p: " + product.m.p);
+ };
+ return [cmd];
+ }
+ }
+}
diff --git a/tests/auto/blackbox/testdata/rescue-transformer-data/transformer-data-rescue.qbs b/tests/auto/blackbox/testdata/rescue-transformer-data/transformer-data-rescue.qbs
new file mode 100644
index 000000000..2eafcc01d
--- /dev/null
+++ b/tests/auto/blackbox/testdata/rescue-transformer-data/transformer-data-rescue.qbs
@@ -0,0 +1,7 @@
+import qbs
+
+CppApplication {
+ type: base.concat(["out"])
+ Depends { name: "m" }
+ files: ["main.cpp"]
+}
diff --git a/tests/auto/blackbox/tst_blackbox.cpp b/tests/auto/blackbox/tst_blackbox.cpp
index 65c0630fc..c4b6a061e 100644
--- a/tests/auto/blackbox/tst_blackbox.cpp
+++ b/tests/auto/blackbox/tst_blackbox.cpp
@@ -1242,6 +1242,83 @@ void TestBlackbox::conflictingArtifacts()
QVERIFY2(m_qbsStderr.contains("Conflicting artifacts"), m_qbsStderr.constData());
}
+void TestBlackbox::cxxLanguageVersion()
+{
+ QDir::setCurrent(testDataDir + "/cxx-language-version");
+ rmDirR(relativeBuildDir());
+ QFETCH(QString, version);
+ QFETCH(QVariantMap, requiredFlags);
+ QFETCH(QVariantMap, forbiddenFlags);
+ QbsRunParameters resolveParams;
+ resolveParams.command = "resolve";
+ resolveParams.arguments << "--force-probe-execution";
+ if (!version.isEmpty())
+ resolveParams.arguments << ("modules.cpp.cxxLanguageVersion:" + version);
+ QCOMPARE(runQbs(resolveParams), 0);
+ QString mapKey;
+ if (m_qbsStdout.contains("is newer MSVC: true"))
+ mapKey = "msvc-new";
+ else if (m_qbsStdout.contains("is older MSVC: true"))
+ mapKey = "msvc_old";
+ else if (m_qbsStdout.contains("is GCC: true"))
+ mapKey = "gcc";
+ QVERIFY2(!mapKey.isEmpty(), m_qbsStdout.constData());
+ QbsRunParameters buildParams;
+ buildParams.expectFailure = mapKey == "gcc" && (version == "c++17" || version == "c++21");
+ buildParams.arguments = QStringList({"--command-echo-mode", "command-line"});
+ const int retVal = runQbs(buildParams);
+ if (!buildParams.expectFailure)
+ QCOMPARE(retVal, 0);
+ const QString requiredFlag = requiredFlags.value(mapKey).toString();
+ if (!requiredFlag.isEmpty())
+ QVERIFY2(m_qbsStdout.contains(requiredFlag.toLocal8Bit()), m_qbsStdout.constData());
+ const QString forbiddenFlag = forbiddenFlags.value(mapKey).toString();
+ if (!forbiddenFlag.isEmpty())
+ QVERIFY2(!m_qbsStdout.contains(forbiddenFlag.toLocal8Bit()), m_qbsStdout.constData());
+}
+
+void TestBlackbox::cxxLanguageVersion_data()
+{
+ QTest::addColumn<QString>("version");
+ QTest::addColumn<QVariantMap>("requiredFlags");
+ QTest::addColumn<QVariantMap>("forbiddenFlags");
+
+ QTest::newRow("C++98")
+ << QString("c++98")
+ << QVariantMap({std::make_pair(QString("gcc"), QString("-std=c++98"))})
+ << QVariantMap({std::make_pair(QString("msvc-old"), QString("/std:")),
+ std::make_pair(QString("msvc-new"), QString("/std:"))});
+ QTest::newRow("C++11")
+ << QString("c++11")
+ << QVariantMap({std::make_pair(QString("gcc"), QString("-std=c++0x"))})
+ << QVariantMap({std::make_pair(QString("msvc-old"), QString("/std:")),
+ std::make_pair(QString("msvc-new"), QString("/std:"))});
+ QTest::newRow("C++14")
+ << QString("c++14")
+ << QVariantMap({std::make_pair(QString("gcc"), QString("-std=c++1y")),
+ std::make_pair(QString("msvc-new"), QString("/std:c++14"))
+ })
+ << QVariantMap({std::make_pair(QString("msvc-old"), QString("/std:"))});
+ QTest::newRow("C++17")
+ << QString("c++17")
+ << QVariantMap({std::make_pair(QString("gcc"), QString("-std=c++17")),
+ std::make_pair(QString("msvc-new"), QString("/std:c++latest"))
+ })
+ << QVariantMap({std::make_pair(QString("msvc-old"), QString("/std:"))});
+ QTest::newRow("C++21")
+ << QString("c++21")
+ << QVariantMap({std::make_pair(QString("gcc"), QString("-std=c++21")),
+ std::make_pair(QString("msvc-new"), QString("/std:c++latest"))
+ })
+ << QVariantMap({std::make_pair(QString("msvc-old"), QString("/std:"))});
+ QTest::newRow("default")
+ << QString()
+ << QVariantMap()
+ << QVariantMap({std::make_pair(QString("gcc"), QString("-std=")),
+ std::make_pair(QString("msvc-old"), QString("/std:")),
+ std::make_pair(QString("msvc-new"), QString("/std:"))});
+}
+
void TestBlackbox::cpuFeatures()
{
QDir::setCurrent(testDataDir + "/cpu-features");
@@ -3503,6 +3580,23 @@ void TestBlackbox::requireDeprecated()
m_qbsStderr.constData());
}
+void TestBlackbox::rescueTransformerData()
+{
+ QDir::setCurrent(testDataDir + "/rescue-transformer-data");
+ QCOMPARE(runQbs(), 0);
+ QVERIFY2(m_qbsStdout.contains("compiling main.cpp") && m_qbsStdout.contains("m.p: undefined"),
+ m_qbsStdout.constData());
+ WAIT_FOR_NEW_TIMESTAMP();
+ touch("main.cpp");
+ QCOMPARE(runQbs(), 0);
+ QVERIFY2(m_qbsStdout.contains("compiling main.cpp") && !m_qbsStdout.contains("m.p: "),
+ m_qbsStdout.constData());
+ QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("modules.m.p:true"))), 0);
+ QCOMPARE(runQbs(), 0);
+ QVERIFY2(!m_qbsStdout.contains("compiling main.cpp") && m_qbsStdout.contains("m.p: true"),
+ m_qbsStdout.constData());
+}
+
void TestBlackbox::multipleChanges()
{
QDir::setCurrent(testDataDir + "/multiple-changes");
@@ -4200,6 +4294,20 @@ void TestBlackbox::checkProjectFilePath()
QVERIFY2(m_qbsStdout.contains("main2.cpp"), m_qbsStdout.constData());
}
+void TestBlackbox::checkTimestamps()
+{
+ QDir::setCurrent(testDataDir + "/check-timestamps");
+ QCOMPARE(runQbs(), 0);
+ QVERIFY2(m_qbsStdout.contains("compiling file.cpp"), m_qbsStdout.constData());
+ QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData());
+ QVERIFY(QFile::remove(relativeBuildGraphFilePath()));
+ WAIT_FOR_NEW_TIMESTAMP();
+ touch("file.h");
+ QCOMPARE(runQbs(QStringList("--check-timestamps")), 0);
+ QVERIFY2(m_qbsStdout.contains("compiling file.cpp"), m_qbsStdout.constData());
+ QVERIFY2(!m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData());
+}
+
class TemporaryDefaultProfileRemover
{
public:
diff --git a/tests/auto/blackbox/tst_blackbox.h b/tests/auto/blackbox/tst_blackbox.h
index 35e5ffe97..b08f43dd8 100644
--- a/tests/auto/blackbox/tst_blackbox.h
+++ b/tests/auto/blackbox/tst_blackbox.h
@@ -55,6 +55,7 @@ private slots:
void changeInImportedFile();
void changeTrackingAndMultiplexing();
void checkProjectFilePath();
+ void checkTimestamps();
void clean();
void cli();
void combinedSources();
@@ -65,6 +66,8 @@ private slots:
void conditionalFileTagger();
void configure();
void conflictingArtifacts();
+ void cxxLanguageVersion();
+ void cxxLanguageVersion_data();
void cpuFeatures();
void dependenciesProperty();
void dependencyProfileMismatch();
@@ -168,6 +171,7 @@ private slots:
void reproducibleBuild_data();
void require();
void requireDeprecated();
+ void rescueTransformerData();
void responseFiles();
void ruleConditions();
void ruleCycle();
diff --git a/tests/auto/tools/tst_tools.cpp b/tests/auto/tools/tst_tools.cpp
index 9cfbb08e3..dca88f438 100644
--- a/tests/auto/tools/tst_tools.cpp
+++ b/tests/auto/tools/tst_tools.cpp
@@ -88,12 +88,21 @@ void TestTools::testFileInfo()
QCOMPARE(FileInfo::path("C:/fileInDriveRoot"), QString("C:/"));
QVERIFY(!FileInfo::isAbsolute("bla/lol"));
QVERIFY(FileInfo::isAbsolute("/bla/lol"));
- if (HostOsInfo::isWindowsHost())
+ if (HostOsInfo::isWindowsHost()) {
QVERIFY(FileInfo::isAbsolute("C:\\bla\\lol"));
+ QVERIFY(FileInfo::isAbsolute("C:\\"));
+ QVERIFY(FileInfo::isAbsolute("C:/"));
+ QVERIFY(!FileInfo::isAbsolute("C:"));
+ }
QCOMPARE(FileInfo::resolvePath("/abc/lol", "waffl"), QString("/abc/lol/waffl"));
QCOMPARE(FileInfo::resolvePath("/abc/def/ghi/jkl/", "../foo/bar"), QString("/abc/def/ghi/foo/bar"));
QCOMPARE(FileInfo::resolvePath("/abc/def/ghi/jkl/", "../../foo/bar"), QString("/abc/def/foo/bar"));
QCOMPARE(FileInfo::resolvePath("/abc", "../../../foo/bar"), QString("/foo/bar"));
+ if (HostOsInfo::isWindowsHost()) {
+ QCOMPARE(FileInfo::resolvePath("C:/share", ".."), QString("C:/"));
+ QCOMPARE(FileInfo::resolvePath("C:/share", "D:/"), QString("D:/"));
+ QCOMPARE(FileInfo::resolvePath("C:/share", "D:"), QString()); // should soft-assert
+ }
QCOMPARE(FileInfo("/does/not/exist").lastModified(), FileTime());
}