summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArthur LAURENT <[email protected]>2022-08-03 02:35:01 +0200
committerArthur LAURENT <[email protected]>2022-08-03 02:35:01 +0200
commit92b8b6629b6c3b4b59d78835b7e4719313c04ae1 (patch)
tree6f630619ebc0dec9425aeca61ed60448c951e4a0
parentab70577eccc2f4b003041e5c8850a775ddc81be0 (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.lua64
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