summaryrefslogtreecommitdiff
path: root/xmake/rules/c++/modules/build_modules/gcc.lua
diff options
context:
space:
mode:
authorArthur LAURENT <[email protected]>2022-07-31 15:21:35 +0200
committerArthur LAURENT <[email protected]>2022-07-31 15:21:35 +0200
commit7788ec532d3730f0a521bb0634a25da12b5bc081 (patch)
tree39328cec8ed7981db629f145a296e0bfb3709eaa /xmake/rules/c++/modules/build_modules/gcc.lua
parente45d9400697a256c4873237329c45374c8c869ce (diff)
Improve C++20 modules support
Diffstat (limited to 'xmake/rules/c++/modules/build_modules/gcc.lua')
-rw-r--r--xmake/rules/c++/modules/build_modules/gcc.lua226
1 files changed, 187 insertions, 39 deletions
diff --git a/xmake/rules/c++/modules/build_modules/gcc.lua b/xmake/rules/c++/modules/build_modules/gcc.lua
index 3bf8b8fcc..97bb9cc9a 100644
--- a/xmake/rules/c++/modules/build_modules/gcc.lua
+++ b/xmake/rules/c++/modules/build_modules/gcc.lua
@@ -20,27 +20,58 @@
-- imports
import("core.tool.compiler")
+import("core.project.project")
+import("core.project.depend")
+import("core.base.json")
+import("core.project.config")
+import("utils.progress")
import("private.action.build.object", {alias = "objectbuilder"})
-import("module_parser")
+
+local default_flags = {"-std=c++20"}
+
+function get_module_mapper()
+ local mapper_file = path.join(config.buildir(), "mapper.txt")
+ if not os.isfile(mapper_file) then
+ io.writefile(mapper_file, "")
+ end
+
+ return mapper_file
+end
+
+function add_module_to_mapper(file, module, bmi)
+ for line in io.lines(file) do
+ if line:startswith(module .. " ") then
+ return false
+ end
+ end
+
+ local f = io.open(file, "a")
+ f:printf("%s %s\n", module, bmi)
+ f:close()
+
+ return true
+end
-- load parent target with modules files
function load_parent(target, opt)
- -- get modules flag
- local modulesflag
- local compinst = compiler.load("cxx", {target = target})
- if compinst:has_flags("-fmodules-ts") then
- modulesflag = "-fmodules-ts"
+ local common = import("common")
+ local cachedir = common.get_cache_dir(target)
+
+ target:add("cxxflags", "-fmodules-ts")
+ if os.isfile(get_module_mapper()) then
+ os.rm(get_module_mapper())
end
- assert(modulesflag, "compiler(gcc): does not support c++ module!")
+ target:add("cxxflags", "-fmodule-mapper=" .. get_module_mapper(), {force = true, expand = false})
- -- add module flags
- target:add("cxxflags", modulesflag)
+ for _, dep in ipairs(target:orderdeps()) do
+ cachedir = common.get_cache_dir(dep)
+ dep:add("cxxflags", "-fmodules-ts")
+ dep:add("cxxflags", "-fmodule-mapper=" .. get_module_mapper(), {force = true, expand = false})
+ end
end
--- build module files
-function build_with_batchjobs(target, batchjobs, sourcebatch, opt)
-
- -- get modules flag
+-- check C++20 module support
+function check_module_support(target)
local modulesflag
local compinst = compiler.load("cxx", {target = target})
if compinst:has_flags("-fmodules-ts") then
@@ -48,37 +79,154 @@ function build_with_batchjobs(target, batchjobs, sourcebatch, opt)
end
assert(modulesflag, "compiler(gcc): does not support c++ module!")
- -- we need patch objectfiles to sourcebatch for linking module objects
- sourcebatch.sourcekind = "cxx"
- sourcebatch.objectfiles = sourcebatch.objectfiles or {}
- sourcebatch.dependfiles = sourcebatch.dependfiles or {}
- for _, sourcefile in ipairs(sourcebatch.sourcefiles) do
- local objectfile = target:objectfile(sourcefile)
- table.insert(sourcebatch.objectfiles, objectfile)
- table.insert(sourcebatch.dependfiles, target:dependfile(objectfile))
+ if compinst:has_flags("-fdep-format=trtbd") then
+ target:data_set("cxx.has_p1689r4", true)
end
+end
+
+function generate_dependencies(target, sourcebatch, opt)
+ local common = import("common")
+ local cachedir = common.get_cache_dir(target)
+ local compinst = target:compiler("cxx")
+ local common_args = {"-E", "-x", "c++"}
- -- load moduledeps
- local moduledeps, moduledeps_files = module_parser.load(target, sourcebatch, opt)
+ for _, sourcefile in ipairs(sourcebatch.sourcefiles) do
+ local dependfile = target:dependfile(sourcefile)
+ depend.on_changed(function()
+ progress.show(opt.progress, "${color.build.object}generating.cxx.module.deps %s", sourcefile)
- -- compile module files to object files
- for i = 1, #sourcebatch.sourcefiles do
- local sourcefile = sourcebatch.sourcefiles[i]
- local moduleinfo = assert(moduledeps_files[sourcefile], "moduleinfo(%s) not found!", sourcefile)
- moduleinfo.job = batchjobs:newjob(sourcefile, function (index, total)
- local opt2 = table.join(opt, {configs = {force = {cxxflags = {"-x c++"}}}})
- opt2.progress = (index * 100) / total
- opt2.objectfile = sourcebatch.objectfiles[i]
- opt2.dependfile = sourcebatch.dependfiles[i]
- opt2.sourcekind = assert(sourcebatch.sourcekind, "%s: sourcekind not found!", sourcefile)
- objectbuilder.build_object(target, sourcefile, opt2)
- end)
+ local outdir = path.translate(path.join(cachedir, path.directory(path.relative(sourcefile, target:scriptdir()))))
+ if not os.isdir(outdir) then
+ os.mkdir(outdir)
+ end
+
+ local jsonfile = path.translate(path.join(outdir, path.filename(sourcefile) .. ".json"))
+
+ if target:data("cxx.has_p1689r4") then
+ local ifile = path.translate(path.join(outdir, path.filename(sourcefile) .. ".i"))
+ local dfile = path.translate(path.join(outdir, path.filename(sourcefile) .. ".d"))
+
+ local args = {sourcefile, "-MD", "-MT", jsonfile, "-MF", dfile, "-fdep-file=" .. jsonfile, "-fdep-format=trtbd", "-fdep-output=" .. target:objectfile(sourcefile), "-o", ifile}
+
+ os.vrunv(compinst:program(), table.join(compinst:compflags({target = target}) or default_flags, common_args, args), {envs = vcvars})
+ else -- fallback as GCC doesn't fully support p1689r4
+ local dependinfo = common.fallback_generate_dependencies(target, jsonfile, sourcefile)
+ local jsondata = json.encode(dependinfo)
+
+ io.writefile(jsonfile, jsondata)
+ end
+
+ local dependinfo = io.readfile(jsonfile)
+
+ return { moduleinfo = dependinfo }
+ end, {dependfile = dependfile, files = {sourcefile}})
end
+end
- -- add module flags
- target:add("cxxflags", modulesflag)
+-- generate target header units
+function generate_headerunits(target, batchcmds, sourcebatch, opt)
+ local common = import("common")
- -- build batchjobs
- module_parser.build_batchjobs(moduledeps, batchjobs, opt.rootjob)
+ local compinst = target:compiler("cxx")
+
+ local cachedir = common.get_cache_dir(target)
+ local stlcachedir = common.get_stlcache_dir(target)
+
+ local mapper_file = get_module_mapper()
+
+ -- build headerunits
+ local objectfiles = {}
+ for _, headerunit in ipairs(sourcebatch) do
+ if not headerunit.stl then
+ local file = path.relative(headerunit.path, target:scriptdir())
+
+ local objectfile = target:objectfile(file)
+
+ local outdir = path.join(cachedir, "include", path.directory(headerunit.name))
+ if not os.isdir(outdir) then
+ os.mkdir(outdir)
+ end
+
+ local bmifilename = path.basename(objectfile) .. ".gcm"
+
+ local bmifile = (outdir and path.join(outdir, bmifilename) or bmifilename)
+ if not os.isdir(path.directory(objectfile)) then
+ os.mkdir(path.directory(objectfile))
+ end
+
+ if add_module_to_mapper(mapper_file, headerunit.path, path.absolute(bmifile, project.directory())) then
+ local args = { "-c" }
+ if headerunit.type == ":quote" then
+ table.join2(args, { "-I", path.directory(headerunit.path), "-x", "c++-user-header", headerunit.name })
+ add_module_to_mapper(mapper_file, path.join(".", path.relative(headerunit.path, project.directory())), path.absolute(bmifile, project.directory()))
+ elseif headerunit.type == ":angle" then
+ table.join2(args, { "-x", "c++-system-header", headerunit.name })
+ add_module_to_mapper(mapper_file, headerunit.name, path.absolute(bmifile, project.directory()))
+ end
+
+ batchcmds:show_progress(opt.progress, "${color.build.object}generating.cxx.headerunit.bmi %s", headerunit.name)
+ batchcmds:vrunv(compinst:program(), table.join(compinst:compflags({target = target}) or default_flags, args))
+
+ batchcmds:add_depfiles(headerunit.path)
+ batchcmds:set_depmtime(os.mtime(bmifile))
+ batchcmds:set_depcache(target:dependfile(bmifile))
+ end
+ else
+ local bmifile = path.join(stlcachedir, headerunit.name .. ".gcm")
+
+ if add_module_to_mapper(mapper_file, headerunit.path, path.absolute(bmifile, project.directory())) then
+ if not os.isfile(bmifile) then
+ local args = { "-c", "-x", "c++-system-header", headerunit.name }
+
+ batchcmds:show_progress(opt.progress, "${color.build.object}generating.cxx.headerunit.bmi %s", headerunit.name)
+ batchcmds:vrunv(compinst:program(), table.join(compinst:compflags({target = target}) or default_flags, args))
+
+ batchcmds:set_depmtime(os.mtime(bmifile))
+ batchcmds:set_depcache(target:dependfile(bmifile))
+ end
+ end
+ end
+
+ end
+end
+
+-- build module files
+function build_modules(target, batchcmds, objectfiles, modules, opt)
+ local cachedir = common.get_cache_dir(target)
+
+ local compinst = target:compiler("cxx")
+
+ local mapper_file = get_module_mapper()
+ local common_args = { "-x", "c++" }
+ for _, objectfile in ipairs(objectfiles) do
+ local m = modules[objectfile]
+
+ if m then
+ if not os.isdir(path.directory(objectfile)) then
+ os.mkdir(path.directory(objectfile))
+ end
+
+ local args = { "-o", objectfile }
+ for name, provide in pairs(m.provides) do
+ batchcmds:show_progress(opt.progress, "${color.build.object}generating.cxx.module.bmi %s", name)
+
+ local bmifile = provide.bmi
+ if add_module_to_mapper(mapper_file, name, path.absolute(bmifile, project.directory())) then
+ table.join2(args, { "-c", provide.sourcefile })
+
+ batchcmds:add_depfiles(provide.sourcefile)
+ batchcmds:set_depmtime(os.mtime(bmifile))
+ batchcmds:set_depcache(target:dependfile(bmifile))
+ end
+ end
+
+ batchcmds:vrunv(compinst:program(), table.join(compinst:compflags({target = target}) or default_flags, common_args, args))
+
+ batchcmds:set_depmtime(os.mtime(objectfile))
+ batchcmds:set_depcache(target:dependfile(objectfile))
+
+ target:add("objectfiles", objectfile)
+ end
+ end
end