diff options
| author | Arthur LAURENT <[email protected]> | 2022-08-03 02:35:01 +0200 |
|---|---|---|
| committer | Arthur LAURENT <[email protected]> | 2022-08-03 02:35:01 +0200 |
| commit | 92b8b6629b6c3b4b59d78835b7e4719313c04ae1 (patch) | |
| tree | 6f630619ebc0dec9425aeca61ed60448c951e4a0 | |
| parent | ab70577eccc2f4b003041e5c8850a775ddc81be0 (diff) | |
[C++20 Modules] Improve support on MSVC Clang and GCC
| -rw-r--r-- | xmake/rules/c++/modules/modules_support/clang.lua (renamed from xmake/rules/c++/modules/build_modules/clang.lua) | 126 | ||||
| -rw-r--r-- | xmake/rules/c++/modules/modules_support/common.lua (renamed from xmake/rules/c++/modules/build_modules/common.lua) | 46 | ||||
| -rw-r--r-- | xmake/rules/c++/modules/modules_support/gcc.lua (renamed from xmake/rules/c++/modules/build_modules/gcc.lua) | 81 | ||||
| -rw-r--r-- | xmake/rules/c++/modules/modules_support/msvc.lua (renamed from xmake/rules/c++/modules/build_modules/msvc.lua) | 152 | ||||
| -rw-r--r-- | xmake/rules/c++/modules/xmake.lua | 64 |
5 files changed, 321 insertions, 148 deletions
diff --git a/xmake/rules/c++/modules/build_modules/clang.lua b/xmake/rules/c++/modules/modules_support/clang.lua index bce008766..e12c7afed 100644 --- a/xmake/rules/c++/modules/build_modules/clang.lua +++ b/xmake/rules/c++/modules/modules_support/clang.lua @@ -22,12 +22,19 @@ 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"}) -local default_flags = { "-std=c++20" } +modulesflag = nil +modulestsflag = nil +implicitmodules = nil +implicitmodulemapsflag = nil +prebuiltmodulepathflag = nil + +function get_bmi_ext() + return ".pcm" +end -- load parent target with modules files function load_parent(target, opt) @@ -36,31 +43,76 @@ function load_parent(target, opt) local stlcachedir = common.get_stlcache_dir(target) -- add module flags - target:add("cxxflags", "-fmodules") + target:add("cxxflags", modulesflag or modulestsflag) -- add the module cache directory - target:add("cxxflags", "-fimplicit-modules", "-fimplicit-module-maps", {force = true}) - target:add("cxxflags", "-fprebuilt-module-path=" .. cachedir, "-fprebuilt-module-path=" .. stlcachedir, {force = true}) + target:add("cxxflags", implicitmodulesflag, {force = true}) + target:add("cxxflags", implicitmodulemapsflag, {force = true}) + + target:add("cxxflags", prebuiltmodulepathflag .. cachedir, prebuiltmodulepathflag .. stlcachedir, {force = true}) for _, dep in ipairs(target:orderdeps()) do cachedir = common.get_cache_dir(dep) - dep:add("cxxflags", "-fmodules") - dep:add("cxxflags", "-fimplicit-modules", "-fimplicit-module-maps", {force = true}) - target:add("cxxflags", "-fprebuilt-module-path=" .. cachedir, "-fprebuilt-module-path=" .. stlcachedir, {force = true}) - target:add("cxxflags", "-fprebuilt-module-path=" .. cachedir, {force = true}) + target:add("cxxflags", prebuiltmodulepathflag .. cachedir, prebuiltmodulepathflag .. stlcachedir, {force = true}) + target:add("cxxflags", prebuiltmodulepathflag .. cachedir, {force = true}) end end -- check C++20 module support function check_module_support(target) - local modulesflag local compinst = compiler.load("cxx", {target = target}) - if compinst:has_flags("-fmodules") then + + if compinst:has_flags("-fmodules", "cxxflags", {flagskey = "clang_modules"}) then modulesflag = "-fmodules" end - assert(modulesflag, "compiler(clang): does not support c++ module!") - target:data_set("cxx.has_p1689r4", false) + if compinst:has_flags("-fmodules-ts", "cxxflags", {flagskey = "clang_modules_ts"}) then + modulestsflag = "-fmodules-ts" + end + assert(modulesflag or modulestsflag, "compiler(clang): does not support c++ module!") + + if compinst:has_flags((modulesflag or modulestsflag) .. " -fimplicit-modules", "cxxflags", {flagskey = "clang_implicit_modules"}) then + implicitmodulesflag = "-fimplicit-modules" + end + assert(implicitmodulesflag, "compiler(clang): does not support c++ module!") + + if compinst:has_flags((modulesflag or modulestsflag) .. " -fimplicit-module-maps" .. os.tmpdir(), "cxxflags", {flagskey = "clang_implicit_module_path"}) then + implicitmodulemapsflag = "-fimplicit-module-maps" + end + assert(implicitmodulemapsflag, "compiler(clang): does not support c++ module!") + + if compinst:has_flags((modulesflag or modulestsflag) .. " -fprebuilt-module-path=" .. os.tmpdir(), "cxxflags", {flagskey = "clang_prebuild_module_path"}) then + prebuiltmodulepathflag = "-fprebuilt-module-path=" + end + assert(prebuiltmodulepathflag, "compiler(clang): does not support c++ module!") + + if compinst:has_flags((modulesflag or modulestsflag) .. " -fmodules-cache-path=" .. os.tmpdir(), "cxxflags", {flagskey = "clang_modules_cache_path"}) then + modulecachepathflag = "-fmodules-cache-path=" + end + assert(modulecachepathflag, "compiler(clang): does not support c++ module!") + + if compinst:has_flags((modulesflag or modulestsflag) .. " -emit-module", "cxxflags", {flagskey = "clang_emit_module"}) then + emitmoduleflag = " -emit-module" + end + assert(emitmoduleflag, "compiler(clang): does not support c++ module!") + + if compinst:has_flags((modulesflag or modulestsflag) .. " -fmodule-file=" .. os.tmpfile() .. get_bmi_ext(), "cxxflags", {flagskey = "clang_module_file"}) then + modulefileflag = "-fmodule-file=" + end + assert(modulefileflag, "compiler(clang): does not support c++ module!") + + if compinst:has_flags((modulesflag or modulestsflag) .. " -emit-module-interface", "cxxflags", {flagskey = "clang_emit_module_interface"}) then + emitmoduleinterfaceflag = "-emit-module-interface" + end + assert(emitmoduleinterfaceflag, "compiler(clang): does not support c++ module!") +end + +function toolchain_include_directories(target) + if is_plat("linux") then + return { "/usr/include/**", "/usr/local/include/**" } + end + + return {} end function generate_dependencies(target, sourcebatch, opt) @@ -79,13 +131,8 @@ function generate_dependencies(target, sourcebatch, opt) local jsonfile = path.translate(path.join(outdir, path.filename(sourcefile) .. ".json")) - if target:data("cxx.has_p1689r4") then - else -- fallback as clang doesn't support p1689r4 - local dependinfo = common.fallback_generate_dependencies(target, jsonfile, sourcefile) - local jsondata = json.encode(dependinfo) - - io.writefile(jsonfile, jsondata) - end + -- no support of p1689 atm + common.fallback_generate_dependencies(target, jsonfile, sourcefile) local dependinfo = io.readfile(jsonfile) @@ -113,19 +160,25 @@ function generate_headerunits(target, batchcmds, sourcebatch, opt) local objectfile = target:objectfile(file) - local outdir = path.join(cachedir, "include", path.directory(headerunit.name)) + local outdir + if headerunit.type == ":quote" then + outdir = path.join(cachedir, path.directory(path.relative(headerunit.path, project.directory()))) + else + outdir = path.join(cachedir, path.directory(headerunit.path)) + end + if not os.isdir(outdir) then os.mkdir(outdir) end - local bmifilename = path.basename(objectfile) .. ".pcm" + local bmifilename = path.basename(objectfile) .. get_bmi_ext() local bmifile = (outdir and path.join(outdir, bmifilename) or bmifilename) if not os.isdir(path.directory(objectfile)) then os.mkdir(path.directory(objectfile)) end - local args = { "-fmodules-cache-path=" .. cachedir, "-emit-module", "-c", "-o", bmifile } + local args = { modulecachepathflag .. cachedir, emitmoduleflag, "-c", "-o", bmifile } if headerunit.type == ":quote" then table.join2(args, { "-I", path.directory(headerunit.path), "-x", "c++-user-header", headerunit.path }) elseif headerunit.type == ":angle" then @@ -133,28 +186,28 @@ function generate_headerunits(target, batchcmds, sourcebatch, opt) 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:vrunv(compinst:program(), table.join(compinst:compflags({target = target}), args)) batchcmds:add_depfiles(headerunit.path) batchcmds:set_depmtime(os.mtime(bmifile)) batchcmds:set_depcache(target:dependfile(bmifile)) - table.append(public_flags, "-fmodule-file=" .. bmifile) + table.append(public_flags, modulefileflag .. bmifile) else - local bmifile = path.join(stlcachedir, headerunit.name .. ".pcm") + local bmifile = path.join(stlcachedir, headerunit.name .. get_bmi_ext()) if not os.isfile(bmifile) then - local args = { "-fmodules-cache-path=" .. stlcachedir, "-c", "-o", bmifile, "-x", "c++-system-header", headerunit.path } + local args = { modulecachepathflag .. stlcachedir, "-c", "-o", bmifile, "-x", "c++-system-header", headerunit.path } 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:vrunv(compinst:program(), table.join(compinst:compflags({target = target}), args)) end batchcmds:set_depmtime(os.mtime(bmifile)) batchcmds:set_depcache(target:dependfile(bmifile)) - table.append(private_flags, "-fmodule-file=" .. bmifile) + table.append(private_flags, modulefileflag .. bmifile) end end @@ -175,7 +228,7 @@ function build_modules(target, batchcmds, objectfiles, modules, opt) flags = table.unique(flags) target:add("cxxflags", flags, {force = true, expand = false}) - local common_args = { "-fmodules-cache-path=" .. cachedir, "-emit-module-interface" } + local common_args = { modulecachepathflag .. cachedir } for _, objectfile in ipairs(objectfiles) do local m = modules[objectfile] @@ -184,24 +237,31 @@ function build_modules(target, batchcmds, objectfiles, modules, opt) os.mkdir(path.directory(objectfile)) end - local args = { } + local args = { emitmoduleinterfaceflag } local flag = {} + local bmifiles = {} 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 table.join2(args, { "-c", "-x", "c++-module", "--precompile", provide.sourcefile, "-o", bmifile }) + table.join2(bmifiles, bmifile) batchcmds:add_depfiles(provide.sourcefile) batchcmds:set_depmtime(os.mtime(bmifile)) batchcmds:set_depcache(target:dependfile(bmifile)) - table.join2(flag, { "-fmodule-file=" .. bmifile }) + table.join2(flag, { modulefileflag .. bmifile }) end - batchcmds:vrunv(compinst:program(), table.join(compinst:compflags({target = target}) or default_flags, common_args, args)) + batchcmds:vrunv(compinst:program(), table.join(compinst:compflags({target = target}), common_args, args)) + batchcmds:vrunv(compinst:program(), table.join(compinst:compflags({target = target}), common_args, bmifiles, {"-c", "-o", objectfile})) + + batchcmds:set_depmtime(os.mtime(objectfile)) + batchcmds:set_depcache(target:dependfile(objectfile)) target:add("cxxflags", flag, {public = true, force = true}) + target:add("objectfiles", objectfile) for _, f in ipairs(flag) do target:data_add("cxx.modules.flags", f) end diff --git a/xmake/rules/c++/modules/build_modules/common.lua b/xmake/rules/c++/modules/modules_support/common.lua index bf64386e4..0bfcc7211 100644 --- a/xmake/rules/c++/modules/build_modules/common.lua +++ b/xmake/rules/c++/modules/modules_support/common.lua @@ -1,10 +1,7 @@ import("core.base.json") import("core.project.config") import("core.tool.compiler") -import("core.cache.globalcache") import("core.project.project") -import("lib.detect") -import("lib.detect.find_package") import("lib.detect.find_file") local stl_headers = { @@ -111,7 +108,7 @@ function get_stlcache_dir(target) os.mkdir(stlcachedir) end - return stlcachedir + return path.translate(stlcachedir) end function get_cache_dir(target) @@ -120,7 +117,7 @@ function get_cache_dir(target) os.mkdir(cachedir) end - return cachedir + return path.translate(cachedir) end function patch_sourcebatch(target, sourcebatch, opt) @@ -141,11 +138,11 @@ end function get_bmi_ext(target) if target:has_tool("cxx", "gcc", "gxx") then - return ".gcm" + return import("gcc").get_bmi_ext() elseif target:has_tool("cxx", "cl") then - return ".ifc" + return import("msvc").get_bmi_ext() elseif target:has_tool("cxx", "clang", "clangxx") then - return ".pcm" + return import("clang").get_bmi_ext() end assert(false) @@ -189,11 +186,12 @@ function parse_dependency_data(target, moduleinfos, opt) for _, provide in ipairs(rule.provides) do m.provides = m.provides or {} + assert(provide["logical-name"]) if provide["compiled-module-path"] then if not path.is_absolute(provide["compiled-module-path"]) then - m.provides[provide["logical-name"] ] = path.absolute(provide["compiled-module-path"]) + m.provides[provide["logical-name"] ] = path.absolute(path.translate(provide["compiled-module-path"])) else - m.provides[provide["logical-name"] ] = provide["compiled-module-path"] + m.provides[provide["logical-name"] ] = path.translate(provide["compiled-module-path"]) end else -- assume path with name local name = provide["logical-name"] .. get_bmi_ext(target) @@ -206,13 +204,14 @@ function parse_dependency_data(target, moduleinfos, opt) end end - modules[rule["primary-output"] ] = m + assert(rule["primary-output"]) + modules[path.translate(rule["primary-output"])] = m end end for _, moduleinfo in ipairs(moduleinfos) do for _, rule in ipairs(moduleinfo.rules) do - local m = modules[rule["primary-output"] ] + local m = modules[path.translate(rule["primary-output"])] for _, r in ipairs(rule.requires) do m.requires = m.requires or {} @@ -228,7 +227,7 @@ function parse_dependency_data(target, moduleinfos, opt) m.requires[r["logical-name"] ] = { method = r["lookup-method"] or "by-name", - path = p, + path = p and path.translate(p) or nil, unique = r["unique-on-source-path"] or false } end @@ -317,8 +316,20 @@ end function find_angle_header_file(target, file) -- check if the header is in subtarget + + local modules_support + if target:has_tool("cxx", "clang", "clangxx") then + modules_support = import("clang") + elseif target:has_tool("cxx", "gcc", "gxx") then + modules_support = import("gcc") + elseif target:has_tool("cxx", "cl") then + modules_support = import("msvc") + else + local _, toolname = target:tool("cxx") + raise("compiler(%s): does not support c++ module!", toolname) + end - local headerpaths = {} + local headerpaths = modules_support.toolchain_include_directories(target) for _, dep in ipairs(target:orderdeps()) do table.append(headerpaths, dep:scriptdir()) @@ -333,8 +344,9 @@ function find_angle_header_file(target, file) table.join2(headerpaths, target:get("includedirs")) - local p = find_file(file, table.join(headerpaths, { "/usr/include/**", "/usr/local/include/**" })) + local p = find_file(file, headerpaths) + assert(p) assert(os.isfile(p)) return p @@ -405,5 +417,7 @@ function fallback_generate_dependencies(target, jsonfile, sourcefile) table.append(output.rules, rule) - return output + local jsondata = json.encode(output) + + io.writefile(jsonfile, jsondata) end
\ No newline at end of file diff --git a/xmake/rules/c++/modules/build_modules/gcc.lua b/xmake/rules/c++/modules/modules_support/gcc.lua index 97bb9cc9a..5f66db54f 100644 --- a/xmake/rules/c++/modules/build_modules/gcc.lua +++ b/xmake/rules/c++/modules/modules_support/gcc.lua @@ -22,13 +22,19 @@ 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"}) -local default_flags = {"-std=c++20"} +modulesflag = nil +modulemapperflag = nil +trtbdflag = nil +function get_bmi_ext() + return ".gcm" +end + +-- get and create the path of module mapper function get_module_mapper() local mapper_file = path.join(config.buildir(), "mapper.txt") if not os.isfile(mapper_file) then @@ -38,6 +44,7 @@ function get_module_mapper() return mapper_file end +-- add a module or header unit into the mapper function add_module_to_mapper(file, module, bmi) for line in io.lines(file) do if line:startswith(module .. " ") then @@ -57,33 +64,50 @@ function load_parent(target, opt) local common = import("common") local cachedir = common.get_cache_dir(target) - target:add("cxxflags", "-fmodules-ts") + target:add("cxxflags", modulesflag) if os.isfile(get_module_mapper()) then os.rm(get_module_mapper()) end target:add("cxxflags", "-fmodule-mapper=" .. get_module_mapper(), {force = true, expand = false}) - - 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 -- 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 + + 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!") - if compinst:has_flags("-fdep-format=trtbd") then - target:data_set("cxx.has_p1689r4", true) + 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!") + + if compinst:has_flags("-fdep-format=trtbd", "cxxflags", {flagskey = "gcc_dep_format"}) then + trtbdflag = "-fdep-format=trtbd" + end + + if compinst:has_flags("-fdep-file=" .. os.tmpfile(), "cxxflags", {flagskey = "gcc_dep_file"}) then + depfileflag = "-fdep-file=" + end + + if compinst:has_flags("-fdep-output=" .. os.tmpfile() .. ".o", "cxxflags", {flagskey = "gcc_dep_output"}) then + depoutputflag = "-fdep-output=" end end +-- provide toolchain include dir for stl headerunit when p1689 is not supported +function toolchain_include_directories(target) + if is_plat("linux") then + return { "/usr/include/**", "/usr/local/include/**" } + end + + return {} +end + +-- generate dependency files function generate_dependencies(target, sourcebatch, opt) local common = import("common") local cachedir = common.get_cache_dir(target) @@ -102,18 +126,15 @@ function generate_dependencies(target, sourcebatch, opt) local jsonfile = path.translate(path.join(outdir, path.filename(sourcefile) .. ".json")) - if target:data("cxx.has_p1689r4") then + if trtbdflag and depfileflag and depoutputflag 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} + local args = {sourcefile, "-MD", "-MT", jsonfile, "-MF", dfile, depfileflag .. jsonfile, trtbdflag, depoutputfile .. 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) + os.vrunv(compinst:program(), table.join(compinst:compflags({target = target}), common_args, args), {envs = vcvars}) + else + common.fallback_generate_dependencies(target, jsonfile, sourcefile) end local dependinfo = io.readfile(jsonfile) @@ -142,12 +163,18 @@ function generate_headerunits(target, batchcmds, sourcebatch, opt) local objectfile = target:objectfile(file) - local outdir = path.join(cachedir, "include", path.directory(headerunit.name)) + local outdir + if headerunit.type == ":quote" then + outdir = path.join(cachedir, path.directory(path.relative(headerunit.path, project.directory()))) + else + outdir = path.join(cachedir, path.directory(headerunit.path)) + end + if not os.isdir(outdir) then os.mkdir(outdir) end - local bmifilename = path.basename(objectfile) .. ".gcm" + local bmifilename = path.basename(objectfile) .. get_bmi_ext() local bmifile = (outdir and path.join(outdir, bmifilename) or bmifilename) if not os.isdir(path.directory(objectfile)) then @@ -165,21 +192,21 @@ function generate_headerunits(target, batchcmds, sourcebatch, opt) 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:vrunv(compinst:program(), table.join(compinst:compflags({target = target}), 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") + local bmifile = path.join(stlcachedir, headerunit.name .. get_bmi_ext()) 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:vrunv(compinst:program(), table.join(compinst:compflags({target = target}), args)) batchcmds:set_depmtime(os.mtime(bmifile)) batchcmds:set_depcache(target:dependfile(bmifile)) @@ -220,7 +247,7 @@ function build_modules(target, batchcmds, objectfiles, modules, opt) end end - batchcmds:vrunv(compinst:program(), table.join(compinst:compflags({target = target}) or default_flags, common_args, args)) + batchcmds:vrunv(compinst:program(), table.join(compinst:compflags({target = target}), common_args, args)) batchcmds:set_depmtime(os.mtime(objectfile)) batchcmds:set_depcache(target:dependfile(objectfile)) diff --git a/xmake/rules/c++/modules/build_modules/msvc.lua b/xmake/rules/c++/modules/modules_support/msvc.lua index ac1386a27..0a701e0f6 100644 --- a/xmake/rules/c++/modules/build_modules/msvc.lua +++ b/xmake/rules/c++/modules/modules_support/msvc.lua @@ -20,11 +20,26 @@ -- imports import("core.tool.compiler") +import("core.project.project") import("core.project.depend") import("utils.progress") import("private.action.build.object", {alias = "objectbuilder"}) -local default_flags = {"/EHsc", "/nologo", "/std:c++20", "/experimental:module"} +modulesflag = nil +ifcoutputflag = nil +ifcsearchdirflag = nil +interfaceflag = nil +referenceflag = nil +headernameflag = nil +headerunitflag = nil +exportheaderflag = nil +stdifcdirflag = nil +scandependenciesflag = nil +cxxsourcefileflag = "/TP" + +function get_bmi_ext() + return ".ifc" +end -- load parent target with modules files function load_parent(target, opt) @@ -36,14 +51,13 @@ function load_parent(target, opt) local cachedir = common.get_cache_dir(target) local stlcachedir = common.get_stlcache_dir(target) - target:add("cxxflags", "/experimental:module") - target:add("cxxflags", {"/ifcSearchDir", cachedir}, {force = true, expand = false}) - target:add("cxxflags", {"/ifcSearchDir", stlcachedir}, {force = true, expand = false}) + target:add("cxxflags", modulesflag) + target:add("cxxflags", {ifcsearchdirflag, cachedir}, {force = true, expand = false}) + target:add("cxxflags", {ifcsearchdirflag, stlcachedir}, {force = true, expand = false}) for _, dep in ipairs(target:orderdeps()) do cachedir = common.get_cache_dir(dep) - dep:add("cxxflags", "/experimental:module") - target:add("cxxflags", {"/ifcSearchDir", cachedir}, {force = true, expand = false}) + target:add("cxxflags", {ifcsearchdirflag, cachedir}, {force = true, expand = false}) end for _, toolchain_inst in ipairs(target:toolchains()) do @@ -52,7 +66,7 @@ function load_parent(target, opt) if vcvars.VCInstallDir and vcvars.VCToolsVersion then local stdifcdir = path.join(vcvars.VCInstallDir, "Tools", "MSVC", vcvars.VCToolsVersion, "ifc", target:is_arch("x64") and "x64" or "x86") if os.isdir(stdifcdir) then - target:add("cxxflags", {"/stdIfcDir", winos.short_path(stdifcdir)}, {force = true, expand = false}) + target:add("cxxflags", {stdifcdirflag, winos.short_path(stdifcdir)}, {force = true, expand = false}) end end break @@ -64,40 +78,93 @@ end function check_module_support(target) local compinst = target:compiler("cxx") - if compinst:has_flags("/experimental:module", "cxxflags") then + if compinst:has_flags("/experimental:module", "cxxflags", {flagskey = "cl_experimental_module"}) then modulesflag = "/experimental:module" end assert(modulesflag, "compiler(msvc): does not support c++ module!") - -- get output flag - local outputflag - if compinst:has_flags("/ifcOutput", "cxxflags") then - outputflag = "/ifcOutput" + -- get ifcoutput flag + if compinst:has_flags("/ifcOutput", "cxxflags", {flagskey = "cl_ifc_output"}) then + ifcoutputflag = "/ifcOutput" + end + assert(ifcoutputflag, "compiler(msvc): does not support c++ module!") + + -- get ifcsearchdir flag + if compinst:has_flags("/ifcSearchDir", "cxxflags", {flagskey = "cl_ifc_search_dir"}) then + ifcsearchdirflag = "/ifcSearchDir" end - assert(outputflag, "compiler(msvc): does not support c++ module!") + assert(ifcsearchdirflag, "compiler(msvc): does not support c++ module!") -- get interface flag - local interfaceflag - if compinst:has_flags("/interface", "cxxflags") then + if compinst:has_flags("/interface", "cxxflags", {flagskey = "cl_interface"}) then interfaceflag = "/interface" end assert(interfaceflag, "compiler(msvc): does not support c++ module!") -- get reference flag - local referenceflag - if compinst:has_flags("/reference", "cxxflags") then + if compinst:has_flags("/reference", "cxxflags", {flagskey = "cl_reference"}) then referenceflag = "/reference" end assert(referenceflag, "compiler(msvc): does not support c++ module!") + -- get headername flag + if compinst:has_flags("/headerName:quote", "cxxflags", {flagskey = "cl_header_name_quote"}) and + compinst:has_flags("/headerName:angle", "cxxflags", {flagskey = "cl_header_name_angle"}) then + headernameflag = "/headerName" + end + assert(headernameflag, "compiler(msvc): does not support c++ module!") + + -- get headerunit flag + if compinst:has_flags("/headerUnit:quote", "cxxflags", {flagskey = "cl_header_unit_quote"}) and + compinst:has_flags("/headerUnit:angle", "cxxflags", {flagskey = "cl_header_unit_angle"}) then + headerunitflag = "/headerUnit" + end + assert(headerunitflag, "compiler(msvc): does not support c++ module!") + + -- get exportheader flag + if compinst:has_flags(modulesflag .. " /exportHeader", "cxxflags", {flagskey = "cl_export_header"}) then + exportheaderflag = "/exportHeader" + end + assert(exportheaderflag, "compiler(msvc): does not support c++ module!") + -- get stdifcdir flag - local stdifcdirflag - if compinst:has_flags("/stdIfcDir", "cxxflags") then + if compinst:has_flags("/stdIfcDir", "cxxflags", {flagskey = "cl_ifc_dir"}) then stdifcdirflag = "/stdIfcDir" end assert(stdifcdirflag, "compiler(msvc): does not support c++ module!") + + -- get scandependencies flag + local scan_dependencies_jsonfile = os.tmpfile() .. ".json" + if compinst:has_flags("/scanDependencies " .. scan_dependencies_jsonfile, "cxflags", {flagskey = "cl_scan_dependencies", + on_check = function (ok, errors) + if os.isfile(scan_dependencies_jsonfile) then + ok = true + end + + if ok and not os.isfile(scan_dependencies_jsonfile) then + ok = false + end + + return ok, errors + end}) then + scandependenciesflag = "/scanDependencies" + end end +-- provide toolchain include dir for stl headerunit when p1689 is not supported +function toolchain_include_directories(target) + for _, toolchain_inst in ipairs(target:toolchains()) do + if toolchain_inst:name() == "msvc" then + local vcvars = toolchain_inst:config("vcvars") + if vcvars.VCInstallDir and vcvars.VCToolsVersion then + return { path.join(vcvars.VCInstallDir, "Tools", "MSVC", vcvars.VCToolsVersion, "include") } + end + break + end + end + + assert(false) +end -- generate dependency files function generate_dependencies(target, sourcebatch, opt) @@ -107,12 +174,12 @@ function generate_dependencies(target, sourcebatch, opt) local common = import("common") local cachedir = common.get_cache_dir(target) - local common_args = {"/TP", "/scanDependencies"} + local common_args = {cxxsourcefileflag, scandependenciesflag} 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) + progress.show(opt.progress, "${color.build.object}generating.cxx.module.deps %s", sourcefile) local outdir = path.join(cachedir, path.directory(path.relative(sourcefile, target:scriptdir()))) if not os.isdir(outdir) then @@ -120,9 +187,14 @@ function generate_dependencies(target, sourcebatch, opt) end local jsonfile = path.join(outdir, path.filename(sourcefile) .. ".json") - local args = {jsonfile, sourcefile, "/Fo" .. target:objectfile(sourcefile)} - - os.vrunv(compinst:program(), table.join(compinst:compflags({target = target}) or default_flags, common_args, args), {envs = vcvars}) + + if scandependenciesflag then + local args = {jsonfile, sourcefile, "/Fo" .. target:objectfile(sourcefile)} + + os.vrunv(compinst:program(), table.join(compinst:compflags({target = target}), common_args, args), {envs = vcvars}) + else + common.fallback_generate_dependencies(target, jsonfile, sourcefile) + end local dependinfo = io.readfile(jsonfile) @@ -143,7 +215,7 @@ function generate_headerunits(target, batchcmds, sourcebatch, opt) local stlcachedir = common.get_stlcache_dir(target) -- build headerunits - local common_args = {"/TP", "/exportHeader", "/c"} + local common_args = {cxxsourcefileflag, exportheaderflag, "/c"} local objectfiles = {} local public_flags = {} local private_flags = {} @@ -153,21 +225,27 @@ function generate_headerunits(target, batchcmds, sourcebatch, opt) local objectfile = target:objectfile(file) - local outdir = path.join(cachedir, "include", path.directory(headerunit.name)) + local outdir + if headerunit.type == ":quote" then + outdir = path.join(cachedir, path.directory(path.relative(headerunit.path, project.directory()))) + else + outdir = path.join(cachedir, path.directory(headerunit.path):sub(3)) + end + if not os.isdir(outdir) then os.mkdir(outdir) end - local bmifilename = path.basename(objectfile) .. ".ifc" + local bmifilename = path.basename(objectfile) .. get_bmi_ext() local bmifile = (outdir and path.join(outdir, bmifilename) or bmifilename) if not os.isdir(path.directory(objectfile)) then os.mkdir(path.directory(objectfile)) end - local args = {"/headerName" .. headerunit.type, headerunit.path, "/ifcOutput", outdir, "/Fo" .. objectfile} + local args = {headernameflag .. headerunit.type, headerunit.path, ifcoutputflag, outdir, "/Fo" .. objectfile} 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, common_args, args), {envs = vcvars}) + batchcmds:vrunv(compinst:program(), table.join(compinst:compflags({target = target}), common_args, args), {envs = vcvars}) batchcmds:add_depfiles(headerunit.path) batchcmds:set_depmtime(os.mtime(bmifile)) @@ -175,19 +253,19 @@ function generate_headerunits(target, batchcmds, sourcebatch, opt) batchcmds:set_depmtime(os.mtime(objectfile)) batchcmds:set_depcache(target:dependfile(objectfile)) - local flag = {"/headerUnit" .. headerunit.type, headerunit.name .. "=" .. path.relative(bmifile, cachedir)} + local flag = {headerunitflag .. headerunit.type, headerunit.name .. "=" .. path.relative(bmifile, cachedir)} table.join2(public_flags, flag) target:add("objectfiles", objectfile) else - local bmifile = path.join(stlcachedir, headerunit.name .. ".ifc") - local args = {"/exportHeader", "/headerName:angle", headerunit.name, "/ifcOutput", stlcachedir} + local bmifile = path.join(stlcachedir, headerunit.name .. get_bmi_ext()) + local args = {exportheaderflag, headernameflag .. ":angle", headerunit.name, ifcoutputflag, stlcachedir} 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), {envs = vcvars}) + batchcmds:vrunv(compinst:program(), table.join(compinst:compflags({target = target}), args), {envs = vcvars}) batchcmds:set_depmtime(os.mtime(bmifile)) batchcmds:set_depcache(target:dependfile(bmifile)) - local flag = {"/headerUnit:angle", headerunit.name .. "=" .. headerunit.name .. ".ifc"} + local flag = {headerunitflag .. ":angle", headerunit.name .. "=" .. headerunit.name .. get_bmi_ext()} table.join2(private_flags, flag) end end @@ -209,7 +287,7 @@ function build_modules(target, batchcmds, objectfiles, modules, opt) end -- compile module files to bmi files - local common_args = {"/TP"} + local common_args = {cxxsourcefileflag} for _, objectfile in ipairs(objectfiles) do local m = modules[objectfile] @@ -225,7 +303,7 @@ function build_modules(target, batchcmds, objectfiles, modules, opt) batchcmds:show_progress(opt.progress, "${color.build.object}generating.cxx.module.bmi %s", name) local bmifile = provide.bmi - table.join2(args, {"/interface", "/ifcOutput", bmifile, provide.sourcefile}) + table.join2(args, {interfaceflag, ifcoutputflag, bmifile, provide.sourcefile}) batchcmds:add_depfiles(provide.sourcefile) batchcmds:set_depmtime(os.mtime(bmifile)) @@ -234,7 +312,7 @@ function build_modules(target, batchcmds, objectfiles, modules, opt) flag = {"/reference", name .. "=" .. path.filename(bmifile)} end - batchcmds:vrunv(compinst:program(), table.join(compinst:compflags({target = target}) or default_flags, common_args, args, bmi_args), {envs = vcvars}) + batchcmds:vrunv(compinst:program(), table.join(compinst:compflags({target = target}), common_args, args, bmi_args), {envs = vcvars}) batchcmds:set_depmtime(os.mtime(objectfile)) batchcmds:set_depcache(target:dependfile(objectfile)) diff --git a/xmake/rules/c++/modules/xmake.lua b/xmake/rules/c++/modules/xmake.lua index 8992e3133..655a52d38 100644 --- a/xmake/rules/c++/modules/xmake.lua +++ b/xmake/rules/c++/modules/xmake.lua @@ -29,34 +29,30 @@ rule("c++.build.modules") local target_with_modules = target:sourcebatches()["c++.build.modules"] and true or false for _, dep in ipairs(target:orderdeps()) do - local modulefiles = dep:get("modulefiles") - if modulefiles and #modulefiles > 0 then - target_with_modules = target:sourcebatches()["c++.build.modules"] and true or target_with_modules - break - end + target_with_modules = dep:sourcebatches()["c++.build.modules"] and true or target_with_modules end if target_with_modules then target:set("policy", "build.across_targets_in_parallel", false) - -- import build_modules - local build_modules + -- import modules_support + local modules_support if target:has_tool("cxx", "clang", "clangxx") then - build_modules = import("build_modules.clang") + modules_support = import("modules_support.clang") elseif target:has_tool("cxx", "gcc", "gxx") then - build_modules = import("build_modules.gcc") + modules_support = import("modules_support.gcc") elseif target:has_tool("cxx", "cl") then - build_modules = import("build_modules.msvc") + modules_support = import("modules_support.msvc") else local _, toolname = target:tool("cxx") raise("compiler(%s): does not support c++ module!", toolname) end -- check C++20 module support - build_modules.check_module_support(target) + modules_support.check_module_support(target) -- load parent - build_modules.load_parent(target, opt) + modules_support.load_parent(target, opt) target:set("cxx.has_modules", true) end @@ -64,33 +60,30 @@ rule("c++.build.modules") rule("c++.build.modules.dependencies") - set_sourcekinds("cxx") - set_extensions(".mpp", ".mxx", ".cppm", ".ixx") - before_build(function(target, opt) if not target:get("cxx.has_modules") then return end - local build_modules + local modules_support if target:has_tool("cxx", "clang", "clangxx") then - build_modules = import("build_modules.clang") + modules_support = import("modules_support.clang") elseif target:has_tool("cxx", "gcc", "gxx") then - build_modules = import("build_modules.gcc") + modules_support = import("modules_support.gcc") elseif target:has_tool("cxx", "cl") then - build_modules = import("build_modules.msvc") + modules_support = import("modules_support.msvc") else local _, toolname = target:tool("cxx") raise("compiler(%s): does not support c++ module!", toolname) end - local common = import("build_modules.common") + local common = import("modules_support.common") -- build dependency data - local batch = target:sourcebatches()["c++.build.modules.dependencies"] + local batch = target:sourcebatches()["c++.build.modules.builder"] common.patch_sourcebatch(target, batch, opt) - build_modules.generate_dependencies(target, batch, opt) + modules_support.generate_dependencies(target, batch, opt) local moduleinfos = common.load(target, batch, opt) local modules = common.parse_dependency_data(target, moduleinfos, opt) @@ -104,26 +97,25 @@ rule("c++.build.modules.builder") before_buildcmd_files(function(target, batchcmds, sourcebatch, opt) if not target:get("cxx.has_modules") then + sourcebatch.objectfiles = {} return end - local build_modules + local modules_support if target:has_tool("cxx", "clang", "clangxx") then - build_modules = import("build_modules.clang") + modules_support = import("modules_support.clang") elseif target:has_tool("cxx", "gcc", "gxx") then - build_modules = import("build_modules.gcc") + modules_support = import("modules_support.gcc") elseif target:has_tool("cxx", "cl") then - build_modules = import("build_modules.msvc") + modules_support = import("modules_support.msvc") else local _, toolname = target:tool("cxx") raise("compiler(%s): does not support c++ module!", toolname) end - local common = import("build_modules.common") + local common = import("modules_support.common") local batch = sourcebatch - print(sourcebatch) - print(batch) batch.objectfiles = {} batch.dependfiles = {} @@ -151,7 +143,7 @@ rule("c++.build.modules.builder") local headerunits_flags local private_headerunits_flags if headerunits then - headerunits_flags, private_headerunits_flags = build_modules.generate_headerunits(target, batchcmds, headerunits, opt) + headerunits_flags, private_headerunits_flags = modules_support.generate_headerunits(target, batchcmds, headerunits, opt) end if headerunits_flags then @@ -166,14 +158,16 @@ rule("c++.build.modules.builder") -- topological sort local objectfiles = common.sort_modules_by_dependencies(batch.objectfiles, modules) - build_modules.build_modules(target, batchcmds, objectfiles, modules, opt) + modules_support.build_modules(target, batchcmds, objectfiles, modules, opt) end) -rules("c++.build.modules.install") +rule("c++.build.modules.install") set_extensions(".mpp", ".mxx", ".cppm", ".ixx") - on_config(function (target) + before_install(function (target) local sourcebatch = target:sourcebatches()["c++.build.modules.install"] - target:add("installfiles", sourcebatch.sourcefiles, {prefixdir = "include"}) - end
\ No newline at end of file + if sourcebatch then + target:add("installfiles", sourcebatch.sourcefiles, {prefixdir = "include"}) + end + end)
\ No newline at end of file |
