diff options
| author | Arthur LAURENT <[email protected]> | 2022-07-31 15:21:35 +0200 |
|---|---|---|
| committer | Arthur LAURENT <[email protected]> | 2022-07-31 15:21:35 +0200 |
| commit | 7788ec532d3730f0a521bb0634a25da12b5bc081 (patch) | |
| tree | 39328cec8ed7981db629f145a296e0bfb3709eaa /xmake/rules/c++/modules/build_modules/gcc.lua | |
| parent | e45d9400697a256c4873237329c45374c8c869ce (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.lua | 226 |
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 |
