summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2022-08-09 10:52:30 +0800
committerGitHub <[email protected]>2022-08-09 10:52:30 +0800
commitd025377baf093a035e11fccc68309a49ae6da471 (patch)
treeb4b59671a866348f471985125d3382d700cfe78c
parent46cf0ad2545d829a255e88371660dfe8bb11de22 (diff)
parentaf7118dcc94785f628abe1cea5cd030514ea9e88 (diff)
Merge pull request #2649 from xmake-io/batchjobs
Adding parallel compilation support for c++ modules
-rw-r--r--tests/apis/rules/xmake.lua13
-rw-r--r--xmake/actions/build/build.lua62
-rw-r--r--xmake/rules/c++/modules/modules_support/clang.lua239
-rw-r--r--xmake/rules/c++/modules/modules_support/common.lua77
-rw-r--r--xmake/rules/c++/modules/modules_support/gcc.lua160
-rw-r--r--xmake/rules/c++/modules/modules_support/msvc.lua223
-rw-r--r--xmake/rules/c++/modules/xmake.lua85
7 files changed, 690 insertions, 169 deletions
diff --git a/tests/apis/rules/xmake.lua b/tests/apis/rules/xmake.lua
index 5a6e5d546..7d67f0dca 100644
--- a/tests/apis/rules/xmake.lua
+++ b/tests/apis/rules/xmake.lua
@@ -58,6 +58,12 @@ rule("stub2")
after_build(function (target)
print("rule(stub2): after_build")
end)
+ before_build_files(function (target)
+ print("rule(stub2): before_build_files")
+ end)
+ after_build_files(function (target)
+ print("rule(stub2): after_build_files")
+ end)
-- define rule: stub1
rule("stub1")
@@ -148,3 +154,10 @@ target("test")
add_files("src/index.md")
add_files("src/test.c.in", {rule = "c code"})
+ before_build(function (target)
+ print("target: before_build")
+ end)
+
+ after_build(function (target)
+ print("target: after_build")
+ end)
diff --git a/xmake/actions/build/build.lua b/xmake/actions/build/build.lua
index a32b8d705..3eddf1610 100644
--- a/xmake/actions/build/build.lua
+++ b/xmake/actions/build/build.lua
@@ -37,25 +37,27 @@ function _clean_target(target)
end
end
--- add builtin batch jobs
-function _add_batchjobs_builtin(batchjobs, rootjob, target)
+-- add batch jobs for rules
+function _add_batchjobs_for_rules(batchjobs, rootjob, target, suffix)
-- uses the rules script?
local job, job_leaf
for _, r in irpairs(target:orderules()) do -- reverse rules order for batchjobs:addjob()
- local script = r:script("build")
+ local scriptname = "build" .. (suffix and ("_" .. suffix) or "")
+ local script = r:script(scriptname)
if script then
- if r:extraconf("build", "batch") then
- job, job_leaf = assert(script(target, batchjobs, {rootjob = job or rootjob}), "rule(%s):on_build(): no returned job!", r:name())
+ if r:extraconf(scriptname, "batch") then
+ job, job_leaf = assert(script(target, batchjobs, {rootjob = job or rootjob}), "rule(%s):%s(): no returned job!", r:name(), scriptname)
else
- job = batchjobs:addjob("rule/" .. r:name() .. "/build", function (index, total)
+ job = batchjobs:addjob("rule/" .. r:name() .. "/" .. scriptname, function (index, total)
script(target, {progress = (index * 100) / total})
end, {rootjob = job or rootjob})
end
else
- local buildcmd = r:script("buildcmd")
+ scriptname = "buildcmd" .. (suffix and ("_" .. suffix) or "")
+ local buildcmd = r:script(scriptname)
if buildcmd then
- job = batchjobs:addjob("rule/" .. r:name() .. "/build", function (index, total)
+ job = batchjobs:addjob("rule/" .. r:name() .. "/" .. scriptname, function (index, total)
local batchcmds_ = batchcmds.new({target = target})
buildcmd(target, batchcmds_, {progress = (index * 100) / total})
batchcmds_:runcmds({dryrun = option.get("dry-run")})
@@ -63,6 +65,14 @@ function _add_batchjobs_builtin(batchjobs, rootjob, target)
end
end
end
+ return job, job_leaf or job
+end
+
+-- add builtin batch jobs
+function _add_batchjobs_builtin(batchjobs, rootjob, target)
+
+ -- add batchjobs for rules
+ local job, job_leaf = _add_batchjobs_for_rules(batchjobs, rootjob, target)
-- uses the builtin target script
if not job and (target:is_static() or target:is_binary() or target:is_shared() or target:is_object()) then
@@ -125,19 +135,6 @@ function _add_batchjobs_for_target(batchjobs, rootjob, target)
if after_build then
after_build(target, {progress = progress})
end
- for _, r in ipairs(target:orderules()) do
- local after_build = r:script("build_after")
- if after_build then
- after_build(target, {progress = progress})
- else
- local after_buildcmd = r:script("buildcmd_after")
- if after_buildcmd then
- local batchcmds_ = batchcmds.new({target = target})
- after_buildcmd(target, batchcmds_, {progress = progress})
- batchcmds_:runcmds({dryrun = option.get("dry-run")})
- end
- end
- end
-- restore environments
if oldenvs then
@@ -146,8 +143,14 @@ function _add_batchjobs_for_target(batchjobs, rootjob, target)
end, {rootjob = rootjob})
+ -- add batchjobs for rules/build_after
+ local rules_job_build_after, rules_job_build_after_leaf = _add_batchjobs_for_rules(batchjobs, job_build_after, target, "after")
+
-- add batch jobs for target, @note only on_build script support batch jobs
- local job_build, job_build_leaf = _add_batchjobs(batchjobs, job_build_after, target)
+ local job_build, job_build_leaf = _add_batchjobs(batchjobs, rules_job_build_after_leaf or job_build_after, target)
+
+ -- add batchjobs for rules/build_before
+ local rules_job_build_before, rules_job_build_before_leaf = _add_batchjobs_for_rules(batchjobs, job_build_leaf, target, "before")
-- add before_build job for target
local job_build_before = batchjobs:addjob(target:name() .. "/before_build", function (index, total)
@@ -166,20 +169,7 @@ function _add_batchjobs_for_target(batchjobs, rootjob, target)
if before_build then
before_build(target, {progress = progress})
end
- for _, r in ipairs(target:orderules()) do
- local before_build = r:script("build_before")
- if before_build then
- before_build(target, {progress = progress})
- else
- local before_buildcmd = r:script("buildcmd_before")
- if before_buildcmd then
- local batchcmds_ = batchcmds.new({target = target})
- before_buildcmd(target, batchcmds_, {progress = progress})
- batchcmds_:runcmds({dryrun = option.get("dry-run")})
- end
- end
- end
- end, {rootjob = job_build_leaf})
+ end, {rootjob = rules_job_build_before_leaf or job_build_leaf})
return job_build_before, job_build, job_build_after
end
diff --git a/xmake/rules/c++/modules/modules_support/clang.lua b/xmake/rules/c++/modules/modules_support/clang.lua
index 35b7cdbc5..866669257 100644
--- a/xmake/rules/c++/modules/modules_support/clang.lua
+++ b/xmake/rules/c++/modules/modules_support/clang.lua
@@ -33,15 +33,14 @@ import("common")
-- -fmodule-file=foo=build/.gens/Foo/rules/modules/cache/foo.pcm
--
function _add_module_to_mapper(target, module, bmi)
- local cache = common.localcache():get("mapflags") or {}
+ local mapflags = common.localcache():get("mapflags") or {}
local modulefileflag = get_modulefileflag(target)
local mapflag = format("%s%s=%s", modulefileflag, module, bmi)
- if table.contains(cache, mapflag) then
+ if table.contains(mapflags, mapflag) then
return
end
- table.insert(cache, mapflag)
- common.localcache():set("mapflags", cache)
- common.localcache():save("mapflags")
+ table.insert(mapflags, mapflag)
+ common.localcache():set("mapflags", mapflags)
end
-- add a header unit into the mapper
@@ -50,16 +49,25 @@ end
-- -fmodule-file=build/.gens/Foo/rules/modules/cache/foo.hpp.pcm
--
function _add_headerunit_to_mapper(target, bmi)
- local cache = common.localcache():get("mapflags") or {}
+ local mapflags = common.memcache():get("mapflags") or {}
local mapflag = format("%s%s", modulefileflag, bmi)
if table.contains(cache, mapflag) then
return
end
- table.insert(cache, mapflag)
- common.localcache():set("mapflags", cache)
+ table.insert(mapflags, mapflag)
+ common.localcache():set("mapflags", mapflags)
+end
+
+-- flush mapflags to mapper file cache
+function _flush_mapflags_to_mapper()
common.localcache():save("mapflags")
end
+-- get mapflags from mapper
+function _get_mapflags_from_mapper()
+ return common.localcache():get("mapflags")
+end
+
-- load module support for the current target
function load(target)
local cachedir = common.modules_cachedir(target)
@@ -143,13 +151,13 @@ function generate_dependencies(target, sourcebatch, opt)
progress.show(opt.progress, "${color.build.object}generating.cxx.module.deps %s", sourcefile)
end
- local outdir = path.translate(path.join(cachedir, path.directory(path.relative(sourcefile, projectdir))))
- if not os.isdir(outdir) then
- os.mkdir(outdir)
+ local outputdir = path.translate(path.join(cachedir, path.directory(path.relative(sourcefile, projectdir))))
+ if not os.isdir(outputdir) then
+ os.mkdir(outputdir)
end
-- no support of p1689 atm
- local jsonfile = path.translate(path.join(outdir, path.filename(sourcefile) .. ".json"))
+ local jsonfile = path.translate(path.join(outputdir, path.filename(sourcefile) .. ".json"))
common.fallback_generate_dependencies(target, jsonfile, sourcefile)
changed = true
@@ -160,16 +168,45 @@ function generate_dependencies(target, sourcebatch, opt)
return changed
end
+-- generate target stl header units for batchjobs
+function generate_stl_headerunits_for_batchjobs(target, batchjobs, headerunits, opt)
+ local compinst = target:compiler("cxx")
+ local stlcachedir = common.stlmodules_cachedir(target)
+ local modulecachepathflag = get_modulecachepathflag(target)
+ local modulefileflag = get_modulefileflag(target)
+ assert(has_headerunitsupport(target), "compiler(clang): does not support c++ header units!")
+
+ -- build headerunits
+ local projectdir = os.projectdir()
+ for i, headerunit in ipairs(headerunits) do
+ local bmifile = path.join(stlcachedir, headerunit.name .. get_bmi_extension())
+ if not os.isfile(bmifile) then
+ batchjobs:addjob(headerunit.name, function (index, total)
+ depend.on_changed(function()
+ progress.show((index * 100) / total, "${color.build.object}generating.cxx.headerunit.bmi %s", headerunit.name)
+ local args = {modulecachepathflag .. stlcachedir, "-c", "-o", bmifile, "-x", "c++-system-header", headerunit.name}
+ os.vrunv(compinst:program(), table.join(compinst:compflags({target = target}), args))
+ end, {dependfile = target:dependfile(bmifile), files = {headerunit.path}})
+ end, {rootjob = opt.rootjob})
+
+ -- libc++ have a builtin module mapper
+ if not target:data_set("cxx.modules.use_libc++") then
+ _add_headerunit_to_mapper(target, bmifile)
+ end
+ end
+ end
+ _flush_mapflags_to_mapper()
+end
+
-- generate target stl header units for batchcmds
function generate_stl_headerunits_for_batchcmds(target, batchcmds, headerunits, opt)
local compinst = target:compiler("cxx")
-- get cachedirs
local stlcachedir = common.stlmodules_cachedir(target)
-
- -- get headerunits flags
local modulecachepathflag = get_modulecachepathflag(target)
local modulefileflag = get_modulefileflag(target)
+ assert(has_headerunitsupport(target), "compiler(clang): does not support c++ header units!")
-- build headerunits
local projectdir = os.projectdir()
@@ -189,6 +226,61 @@ function generate_stl_headerunits_for_batchcmds(target, batchcmds, headerunits,
depmtime = math.max(depmtime, os.mtime(bmifile))
end
batchcmds:set_depmtime(depmtime)
+ _flush_mapflags_to_mapper()
+end
+
+-- generate target user header units for batchjobs
+function generate_user_headerunits_for_batchjobs(target, batchjobs, headerunits, opt)
+ local compinst = target:compiler("cxx")
+ assert(has_headerunitsupport(target), "compiler(clang): does not support c++ header units!")
+
+ -- get cachedirs
+ local cachedir = common.modules_cachedir(target)
+ local modulecachepathflag = get_modulecachepathflag(target)
+ local emitmoduleflag = get_emitmoduleflag(target)
+ local modulefileflag = get_modulefileflag(target)
+
+ -- build headerunits
+ local objectfiles = {}
+ local flags = {}
+ local projectdir = os.projectdir()
+ for _, headerunit in ipairs(headerunits) do
+ local file = path.relative(headerunit.path, target:scriptdir())
+ local objectfile = target:objectfile(file)
+
+ local outputdir
+ if headerunit.type == ":quote" then
+ outputdir = path.join(cachedir, path.directory(path.relative(headerunit.path, projectdir)))
+ else
+ outputdir = path.join(cachedir, path.directory(headerunit.path))
+ end
+ local bmifilename = path.basename(objectfile) .. get_bmi_extension()
+ local bmifile = (outputdir and path.join(outputdir, bmifilename) or bmifilename)
+ batchjobs:addjob(headerunit.name, function (index, total)
+ depend.on_changed(function()
+ progress.show((index * 100) / total, "${color.build.object}generating.cxx.headerunit.bmi %s", headerunit.name)
+ local objectdir = path.directory(objectfile)
+ if not os.isdir(objectdir) then
+ os.mkdir(objectdir)
+ end
+ if not os.isdir(outputdir) then
+ os.mkdir(outputdir)
+ end
+
+ -- generate headerunit
+ 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
+ table.join2(args, {"-x", "c++-system-header", headerunit.name})
+ end
+ os.vrunv(compinst:program(), table.join(compinst:compflags({target = target}), args))
+
+ end, {dependfile = target:dependfile(bmifile), files = {headerunit.path}})
+ end, {rootjob = opt.rootjob})
+ _add_headerunit_to_mapper(target, bmifile)
+ end
+ _flush_mapflags_to_mapper()
end
-- generate target user header units for batchcmds
@@ -198,8 +290,6 @@ function generate_user_headerunits_for_batchcmds(target, batchcmds, headerunits,
-- get cachedirs
local cachedir = common.modules_cachedir(target)
-
- -- get headerunits flags
local modulecachepathflag = get_modulecachepathflag(target)
local emitmoduleflag = get_emitmoduleflag(target)
local modulefileflag = get_modulefileflag(target)
@@ -213,16 +303,16 @@ function generate_user_headerunits_for_batchcmds(target, batchcmds, headerunits,
local file = path.relative(headerunit.path, target:scriptdir())
local objectfile = target:objectfile(file)
- local outdir
+ local outputdir
if headerunit.type == ":quote" then
- outdir = path.join(cachedir, path.directory(path.relative(headerunit.path, projectdir)))
+ outputdir = path.join(cachedir, path.directory(path.relative(headerunit.path, projectdir)))
else
- outdir = path.join(cachedir, path.directory(headerunit.path))
+ outputdir = path.join(cachedir, path.directory(headerunit.path))
end
- batchcmds:mkdir(outdir)
+ batchcmds:mkdir(outputdir)
local bmifilename = path.basename(objectfile) .. get_bmi_extension()
- local bmifile = (outdir and path.join(outdir, bmifilename) or bmifilename)
+ local bmifile = (outputdir and path.join(outputdir, bmifilename) or bmifilename)
batchcmds:mkdir(path.directory(objectfile))
local args = { modulecachepathflag .. cachedir, emitmoduleflag, "-c", "-o", bmifile}
@@ -240,26 +330,19 @@ function generate_user_headerunits_for_batchcmds(target, batchcmds, headerunits,
depmtime = math.max(depmtime, os.mtime(bmifile))
end
batchcmds:set_depmtime(depmtime)
+ _flush_mapflags_to_mapper()
end
--- build module files for batchcmds
-function build_modules_for_batchcmds(target, batchcmds, objectfiles, modules, opt)
+-- build module files for batchjobs
+function build_modules_for_batchjobs(target, batchjobs, objectfiles, modules, opt)
local compinst = target:compiler("cxx")
-
- -- get cachedirs
local cachedir = common.modules_cachedir(target)
-
- -- get modules flags
local modulecachepathflag = get_modulecachepathflag(target)
local emitmoduleinterfaceflag = get_emitmoduleinterfaceflag(target)
- -- append module mapper flags
- local cache = common.localcache():get("mapflags") or {}
- target:add("cxxflags", cache, {force = true})
-
-- build modules
local common_args = {modulecachepathflag .. cachedir}
- local depmtime = 0
+ local provided_modules = {}
for _, objectfile in ipairs(objectfiles) do
local m = modules[objectfile]
if m and m.provides then
@@ -276,16 +359,98 @@ function build_modules_for_batchcmds(target, batchcmds, objectfiles, modules, op
end
local bmifile = provide.bmi
+ local moduleinfo = table.copy(provide)
+ moduleinfo.job = batchjobs:newjob(provide.sourcefile, function (index, total)
+ depend.on_changed(function()
+ progress.show((index * 100) / total, "${color.build.object}generating.cxx.module.bmi %s", name)
+ local objectdir = path.directory(objectfile)
+ if not os.isdir(objectdir) then
+ os.mkdir(objectdir)
+ end
+ -- append module mapper flags first
+ -- @note we add it at the end to ensure that the full mapflags are already stored in the mapper
+ if not target:data("cxx.add_modules_mapflags") then
+ local mapflags = _get_mapflags_from_mapper()
+ if mapflags then
+ target:add("cxxflags", mapflags, {force = true})
+ end
+ target:data_set("cxx.add_modules_mapflags", true)
+ end
+ local args = {emitmoduleinterfaceflag, "-c", "-x", "c++-module", "--precompile", provide.sourcefile, "-o", bmifile}
+ os.vrunv(compinst:program(), table.join(compinst:compflags({target = target}), common_args, args))
+ os.vrunv(compinst:program(), table.join(compinst:compflags({target = target}), common_args, {bmifile}, {"-c", "-o", objectfile}))
+ end, {dependfile = target:dependfile(bmifile), files = {provide.sourcefile}})
+ end)
+ if m.requires then
+ moduleinfo.deps = table.keys(m.requires)
+ end
+ moduleinfo.name = name
+ provided_modules[name] = moduleinfo
+ _add_module_to_mapper(target, name, bmifile)
+ target:add("objectfiles", objectfile)
+ end
+ end
+ _flush_mapflags_to_mapper()
+
+ -- build batchjobs for modules
+ common.build_batchjobs_for_modules(provided_modules, batchjobs, opt.rootjob)
+end
+
+-- build module files for batchcmds
+function build_modules_for_batchcmds(target, batchcmds, objectfiles, modules, opt)
+ local compinst = target:compiler("cxx")
+ local cachedir = common.modules_cachedir(target)
+ local modulecachepathflag = get_modulecachepathflag(target)
+ local emitmoduleinterfaceflag = get_emitmoduleinterfaceflag(target)
+
+ -- we need update mapper first
+ for _, objectfile in ipairs(objectfiles) do
+ local m = modules[objectfile]
+ if m and m.provides then
+ -- assume there that provides is only one, until we encounter the case
+ local length = 0
+ local name, provide
+ for k, v in pairs(m.provides) do
+ length = length + 1
+ name = k
+ provide = v
+ if length > 1 then
+ raise("multiple provides are not supported now!")
+ end
+ end
+
+ local bmifile = provide.bmi
+ _add_module_to_mapper(target, name, bmifile)
+ target:add("objectfiles", objectfile)
+ end
+ end
+ _flush_mapflags_to_mapper()
+
+ -- append module mapper flags
+ local mapflags = _get_mapflags_from_mapper()
+ if mapflags then
+ target:add("cxxflags", mapflags, {force = true})
+ end
+
+ -- build modules
+ local depmtime = 0
+ local common_args = {modulecachepathflag .. cachedir}
+ for _, objectfile in ipairs(objectfiles) do
+ local m = modules[objectfile]
+ if m and m.provides then
+ local name, provide
+ for k, v in pairs(m.provides) do
+ name = k
+ provide = v
+ break
+ end
+ local bmifile = provide.bmi
local args = { emitmoduleinterfaceflag, "-c", "-x", "c++-module", "--precompile", provide.sourcefile, "-o", bmifile }
batchcmds:show_progress(opt.progress, "${color.build.object}generating.cxx.module.bmi %s", name)
batchcmds:mkdir(path.directory(objectfile))
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, {bmifile}, {"-c", "-o", objectfile}))
batchcmds:add_depfiles(provide.sourcefile)
-
- _add_module_to_mapper(target, name, bmifile)
-
- target:add("objectfiles", objectfile)
depmtime = math.max(depmtime, os.mtime(bmifile))
end
end
@@ -429,4 +594,4 @@ function has_headerunitsupport(target)
_g.support_headerunits = support_headerunits or false
end
return support_headerunits or nil
-end \ No newline at end of file
+end
diff --git a/xmake/rules/c++/modules/modules_support/common.lua b/xmake/rules/c++/modules/modules_support/common.lua
index 34d014238..31ab47a81 100644
--- a/xmake/rules/c++/modules/modules_support/common.lua
+++ b/xmake/rules/c++/modules/modules_support/common.lua
@@ -411,20 +411,26 @@ function fallback_generate_dependencies(target, jsonfile, sourcefile)
io.writefile(jsonfile, jsondata)
end
--- generate dependencies
-function generate_dependencies(target, sourcebatch, opt)
- local modules = localcache():get("modules")
- local changed = modules_support(target).generate_dependencies(target, sourcebatch, opt)
- if changed or modules == nil then
- local moduleinfos = load_moduleinfos(target, sourcebatch)
- modules = parse_dependency_data(target, moduleinfos)
- localcache():set("modules", modules)
- localcache():save()
+-- get module dependencies
+function get_module_dependencies(target, sourcebatch, opt)
+ local cachekey = target:name() .. "/" .. sourcebatch.rulename
+ local modules = memcache():get2("modules", cachekey)
+ if modules == nil then
+ modules = localcache():get2("modules", cachekey)
+ opt.progress = opt.progress or 0
+ local changed = modules_support(target).generate_dependencies(target, sourcebatch, opt)
+ if changed or modules == nil then
+ local moduleinfos = load_moduleinfos(target, sourcebatch)
+ modules = parse_dependency_data(target, moduleinfos)
+ localcache():set2("modules", cachekey, modules)
+ localcache():save()
+ end
+ memcache():set2("modules", cachekey, modules)
end
return modules
end
--- generate headerunits for batchjobs, TODO
+-- generate headerunits for batchjobs
function generate_headerunits_for_batchjobs(target, batchjobs, sourcebatch, modules, opt)
-- get headerunits info
@@ -435,11 +441,11 @@ function generate_headerunits_for_batchjobs(target, batchjobs, sourcebatch, modu
local headerunits_flags
if stl_headerunits then
headerunits_flags = headerunits_flags or {}
--- table.join2(headerunits_flags, modules_support(target).generate_stl_headerunits_for_batchjobs(target, batchjobs, stl_headerunits, opt))
+ table.join2(headerunits_flags, modules_support(target).generate_stl_headerunits_for_batchjobs(target, batchjobs, stl_headerunits, opt))
end
if headerunits then
headerunits_flags = headerunits_flags or {}
--- table.join2(headerunits_flags, modules_support(target).generate_user_headerunits_for_batchjobs(target, batchjobs, headerunits, opt))
+ table.join2(headerunits_flags, modules_support(target).generate_user_headerunits_for_batchjobs(target, batchjobs, headerunits, opt))
end
return headerunits_flags
end
@@ -463,10 +469,50 @@ function generate_headerunits_for_batchcmds(target, batchcmds, sourcebatch, modu
end
end
--- build modules for batchjobs, TODO
+-- build batch jobs for module dependencies
+function _build_batchjobs_for_moduledeps(modules, batchjobs, rootjob, jobrefs, moduleinfo)
+ local targetjob_ref = jobrefs[moduleinfo.name]
+ if targetjob_ref then
+ batchjobs:add(targetjob_ref, rootjob)
+ else
+ local modulejob = batchjobs:add(moduleinfo.job, rootjob)
+ if modulejob then
+ jobrefs[moduleinfo.name] = modulejob
+ for _, depname in ipairs(moduleinfo.deps) do
+ local dep = modules[depname]
+ if dep then -- maybe nil, e.g. `import <string>;`
+ _build_batchjobs_for_moduledeps(modules, batchjobs, modulejob, jobrefs, dep)
+ end
+ end
+ end
+ end
+end
+
+-- build batchjobs for modules
+function build_batchjobs_for_modules(modules, batchjobs, rootjob)
+ local depset = hashset.new()
+ for _, moduleinfo in pairs(modules) do
+ assert(moduleinfo.job)
+ for _, depname in ipairs(moduleinfo.deps) do
+ depset:insert(depname)
+ end
+ end
+ local modules_root = {}
+ for _, moduleinfo in pairs(modules) do
+ if not depset:has(moduleinfo.name) then
+ table.insert(modules_root, moduleinfo)
+ end
+ end
+ local jobrefs = {}
+ for _, moduleinfo in pairs(modules_root) do
+ _build_batchjobs_for_moduledeps(modules, batchjobs, rootjob, jobrefs, moduleinfo)
+ end
+end
+
+-- build modules for batchjobs
function build_modules_for_batchjobs(target, batchjobs, sourcebatch, modules, opt)
local objectfiles = sort_modules_by_dependencies(sourcebatch.objectfiles, modules)
--- modules_support(target).build_modules_for_batchjobs(target, batchjobs, objectfiles, modules, opt)
+ modules_support(target).build_modules_for_batchjobs(target, batchjobs, objectfiles, modules, opt)
end
-- build modules for batchcmds
@@ -475,6 +521,7 @@ function build_modules_for_batchcmds(target, batchcmds, sourcebatch, modules, op
modules_support(target).build_modules_for_batchcmds(target, batchcmds, objectfiles, modules, opt)
end
+-- append headerunits objectfiles to link
function append_headerunits_objectfiles(target)
local cache = localcache():get("headerunit_objectfiles") or {}
if target:is_binary() then
@@ -484,4 +531,4 @@ function append_headerunits_objectfiles(target)
elseif target:is_shared() == "shared" then
target:add("shflags", cache, {force = true})
end
-end \ No newline at end of file
+end
diff --git a/xmake/rules/c++/modules/modules_support/gcc.lua b/xmake/rules/c++/modules/modules_support/gcc.lua
index 99045cf54..a37346bad 100644
--- a/xmake/rules/c++/modules/modules_support/gcc.lua
+++ b/xmake/rules/c++/modules/modules_support/gcc.lua
@@ -131,15 +131,15 @@ function generate_dependencies(target, sourcebatch, opt)
progress.show(opt.progress, "${color.build.object}generating.cxx.module.deps %s", sourcefile)
end
- local outdir = path.translate(path.join(cachedir, path.directory(path.relative(sourcefile, projectdir))))
- if not os.isdir(outdir) then
- os.mkdir(outdir)
+ local outputdir = path.translate(path.join(cachedir, path.directory(path.relative(sourcefile, projectdir))))
+ if not os.isdir(outputdir) then
+ os.mkdir(outputdir)
end
- local jsonfile = path.translate(path.join(outdir, path.filename(sourcefile) .. ".json"))
+ local jsonfile = path.translate(path.join(outputdir, path.filename(sourcefile) .. ".json"))
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 ifile = path.translate(path.join(outputdir, path.filename(sourcefile) .. ".i"))
+ local dfile = path.translate(path.join(outputdir, path.filename(sourcefile) .. ".d"))
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}), common_args, args), {envs = vcvars})
else
@@ -154,12 +154,33 @@ function generate_dependencies(target, sourcebatch, opt)
return changed
end
+-- generate target stl header units for batchjobs
+function generate_stl_headerunits_for_batchjobs(target, batchjobs, headerunits, opt)
+ local compinst = target:compiler("cxx")
+ local mapper_file = _get_module_mapper()
+ local stlcachedir = common.stlmodules_cachedir(target)
+
+ -- build headerunits
+ local projectdir = os.projectdir()
+ for _, headerunit in ipairs(headerunits) do
+ local bmifile = path.join(stlcachedir, headerunit.name .. get_bmi_extension())
+ if not os.isfile(bmifile) then
+ batchjobs:addjob(headerunit.name, function (index, total)
+ depend.on_changed(function()
+ progress.show((index * 100) / total, "${color.build.object}generating.cxx.headerunit.bmi %s", headerunit.name)
+ local args = {"-c", "-x", "c++-system-header", headerunit.name}
+ os.vrunv(compinst:program(), table.join(compinst:compflags({target = target}), args))
+ end, {dependfile = target:dependfile(bmifile), files = {headerunit.path}})
+ end, {rootjob = opt.rootjob})
+ end
+ _add_module_to_mapper(mapper_file, headerunit.path, path.absolute(bmifile, projectdir))
+ end
+end
+
-- generate target stl header units for batchcmds
function generate_stl_headerunits_for_batchcmds(target, batchcmds, headerunits, opt)
local compinst = target:compiler("cxx")
local mapper_file = _get_module_mapper()
-
- -- get cachedirs
local stlcachedir = common.stlmodules_cachedir(target)
-- build headerunits
@@ -172,21 +193,69 @@ function generate_stl_headerunits_for_batchcmds(target, batchcmds, headerunits,
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}), args))
end
-
batchcmds:add_depfiles(headerunit.path)
-
_add_module_to_mapper(mapper_file, headerunit.path, path.absolute(bmifile, projectdir))
depmtime = math.max(depmtime, os.mtime(bmifile))
end
batchcmds:set_depmtime(depmtime)
end
+-- generate target user header units for batchjobs
+function generate_user_headerunits_for_batchjobs(target, batchjobs, headerunits, opt)
+ local compinst = target:compiler("cxx")
+ local mapper_file = _get_module_mapper()
+ local cachedir = common.modules_cachedir(target)
+
+ -- build headerunits
+ local projectdir = os.projectdir()
+ for _, headerunit in ipairs(headerunits) do
+ local file = path.relative(headerunit.path, projectdir)
+ local objectfile = target:objectfile(file)
+ local outputdir
+ local headerunit_path
+ if headerunit.type == ":quote" then
+ outputdir = path.join(cachedir, path.directory(path.relative(headerunit.path, projectdir)))
+ else
+ outputdir = path.join(cachedir, path.directory(headerunit.path))
+ end
+ local bmifilename = path.basename(objectfile) .. get_bmi_extension()
+ local bmifile = (outputdir and path.join(outputdir, bmifilename) or bmifilename)
+ if headerunit.type == ":quote" then
+ headerunit_path = path.join(".", path.relative(headerunit.path, projectdir))
+ elseif headerunit.type == ":angle" then
+ -- if path is relative then its a subtarget path
+ headerunit_path = path.is_absolute(headerunit.path) and headerunit.path or path.join(".", headerunit.path)
+ end
+ batchjobs:addjob(headerunit.name, function (index, total)
+ depend.on_changed(function()
+ progress.show((index * 100) / total, "${color.build.object}generating.cxx.headerunit.bmi %s", headerunit.name)
+ local objectdir = path.directory(objectfile)
+ if not os.isdir(objectdir) then
+ os.mkdir(objectdir)
+ end
+ if not os.isdir(outputdir) then
+ os.mkdir(outputdir)
+ end
+
+ -- generate headerunit
+ local args = { "-c" }
+ if headerunit.type == ":quote" then
+ table.join2(args, { "-I", path.directory(path.relative(headerunit.path, projectdir)), "-x", "c++-user-header", headerunit.name })
+ elseif headerunit.type == ":angle" then
+ table.join2(args, { "-x", "c++-system-header", headerunit.name })
+ end
+ os.vrunv(compinst:program(), table.join(compinst:compflags({target = target}), args))
+
+ end, {dependfile = target:dependfile(bmifile), files = {headerunit.path}})
+ end, {rootjob = opt.rootjob})
+ _add_module_to_mapper(mapper_file, headerunit_path, path.absolute(bmifile, projectdir))
+ end
+end
+
-- generate target user header units for batchcmds
function generate_user_headerunits_for_batchcmds(target, batchcmds, headerunits, opt)
local compinst = target:compiler("cxx")
local mapper_file = _get_module_mapper()
-
- -- get cachedirs
local cachedir = common.modules_cachedir(target)
-- build headerunits
@@ -195,17 +264,16 @@ function generate_user_headerunits_for_batchcmds(target, batchcmds, headerunits,
for _, headerunit in ipairs(headerunits) do
local file = path.relative(headerunit.path, projectdir)
local objectfile = target:objectfile(file)
-
- local outdir
+ local outputdir
if headerunit.type == ":quote" then
- outdir = path.join(cachedir, path.directory(path.relative(headerunit.path, projectdir)))
+ outputdir = path.join(cachedir, path.directory(path.relative(headerunit.path, projectdir)))
else
- outdir = path.join(cachedir, path.directory(headerunit.path))
+ outputdir = path.join(cachedir, path.directory(headerunit.path))
end
- batchcmds:mkdir(outdir)
+ batchcmds:mkdir(outputdir)
local bmifilename = path.basename(objectfile) .. get_bmi_extension()
- local bmifile = (outdir and path.join(outdir, bmifilename) or bmifilename)
+ local bmifile = (outputdir and path.join(outputdir, bmifilename) or bmifilename)
batchcmds:mkdir(path.directory(objectfile))
local args = { "-c" }
@@ -229,13 +297,63 @@ function generate_user_headerunits_for_batchcmds(target, batchcmds, headerunits,
batchcmds:set_depmtime(depmtime)
end
+-- build module files for batchjobs
+function build_modules_for_batchjobs(target, batchjobs, objectfiles, modules, opt)
+ local compinst = target:compiler("cxx")
+ local mapper_file = _get_module_mapper()
+ local common_args = {"-x", "c++"}
+ local cachedir = common.modules_cachedir(target)
+
+ -- build modules
+ local projectdir = os.projectdir()
+ local provided_modules = {}
+ for _, objectfile in ipairs(objectfiles) do
+ local m = modules[objectfile]
+ if m and m.provides then
+ -- assume there that provides is only one, until we encounter the case
+ local length = 0
+ local name, provide
+ for k, v in pairs(m.provides) do
+ length = length + 1
+ name = k
+ provide = v
+ if length > 1 then
+ raise("multiple provides are not supported now!")
+ end
+ end
+
+ local bmifile = provide.bmi
+ local moduleinfo = table.copy(provide)
+ moduleinfo.job = batchjobs:newjob(provide.sourcefile, function (index, total)
+ depend.on_changed(function()
+ progress.show((index * 100) / total, "${color.build.object}generating.cxx.module.bmi %s", name)
+ local objectdir = path.directory(objectfile)
+ if not os.isdir(objectdir) then
+ os.mkdir(objectdir)
+ end
+ local args = {"-o", objectfile, "-c", provide.sourcefile}
+ os.vrunv(compinst:program(), table.join(compinst:compflags({target = target}), common_args, args))
+ end, {dependfile = target:dependfile(bmifile), files = {provide.sourcefile}})
+ end)
+ if m.requires then
+ moduleinfo.deps = table.keys(m.requires)
+ end
+ moduleinfo.name = name
+ provided_modules[name] = moduleinfo
+ _add_module_to_mapper(mapper_file, name, path.absolute(bmifile, projectdir))
+ target:add("objectfiles", objectfile)
+ end
+ end
+
+ -- build batchjobs for modules
+ common.build_batchjobs_for_modules(provided_modules, batchjobs, opt.rootjob)
+end
+
-- build module files for batchcmds
function build_modules_for_batchcmds(target, batchcmds, objectfiles, modules, opt)
local compinst = target:compiler("cxx")
local mapper_file = _get_module_mapper()
local common_args = {"-x", "c++"}
-
- -- get cachedirs
local cachedir = common.modules_cachedir(target)
-- build modules
@@ -336,4 +454,4 @@ function get_depoutputflag(target)
_g.depoutputflag = depoutputflag or false
end
return depoutputflag or nil
-end \ No newline at end of file
+end
diff --git a/xmake/rules/c++/modules/modules_support/msvc.lua b/xmake/rules/c++/modules/modules_support/msvc.lua
index b2b2e605a..bcc781248 100644
--- a/xmake/rules/c++/modules/modules_support/msvc.lua
+++ b/xmake/rules/c++/modules/modules_support/msvc.lua
@@ -34,16 +34,25 @@ import("common")
-- /headerUnit:angle glm/mat4x4.hpp=Users\arthu\AppData\Local\.xmake\packages\g\glm\0.9.9+8\91454f3ee0be416cb9c7452970a2300f\include\glm\mat4x4.hpp.ifc
--
function _add_module_to_mapper(argument, module)
- local cache = common.localcache():get("mapflags") or {}
+ local mapflags = common.localcache():get("mapflags") or {}
local mapflag = format("%s %s", argument, module)
- if table.contains(cache, mapflag) then
+ if table.contains(mapflags, mapflag) then
return
end
- table.insert(cache, mapflag)
- common.localcache():set("mapflags", cache)
+ table.insert(mapflags, mapflag)
+ common.localcache():set("mapflags", mapflags)
+end
+
+-- flush mapflags to mapper file cache
+function _flush_mapflags_to_mapper()
common.localcache():save("mapflags")
end
+-- get mapflags from mapper
+function _get_mapflags_from_mapper()
+ return common.localcache():get("mapflags")
+end
+
-- add an objectfile to the linker args
--
-- e.g
@@ -150,11 +159,12 @@ function generate_dependencies(target, sourcebatch, opt)
return changed
end
--- generate target stl header units for batchcmds
-function generate_stl_headerunits_for_batchcmds(target, batchcmds, headerunits, opt)
+-- generate target stl header units for batchjobs
+function generate_stl_headerunits_for_batchjobs(target, batchjobs, headerunits, opt)
local compinst = target:compiler("cxx")
local toolchain = target:toolchain("msvc")
local vcvars = toolchain:config("vcvars")
+ local stlcachedir = common.stlmodules_cachedir(target)
-- get flags
local exportheaderflag = get_exportheaderflag(target)
@@ -163,9 +173,40 @@ function generate_stl_headerunits_for_batchcmds(target, batchcmds, headerunits,
local ifcoutputflag = get_ifcoutputflag(target)
assert(headerunitflag and headernameflag and exportheaderflag, "compiler(msvc): does not support c++ header units!")
- -- get cachedirs
+ -- build headerunits
+ local common_args = {"-TP", exportheaderflag, "-c"}
+ for _, headerunit in ipairs(headerunits) do
+ local bmifile = path.join(stlcachedir, headerunit.name .. get_bmi_extension())
+ local objectfile = bmifile .. ".obj"
+ if not os.isfile(bmifile) or not os.isfile(objectfile) then
+ batchjobs:addjob(headerunit.name, function(index, total)
+ depend.on_changed(function()
+ progress.show((index * 100) / total, "${color.build.object}generating.cxx.headerunit.bmi %s", headerunit.name)
+ local args = {headernameflag .. ":angle", headerunit.name, ifcoutputflag, stlcachedir, "-Fo" .. objectfile}
+ os.vrunv(compinst:program(), table.join(compinst:compflags({target = target}), common_args, args), {envs = vcvars})
+ end, {dependfile = target:dependfile(bmifile), files = {headerunit.path}})
+ end, {rootjob = opt.rootjob})
+ _add_module_to_mapper(headerunitflag .. ":angle", headerunit.name .. "=" .. path.filename(headerunit.name) .. get_bmi_extension())
+ _add_objectfile_to_link_arguments(objectfile)
+ end
+ end
+ _flush_mapflags_to_mapper()
+end
+
+-- generate target stl header units for batchcmds
+function generate_stl_headerunits_for_batchcmds(target, batchcmds, headerunits, opt)
+ local compinst = target:compiler("cxx")
+ local toolchain = target:toolchain("msvc")
+ local vcvars = toolchain:config("vcvars")
local stlcachedir = common.stlmodules_cachedir(target)
+ -- 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!")
+
-- build headerunits
local common_args = {"-TP", exportheaderflag, "-c"}
local depmtime = 0
@@ -184,13 +225,15 @@ function generate_stl_headerunits_for_batchcmds(target, batchcmds, headerunits,
depmtime = math.max(depmtime, os.mtime(bmifile))
end
batchcmds:set_depmtime(depmtime)
+ _flush_mapflags_to_mapper()
end
-- generate target user header units for batchcmds
-function generate_user_headerunits_for_batchcmds(target, batchcmds, headerunits, opt)
+function generate_user_headerunits_for_batchjobs(target, batchjobs, headerunits, opt)
local compinst = target:compiler("cxx")
local toolchain = target:toolchain("msvc")
local vcvars = toolchain:config("vcvars")
+ local cachedir = common.modules_cachedir(target)
-- get flags
local exportheaderflag = get_exportheaderflag(target)
@@ -199,9 +242,58 @@ function generate_user_headerunits_for_batchcmds(target, batchcmds, headerunits,
local ifcoutputflag = get_ifcoutputflag(target)
assert(headerunitflag and headernameflag and exportheaderflag, "compiler(msvc): does not support c++ header units!")
- -- get cachedirs
+ -- build headerunits
+ local common_args = {"-TP", exportheaderflag, "-c"}
+ local projectdir = os.projectdir()
+ for _, headerunit in ipairs(headerunits) do
+ local file = path.relative(headerunit.path, target:scriptdir())
+ local objectfile = target:objectfile(file)
+ local outputdir
+ if headerunit.type == ":quote" then
+ outputdir = path.join(cachedir, path.directory(path.relative(headerunit.path, projectdir)))
+ else
+ -- if path is relative then its a subtarget path
+ outputdir = path.join(cachedir, path.is_absolute(headerunit.path) and path.directory(headerunit.path):sub(3) or headerunit.path)
+ end
+ local bmifilename = path.basename(objectfile) .. get_bmi_extension()
+ local bmifile = path.join(outputdir, bmifilename)
+ batchjobs:addjob(headerunit.name, function (index, total)
+ depend.on_changed(function()
+ progress.show((index * 100) / total, "${color.build.object}generating.cxx.headerunit.bmi %s", headerunit.name)
+ local objectdir = path.directory(objectfile)
+ if not os.isdir(objectdir) then
+ os.mkdir(objectdir)
+ end
+ if not os.isdir(outputdir) then
+ os.mkdir(outputdir)
+ end
+
+ -- generate headerunit
+ local args = {headernameflag .. headerunit.type, headerunit.path, ifcoutputflag, outputdir, "/Fo" .. objectfile}
+ os.vrunv(compinst:program(), table.join(compinst:compflags({target = target}), common_args, args), {envs = vcvars})
+
+ end, {dependfile = target:dependfile(bmifile), files = {headerunit.path}})
+ end, {rootjob = opt.rootjob})
+ _add_module_to_mapper(headerunitflag .. headerunit.type, headerunit.name .. "=" .. path.relative(bmifile, cachedir))
+ _add_objectfile_to_link_arguments(objectfile)
+ end
+ _flush_mapflags_to_mapper()
+end
+
+-- generate target user header units for batchcmds
+function generate_user_headerunits_for_batchcmds(target, batchcmds, headerunits, opt)
+ local compinst = target:compiler("cxx")
+ local toolchain = target:toolchain("msvc")
+ local vcvars = toolchain:config("vcvars")
local cachedir = common.modules_cachedir(target)
+ -- 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!")
+
-- build headerunits
local common_args = {"-TP", exportheaderflag, "-c"}
local projectdir = os.projectdir()
@@ -234,15 +326,14 @@ function generate_user_headerunits_for_batchcmds(target, batchcmds, headerunits,
depmtime = math.max(depmtime, os.mtime(bmifile))
end
batchcmds:set_depmtime(depmtime)
+ _flush_mapflags_to_mapper()
end
--- build module files for batchcmds
-function build_modules_for_batchcmds(target, batchcmds, objectfiles, modules, opt)
+-- build module files for batchjobs
+function build_modules_for_batchjobs(target, batchjobs, objectfiles, modules, opt)
local compinst = target:compiler("cxx")
local toolchain = target:toolchain("msvc")
local vcvars = toolchain:config("vcvars")
-
- -- get cachedirs
local cachedir = common.modules_cachedir(target)
-- get flags
@@ -250,13 +341,9 @@ function build_modules_for_batchcmds(target, batchcmds, objectfiles, modules, op
local interfaceflag = get_interfaceflag(target)
local referenceflag = get_referenceflag(target)
- -- append module mapper flags
- local cache = common.localcache():get("mapflags") or {}
- target:add("cxxflags", cache, {force = true})
-
-- build modules
local common_args = {"-TP"}
- local depmtime = 0
+ local provided_modules = {}
for _, objectfile in ipairs(objectfiles) do
local m = modules[objectfile]
if m and m.provides then
@@ -273,20 +360,106 @@ function build_modules_for_batchcmds(target, batchcmds, objectfiles, modules, op
end
local bmifile = provide.bmi
- local args = {"-c", "-Fo" .. objectfile, interfaceflag, ifcoutputflag, bmifile, provide.sourcefile}
+ local moduleinfo = table.copy(provide)
+ moduleinfo.job = batchjobs:newjob(provide.sourcefile, function (index, total)
+ depend.on_changed(function()
+ progress.show((index * 100) / total, "${color.build.object}generating.cxx.module.bmi %s", name)
+ local objectdir = path.directory(objectfile)
+ if not os.isdir(objectdir) then
+ os.mkdir(objectdir)
+ end
+ -- append module mapper flags first
+ -- @note we add it at the end to ensure that the full mapflags are already stored in the mapper
+ if not target:data("cxx.add_modules_mapflags") then
+ local mapflags = _get_mapflags_from_mapper()
+ if mapflags then
+ target:add("cxxflags", mapflags, {force = true})
+ end
+ target:data_set("cxx.add_modules_mapflags", true)
+ end
+ local args = {"-c", "-Fo" .. objectfile, interfaceflag, ifcoutputflag, bmifile, provide.sourcefile}
+ os.vrunv(compinst:program(), table.join(compinst:compflags({target = target}), common_args, args), {envs = vcvars})
+ end, {dependfile = target:dependfile(bmifile), files = {provide.sourcefile}})
+ end)
+ if m.requires then
+ moduleinfo.deps = table.keys(m.requires)
+ end
+ moduleinfo.name = name
+ provided_modules[name] = moduleinfo
+ _add_module_to_mapper(referenceflag, name .. "=" .. path.filename(bmifile))
+ target:add("objectfiles", objectfile)
+ end
+ end
+ _flush_mapflags_to_mapper()
+
+
+ -- build batchjobs for modules
+ common.build_batchjobs_for_modules(provided_modules, batchjobs, opt.rootjob)
+end
+
+-- build module files for batchcmds
+function build_modules_for_batchcmds(target, batchcmds, objectfiles, modules, opt)
+ local compinst = target:compiler("cxx")
+ local toolchain = target:toolchain("msvc")
+ local vcvars = toolchain:config("vcvars")
+ local cachedir = common.modules_cachedir(target)
+
+ -- get flags
+ local ifcoutputflag = get_ifcoutputflag(target)
+ local interfaceflag = get_interfaceflag(target)
+ local referenceflag = get_referenceflag(target)
+
+ -- we need update mapper first
+ for _, objectfile in ipairs(objectfiles) do
+ local m = modules[objectfile]
+ if m and m.provides then
+ -- assume there that provides is only one, until we encounter the case
+ local length = 0
+ local name, provide
+ for k, v in pairs(m.provides) do
+ length = length + 1
+ name = k
+ provide = v
+ if length > 1 then
+ raise("multiple provides are not supported now!")
+ end
+ end
+
+ local bmifile = provide.bmi
+ _add_module_to_mapper(referenceflag, name .. "=" .. path.filename(bmifile))
+ target:add("objectfiles", objectfile)
+ end
+ end
+ _flush_mapflags_to_mapper()
+
+ -- append module mapper flags
+ local mapflags = _get_mapflags_from_mapper()
+ if mapflags then
+ target:add("cxxflags", mapflags, {force = true})
+ end
+
+ -- build modules
+ local common_args = {"-TP"}
+ local depmtime = 0
+ for _, objectfile in ipairs(objectfiles) do
+ local m = modules[objectfile]
+ if m and m.provides then
+ local name, provide
+ for k, v in pairs(m.provides) do
+ name = k
+ provide = v
+ break
+ end
+ local bmifile = provide.bmi
+ local args = {"-c", "-Fo" .. objectfile, interfaceflag, ifcoutputflag, bmifile, provide.sourcefile}
batchcmds:show_progress(opt.progress, "${color.build.object}generating.cxx.module.bmi %s", name)
batchcmds:mkdir(path.directory(objectfile))
batchcmds:vrunv(compinst:program(), table.join(compinst:compflags({target = target}), common_args, args), {envs = vcvars})
batchcmds:add_depfiles(provide.sourcefile)
-
- _add_module_to_mapper(referenceflag, name .. "=" .. path.filename(bmifile))
-
- target:add("objectfiles", objectfile)
depmtime = math.max(depmtime, os.mtime(bmifile))
end
end
-
batchcmds:set_depmtime(depmtime)
end
@@ -430,4 +603,4 @@ function get_scandependenciesflag(target)
_g.scandependenciesflag = scandependenciesflag or false
end
return scandependenciesflag or nil
-end \ No newline at end of file
+end
diff --git a/xmake/rules/c++/modules/xmake.lua b/xmake/rules/c++/modules/xmake.lua
index 4117004cc..23f9a0f77 100644
--- a/xmake/rules/c++/modules/xmake.lua
+++ b/xmake/rules/c++/modules/xmake.lua
@@ -53,55 +53,70 @@ rule("c++.build.modules.builder")
set_sourcekinds("cxx")
set_extensions(".mpp", ".mxx", ".cppm", ".ixx")
- -- TODO parallel build support to accelerate `xmake build` to build modules
- --[[
+ -- generate headerunits
+ -- parallel build support to accelerate `xmake build` to build headerunits
+ before_build(function(target, batchjobs, opt)
+ local job
+ if target:data("cxx.has_modules") then
+ import("modules_support.common")
+ local sourcebatch = target:sourcebatches()["c++.build.modules.builder"]
+ common.patch_sourcebatch(target, sourcebatch, opt)
+ local modules = common.get_module_dependencies(target, sourcebatch, opt)
+ batchjobs:group_enter(target:name() .. "/generate_headerunits")
+ common.generate_headerunits_for_batchjobs(target, batchjobs, sourcebatch, modules, opt)
+ job = batchjobs:group_leave()
+ end
+ return job or opt.rootjob
+ end, {batch = true})
+
+ -- build modules
+ -- parallel build support to accelerate `xmake build` to build modules
before_build_files(function(target, batchjobs, sourcebatch, opt)
- if not target:data("cxx.has_modules") then
+ if target:data("cxx.has_modules") then
+ import("modules_support.common")
+ common.patch_sourcebatch(target, sourcebatch, opt)
+ local modules = common.get_module_dependencies(target, sourcebatch, opt)
+ common.build_modules_for_batchjobs(target, batchjobs, sourcebatch, modules, opt)
+ else
+ -- avoid duplicate linking of object files of non-module programs
sourcebatch.objectfiles = {}
- return
end
+ end, {batch = true})
- -- patch sourcebatch
- import("modules_support.common")
- common.patch_sourcebatch(target, sourcebatch, opt)
-
- -- generate dependencies
- local modules = common.generate_dependencies(target, sourcebatch, opt)
+ -- serial compilation only, usually used to support project generator
+ before_buildcmd_files(function(target, batchcmds, sourcebatch, opt)
+ if target:data("cxx.has_modules") then
+ import("modules_support.common")
- -- generate headerunits
- local headerunits_flags = common.generate_headerunits_for_batchjobs(target, batchjobs, sourcebatch, modules, opt)
- if headerunits_flags then
- target:add("cxxflags", headerunits_flags, {force = true, expand = false})
- end
+ -- patch sourcebatch
+ common.patch_sourcebatch(target, sourcebatch, opt)
- -- build modules
- common.build_modules_for_batchjobs(target, batchjobs, sourcebatch, modules, opt)
- end, {batch = true})]]
+ -- generate headerunits
+ local modules = common.get_module_dependencies(target, sourcebatch, opt)
+ common.generate_headerunits_for_batchcmds(target, batchcmds, sourcebatch, modules, opt)
- -- serial compilation only, usually used to support project generator
- before_buildcmd_files(function(target, batchcmds, sourcebatch, opt)
- if not target:data("cxx.has_modules") then
+ -- build modules
+ common.build_modules_for_batchcmds(target, batchcmds, sourcebatch, modules, opt)
+ else
+ -- avoid duplicate linking of object files of non-module programs
sourcebatch.objectfiles = {}
- return
end
+ end)
- -- patch sourcebatch
+ before_link(function (target)
import("modules_support.common")
- common.patch_sourcebatch(target, sourcebatch, opt)
-
- -- generate dependencies
- local modules = common.generate_dependencies(target, sourcebatch, opt)
-
- -- generate headerunits
- common.generate_headerunits_for_batchcmds(target, batchcmds, sourcebatch, modules, opt)
-
- -- build modules
- common.build_modules_for_batchcmds(target, batchcmds, sourcebatch, modules, opt)
+ common.append_headerunits_objectfiles(target)
end)
- before_link(function(target)
+ after_clean(function (target)
+ import("core.base.option")
import("modules_support.common")
- common.append_headerunits_objectfiles(target)
+ os.tryrm(common.modules_cachedir(target))
+ if option.get("all") then
+ os.tryrm(common.stlmodules_cachedir(target))
+ common.localcache():clear()
+ common.localcache():save()
+ end
end)
-- install modules