Skip to content

Commit

Permalink
Refactor gcc module support
Browse files Browse the repository at this point in the history
  • Loading branch information
Arthapz committed Oct 25, 2023
1 parent 4c81372 commit 19055f4
Show file tree
Hide file tree
Showing 7 changed files with 381 additions and 307 deletions.
2 changes: 1 addition & 1 deletion xmake/rules/c++/modules/modules_support/builder.lua
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
--
-- Copyright (C) 2015-present, TBOOX Open Source Group.
--
-- @author Arthapz, ruki
-- @author ruki, Arthapz
-- @file common.lua
--

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
-- Copyright (C) 2015-present, TBOOX Open Source Group.
--
-- @author ruki, Arthapz
-- @file dependencies.lua
-- @file dependency_scanner.lua
--

-- imports
Expand Down

Large diffs are not rendered by default.

192 changes: 192 additions & 0 deletions xmake/rules/c++/modules/modules_support/gcc/compiler_support.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
--!A cross-platform build utility based on Lua
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
-- Copyright (C) 2015-present, TBOOX Open Source Group.
--
-- @author ruki, Arthapz
-- @file gcc/compiler_support.lua
--

-- imports
import("core.base.semver")
import("core.project.config")
import("lib.detect.find_tool")
import(".compiler_support", {inherit = true})

-- load module support for the current target
function load(target)
local modulesflag = get_modulesflag(target)
local modulemapperflag = get_modulemapperflag(target)
local mapper_file = path.join(config.buildir(), target:name(), "mapper.txt")
target:add("cxxflags", {modulesflag, modulemapperflag .. path.translate(mapper_file)}, {force = true, expand = false})
-- 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
target:add("cxxflags", "-D_GLIBCXX_USE_CXX11_ABI=1")
else
target:add("cxxflags", "-D_GLIBCXX_USE_CXX11_ABI=0")
end
end

-- provide toolchain include directories for stl headerunit when p1689 is not supported
function toolchain_includedirs(target)
local includedirs = _g.includedirs
if includedirs == nil then
includedirs = {}
local gcc, toolname = target:tool("cxx")
assert(toolname == "gcc")
_get_toolchain_includedirs_for_stlheaders(includedirs, gcc)
local _, result = try {function () return os.iorunv(gcc, {"-E", "-Wp,-v", "-xc", os.nuldev()}) end}
if result then
for _, line in ipairs(result:split("\n", {plain = true})) do
line = line:trim()
if os.isdir(line) then
table.insert(includedirs, path.normalize(line))
elseif line:startswith("End") then
break
end
end
end
_g.includedirs = includedirs
end
return includedirs
end

-- not supported atm
function get_stdmodules(target)
local modules = {}
return modules
end

function get_bmi_extension()
return ".gcm"
end

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
modulesflag = "-fmodules-ts"
end
assert(modulesflag, "compiler(gcc): does not support c++ module!")
_g.modulesflag = modulesflag or false
end
return modulesflag or nil
end

function get_modulemapperflag(target)
local modulemapperflag = _g.modulemapperflag
if modulemapperflag == nil then
local compinst = target:compiler("cxx")
if compinst:has_flags("-fmodule-mapper=" .. os.tmpfile(), "cxxflags", {flagskey = "gcc_module_mapper"}) then
modulemapperflag = "-fmodule-mapper="
end
assert(modulemapperflag, "compiler(gcc): does not support c++ module!")
_g.modulemapperflag = modulemapperflag or false
end
return modulemapperflag or nil
end

function get_depsflag(target)
local depflag = _g.depflag
if depflag == nil then
local compinst = target:compiler("cxx")
if compinst:has_flags("-fdeps-format=p1689r5", "cxxflags", {flagskey = "gcc_deps_format",
on_check = function (ok, errors)
if errors:find("-M") then
ok = true
end
return ok, errors
end}) then
depflag = "-fdeps-format=p1689r5"
end
_g.depflag = depflag or false
end
return depflag or nil
end

function get_depsfileflag(target)
local depfileflag = _g.depfileflag
if depfileflag == nil then
local compinst = target:compiler("cxx")
if compinst:has_flags("-fdeps-file=" .. os.tmpfile(), "cxxflags", {flagskey = "gcc_deps_file",
on_check = function (ok, errors)
if errors:find("-M") then
ok = true
end
return ok, errors
end}) then
depfileflag = "-fdeps-file="
end
_g.depfileflag = depfileflag or false
end
return depfileflag or nil
end

function get_depstargetflag(target)
local depoutputflag = _g.depoutputflag
if depoutputflag == nil then
local compinst = target:compiler("cxx")
if compinst:has_flags("-fdeps-target=" .. os.tmpfile() .. ".o", "cxxflags", {flagskey = "gcc_deps_output",
on_check = function (ok, errors)
if errors:find("-M") then
ok = true
end
return ok, errors
end}) then
depoutputflag = "-fdeps-target="
end
_g.depoutputflag = depoutputflag or false
end
return depoutputflag or nil
end

function get_cppversionflag(target)
local cppversionflag = _g.cppversionflag
if cppversionflag == nil then
local compinst = target:compiler("cxx")
local flags = compinst:compflags({target = target})
cppversionflag = table.find_if(flags, function(v) string.startswith(v, "-std=c++") end) or "-std=c++20"
_g.cppversionflag = cppversionflag
end
return cppversionflag or nil
end

-- get includedirs for stl headers
--
-- $ echo '#include <vector>' | gcc -x c++ -E - | grep '/vector"'
-- # 1 "/usr/include/c++/11/vector" 1 3
-- # 58 "/usr/include/c++/11/vector" 3
-- # 59 "/usr/include/c++/11/vector" 3
--
function _get_toolchain_includedirs_for_stlheaders(includedirs, gcc)
local tmpfile = os.tmpfile() .. ".cc"
io.writefile(tmpfile, "#include <vector>")
local result = try {function () return os.iorunv(gcc, {"-E", "-x", "c++", tmpfile}) end}
if result then
for _, line in ipairs(result:split("\n", {plain = true})) do
line = line:trim()
if line:startswith("#") and line:find("/vector\"", 1, true) then
local includedir = line:match("\"(.+)/vector\"")
if includedir and os.isdir(includedir) then
table.insert(includedirs, path.normalize(includedir))
break
end
end
end
end
os.tryrm(tmpfile)
end
79 changes: 79 additions & 0 deletions xmake/rules/c++/modules/modules_support/gcc/dependency_scanner.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
--!A cross-platform build utility based on Lua
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
-- Copyright (C) 2015-present, TBOOX Open Source Group.
--
-- @author ruki, Arthapz
-- @file gcc/dependency_scanner.lua
--

-- imports
import("core.base.json")
import("core.base.semver")
import("core.project.depend")
import("utils.progress")
import("compiler_support")
import("builder")
import(".dependency_scanner", {inherit = true})

-- generate dependency files
function generate_dependencies(target, sourcebatch, opt)
local compinst = target:compiler("cxx")
local common_args = {"-E", "-x", "c++"}
local depsformatflag = compiler_support.get_depsflag(target, "p1689r5")
local depsfileflag = compiler_support.get_depsfileflag(target)
local depstargetflag = compiler_support.get_depstargetflag(target)
local changed = false
for _, sourcefile in ipairs(sourcebatch.sourcefiles) do
local dependfile = target:dependfile(sourcefile)
depend.on_changed(function()
if opt.progress then
progress.show(opt.progress, "${color.build.object}generating.module.deps %s", sourcefile)
end

local outputdir = compiler_support.get_outputdir(target, sourcefile)
local jsonfile = path.translate(path.join(outputdir, path.filename(sourcefile) .. ".json"))
if depsformatflag and depsfileflag and depstargetflag and not target:policy("build.c++.gcc.fallbackscanner") then
local ifile = path.translate(path.join(outputdir, path.filename(sourcefile) .. ".i"))
local dfile = path.translate(path.join(outputdir, path.filename(sourcefile) .. ".d"))
local args = {sourcefile, "-MT", jsonfile, "-MD", "-MF", dfile, depsformatflag, depsfileflag .. jsonfile, depstargetflag .. target:objectfile(sourcefile), "-o", ifile}
local compflags = compinst:compflags({sourcefile = sourcefile, target = target})
-- module mapper flag force gcc to check the imports but this is not wanted at this stage
local modulemapperflag = compiler_support.get_modulemapperflag(target) .. path.translate(builder.get_module_mapper(target))
table.remove(compflags, table.unpack(table.find(compflags, modulemapperflag)))
os.vrunv(compinst:program(), table.join(compflags, common_args, args))
os.rm(ifile)
os.rm(dfile)
else
fallback_generate_dependencies(target, jsonfile, sourcefile, function(file)
local compinst = target:compiler("cxx")
local compflags = compinst:compflags({sourcefile = file, target = target})
-- exclude -fmodule* flags because, when they are set gcc try to find bmi of imported modules but they don't exists a this point of compilation
table.remove_if(compflags, function(_, flag) return flag:startswith("-fmodule") end)
local ifile = path.translate(path.join(outputdir, path.filename(file) .. ".i"))
os.vrunv(compinst:program(), table.join(common_args, compflags, {file, "-o", ifile}))
local content = io.readfile(ifile)
os.rm(ifile)
return content
end)
end
changed = true

local dependinfo = io.readfile(jsonfile)
return { moduleinfo = dependinfo }
end, {dependfile = dependfile, files = {sourcefile}, changed = target:is_rebuilt()})
end
return changed
end

2 changes: 1 addition & 1 deletion xmake/rules/c++/modules/modules_support/stl_headers.lua
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
--
-- Copyright (C) 2015-present, TBOOX Open Source Group.
--
-- @author Arthapz, ruki
-- @author ruki, Arthapz
-- @file stl_headers.lua
--

Expand Down
2 changes: 1 addition & 1 deletion xmake/rules/c++/modules/xmake.lua
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
--
-- Copyright (C) 2015-present, TBOOX Open Source Group.
--
-- @author ruki
-- @author ruki, Arthapz
-- @file xmake.lua
--

Expand Down

0 comments on commit 19055f4

Please sign in to comment.