Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for libstdc++ standard library modules #5869

Merged
merged 3 commits into from
Nov 26, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 72 additions & 3 deletions xmake/rules/c++/modules/modules_support/gcc/compiler_support.lua
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
--

-- imports
import("core.base.json")
import("core.base.semver")
import("core.project.config")
import("lib.detect.find_tool")
Expand Down Expand Up @@ -58,7 +59,9 @@ function load(target)
-- fix cxxabi issue
-- @see https://github.com/xmake-io/xmake/issues/2716#issuecomment-1225057760
-- https://github.com/xmake-io/xmake/issues/3855
if target:policy("build.c++.gcc.modules.cxx11abi") then

-- libstdc++ std modules cannot compile with -D_GLIBCXX_USE_CXX11_ABI=0
if target:policy("build.c++.modules.std") or target:policy("build.c++.gcc.modules.cxx11abi") then
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it will break

target:add("cxxflags", "-D_GLIBCXX_USE_CXX11_ABI=1")
else
target:add("cxxflags", "-D_GLIBCXX_USE_CXX11_ABI=0")
Expand Down Expand Up @@ -132,8 +135,50 @@ function get_target_module_mapperpath(target)
return path
end

-- not supported atm
function _get_std_module_manifest_path(target)
local compinst = target:compiler("cxx")
local modules_json_path, _ = try {
function()
return os.iorunv(compinst:program(), {"-print-file-name=libstdc++.modules.json"}, {envs = compinst:runenvs()})
end
}

if modules_json_path then
modules_json_path = modules_json_path:trim()
if os.isfile(modules_json_path) then
return modules_json_path
end
end

-- fallback on custom detection
-- manifest can be found alongside libstdc++.so

-- TODO
end

function get_stdmodules(target)
if not target:policy("build.c++.modules.std") then
return nil
end

local modules_json_path = _get_std_module_manifest_path(target)
if not modules_json_path then
return nil
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)
end
table.insert(std_module_files, module_file_path)
end
return std_module_files
end
end

function get_bmi_extension()
Expand All @@ -144,7 +189,15 @@ function get_modulesflag(target)
local modulesflag = _g.modulesflag
if modulesflag == nil then
local compinst = target:compiler("cxx")
if compinst:has_flags("-fmodules-ts", "cxxflags", {flagskey = "gcc_modules_ts"}) then
local gcc_version = get_gcc_version(target)
-- GCC 12 and earlier version has a option '-fmodules' for Modula-2
if gcc_version and semver.compare(gcc_version, "12") > 0 then
if compinst:has_flags("-fmodules", "cxxflags", {flagskey = "gcc_modules"}) then
modulesflag = "-fmodules"
elseif compinst:has_flags("-fmodules-ts", "cxxflags", {flagskey = "gcc_modules_ts"}) then
modulesflag = "-fmodules-ts"
end
elseif compinst:has_flags("-fmodules-ts", "cxxflags", {flagskey = "gcc_modules_ts"}) then
modulesflag = "-fmodules-ts"
end
assert(modulesflag, "compiler(gcc): does not support c++ module!")
Expand Down Expand Up @@ -255,3 +308,19 @@ function get_cppversionflag(target)
return cppversionflag or nil
end

function get_gcc_version(target)
local gcc_version = _g.gcc_version
if not gcc_version then
local program, toolname = target:tool("cxx")
if program and toolname:startswith("gcc") then
local gcc = find_tool(toolname, {program = program, version = true,
envs = os.getenvs(), cachekey = "modules_support_gcc_" .. toolname})
if gcc then
gcc_version = gcc.version
end
end
gcc_version = gcc_version or false
_g.gcc_version = gcc_version
end
return gcc_version or nil
end