aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--changelogs/changes-3.0.0.md1
-rw-r--r--doc/reference/modules/cpp-module.qdoc26
-rw-r--r--doc/tutorial.qdoc32
-rw-r--r--share/qbs/imports/qbs/Probes/MsvcProbe.qbs5
-rw-r--r--share/qbs/modules/cpp/CppModule.qbs10
-rw-r--r--share/qbs/modules/cpp/GenericGCC.qbs20
-rw-r--r--share/qbs/modules/cpp/gcc.js49
-rw-r--r--share/qbs/modules/cpp/msvc.js37
-rw-r--r--share/qbs/modules/cpp/windows-msvc.qbs20
-rw-r--r--tests/auto/blackbox/testdata/cxx-modules/import-std-compat/import-std-compat.qbs26
-rw-r--r--tests/auto/blackbox/testdata/cxx-modules/import-std-compat/main.cpp10
-rw-r--r--tests/auto/blackbox/testdata/cxx-modules/import-std/import-std.qbs26
-rw-r--r--tests/auto/blackbox/testdata/cxx-modules/import-std/main.cpp6
-rw-r--r--tests/auto/blackbox/tst_blackbox.cpp2
-rw-r--r--tutorial/chapter-10-3/main.cpp13
-rw-r--r--tutorial/chapter-10-3/myproject.qbs28
16 files changed, 311 insertions, 0 deletions
diff --git a/changelogs/changes-3.0.0.md b/changelogs/changes-3.0.0.md
index 96cefeee1..164a07910 100644
--- a/changelogs/changes-3.0.0.md
+++ b/changelogs/changes-3.0.0.md
@@ -4,6 +4,7 @@
* Errors during project resolving print a sort of stack trace now, giving users
a better idea about what is going wrong.
* The JavaScript backend was switched to `QuickJS-NG`, which is actively maintained.
+* Added support for C++ standard library modules - "import std;" and "import std.compat;".
# Language
* Introduced new property `minimal` to `Depends` item that controls whether the
diff --git a/doc/reference/modules/cpp-module.qdoc b/doc/reference/modules/cpp-module.qdoc
index 76b15ce7b..d35a87ea7 100644
--- a/doc/reference/modules/cpp-module.qdoc
+++ b/doc/reference/modules/cpp-module.qdoc
@@ -1998,3 +1998,29 @@
\defaultvalue \c{false}
*/
+
+/*!
+ \qmlproperty bool cpp::forceUseImportStd
+ \since Qbs 3.0
+
+ Set this property to \c true to force the use of the C++23 standard library module via
+ \c{import std;}.
+
+ \note This property is only effective with toolchains and standard libraries that support
+ the C++23 standard library module.
+
+ \defaultvalue \c{false}
+*/
+
+/*!
+ \qmlproperty bool cpp::forceUseImportStdCompat
+ \since Qbs 3.0
+
+ Set this property to \c true to force the use of the C++23 standard library compatibility
+ module via \c{import std.compat;}.
+
+ \note This property is only effective with toolchains and standard libraries that support
+ the C++23 standard library compatibility module.
+
+ \defaultvalue \c{false}
+*/
diff --git a/doc/tutorial.qdoc b/doc/tutorial.qdoc
index c076d054a..a04d3b3af 100644
--- a/doc/tutorial.qdoc
+++ b/doc/tutorial.qdoc
@@ -726,4 +726,36 @@
For more details, see the complete
\l{https://github.com/qbs/qbs/tree/2.5/tutorial/chapter-10-2}{example}.
+
+ \section1 Import std module
+
+ Starting with C++23, you can use the standard library as a module by using \c{import std;} or
+ \c{import std.compat;}.
+
+ In order to use \c{import std;}, you need to set the
+ \l{cpp::forceUseImportStd}{cpp.forceUseImportStd} property to \c{true}.
+
+ Here's a simple example that demonstrates the use of the standard library module:
+
+ \snippet ../tutorial/chapter-10-3/main.cpp 0
+
+ The project file needs to be configured to use C++23 and enable the standard library module:
+
+ \snippet ../tutorial/chapter-10-3/myproject.qbs 0
+
+ \note This feature requires a compiler and standard library that support the C++23 standard
+ library module. Currently, this feature is experimental and may not be available in all
+ toolchains.
+
+ The full product file may look like this:
+
+ \snippet ../tutorial/chapter-10-3/myproject.qbs 1
+
+ In order to use \c{import std.compat;}, you will also need to set the
+ \l{cpp::forceUseImportStdCompat}{cpp.forceUseImportStdCompat} to \c{true}:
+
+ \code
+ cpp.forceUseImportStd: true
+ cpp.forceUseImportCompatStd: true
+ \endcode
*/ \ No newline at end of file
diff --git a/share/qbs/imports/qbs/Probes/MsvcProbe.qbs b/share/qbs/imports/qbs/Probes/MsvcProbe.qbs
index d3624e010..03959bfab 100644
--- a/share/qbs/imports/qbs/Probes/MsvcProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/MsvcProbe.qbs
@@ -46,6 +46,7 @@ PathProbe {
property int versionMinor
property int versionPatch
property stringList includePaths
+ property string modulesPath
property var buildEnv
property var compilerDefinesByLanguage
@@ -87,6 +88,10 @@ PathProbe {
if (File.exists(inclPath))
includePaths = [inclPath];
+ var modsPath = FileInfo.joinPaths(clParentDir, "..", "..", "modules");
+ if (File.exists(modsPath))
+ modulesPath = modsPath;
+
if (preferredArchitecture && Utilities.canonicalArchitecture(preferredArchitecture)
!== Utilities.canonicalArchitecture(architecture)) {
throw "'" + preferredArchitecture +
diff --git a/share/qbs/modules/cpp/CppModule.qbs b/share/qbs/modules/cpp/CppModule.qbs
index a18bc8b4f..bb80b7046 100644
--- a/share/qbs/modules/cpp/CppModule.qbs
+++ b/share/qbs/modules/cpp/CppModule.qbs
@@ -64,6 +64,9 @@ Module {
property bool useObjcPrecompiledHeader: true
property bool useObjcxxPrecompiledHeader: true
property bool forceUseCxxModules: false
+ property bool forceUseImportStd: false
+ property bool forceUseImportStdCompat: false
+ property stringList stdModulesFiles
property string moduleOutputFlag // undocumented
property string moduleFileFlag // undocumented
@@ -429,6 +432,13 @@ Module {
property bool importPrivateLibraries: true
+ Group {
+ name: "std modules"
+ condition: stdModulesFiles !== undefined
+ files: stdModulesFiles
+ fileTags: "cppm"
+ }
+
// TODO: The following four rules could use a convenience base item if rule properties
// were available in Artifact items and prepare scripts.
Rule {
diff --git a/share/qbs/modules/cpp/GenericGCC.qbs b/share/qbs/modules/cpp/GenericGCC.qbs
index ed66f19c0..1936519cc 100644
--- a/share/qbs/modules/cpp/GenericGCC.qbs
+++ b/share/qbs/modules/cpp/GenericGCC.qbs
@@ -73,6 +73,26 @@ CppModule {
flags: targetDriverFlags.concat(sysrootFlags)
_sysroot: sysroot
}
+
+ stdModulesFiles: stdModulesProbe.found ? stdModulesProbe._stdModulesFiles : undefined
+ Probe {
+ // input
+ property bool _forceUseImportStd : forceUseImportStd
+ property bool _forceUseImportStdCompat : forceUseImportStdCompat
+ property stringList _toolchain: qbs.toolchain
+ property string _compilerPath : compilerPathByLanguage["cpp"]
+
+ // output
+ property stringList _stdModulesFiles
+
+ id: stdModulesProbe
+ condition: !_skipAllChecks
+ && stdModulesFiles === undefined
+ && !qbs.toolchain.includes("mingw")
+ && (forceUseImportStd || forceUseImportStdCompat)
+ configure: Gcc.configureStdModules()
+ }
+
property var probeEnv
Probes.BinaryProbe {
diff --git a/share/qbs/modules/cpp/gcc.js b/share/qbs/modules/cpp/gcc.js
index 09f7ee69f..6d84cbed9 100644
--- a/share/qbs/modules/cpp/gcc.js
+++ b/share/qbs/modules/cpp/gcc.js
@@ -1791,3 +1791,52 @@ function wasmArtifacts(product)
return artifacts;
}
+
+function configureStdModules() {
+ try {
+ var probe = new Process();
+ // check which stdlib is used? this actually works:
+ // clang-18 -print-file-name=libstdc++.modules.json --sysroot /opt/gcc-15/
+ const modulesJsonFiles = [
+ "libc++.modules.json",
+ "libstdc++.modules.json",
+ "../../c++/libc++.modules.json",
+ ];
+ for (var i = 0; i < modulesJsonFiles.length; ++i) {
+ const modulesJsonFile = modulesJsonFiles[i];
+ const result = probe.exec(_compilerPath, ["-print-file-name=" + modulesJsonFile], false);
+ if (result !== 0)
+ continue;
+ const path = probe.readStdOut().trim();
+ if (path !== modulesJsonFile && FileInfo.isAbsolutePath(path) && File.exists(path)) {
+ const jsonFile = new TextFile(path, TextFile.ReadOnly);
+
+ const json = JSON.parse(jsonFile.readAll());
+ jsonFile.close();
+ const modules = json.modules
+ .filter(function(module) {
+ const logicalName = module["logical-name"];
+ if (logicalName === "std" && (_forceUseImportStd || _forceUseImportStdCompat)) {
+ return true;
+ } else if (logicalName === "std.compat" && _forceUseImportStdCompat) {
+ return true;
+ }
+ return false;
+ })
+ .map(function(module) {
+ return FileInfo.joinPaths(FileInfo.path(path), module["source-path"]);
+ })
+ .filter(function(module) {
+ return File.exists(module);
+ });
+ if (modules.length > 0) {
+ found = true;
+ _stdModulesFiles = modules;
+ break;
+ }
+ }
+ }
+ } finally {
+ probe.close();
+ }
+}
diff --git a/share/qbs/modules/cpp/msvc.js b/share/qbs/modules/cpp/msvc.js
index 192d7b1cb..b079c3215 100644
--- a/share/qbs/modules/cpp/msvc.js
+++ b/share/qbs/modules/cpp/msvc.js
@@ -33,6 +33,7 @@ var Cpp = require("cpp.js");
var File = require("qbs.File");
var FileInfo = require("qbs.FileInfo");
var ModUtils = require("qbs.ModUtils");
+var TextFile = require("qbs.TextFile");
var Utilities = require("qbs.Utilities");
var WindowsUtils = require("qbs.WindowsUtils");
@@ -808,3 +809,39 @@ function appLinkerOutputArtifacts(product)
}
return artifacts;
}
+
+function configureStdModules() {
+ try {
+ const modulesJsonPath = FileInfo.joinPaths(_modulesDirPath, "modules.json");
+ if (File.exists(modulesJsonPath)) {
+ const jsonFile = new TextFile(modulesJsonPath, TextFile.ReadOnly);
+ const json = JSON.parse(jsonFile.readAll());
+ jsonFile.close();
+
+ const moduleSources = json["module-sources"];
+ if (moduleSources) {
+ const modules = moduleSources
+ .filter(function(module) {
+ if (module === "std.ixx" && (_forceUseImportStd || _forceUseImportStdCompat)) {
+ return true;
+ } else if (module === "std.compat.ixx" && _forceUseImportStdCompat) {
+ return true;
+ }
+ return false;
+ })
+ .map(function(module) {
+ return FileInfo.joinPaths(_modulesDirPath, module);
+ })
+ .filter(function(module) {
+ return File.exists(module);
+ });
+ if (modules.length > 0) {
+ found = true;
+ _stdModulesFiles = modules;
+ }
+ }
+ }
+ } catch (e) {
+ console.error("Error reading modules.json: " + e);
+ }
+}
diff --git a/share/qbs/modules/cpp/windows-msvc.qbs b/share/qbs/modules/cpp/windows-msvc.qbs
index a7b99c324..4bb9f3963 100644
--- a/share/qbs/modules/cpp/windows-msvc.qbs
+++ b/share/qbs/modules/cpp/windows-msvc.qbs
@@ -32,6 +32,7 @@
import qbs.Host
import qbs.Probes
import "windows-msvc-base.qbs" as MsvcBaseModule
+import 'msvc.js' as MSVC
MsvcBaseModule {
condition: Host.os().includes('windows') &&
@@ -75,4 +76,23 @@ MsvcBaseModule {
compiledModuleSuffix: ".ifc"
moduleOutputFlag: "-ifcOutput "
moduleFileFlag: "-reference %module%="
+
+ stdModulesFiles: stdModulesProbe.found ? stdModulesProbe._stdModulesFiles : undefined
+ Probe {
+ id: stdModulesProbe
+ condition: msvcProbe.found
+ && !_skipAllChecks
+ && stdModulesFiles === undefined
+ && (forceUseImportStd || forceUseImportStdCompat)
+
+ // input
+ property string _modulesDirPath: msvcProbe.modulesPath
+ property bool _forceUseImportStd : forceUseImportStd
+ property bool _forceUseImportStdCompat : forceUseImportStdCompat
+
+ // output
+ property stringList _stdModulesFiles
+
+ configure: MSVC.configureStdModules()
+ }
}
diff --git a/tests/auto/blackbox/testdata/cxx-modules/import-std-compat/import-std-compat.qbs b/tests/auto/blackbox/testdata/cxx-modules/import-std-compat/import-std-compat.qbs
new file mode 100644
index 000000000..1f97b5679
--- /dev/null
+++ b/tests/auto/blackbox/testdata/cxx-modules/import-std-compat/import-std-compat.qbs
@@ -0,0 +1,26 @@
+// Checks simple case with a single module.
+CppApplication {
+ name: "import-std-compat"
+ condition: {
+ if (qbs.toolchainType === "msvc"
+ || ((qbs.toolchainType === "gcc" || qbs.toolchainType === "mingw")
+ && cpp.compilerVersionMajor >= 15)
+ || (qbs.toolchainType === "clang" && cpp.compilerVersionMajor >= 18)) {
+ return true;
+ }
+ console.info("Unsupported toolchainType " + qbs.toolchainType);
+ return false;
+ }
+ consoleApplication: true
+ files: [
+ "main.cpp"
+ ]
+ cpp.cxxLanguageVersion: "c++23"
+ cpp.forceUseCxxModules: true
+ cpp.forceUseImportStdCompat: true
+ Properties {
+ condition: qbs.toolchainType === "clang"
+ cpp.cxxFlags: ["-Wno-reserved-module-identifier"]
+ cpp.cxxStandardLibrary: "libc++"
+ }
+} \ No newline at end of file
diff --git a/tests/auto/blackbox/testdata/cxx-modules/import-std-compat/main.cpp b/tests/auto/blackbox/testdata/cxx-modules/import-std-compat/main.cpp
new file mode 100644
index 000000000..9ecdf7b38
--- /dev/null
+++ b/tests/auto/blackbox/testdata/cxx-modules/import-std-compat/main.cpp
@@ -0,0 +1,10 @@
+import std.compat;
+
+int main()
+{
+ std::cout << "Hello from std.compat!" << std::endl;
+
+ printf("Using printf from std.compat\n");
+
+ return 0;
+} \ No newline at end of file
diff --git a/tests/auto/blackbox/testdata/cxx-modules/import-std/import-std.qbs b/tests/auto/blackbox/testdata/cxx-modules/import-std/import-std.qbs
new file mode 100644
index 000000000..2b87bbfe9
--- /dev/null
+++ b/tests/auto/blackbox/testdata/cxx-modules/import-std/import-std.qbs
@@ -0,0 +1,26 @@
+// Checks simple case with a single module.
+CppApplication {
+ name: "import-std"
+ condition: {
+ if (qbs.toolchainType === "msvc"
+ || ((qbs.toolchainType === "gcc" || qbs.toolchainType === "mingw")
+ && cpp.compilerVersionMajor >= 15)
+ || (qbs.toolchainType === "clang" && cpp.compilerVersionMajor >= 18)) {
+ return true;
+ }
+ console.info("Unsupported toolchainType " + qbs.toolchainType);
+ return false;
+ }
+ consoleApplication: true
+ files: [
+ "main.cpp"
+ ]
+ cpp.cxxLanguageVersion: "c++23"
+ cpp.forceUseCxxModules: true
+ cpp.forceUseImportStd: true
+ Properties {
+ condition: qbs.toolchainType === "clang"
+ cpp.cxxFlags: ["-Wno-reserved-module-identifier"]
+ cpp.cxxStandardLibrary: "libc++"
+ }
+}
diff --git a/tests/auto/blackbox/testdata/cxx-modules/import-std/main.cpp b/tests/auto/blackbox/testdata/cxx-modules/import-std/main.cpp
new file mode 100644
index 000000000..521b58ec8
--- /dev/null
+++ b/tests/auto/blackbox/testdata/cxx-modules/import-std/main.cpp
@@ -0,0 +1,6 @@
+import std;
+
+int main()
+{
+ std::cout << "Hello World!" << std::endl;
+}
diff --git a/tests/auto/blackbox/tst_blackbox.cpp b/tests/auto/blackbox/tst_blackbox.cpp
index 7bc58b549..c1342061d 100644
--- a/tests/auto/blackbox/tst_blackbox.cpp
+++ b/tests/auto/blackbox/tst_blackbox.cpp
@@ -2136,6 +2136,8 @@ void TestBlackbox::cxxModules_data()
QTest::newRow("single-module") << "single-mod";
QTest::newRow("dot-in-name") << "dot-in-name";
QTest::newRow("export-import") << "export-import";
+ QTest::newRow("import-std") << "import-std";
+ QTest::newRow("import-std-compat") << "import-std-compat";
QTest::newRow("dependent-modules") << "dep-mods";
QTest::newRow("declaration-implementation") << "decl-impl";
QTest::newRow("library-module") << "lib-mod";
diff --git a/tutorial/chapter-10-3/main.cpp b/tutorial/chapter-10-3/main.cpp
new file mode 100644
index 000000000..88594765d
--- /dev/null
+++ b/tutorial/chapter-10-3/main.cpp
@@ -0,0 +1,13 @@
+//![0]
+// main.cpp
+
+import std;
+
+int main()
+{
+ std::vector<int> numbers = {1, 2, 3, 4, 5};
+ std::ranges::for_each(numbers, [](int n) { std::cout << n << ' '; });
+ std::cout << std::endl;
+ return 0;
+}
+//![0]
diff --git a/tutorial/chapter-10-3/myproject.qbs b/tutorial/chapter-10-3/myproject.qbs
new file mode 100644
index 000000000..f22e504e1
--- /dev/null
+++ b/tutorial/chapter-10-3/myproject.qbs
@@ -0,0 +1,28 @@
+//![1]
+// myproject.qbs
+CppApplication {
+ condition: {
+ if (qbs.toolchainType === "msvc"
+ || ((qbs.toolchainType === "gcc")
+ && cpp.compilerVersionMajor >= 15)
+ || (qbs.toolchainType === "clang" && cpp.compilerVersionMajor >= 18)) {
+ return true;
+ }
+ console.info("Unsupported toolchainType " + qbs.toolchainType);
+ return false;
+ }
+ consoleApplication: true
+ install: true
+ files: ["main.cpp" ]
+ //![0]
+ cpp.cxxLanguageVersion: "c++23"
+ cpp.forceUseCxxModules: true
+ cpp.forceUseImportStd: true
+ //![0]
+ Properties {
+ condition: qbs.toolchainType === "clang"
+ cpp.cxxFlags: ["-Wno-reserved-module-identifier"]
+ cpp.cxxStandardLibrary: "libc++"
+ }
+}
+//![1]