summaryrefslogtreecommitdiff
path: root/xmake/rules/c++/modules/modules_support
diff options
context:
space:
mode:
authorArthur LAURENT <[email protected]>2022-08-03 04:10:04 +0200
committerArthur LAURENT <[email protected]>2022-08-03 08:32:49 +0200
commit728126bd7816bbd5fb6b93cedc7163a425343fba (patch)
treeb3b355973fa7b53e11ed74daf0c360f874d5d026 /xmake/rules/c++/modules/modules_support
parenta9ed54fd3af64a04bb7d617a51dde689d23c80de (diff)
[C++20 Modules] Improve support
Diffstat (limited to 'xmake/rules/c++/modules/modules_support')
-rw-r--r--xmake/rules/c++/modules/modules_support/clang.lua260
-rw-r--r--xmake/rules/c++/modules/modules_support/common.lua23
-rw-r--r--xmake/rules/c++/modules/modules_support/gcc.lua145
-rw-r--r--xmake/rules/c++/modules/modules_support/msvc.lua292
4 files changed, 475 insertions, 245 deletions
diff --git a/xmake/rules/c++/modules/modules_support/clang.lua b/xmake/rules/c++/modules/modules_support/clang.lua
index e12c7afed..49dbee0a2 100644
--- a/xmake/rules/c++/modules/modules_support/clang.lua
+++ b/xmake/rules/c++/modules/modules_support/clang.lua
@@ -25,35 +25,16 @@ import("core.project.depend")
import("core.project.config")
import("utils.progress")
import("private.action.build.object", {alias = "objectbuilder"})
-
-modulesflag = nil
-modulestsflag = nil
-implicitmodules = nil
-implicitmodulemapsflag = nil
-prebuiltmodulepathflag = nil
-
-function get_bmi_ext()
- return ".pcm"
-end
+import("common")
-- load parent target with modules files
function load_parent(target, opt)
- local common = import("common")
local cachedir = common.get_cache_dir(target)
- local stlcachedir = common.get_stlcache_dir(target)
- -- add module flags
- target:add("cxxflags", modulesflag or modulestsflag)
-
- -- add the module cache directory
- target:add("cxxflags", implicitmodulesflag, {force = true})
- target:add("cxxflags", implicitmodulemapsflag, {force = true})
-
- target:add("cxxflags", prebuiltmodulepathflag .. cachedir, prebuiltmodulepathflag .. stlcachedir, {force = true})
+ local prebuiltmodulepathflag = get_prebuiltmodulepathflag(target)
for _, dep in ipairs(target:orderdeps()) do
cachedir = common.get_cache_dir(dep)
- target:add("cxxflags", prebuiltmodulepathflag .. cachedir, prebuiltmodulepathflag .. stlcachedir, {force = true})
target:add("cxxflags", prebuiltmodulepathflag .. cachedir, {force = true})
end
end
@@ -61,68 +42,57 @@ end
-- check C++20 module support
function check_module_support(target)
local compinst = compiler.load("cxx", {target = target})
+ local cachedir = common.get_cache_dir(target)
+ local stlcachedir = common.get_stlcache_dir(target)
- if compinst:has_flags("-fmodules", "cxxflags", {flagskey = "clang_modules"}) then
- modulesflag = "-fmodules"
- end
-
- 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!")
+ -- get module and module cache flags
+ local modulesflag = get_modulesflag(target)
+ local implicitmodulesflag = get_implicitmodulesflag(target)
+ local implicitmodulemapsflag = get_implicitmodulemapsflag(target)
+ local prebuiltmodulepathflag = get_prebuiltmodulepathflag(target)
- 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!")
+ -- add module flags
+ target:add("cxxflags", modulesflag)
- 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!")
+ -- add the module cache directory
+ target:add("cxxflags", implicitmodulesflag, {force = true})
+ target:add("cxxflags", implicitmodulemapsflag, {force = true})
- 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!")
+ target:add("cxxflags", prebuiltmodulepathflag .. cachedir, prebuiltmodulepathflag .. stlcachedir, {force = true})
end
function toolchain_include_directories(target)
- if is_plat("linux") then
- return { "/usr/include/**", "/usr/local/include/**" }
- end
+ local includedirs = _g.includedirs
+ if includedirs == nil then
+ includedirs = {}
- return {}
+ local gcc, toolname = target:tool("cc")
+ assert(toolname, "clang")
+
+ local _, result = try {function () return os.iorunv(gcc, {"-E", "-Wp,-v", "-xc", os.nuldev()}) end}
+ if result then
+ for _, line in ipairs(result:split("\n", {plain = true})) do
+ line = line:trim()
+ if os.isdir(line) then
+ table.append(includedirs, line)
+ break
+ elseif line:startswith("End") then
+ break
+ end
+ end
+ end
+ _g.includedirs = includedirs or {}
+ end
+ return includedirs
end
function generate_dependencies(target, sourcebatch, opt)
- local common = import("common")
local cachedir = common.get_cache_dir(target)
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.translate(path.join(cachedir, path.directory(path.relative(sourcefile, target:scriptdir()))))
if not os.isdir(outdir) then
@@ -143,13 +113,17 @@ end
-- generate target header units
function generate_headerunits(target, batchcmds, sourcebatch, opt)
- local common = import("common")
-
local compinst = target:compiler("cxx")
-
local cachedir = common.get_cache_dir(target)
local stlcachedir = common.get_stlcache_dir(target)
+ assert(has_headerunitsupport(target), "compiler(clang): does not support c++ header units!")
+
+ -- get headerunits flags
+ local modulecachepathflag = get_modulecachepathflag(target)
+ local emitmoduleflag = get_emitmoduleflag(target)
+ local modulefileflag = get_modulefileflag(target)
+
-- build headerunits
local objectfiles = {}
local public_flags = {}
@@ -210,15 +184,18 @@ function generate_headerunits(target, batchcmds, sourcebatch, opt)
table.append(private_flags, modulefileflag .. bmifile)
end
end
-
return public_flags, private_flags
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 cachedir = common.get_cache_dir(target)
+
+ -- get modules flags
+ local modulecachepathflag = get_modulecachepathflag(target)
+ local emitmoduleinterfaceflag = get_emitmoduleinterfaceflag(target)
+ local modulefileflag = get_modulefileflag(target)
-- append deps modules
local flags = {}
@@ -268,3 +245,140 @@ function build_modules(target, batchcmds, objectfiles, modules, opt)
end
end
end
+
+function get_bmi_ext()
+ return ".pcm"
+end
+
+function get_modulesflag(target)
+ local modulesflag = _g.modulesflag
+ if modulesflag == nil then
+ local compinst = target:compiler("cxx")
+ if compinst:has_flags("-fmodules", "cxxflags", {flagskey = "clang_modules"}) then
+ modulesflag = "-fmodules"
+ end
+
+ if not modulesflag then
+ if compinst:has_flags("-fmodules-ts", "cxxflags", {flagskey = "clang_modules_ts"}) then
+ modulesflag = "-fmodules-ts"
+ end
+ end
+
+ assert(modulesflag, "compiler(clang): does not support c++ module!")
+
+ _g.modulesflag = modulesflag or false
+ end
+ return modulesflag
+end
+
+function get_implicitmodulesflag(target)
+ local implicitmodulesflag = _g.implicitmodulesflag
+ if implicitmodulesflag == nil then
+ local compinst = target:compiler("cxx")
+ if compinst:has_flags("-fimplicit-modules", "cxxflags", {flagskey = "clang_implicit_modules"}) then
+ implicitmodulesflag = "-fimplicit-modules"
+ end
+ assert(implicitmodulesflag, "compiler(clang): does not support c++ module!")
+
+ _g.implicitmodulesflag = implicitmodulesflag or false
+ end
+ return implicitmodulesflag
+end
+
+function get_implicitmodulemapsflag(target)
+ local implicitmodulemapsflag = _g.implicitmodulemapsflag
+ if implicitmodulemapsflag == nil then
+ local compinst = target:compiler("cxx")
+ if compinst:has_flags("-fimplicit-module-maps", "cxxflags", {flagskey = "clang_implicit_module_maps"}) then
+ implicitmodulemapsflag = "-fimplicit-module-maps"
+ end
+ assert(implicitmodulemapsflag, "compiler(clang): does not support c++ module!")
+
+ _g.implicitmodulemapsflag = implicitmodulemapsflag or false
+ end
+ return implicitmodulemapsflag
+end
+
+function get_prebuiltmodulepathflag(target)
+ local prebuiltmodulepathflag = _g.prebuiltmodulepathflag
+ if prebuiltmodulepathflag == nil then
+ local compinst = target:compiler("cxx")
+ if compinst:has_flags("-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!")
+
+ _g.prebuiltmodulepathflag = prebuiltmodulepathflag or false
+ end
+ return prebuiltmodulepathflag
+end
+
+function get_modulecachepathflag(target)
+ local modulecachepathflag = _g.modulecachepathflag
+ if modulecachepathflag == nil then
+ local compinst = target:compiler("cxx")
+ if compinst:has_flags("-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!")
+
+ _g.modulecachepathflag = modulecachepathflag or false
+ end
+ return modulecachepathflag
+end
+
+function get_emitmoduleflag(target)
+ local emitmoduleflag = _g.emitmoduleflag
+ if emitmoduleflag == nil then
+ local compinst = target:compiler("cxx")
+ if compinst:has_flags("-emit-module", "cxxflags", {flagskey = "clang_emit_module"}) then
+ emitmoduleflag = " -emit-module"
+ end
+ assert(emitmoduleflag, "compiler(clang): does not support c++ module!")
+
+ _g.emitmoduleflag = emitmoduleflag or false
+ end
+ return emitmoduleflag
+end
+
+function get_modulefileflag(target)
+ local modulefileflag = _g.modulefileflag
+ if modulefileflag == nil then
+ local compinst = target:compiler("cxx")
+ if compinst:has_flags("-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!")
+
+ _g.modulefileflag = modulefileflag or false
+ end
+ return modulefileflag
+end
+
+function get_emitmoduleinterfaceflag(target)
+ local emitmoduleinterfaceflag = _g.emitmoduleinterfaceflag
+ if emitmoduleinterfaceflag == nil then
+ local compinst = target:compiler("cxx")
+ if compinst:has_flags("-emit-module-interface", "cxxflags", {flagskey = "clang_emit_module_interface"}) then
+ emitmoduleinterfaceflag = "-emit-module-interface"
+ end
+ assert(emitmoduleinterfaceflag, "compiler(clang): does not support c++ module!")
+
+ _g.emitmoduleinterfaceflag = emitmoduleinterfaceflag or false
+ end
+ return emitmoduleinterfaceflag
+end
+
+function has_headerunitsupport(target)
+ local support_headerunits = _g.support_headerunits
+ if support_headerunits == nil then
+ local compinst = target:compiler("cxx")
+ if compinst:has_flags("-x c++-user-header", "cxxflags", {flagskey = "clang_user_header_unit_support"}) and
+ compinst:has_flags("-x c++-system-header", "cxxflags", {flagskey = "clang_system_header_unit_support"}) then
+ support_headerunits = true
+ end
+
+ _g.support_headerunits = support_headerunits or false
+ end
+ return support_headerunits
+end \ No newline at end of file
diff --git a/xmake/rules/c++/modules/modules_support/common.lua b/xmake/rules/c++/modules/modules_support/common.lua
index ca637cbf2..e706f4e81 100644
--- a/xmake/rules/c++/modules/modules_support/common.lua
+++ b/xmake/rules/c++/modules/modules_support/common.lua
@@ -1,10 +1,11 @@
import("core.base.json")
+import("core.base.hashset")
import("core.project.config")
import("core.tool.compiler")
import("core.project.project")
import("lib.detect.find_file")
-local stl_headers = {
+_g.stl_headers = {
"algorithm",
"forward_list",
"numbers",
@@ -86,17 +87,11 @@ local stl_headers = {
"stdexcept"}
function get_stl_headers()
- return stl_headers
+ return hashset.from(_g.stl_headers)
end
function is_stl_header(header)
- for _, stl_header in ipairs(stl_headers) do
- if stl_header == header then
- return true
- end
- end
-
- return false
+ return get_stl_headers():has(header)
end
function get_stlcache_dir(target)
@@ -107,7 +102,6 @@ function get_stlcache_dir(target)
if not os.isdir(stlcachedir) then
os.mkdir(stlcachedir)
end
-
return path.translate(stlcachedir)
end
@@ -116,7 +110,6 @@ function get_cache_dir(target)
if not os.isdir(cachedir) then
os.mkdir(cachedir)
end
-
return path.translate(cachedir)
end
@@ -133,7 +126,6 @@ function patch_sourcebatch(target, sourcebatch, opt)
table.insert(sourcebatch.objectfiles, objectfile)
table.insert(sourcebatch.dependfiles, dependfile)
end
-
end
function get_bmi_ext(target)
@@ -144,7 +136,6 @@ function get_bmi_ext(target)
elseif target:has_tool("cxx", "clang", "clangxx") then
return import("clang").get_bmi_ext()
end
-
assert(false)
end
@@ -164,7 +155,8 @@ function modules_support(target)
end
function contains_modules(target)
- local target_with_modules
+ local target_with_modules = target:sourcebatches()["c++.build.modules"] and true or false
+
for _, dep in ipairs(target:orderdeps()) do
local sourcebatches = dep:sourcebatches()
if sourcebatches and sourcebatches["c++.build.modules"] then
@@ -195,7 +187,6 @@ function load(target, sourcebatch, opt)
end
end
end
-
return moduleinfos
end
@@ -260,7 +251,6 @@ function parse_dependency_data(target, moduleinfos, opt)
end
end
end
-
return modules
end
@@ -329,7 +319,6 @@ function sort_modules_by_dependencies(objectfiles, modules)
_topological_sort_visit(node, nodes, modules, output)
end
-
return output
end
diff --git a/xmake/rules/c++/modules/modules_support/gcc.lua b/xmake/rules/c++/modules/modules_support/gcc.lua
index 5f66db54f..0c8027b6e 100644
--- a/xmake/rules/c++/modules/modules_support/gcc.lua
+++ b/xmake/rules/c++/modules/modules_support/gcc.lua
@@ -25,14 +25,7 @@ import("core.project.depend")
import("core.project.config")
import("utils.progress")
import("private.action.build.object", {alias = "objectbuilder"})
-
-modulesflag = nil
-modulemapperflag = nil
-trtbdflag = nil
-
-function get_bmi_ext()
- return ".gcm"
-end
+import("common")
-- get and create the path of module mapper
function get_module_mapper()
@@ -53,7 +46,7 @@ function add_module_to_mapper(file, module, bmi)
end
local f = io.open(file, "a")
- f:printf("%s %s\n", module, bmi)
+ f:print("%s %s", module, bmi)
f:close()
return true
@@ -61,63 +54,63 @@ end
-- load parent target with modules files
function load_parent(target, opt)
- local common = import("common")
- local cachedir = common.get_cache_dir(target)
-
- 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})
end
-- check C++20 module support
function check_module_support(target)
local compinst = compiler.load("cxx", {target = target})
- 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!")
+ local modulesflag = get_modulesflag(target)
+ local modulemapperflag = get_modulemapperflag(target)
- 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
+ target:add("cxxflags", modulesflag)
- if compinst:has_flags("-fdep-output=" .. os.tmpfile() .. ".o", "cxxflags", {flagskey = "gcc_dep_output"}) then
- depoutputflag = "-fdep-output="
+ if os.isfile(get_module_mapper()) then
+ os.rm(get_module_mapper())
end
+ target:add("cxxflags", modulemapperflag .. get_module_mapper(), {force = true, expand = false})
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 {}
+ local includedirs = _g.includedirs
+ if includedirs == nil then
+ includedirs = {}
+
+ local gcc, toolname = target:tool("cc")
+ assert(toolname, "gcc")
+
+ local _, result = try {function () return os.iorunv(gcc, {"-E", "-Wp,-v", "-xc", os.nuldev()}) end}
+ if result then
+ for _, line in ipairs(result:split("\n", {plain = true})) do
+ line = line:trim()
+ if os.isdir(line) then
+ table.append(includedirs, line)
+ break
+ elseif line:startswith("End") then
+ break
+ end
+ end
+ end
+ _g.includedirs = includedirs or {}
+ end
+ return includedirs
end
-- generate dependency files
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++"}
+ local trtbdflag = get_trtbdflag(target)
+ local depfileflag = get_depfileflag(target)
+ local depoutputflag = get_depoutputflag(target)
+
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.translate(path.join(cachedir, path.directory(path.relative(sourcefile, target:scriptdir()))))
if not os.isdir(outdir) then
@@ -146,8 +139,6 @@ end
-- generate target header units
function generate_headerunits(target, batchcmds, sourcebatch, opt)
- local common = import("common")
-
local compinst = target:compiler("cxx")
local cachedir = common.get_cache_dir(target)
@@ -213,7 +204,6 @@ function generate_headerunits(target, batchcmds, sourcebatch, opt)
end
end
end
-
end
end
@@ -257,3 +247,68 @@ function build_modules(target, batchcmds, objectfiles, modules, opt)
end
end
+function get_bmi_ext()
+ return ".gcm"
+end
+
+function get_modulesflag(target)
+ local modulesflag = _g.modulesflag
+ if modulesflag == nil then
+ local compinst = target:compiler("cxx")
+ if compinst:has_flags("-fmodules-ts", "cxxflags", {flagskey = "gcc_modules_ts"}) then
+ modulesflag = "-fmodules-ts"
+ end
+ assert(modulesflag, "compiler(gcc): does not support c++ module!")
+ _g.modulesflag = modulesflag or false
+ end
+ return modulesflag
+end
+
+function get_modulemapperflag(target)
+ local modulemapperflag = _g.modulemapperflag
+ if modulemapperflag == nil then
+ local compinst = target:compiler("cxx")
+ if compinst:has_flags("-fmodule-mapper=" .. os.tmpfile(), "cxxflags", {flagskey = "gcc_module_mapper"}) then
+ modulemapperflag = "-fmodule-mapper="
+ end
+ assert(modulemapperflag, "compiler(gcc): does not support c++ module!")
+ _g.modulemapperflag = modulemapperflag or false
+ end
+ return modulemapperflag
+end
+
+function get_trtbdflag(target)
+ local trtbdflag = _g.trtbdflag
+ if trtbdflag == nil then
+ local compinst = target:compiler("cxx")
+ if compinst:has_flags("-fdep-format=trtbd", "cxxflags", {flagskey = "gcc_dep_format"}) then
+ trtbdflag = "-fdep-format=trtbd"
+ end
+ _g.trtbdflag = trtbdflag or false
+ end
+ return trtbdflag
+end
+
+function get_depfileflag(target)
+ local depfileflag = _g.depfileflag
+ if depfileflag == nil then
+ local compinst = target:compiler("cxx")
+ if compinst:has_flags("-fdep-file=" .. os.tmpfile(), "cxxflags", {flagskey = "gcc_dep_file"}) then
+ depfileflag = "-fdep-file="
+ end
+ _g.depfileflag = depfileflag or false
+ end
+ return depfileflag
+end
+
+function get_depoutputflag(target)
+ local depoutputflag = _g.depoutputflag
+ if depoutputflag == nil then
+ local compinst = target:compiler("cxx")
+ if compinst:has_flags("-fdep-output=" .. os.tmpfile() .. ".o", "cxxflags", {flagskey = "gcc_dep_output"}) then
+ depoutputflag = "-fdep-output="
+ end
+ _g.depoutputflag = depoutputflag or false
+ end
+ return depoutputflag
+end
diff --git a/xmake/rules/c++/modules/modules_support/msvc.lua b/xmake/rules/c++/modules/modules_support/msvc.lua
index 0a701e0f6..1851d678c 100644
--- a/xmake/rules/c++/modules/modules_support/msvc.lua
+++ b/xmake/rules/c++/modules/modules_support/msvc.lua
@@ -24,42 +24,35 @@ import("core.project.project")
import("core.project.depend")
import("utils.progress")
import("private.action.build.object", {alias = "objectbuilder"})
+import("common")
-modulesflag = nil
-ifcoutputflag = nil
-ifcsearchdirflag = nil
-interfaceflag = nil
-referenceflag = nil
-headernameflag = nil
-headerunitflag = nil
-exportheaderflag = nil
-stdifcdirflag = nil
-scandependenciesflag = nil
-cxxsourcefileflag = "/TP"
+-- load parent target with modules files
+function load_parent(target, opt)
+ local ifcsearchdirflag = get_ifcsearchdirflag(target)
-function get_bmi_ext()
- return ".ifc"
+ for _, dep in ipairs(target:orderdeps()) do
+ cachedir = common.get_cache_dir(dep)
+ target:add("cxxflags", {ifcsearchdirflag, cachedir}, {force = true, expand = false})
+ end
end
--- load parent target with modules files
-function load_parent(target, opt)
- local common = import("common")
- -- get modules flag
+-- check C++20 module support
+function check_module_support(target)
local compinst = target:compiler("cxx")
-
- -- add module flags
local cachedir = common.get_cache_dir(target)
local stlcachedir = common.get_stlcache_dir(target)
+ -- get flags
+ local modulesflag = get_modulesflag(target)
+ local ifcsearchdirflag = get_ifcsearchdirflag(target)
+
+ -- add modules flags
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)
- target:add("cxxflags", {ifcsearchdirflag, cachedir}, {force = true, expand = false})
- end
-
+ -- add stdifcdir in case of if the user want to use Microsoft modularised STL
+ local stdifcdirflag = get_stdifcdirflag(target)
for _, toolchain_inst in ipairs(target:toolchains()) do
if toolchain_inst:name() == "msvc" then
local vcvars = toolchain_inst:config("vcvars")
@@ -74,83 +67,6 @@ function load_parent(target, opt)
end
end
--- check C++20 module support
-function check_module_support(target)
- local compinst = target:compiler("cxx")
-
- 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 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(ifcsearchdirflag, "compiler(msvc): does not support c++ module!")
-
- -- get interface flag
- 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
- 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
- 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
@@ -162,7 +78,6 @@ function toolchain_include_directories(target)
break
end
end
-
assert(false)
end
@@ -172,13 +87,14 @@ function generate_dependencies(target, sourcebatch, opt)
local toolchain = target:toolchain("msvc")
local vcvars = toolchain:config("vcvars")
- local common = import("common")
+ local scandependenciesflag = get_scandependenciesflag(target)
+
local cachedir = common.get_cache_dir(target)
- local common_args = {cxxsourcefileflag, scandependenciesflag}
+ local common_args = {"/TP", scandependenciesflag}
for _, sourcefile in ipairs(sourcebatch.sourcefiles) do
local dependfile = target:dependfile(sourcefile)
- depend.on_changed(function()
+ depend.on_changed(function ()
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())))
@@ -205,17 +121,23 @@ end
-- generate target header units
function generate_headerunits(target, batchcmds, sourcebatch, opt)
- local common = import("common")
-
local compinst = target:compiler("cxx")
local toolchain = target:toolchain("msvc")
local vcvars = toolchain:config("vcvars")
+ -- get flags
+ local exportheaderflag = get_exportheaderflag(target)
+ local headerunitflag = get_headerunitflag(target)
+ local headernameflag = get_headernameflag(target)
+ local ifcoutputflag = get_ifcoutputflag(target)
+
+ assert(headerunitflag and headernameflag and exportheaderflag, "compiler(msvc): does not support c++ header units!")
+
local cachedir = common.get_cache_dir(target)
local stlcachedir = common.get_stlcache_dir(target)
-- build headerunits
- local common_args = {cxxsourcefileflag, exportheaderflag, "/c"}
+ local common_args = {"/TP", exportheaderflag, "/c"}
local objectfiles = {}
local public_flags = {}
local private_flags = {}
@@ -281,13 +203,18 @@ function build_modules(target, batchcmds, objectfiles, modules, opt)
local toolchain = target:toolchain("msvc")
local vcvars = toolchain:config("vcvars")
+ -- get flags
+ local ifcoutputflag = get_ifcoutputflag(target)
+ local interfaceflag = get_interfaceflag(target)
+ local referenceflag = get_referenceflag(target)
+
-- append deps modules
for _, dep in ipairs(target:orderdeps()) do
target:add("cxxflags", dep:data("cxx.modules.flags"), {force = true, expand = false})
end
-- compile module files to bmi files
- local common_args = {cxxsourcefileflag}
+ local common_args = {"/TP"}
for _, objectfile in ipairs(objectfiles) do
local m = modules[objectfile]
@@ -309,7 +236,7 @@ function build_modules(target, batchcmds, objectfiles, modules, opt)
batchcmds:set_depmtime(os.mtime(bmifile))
batchcmds:set_depcache(target:dependfile(bmifile))
- flag = {"/reference", name .. "=" .. path.filename(bmifile)}
+ flag = {referenceflag, name .. "=" .. path.filename(bmifile)}
end
batchcmds:vrunv(compinst:program(), table.join(compinst:compflags({target = target}), common_args, args, bmi_args), {envs = vcvars})
@@ -325,3 +252,148 @@ function build_modules(target, batchcmds, objectfiles, modules, opt)
end
end
end
+
+function get_bmi_ext()
+ return ".ifc"
+end
+
+function get_modulesflag(target)
+ local modulesflag = _g.modulesflag
+ if modulesflag == nil then
+ local compinst = target:compiler("cxx")
+ 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!")
+ _g.modulesflag = modulesflag or false
+ end
+ return modulesflag
+end
+
+function get_ifcoutputflag(target)
+ local ifcoutputflag = _g.ifcoutputflag
+ if ifcoutputflag == nil then
+ local compinst = target:compiler("cxx")
+ if compinst:has_flags("/ifcOutput", "cxxflags", {flagskey = "cl_ifc_output"}) then
+ ifcoutputflag = "/ifcOutput"
+ end
+ assert(ifcoutputflag, "compiler(msvc): does not support c++ module!")
+ _g.ifcoutputflag = ifcoutputflag or false
+ end
+ return ifcoutputflag
+end
+
+function get_ifcsearchdirflag(target)
+ local ifcsearchdirflag = _g.ifcsearchdirflag
+ if ifcsearchdirflag == nil then
+ local compinst = target:compiler("cxx")
+ if compinst:has_flags("/ifcSearchDir", "cxxflags", {flagskey = "cl_ifc_search_dir"}) then
+ ifcsearchdirflag = "/ifcSearchDir"
+ end
+ assert(ifcsearchdirflag, "compiler(msvc): does not support c++ module!")
+ _g.ifcsearchdirflag = ifcsearchdirflag or false
+ end
+ return ifcsearchdirflag
+end
+
+function get_interfaceflag(target)
+ local interfaceflag = _g.interfaceflag
+ if interfaceflag == nil then
+ local compinst = target:compiler("cxx")
+ if compinst:has_flags("/interface", "cxxflags", {flagskey = "cl_interface"}) then
+ interfaceflag = "/interface"
+ end
+ assert(interfaceflag, "compiler(msvc): does not support c++ module!")
+ _g.interfaceflag = interfaceflag or false
+ end
+ return interfaceflag
+end
+
+function get_referenceflag(target)
+ local referenceflag = _g.referenceflag
+ if referenceflag == nil then
+ local compinst = target:compiler("cxx")
+ if compinst:has_flags("/reference", "cxxflags", {flagskey = "cl_reference"}) then
+ referenceflag = "/reference"
+ end
+ assert(referenceflag, "compiler(msvc): does not support c++ module!")
+ _g.referenceflag = referenceflag or false
+ end
+ return referenceflag
+end
+
+function get_headernameflag(target)
+ local headernameflag = _g.headernameflag
+ if headernameflag == nil then
+ local compinst = target:compiler("cxx")
+ 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
+ _g.headernameflag = headernameflag or false
+ end
+ return headernameflag
+end
+
+function get_headerunitflag(target)
+ local headerunitflag = _g.headerunitflag
+ if headerunitflag == nil then
+ local compinst = target:compiler("cxx")
+ 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
+ _g.headerunitflag = headerunitflag or false
+ end
+ return headerunitflag
+end
+
+function get_exportheaderflag(target)
+ local modulesflag = get_modulesflag(target)
+
+ local exportheaderflag = _g.exportheaderflag
+ if exportheaderflag == nil then
+ local compinst = target:compiler("cxx")
+ if compinst:has_flags(modulesflag .. " /exportHeader", "cxxflags", {flagskey = "cl_export_header"}) then
+ exportheaderflag = "/exportHeader"
+ end
+ _g.exportheaderflag = exportheaderflag or false
+ end
+ return exportheaderflag
+end
+
+function get_stdifcdirflag(target)
+ local stdifcdirflag = _g.stdifcdirflag
+ if stdifcdirflag == nil then
+ local compinst = target:compiler("cxx")
+ if compinst:has_flags("/stdIfcDir", "cxxflags", {flagskey = "cl_std_ifc_dir"}) then
+ stdifcdirflag = "/stdIfcDir"
+ end
+ _g.stdifcdirflag = stdifcdirflag or false
+ end
+ return stdifcdirflag
+end
+
+function get_scandependenciesflag(target)
+ local scandependenciesflag = _g.scandependenciesflag
+ if scandependenciesflag == nil then
+ local compinst = target:compiler("cxx")
+ 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
+ _g.scandependenciesflag = scandependenciesflag or false
+ end
+ return scandependenciesflag
+end