summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2025-05-12 21:52:11 +0800
committerGitHub <[email protected]>2025-05-12 21:52:11 +0800
commit715b1767f84c804fcb30fbc79e4fe8cc212db534 (patch)
treeec686272a1208650bddad62d326db05d96b2a28c
parent9ecfe9b05e0891ea06f834b8ca75f2433504ce31 (diff)
parent730ec08c13052e980b84a28cd36e495135df40c2 (diff)
Merge pull request #6421 from Arthapz/improve-libstdc++-module
(C++ modules support) improve std module support for gcc and clang
-rw-r--r--tests/projects/c++/modules/stdmodules_deps/src/bar.mpp7
-rw-r--r--tests/projects/c++/modules/stdmodules_deps/src/foo.cpp3
-rw-r--r--tests/projects/c++/modules/stdmodules_deps/src/foo.mpp6
-rw-r--r--tests/projects/c++/modules/stdmodules_deps/xmake.lua1
-rw-r--r--tests/projects/c++/modules/test_stdmodules.lua28
-rw-r--r--xmake/core/project/policy.lua2
-rw-r--r--xmake/rules/c++/modules/clang/support.lua69
-rw-r--r--xmake/rules/c++/modules/gcc/support.lua55
-rw-r--r--xmake/rules/c++/modules/msvc/support.lua45
9 files changed, 114 insertions, 102 deletions
diff --git a/tests/projects/c++/modules/stdmodules_deps/src/bar.mpp b/tests/projects/c++/modules/stdmodules_deps/src/bar.mpp
index 79d91a393..001cd7c2d 100644
--- a/tests/projects/c++/modules/stdmodules_deps/src/bar.mpp
+++ b/tests/projects/c++/modules/stdmodules_deps/src/bar.mpp
@@ -4,8 +4,11 @@ import std;
export auto my_sum2(std::size_t a, std::size_t b) -> std::size_t;
+#if defined(__GNUC__) && !defined(__clang__)
+inline
+#else
module :private;
-
-auto my_sum2(std::size_t a, std::size_t b) -> std::size_t {
+#endif
+ auto my_sum2(std::size_t a, std::size_t b) -> std::size_t {
return a + a + b + b;
}
diff --git a/tests/projects/c++/modules/stdmodules_deps/src/foo.cpp b/tests/projects/c++/modules/stdmodules_deps/src/foo.cpp
new file mode 100644
index 000000000..c1e34dec6
--- /dev/null
+++ b/tests/projects/c++/modules/stdmodules_deps/src/foo.cpp
@@ -0,0 +1,3 @@
+module foo;
+
+auto my_sum(std::size_t a, std::size_t b) -> std::size_t { return a + b; }
diff --git a/tests/projects/c++/modules/stdmodules_deps/src/foo.mpp b/tests/projects/c++/modules/stdmodules_deps/src/foo.mpp
index 17a3795b7..b0aab2fee 100644
--- a/tests/projects/c++/modules/stdmodules_deps/src/foo.mpp
+++ b/tests/projects/c++/modules/stdmodules_deps/src/foo.mpp
@@ -3,9 +3,3 @@ export module foo;
import std;
export auto my_sum(std::size_t a, std::size_t b) -> std::size_t;
-
-module :private;
-
-auto my_sum(std::size_t a, std::size_t b) -> std::size_t {
- return a + b;
-}
diff --git a/tests/projects/c++/modules/stdmodules_deps/xmake.lua b/tests/projects/c++/modules/stdmodules_deps/xmake.lua
index 7ee801b8c..6c53ff594 100644
--- a/tests/projects/c++/modules/stdmodules_deps/xmake.lua
+++ b/tests/projects/c++/modules/stdmodules_deps/xmake.lua
@@ -3,6 +3,7 @@ set_languages("c++latest")
target("foo")
set_kind("static")
+ add_files("src/foo.cpp")
add_files("src/foo.mpp", {public = true})
target("bar")
diff --git a/tests/projects/c++/modules/test_stdmodules.lua b/tests/projects/c++/modules/test_stdmodules.lua
index d9b25ef56..0ca1cc9de 100644
--- a/tests/projects/c++/modules/test_stdmodules.lua
+++ b/tests/projects/c++/modules/test_stdmodules.lua
@@ -38,21 +38,25 @@ function main(t)
end
end
elseif is_subhost("msys") then
- -- os.exec("xmake f -c -p mingw --yes")
- -- _build()
+ local gcc = find_tool("gcc", {version = true})
+ if is_host("linux") and gcc and gcc.version and semver.compare(gcc.version, "15.0") >= 0 then
+ os.exec("xmake f -c -p mingw --yes")
+ _build()
+ end
elseif is_host("linux") then -- or is_host("macosx") then
- -- gcc don't support std modules atm
- -- local gcc = find_tool("gcc", {version = true})
- -- if is_host("linux") and gcc and gcc.version and semver.compare(gcc.version, "11.0") >= 0 then
- -- os.exec("xmake f -c --yes")
- -- _build()
- -- end
+ local gcc = find_tool("gcc", {version = true})
+ if is_host("linux") and gcc and gcc.version and semver.compare(gcc.version, "15.0") >= 0 then
+ os.exec("xmake f -c --yes")
+ _build()
+ end
local clang = find_tool("clang", {version = true})
if clang and clang.version and semver.compare(clang.version, "19.0") >= 0 then
- -- clang don't support libstdc++ std modules atm
- -- os.exec("xmake clean -a")
- -- os.exec("xmake f --toolchain=clang -c --yes")
- -- _build()
+ local gcc = find_tool("clang", {version = true})
+ if gcc and gcc.version and semver.compare(gcc.version, "15.0") >= 0 then
+ os.exec("xmake clean -a")
+ os.exec("xmake f --toolchain=clang -c --yes")
+ _build()
+ end
os.exec("xmake clean -a")
os.exec("xmake f --toolchain=clang --runtimes=c++_shared -c --yes")
_build()
diff --git a/xmake/core/project/policy.lua b/xmake/core/project/policy.lua
index cad9fd4cd..0c79be649 100644
--- a/xmake/core/project/policy.lua
+++ b/xmake/core/project/policy.lua
@@ -101,7 +101,7 @@ function policy.policies()
-- If in the future, gcc can support it well, we'll turn it on by default
-- https://github.com/xmake-io/xmake/issues/3855
["build.c++.modules.gcc.cxx11abi"] = {description = "Force to enable new cxx11 abi in C++ modules for gcc.", type = "boolean"},
- ["build.c++.gcc.modules.cxx11abi"] = {description = "Force to enable new cxx11 abi in C++ modules for gcc. (deprecated)", type = "boolean", default = false},
+ ["build.c++.gcc.modules.cxx11abi"] = {description = "Force to enable new cxx11 abi in C++ modules for gcc. (deprecated)", type = "boolean"},
-- Set the default vs runtime, e.g. MT, MD
["build.c++.msvc.runtime"] = {description = "Set the default vs runtime.", type = "string", values = {"MT", "MD"}},
-- Enable cuda device link
diff --git a/xmake/rules/c++/modules/clang/support.lua b/xmake/rules/c++/modules/clang/support.lua
index fd27bcb96..f35796959 100644
--- a/xmake/rules/c++/modules/clang/support.lua
+++ b/xmake/rules/c++/modules/clang/support.lua
@@ -71,7 +71,7 @@ function _get_cpplibrary_name(target)
elseif target:has_runtime("MD", "MT", "MDd", "MTd") then
return "msstl"
end
- if target:is_plat("macosx") then
+ if target:is_plat("macosx", "iphoneos", "appletvos") then
return "c++"
elseif target:is_plat("linux") then
return "stdc++"
@@ -258,49 +258,42 @@ end
function get_stdmodules(target)
- if target:policy("build.c++.modules.std") then
- local cpplib = _get_cpplibrary_name(target)
- if cpplib then
- if cpplib == "c++" then
- -- libc++ module is found by parsing libc++.modules.json
- local modules_json_path = _get_std_module_manifest_path(target)
- if modules_json_path then
- local modules_json = json.decode(io.readfile(modules_json_path))
- if modules_json and modules_json.modules and #modules_json.modules > 0 then
- local std_module_directory = path.directory(modules_json.modules[1]["source-path"])
- if not path.is_absolute(std_module_directory) then
- std_module_directory = path.join(path.directory(modules_json_path), std_module_directory)
- end
- if os.isdir(std_module_directory) then
- return {path.normalize(path.join(std_module_directory, "std.cppm")), path.normalize(path.join(std_module_directory, "std.compat.cppm"))}
- end
+ if not target:policy("build.c++.modules.std") then
+ return
+ end
+ local cpplib = _get_cpplibrary_name(target)
+ if cpplib then
+ if cpplib == "c++" then
+ -- libc++ module is found by parsing libc++.modules.json
+ local modules_json_path = _get_std_module_manifest_path(target)
+ if modules_json_path then
+ local modules_json = json.decode(io.readfile(modules_json_path))
+ if modules_json and modules_json.modules and #modules_json.modules > 0 then
+ local std_module_directory = path.directory(modules_json.modules[1]["source-path"])
+ if not path.is_absolute(std_module_directory) then
+ std_module_directory = path.join(path.directory(modules_json_path), std_module_directory)
end
- end
- elseif cpplib == "stdc++" then
- -- libstdc++ doesn't have a std module file atm
- elseif cpplib == "msstl" then
- -- msstl std module file is not compatible with llvm < 19
- local clang_version = get_clang_version(target)
- if clang_version and semver.compare(clang_version, "19.0") >= 0 then
- local toolchain = target:toolchain("llvm") or target:toolchain("clang") or target:toolchain("clang-cl")
- local msvc = import("core.tool.toolchain", {anonymous = true}).load("msvc", {plat = toolchain:plat(), arch = toolchain:arch()})
- if msvc and msvc:check({ignore_sdk = true}) then
- local vcvars = msvc:config("vcvars")
- if vcvars.VCInstallDir and vcvars.VCToolsVersion then
- local stdmodulesdir = path.join(vcvars.VCInstallDir, "Tools", "MSVC", vcvars.VCToolsVersion, "modules")
- if os.isdir(stdmodulesdir) then
- return {path.normalize(path.join(stdmodulesdir, "std.ixx")), path.normalize(path.join(stdmodulesdir, "std.compat.ixx"))}
- end
- end
+ if os.isdir(std_module_directory) then
+ return {path.normalize(path.join(std_module_directory, "std.cppm")), path.normalize(path.join(std_module_directory, "std.compat.cppm"))}
end
- else
- wprint("msstl std module file is not compatible with llvm < 19, please upgrade clang/clang-cl version!")
- return
end
end
+ elseif cpplib == "stdc++" then
+ -- dont be greedy and don't enable stdc++ std module support for llvm < 19
+ local clang_version = get_clang_version(target)
+ if clang_version and semver.compare(clang_version, "19.0") >= 0 then
+ return import(".gcc.support").get_stdmodules(target)
+ end
+ elseif cpplib == "msstl" then
+ -- msstl std module file is not compatible with llvm < 19
+ local clang_version = get_clang_version(target)
+ if clang_version and semver.compare(clang_version, "19.0") >= 0 then
+ local toolchain = target:toolchain("llvm") or target:toolchain("clang") or target:toolchain("clang-cl")
+ return import(".msvc.support").get_stdmodules(target, {toolchain = toolchain})
+ end
end
- wprint("std and std.compat modules not found! maybe try to add --sdk=<PATH/TO/LLVM> or install libc++")
end
+ wprint("std and std.compat modules not found! maybe try to add --sdk=<PATH/TO/LLVM> or install libc++")
end
function get_bmi_extension()
diff --git a/xmake/rules/c++/modules/gcc/support.lua b/xmake/rules/c++/modules/gcc/support.lua
index bc924f35c..dd7986475 100644
--- a/xmake/rules/c++/modules/gcc/support.lua
+++ b/xmake/rules/c++/modules/gcc/support.lua
@@ -61,6 +61,13 @@ function load(target)
-- https://github.com/xmake-io/xmake/issues/3855
local cxx11abi = target:policy("build.c++.modules.gcc.cxx11abi") or
target:policy("build.c++.gcc.modules.cxx11abi")
+ if cxx11abi == nil then
+ -- enable cxx11abi on GCC >= 15 as it is required for C++23 module
+ local gcc_version = get_gcc_version(target)
+ if gcc_version and semver.compare(gcc_version, "15") > 0 then
+ cxx11abi = true
+ end
+ end
if cxx11abi then
target:add("cxxflags", "-D_GLIBCXX_USE_CXX11_ABI=1")
else
@@ -139,10 +146,24 @@ function _get_std_module_manifest_path(target)
return modules_json_path
end
end
- -- fallback on custom detection
- -- manifest can be found alongside libstdc++.so
-
- -- TODO
+ local ext = ".so"
+ if target:is_plat("windows", "mingw") then
+ ext = ".dll"
+ elseif target:is_plat("macosx", "iphoneos", "appletvos") then
+ ext = ".dylib"
+ end
+ local stdcpp_libfile, _ = try {
+ function()
+ return os.iorunv(compinst:program(), {"-print-file-name=libstdc++" .. ext}, {envs = compinst:runenvs()})
+ end
+ }
+ if stdcpp_libfile then
+ modules_json_path = path.join(path.directory(stdcpp_libfile), "libstdc++.modules.json")
+ modules_json_path = modules_json_path:trim()
+ if os.isfile(modules_json_path) then
+ return modules_json_path
+ end
+ end
end
function get_stdmodules(target)
@@ -150,22 +171,22 @@ function get_stdmodules(target)
return
end
local modules_json_path = _get_std_module_manifest_path(target)
- if not modules_json_path then
- return
- end
- local modules_json = json.loadfile(modules_json_path)
- if modules_json and modules_json.modules and #modules_json.modules > 0 then
- local std_module_files = {}
- local modules_json_dir = path.directory(modules_json_path)
- for _, module_file in ipairs(modules_json.modules) do
- local module_file_path = module_file["source-path"]
- if not path.is_absolute(module_file_path) then
- module_file_path = path.join(modules_json_dir, module_file_path)
+ if modules_json_path then
+ local modules_json = json.loadfile(modules_json_path)
+ if modules_json and modules_json.modules and #modules_json.modules > 0 then
+ local std_module_files = {}
+ local modules_json_dir = path.directory(modules_json_path)
+ for _, module_file in ipairs(modules_json.modules) do
+ local module_file_path = module_file["source-path"]
+ if not path.is_absolute(module_file_path) then
+ module_file_path = path.join(modules_json_dir, module_file_path)
+ end
+ table.insert(std_module_files, path.normalize(module_file_path))
end
- table.insert(std_module_files, module_file_path)
+ return std_module_files
end
- return std_module_files
end
+ wprint("std and std.compat modules not found! maybe try to add --sdk=<PATH/TO/LLVM> or install libc++")
end
function get_bmi_extension()
diff --git a/xmake/rules/c++/modules/msvc/support.lua b/xmake/rules/c++/modules/msvc/support.lua
index f8a6ca3c4..41c5cd44e 100644
--- a/xmake/rules/c++/modules/msvc/support.lua
+++ b/xmake/rules/c++/modules/msvc/support.lua
@@ -20,6 +20,7 @@
-- imports
import("core.base.semver")
+import("core.tool.toolchain")
import("core.project.config")
import("lib.detect.find_tool")
import(".support", {inherit = true})
@@ -99,7 +100,6 @@ end
-- provide toolchain include dir for stl headerunit when p1689 is not supported
function toolchain_includedirs(target)
-
for _, toolchain_inst in ipairs(target:toolchains()) do
if toolchain_inst:name() == "msvc" then
local vcvars = toolchain_inst:config("vcvars")
@@ -117,24 +117,27 @@ function has_two_phase_compilation_support(_)
end
-- build c++23 standard modules if needed
-function get_stdmodules(target)
-
- if target:policy("build.c++.modules.std") then
- local msvc = target:toolchain("msvc")
- if msvc then
- local vcvars = msvc:config("vcvars")
- if vcvars.VCInstallDir and vcvars.VCToolsVersion then
- modules = {}
-
- local stdmodulesdir = path.join(vcvars.VCInstallDir, "Tools", "MSVC", vcvars.VCToolsVersion, "modules")
-
- if os.isdir(stdmodulesdir) then
- return {path.normalize(path.join(stdmodulesdir, "std.ixx")), path.normalize(path.join(stdmodulesdir, "std.compat.ixx"))}
- end
+function get_stdmodules(target, opt)
+ opt = opt or {}
+ if not target:policy("build.c++.modules.std") then
+ return
+ end
+ local msvc
+ if opt.toolchain then
+ msvc = toolchain.load("msvc", {plat = opt.toolchain:plat(), arch = opt.toolchain:arch()})
+ else
+ msvc = target:toolchain("msvc")
+ end
+ if msvc and msvc:check() then
+ local vcvars = msvc:config("vcvars")
+ if vcvars.VCInstallDir and vcvars.VCToolsVersion then
+ local stdmodulesdir = path.join(vcvars.VCInstallDir, "Tools", "MSVC", vcvars.VCToolsVersion, "modules")
+ if os.isdir(stdmodulesdir) then
+ return {path.normalize(path.join(stdmodulesdir, "std.ixx")), path.normalize(path.join(stdmodulesdir, "std.compat.ixx"))}
end
end
- wprint("std and std.compat modules not found! disabling them for the build")
end
+ wprint("std and std.compat modules not found! disabling them for the build")
end
function get_bmi_extension()
@@ -142,7 +145,6 @@ function get_bmi_extension()
end
function get_ifcoutputflag(target)
-
local ifcoutputflag = _g.ifcoutputflag
if ifcoutputflag == nil then
local compinst = target:compiler("cxx")
@@ -156,7 +158,6 @@ function get_ifcoutputflag(target)
end
function get_ifconlyflag(target)
-
local ifconlyflag = _g.ifconlyflag
if ifconlyflag == nil then
local compinst = target:compiler("cxx")
@@ -169,7 +170,6 @@ function get_ifconlyflag(target)
end
function get_interfaceflag(target)
-
local interfaceflag = _g.interfaceflag
if interfaceflag == nil then
local compinst = target:compiler("cxx")
@@ -183,7 +183,6 @@ function get_interfaceflag(target)
end
function get_referenceflag(target)
-
local referenceflag = _g.referenceflag
if referenceflag == nil then
local compinst = target:compiler("cxx")
@@ -197,7 +196,6 @@ function get_referenceflag(target)
end
function get_headernameflag(target)
-
local headernameflag = _g.headernameflag
if headernameflag == nil then
local compinst = target:compiler("cxx")
@@ -211,7 +209,6 @@ function get_headernameflag(target)
end
function get_headerunitflag(target)
-
local headerunitflag = _g.headerunitflag
if headerunitflag == nil then
local compinst = target:compiler("cxx")
@@ -226,7 +223,6 @@ function get_headerunitflag(target)
end
function get_exportheaderflag(target)
-
local exportheaderflag = _g.exportheaderflag
if exportheaderflag == nil then
if get_headernameflag(target) then
@@ -238,7 +234,6 @@ function get_exportheaderflag(target)
end
function get_scandependenciesflag(target)
-
local scandependenciesflag = _g.scandependenciesflag
if scandependenciesflag == nil then
local compinst = target:compiler("cxx")
@@ -261,7 +256,6 @@ function get_scandependenciesflag(target)
end
function get_cppversionflag(target)
-
local cppversionflag = _g.cppversionflag
if cppversionflag == nil then
local compinst = target:compiler("cxx")
@@ -272,7 +266,6 @@ function get_cppversionflag(target)
end
function get_internalpartitionflag(target)
-
local internalpartitionflag = _g.internalpartitionflag
if internalpartitionflag == nil then
local compinst = target:compiler("cxx")