summaryrefslogtreecommitdiff
path: root/xmake/rules/c++/modules
diff options
context:
space:
mode:
authorChristian Rendina <[email protected]>2025-04-10 09:50:37 +0200
committerChristian Rendina <[email protected]>2025-04-10 09:50:37 +0200
commit78723913d76fb8b615df34541236b8ea588d30db (patch)
treeb6b6ff550e4a2f73d94c63a61876cec31a4b3ae3 /xmake/rules/c++/modules
parent2051c13f735a626f7b6fd8b98aa69f01fd9cef7e (diff)
parentfd49b7754c6709a87b5beb5526788bbc1a663965 (diff)
Merge branch 'dev' of https://github.com/xmake-io/xmake into dev
Diffstat (limited to 'xmake/rules/c++/modules')
-rw-r--r--xmake/rules/c++/modules/modules_support/builder.lua208
-rw-r--r--xmake/rules/c++/modules/modules_support/clang/builder.lua122
-rw-r--r--xmake/rules/c++/modules/modules_support/clang/dependency_scanner.lua2
-rw-r--r--xmake/rules/c++/modules/modules_support/compiler_support.lua16
-rw-r--r--xmake/rules/c++/modules/modules_support/dependency_scanner.lua88
-rw-r--r--xmake/rules/c++/modules/modules_support/gcc/builder.lua130
-rw-r--r--xmake/rules/c++/modules/modules_support/gcc/dependency_scanner.lua2
-rw-r--r--xmake/rules/c++/modules/modules_support/msvc/builder.lua122
-rw-r--r--xmake/rules/c++/modules/modules_support/msvc/dependency_scanner.lua2
-rw-r--r--xmake/rules/c++/modules/xmake.lua106
10 files changed, 582 insertions, 216 deletions
diff --git a/xmake/rules/c++/modules/modules_support/builder.lua b/xmake/rules/c++/modules/modules_support/builder.lua
index a71e2c392..7ec120cc9 100644
--- a/xmake/rules/c++/modules/modules_support/builder.lua
+++ b/xmake/rules/c++/modules/modules_support/builder.lua
@@ -44,10 +44,15 @@ function _build_modules(target, sourcebatch, modules, opt)
cppfile = cppfile or module.cppfile
local deps = {}
- for _, dep in ipairs(table.keys(module.requires or {})) do
- table.insert(deps, opt.batchjobs and target:name() .. dep or dep)
+ for name, req in pairs(module.requires or {}) do
+ -- we need to use the full path as dep name if requre item is headerunit
+ local dep = name
+ if req.method:startswith("include-") and req.path then
+ dep = path.normalize(req.path)
+ end
+ local depname = target:fullname() .. "/module/" .. dep
+ table.insert(deps, depname)
end
-
opt.build_module(deps, module, name, objectfile, cppfile)
::continue::
@@ -56,7 +61,6 @@ end
-- build target headerunits
function _build_headerunits(target, headerunits, opt)
-
local outputdir = compiler_support.headerunits_cachedir(target, {mkdir = true})
if opt.stl_headerunit then
outputdir = path.join(outputdir, "stl")
@@ -70,11 +74,9 @@ function _build_headerunits(target, headerunits, opt)
local bmifile = path.join(outputdir, path.filename(headerunit.name) .. compiler_support.get_bmi_extension(target))
local key = path.normalize(headerunit.path)
local build = should_build(target, headerunit.path, bmifile, {key = key, headerunit = true})
-
if build then
mark_build(target, key)
end
-
opt.build_headerunit(headerunit, key, bmifile, outputdir, build)
end
end
@@ -128,7 +130,7 @@ function _try_reuse_modules(target, modules)
end
local mapped = get_from_target_mapper(dep, name)
if mapped then
- compiler_support.memcache():set2(target:name() .. name, "reuse", true)
+ compiler_support.memcache():set2(target:fullname() .. name, "reuse", true)
add_module_to_target_mapper(target, mapped.name, mapped.sourcefile, mapped.bmi, table.join(mapped.opt or {}, {target = dep}))
break
end
@@ -156,8 +158,8 @@ function should_build(target, sourcefile, bmifile, opt)
for required, _ in table.orderpairs(requires) do
local m = get_from_target_mapper(target, required)
if m then
- local rebuild = (m.opt and m.opt.target) and compiler_support.memcache():get2("should_build_in_" .. m.opt.target:name(), m.key)
- or compiler_support.memcache():get2("should_build_in_" .. target:name(), m.key)
+ local rebuild = (m.opt and m.opt.target) and compiler_support.memcache():get2("should_build_in_" .. m.opt.target:fullname(), m.key)
+ or compiler_support.memcache():get2("should_build_in_" .. target:fullname(), m.key)
if rebuild then
dependinfo.files = {}
table.insert(dependinfo.files, sourcefile)
@@ -172,7 +174,7 @@ function should_build(target, sourcefile, bmifile, opt)
if opt.name then
local m = get_from_target_mapper(target, opt.name)
if m and m.opt and m.opt.target then
- local rebuild = compiler_support.memcache():get2("should_build_in_" .. m.opt.target:name(), m.key)
+ local rebuild = compiler_support.memcache():get2("should_build_in_" .. m.opt.target:fullname(), m.key)
if rebuild then
dependinfo.files = {}
table.insert(dependinfo.files, sourcefile)
@@ -204,7 +206,6 @@ end
-- "file": "foo.cppm"
-- }
function _generate_meta_module_info(target, name, sourcefile, requires)
-
local modulehash = compiler_support.get_modulehash(target, sourcefile)
local module_metadata = {name = name, file = path.join(modulehash, path.filename(sourcefile))}
@@ -223,7 +224,7 @@ end
function _target_module_map_cachekey(target)
local mode = config.mode()
- return target:name() .. "module_mapper" .. (mode or "")
+ return target:fullname() .. "module_mapper" .. (mode or "")
end
function _is_duplicated_headerunit(target, key)
@@ -251,7 +252,7 @@ function _builder(target)
end
function mark_build(target, name)
- compiler_support.memcache():set2("should_build_in_" .. target:name(), name, true)
+ compiler_support.memcache():set2("should_build_in_" .. target:fullname(), name, true)
end
-- build batchjobs for modules
@@ -262,11 +263,11 @@ end
-- build modules for batchjobs
function build_modules_for_batchjobs(target, batchjobs, sourcebatch, modules, opt)
opt.rootjob = batchjobs:group_leave() or opt.rootjob
- batchjobs:group_enter(target:name() .. "/build_modules", {rootjob = opt.rootjob})
+ batchjobs:group_enter(target:fullname() .. "/module/build_modules", {rootjob = opt.rootjob})
-- add populate module job
local modulesjobs = {}
- local populate_jobname = target:name() .. "_populate_module_map"
+ local populate_jobname = target:fullname() .. "/module/populate_module_map"
modulesjobs[populate_jobname] = {
name = populate_jobname,
job = batchjobs:newjob(populate_jobname, function(_, _)
@@ -277,20 +278,49 @@ function build_modules_for_batchjobs(target, batchjobs, sourcebatch, modules, op
-- add module jobs
_build_modules(target, sourcebatch, modules, table.join(opt, {
- build_module = function(deps, module, name, objectfile, cppfile)
- local job_name = name and target:name() .. name or cppfile
- modulesjobs[job_name] = _builder(target).make_module_buildjobs(target, batchjobs, job_name, deps,
- {module = module, objectfile = objectfile, cppfile = cppfile})
- end
+ build_module = function(deps, module, name, objectfile, cppfile)
+ local job_name = target:fullname() .. "/module/" .. (name or cppfile)
+ modulesjobs[job_name] = _builder(target).make_module_buildjobs(target, batchjobs, job_name, deps,
+ {module = module, objectfile = objectfile, cppfile = cppfile})
+ end
}))
-- build batchjobs for modules
build_batchjobs_for_modules(modulesjobs, batchjobs, opt.rootjob)
end
+-- build modules for jobgraph
+function build_modules_for_jobgraph(target, jobgraph, sourcebatch, modules, opt)
+ local jobdeps = {}
+ local jobsize = jobgraph:size()
+ local build_modules_group = target:fullname() .. "/module/build_modules"
+ jobgraph:group(build_modules_group, function ()
+
+ -- add populate module job
+ local populate_jobname = target:fullname() .. "/module/populate_module_map"
+ jobgraph:add(populate_jobname, function(index, total, opt)
+ _try_reuse_modules(target, modules)
+ _builder(target).populate_module_map(target, modules)
+ end)
+
+ -- add module jobs
+ _build_modules(target, sourcebatch, modules, table.join(opt, {
+ build_module = function(deps, module, name, objectfile, cppfile)
+ local jobname = target:fullname() .. "/module/" .. (name or cppfile)
+ _builder(target).make_module_jobgraph(target, jobgraph, {
+ module = module, objectfile = objectfile, cppfile = cppfile
+ })
+ jobdeps[jobname] = table.join(populate_jobname, deps)
+ end})
+ )
+ end)
+ if jobgraph:size() > jobsize then
+ return build_modules_group, jobdeps
+ end
+end
+
-- build modules for batchcmds
function build_modules_for_batchcmds(target, batchcmds, sourcebatch, modules, opt)
-
local depmtime = 0
opt.progress = opt.progress or 0
@@ -299,15 +329,16 @@ function build_modules_for_batchcmds(target, batchcmds, sourcebatch, modules, op
-- build modules
_build_modules(target, sourcebatch, modules, table.join(opt, {
- build_module = function(_, module, _, objectfile, cppfile)
- depmtime = math.max(depmtime, _builder(target).make_module_buildcmds(target, batchcmds, {module = module, cppfile = cppfile, objectfile = objectfile, progress = opt.progress}))
- end
+ build_module = function(_, module, _, objectfile, cppfile)
+ depmtime = math.max(depmtime, _builder(target).make_module_buildcmds(target, batchcmds, {
+ module = module, cppfile = cppfile, objectfile = objectfile, progress = opt.progress}))
+ end
}))
batchcmds:set_depmtime(depmtime)
end
--- generate headerunits for batchjobs
+-- build headerunits for batchjobs
function build_headerunits_for_batchjobs(target, batchjobs, sourcebatch, modules, opt)
local user_headerunits, stl_headerunits = dependency_scanner.get_headerunits(target, sourcebatch, modules)
@@ -318,13 +349,13 @@ function build_headerunits_for_batchjobs(target, batchjobs, sourcebatch, modules
-- we need new group(headerunits)
-- e.g. group(build_modules) -> group(headerunits)
opt.rootjob = batchjobs:group_leave() or opt.rootjob
- batchjobs:group_enter(target:name() .. "/build_headerunits", {rootjob = opt.rootjob})
+ batchjobs:group_enter(target:fullname() .. "/module/build_headerunits", {rootjob = opt.rootjob})
local build_headerunits = function(headerunits)
local modulesjobs = {}
_build_headerunits(target, headerunits, table.join(opt, {
build_headerunit = function(headerunit, key, bmifile, outputdir, build)
- local job_name = target:name() .. key
+ local job_name = target:fullname() .. "/module/" .. key
local job = _builder(target).make_headerunit_buildjobs(target, job_name, batchjobs, headerunit, bmifile, outputdir, table.join(opt, {build = build}))
if job then
modulesjobs[job_name] = job
@@ -345,9 +376,46 @@ function build_headerunits_for_batchjobs(target, batchjobs, sourcebatch, modules
end
end
--- generate headerunits for batchcmds
-function build_headerunits_for_batchcmds(target, batchcmds, sourcebatch, modules, opt)
+-- build headerunits for jobgraph
+function build_headerunits_for_jobgraph(target, jobgraph, sourcebatch, modules, opt)
+ local user_headerunits, stl_headerunits = dependency_scanner.get_headerunits(target, sourcebatch, modules)
+ if not user_headerunits and not stl_headerunits then
+ return
+ end
+
+ -- we need new group(headerunits)
+ -- e.g. group(build_modules) -> group(headerunits)
+ local jobsize = jobgraph:size()
+ local build_headerunits_group = target:fullname() .. "/module/build_headerunits"
+ jobgraph:group(build_headerunits_group, function ()
+ local build_headerunits = function(headerunits)
+ local modulesjobs = {}
+ _build_headerunits(target, headerunits, table.join(opt, {
+ build_headerunit = function(headerunit, key, bmifile, outputdir, build)
+ local job_name = target:fullname() .. "/module/" .. key
+ _builder(target).make_headerunit_jobgraph(target,
+ job_name, jobgraph, headerunit, bmifile, outputdir, table.join(opt, {build = build}))
+ end
+ }))
+ end
+ -- build stl header units first as other headerunits may need them
+ if stl_headerunits then
+ opt.stl_headerunit = true
+ build_headerunits(stl_headerunits)
+ end
+ if user_headerunits then
+ opt.stl_headerunit = false
+ build_headerunits(user_headerunits)
+ end
+ end)
+ if jobgraph:size() > jobsize then
+ return build_headerunits_group
+ end
+end
+
+-- build headerunits for batchcmds
+function build_headerunits_for_batchcmds(target, batchcmds, sourcebatch, modules, opt)
local user_headerunits, stl_headerunits = dependency_scanner.get_headerunits(target, sourcebatch, modules)
if not user_headerunits and not stl_headerunits then
return
@@ -374,6 +442,31 @@ function build_headerunits_for_batchcmds(target, batchcmds, sourcebatch, modules
end
end
+-- build modules and headerunits, and we need to build headerunits first
+function build_modules_and_headerunits(target, jobgraph, sourcebatch, modules, opt)
+ if jobgraph.add_orders then
+ local build_modules_group, jobdeps = build_modules_for_jobgraph(target, jobgraph, sourcebatch, modules, opt)
+ local build_headerunits_group = build_headerunits_for_jobgraph(target, jobgraph, sourcebatch, modules, opt)
+ if build_modules_group then
+ for jobname, deps in pairs(jobdeps) do
+ for _, depname in ipairs(deps) do
+ jobgraph:add_orders(depname, jobname)
+ end
+ end
+ if build_headerunits_group then
+ jobgraph:add_orders(build_headerunits_group, build_modules_group)
+ end
+ end
+ elseif jobgraph.runcmds then
+ build_headerunits_for_batchcmds(target, jobgraph, sourcebatch, modules, opt)
+ build_modules_for_batchcmds(target, jobgraph, sourcebatch, modules, opt)
+ elseif jobgraph.newjob then -- deprecated
+ build_modules_for_batchjobs(target, jobgraph, sourcebatch, modules, opt)
+ build_headerunits_for_batchjobs(target, jobgraph, sourcebatch, modules, opt)
+ end
+end
+
+-- generate metadata
function generate_metadata(target, modules)
local public_modules
for _, module in table.orderpairs(modules) do
@@ -391,11 +484,11 @@ function generate_metadata(target, modules)
end
local jobs = option.get("jobs") or os.default_njob()
- runjobs(target:name() .. "_install_modules", function(index, total, jobopt)
+ runjobs(target:fullname() .. "/module/install_modules", function(index, total, jobopt)
local module = public_modules[index]
local name, _, cppfile = compiler_support.get_provided_module(module)
local metafilepath = compiler_support.get_metafile(target, cppfile)
- progress.show(jobopt.progress, "${color.build.target}<%s> generating.module.metadata %s", target:name(), name)
+ progress.show(jobopt.progress, "${color.build.target}<%s> generating.module.metadata %s", target:fullname(), name)
local metadata = _generate_meta_module_info(target, name, cppfile, module.requires)
json.savefile(metafilepath, metadata)
end, {comax = jobs, total = #public_modules})
@@ -404,20 +497,20 @@ end
-- flush target module mapper keys
function flush_target_module_mapper_keys(target)
local memcache = compiler_support.memcache()
- memcache:set2(target:name(), "module_mapper_keys", nil)
+ memcache:set2(target:fullname(), "module_mapper_keys", nil)
end
-- get or create a target module mapper
function get_target_module_mapper(target)
local memcache = compiler_support.memcache()
- local mapper = memcache:get2(target:name(), "module_mapper")
+ local mapper = memcache:get2(target:fullname(), "module_mapper")
if not mapper then
mapper = {}
- memcache:set2(target:name(), "module_mapper", mapper)
+ memcache:set2(target:fullname(), "module_mapper", mapper)
end
-- we generate the keys map to optimise the efficiency of _is_duplicated_headerunit
- local mapper_keys = memcache:get2(target:name(), "module_mapper_keys")
+ local mapper_keys = memcache:get2(target:fullname(), "module_mapper_keys")
if not mapper_keys then
mapper_keys = {}
for _, item in pairs(mapper) do
@@ -425,7 +518,7 @@ function get_target_module_mapper(target)
mapper_keys[item.key] = item
end
end
- memcache:set2(target:name(), "module_mapper_keys", mapper_keys)
+ memcache:set2(target:fullname(), "module_mapper_keys", mapper_keys)
end
return mapper, mapper_keys
end
@@ -463,7 +556,7 @@ end
-- check if dependencies changed
function is_dependencies_changed(target, module)
- local cachekey = target:name() .. module.name
+ local cachekey = target:fullname() .. module.name
local requires = hashset.from(table.keys(module.requires or {}))
local oldrequires = compiler_support.memcache():get2(cachekey, "oldrequires")
local changed = false
@@ -481,3 +574,44 @@ function is_dependencies_changed(target, module)
end
return requires, changed
end
+
+-- patch sourcebatch
+function patch_sourcebatch(target, sourcebatch, opt)
+
+ -- add target deps modules
+ if target:orderdeps() then
+ local deps_sourcefiles = dependency_scanner.get_targetdeps_modules(target)
+ if deps_sourcefiles then
+ table.join2(sourcebatch.sourcefiles, deps_sourcefiles)
+ end
+ end
+
+ -- append std module
+ local std_modules = compiler_support.get_stdmodules(target)
+ if std_modules then
+ table.join2(sourcebatch.sourcefiles, std_modules)
+ end
+
+ -- extract packages modules dependencies
+ local package_modules_data = dependency_scanner.get_all_packages_modules(target, opt)
+ if package_modules_data then
+ -- append to sourcebatch
+ for _, package_module_data in table.orderpairs(package_modules_data) do
+ table.insert(sourcebatch.sourcefiles, package_module_data.file)
+ target:fileconfig_set(package_module_data.file, {external = package_module_data.external, defines = package_module_data.metadata.defines})
+ end
+ end
+
+ -- patch objectfiles and dependencies
+ sourcebatch.sourcekind = "cxx"
+ sourcebatch.objectfiles = {}
+ sourcebatch.dependfiles = {}
+ for _, sourcefile in ipairs(sourcebatch.sourcefiles) do
+ local objectfile = target:objectfile(sourcefile)
+ table.insert(sourcebatch.objectfiles, objectfile)
+
+ local dependfile = target:dependfile(sourcefile or objectfile)
+ table.insert(sourcebatch.dependfiles, dependfile)
+ end
+end
+
diff --git a/xmake/rules/c++/modules/modules_support/clang/builder.lua b/xmake/rules/c++/modules/modules_support/clang/builder.lua
index 972694254..ec6692c35 100644
--- a/xmake/rules/c++/modules/modules_support/clang/builder.lua
+++ b/xmake/rules/c++/modules/modules_support/clang/builder.lua
@@ -134,7 +134,7 @@ function _get_requiresflags(target, module, opt)
local modulefileflag = compiler_support.get_modulefileflag(target)
local name = module.name
- local cachekey = target:name() .. name
+ local cachekey = target:fullname() .. name
local requires, requires_changed = is_dependencies_changed(target, module)
local requiresflags = compiler_support.memcache():get2(cachekey, "requiresflags")
@@ -216,11 +216,11 @@ function make_module_buildjobs(target, batchjobs, job_name, deps, opt)
return {
name = job_name,
- deps = table.join(target:name() .. "_populate_module_map", deps),
+ deps = table.join(target:fullname() .. "/module/populate_module_map", deps),
sourcefile = opt.cppfile,
- job = batchjobs:newjob(name or opt.cppfile, function(index, total, jobopt)
+ job = batchjobs:newjob(target:fullname() .. "/module/" .. (name or opt.cppfile), function(index, total, jobopt)
local mapped_bmi
- if provide and compiler_support.memcache():get2(target:name() .. name, "reuse") then
+ if provide and compiler_support.memcache():get2(target:fullname() .. name, "reuse") then
mapped_bmi = get_from_target_mapper(target, name).bmi
end
@@ -263,11 +263,11 @@ function make_module_buildjobs(target, batchjobs, job_name, deps, opt)
local is_mapped_bmi = mapped_bmi ~= nil
if external and not from_moduleonly then
if not mapped_bmi then
- progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.bmi.$(mode) %s", target:name(), name or opt.cppfile)
+ progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.bmi.$(mode) %s", target:fullname(), name or opt.cppfile)
_compile_bmi_step(target, bmifile, opt.cppfile, {std = (name == "std" or name == "std.compat")})
end
else
- progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.module.$(mode) %s", target:name(), name or opt.cppfile)
+ progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.module.$(mode) %s", target:fullname(), name or opt.cppfile)
_compile_one_step(target, bmifile, opt.cppfile, opt.objectfile, {std = (name == "std" or name == "std.compat"), is_mapped_bmi = is_mapped_bmi})
end
else
@@ -278,6 +278,75 @@ function make_module_buildjobs(target, batchjobs, job_name, deps, opt)
end)}
end
+-- build module file for jobgraph
+function make_module_jobgraph(target, jobgraph, opt)
+
+ local name, provide, _ = compiler_support.get_provided_module(opt.module)
+ local bmifile = provide and compiler_support.get_bmi_path(provide.bmi)
+ local dryrun = option.get("dry-run")
+
+ local jobname = target:fullname() .. "/module/" .. (name or opt.cppfile)
+ jobgraph:add(jobname, function(index, total, jobopt)
+ local mapped_bmi
+ if provide and compiler_support.memcache():get2(target:fullname() .. name, "reuse") then
+ mapped_bmi = get_from_target_mapper(target, name).bmi
+ end
+
+ local build, dependinfo
+ local dependfile = target:dependfile(bmifile or opt.objectfile)
+ if provide or compiler_support.has_module_extension(opt.cppfile) then
+ build, dependinfo = should_build(target, opt.cppfile, bmifile, {name = name, objectfile = opt.objectfile, requires = opt.module.requires})
+
+ -- needed to detect rebuild of dependencies
+ if provide and build then
+ mark_build(target, name)
+ end
+ end
+
+ -- append requires flags
+ if opt.module.requires then
+ _append_requires_flags(target, opt.module, name, opt.cppfile, bmifile, opt)
+ end
+
+ -- for cpp file we need to check after appendings the flags
+ if build == nil then
+ build, dependinfo = should_build(target, opt.cppfile, bmifile, {name = name, objectfile = opt.objectfile, requires = opt.module.requires})
+ end
+
+ if build then
+ -- compile if it's a named module
+ if provide or compiler_support.has_module_extension(opt.cppfile) then
+ if not dryrun then
+ local objectdir = path.directory(opt.objectfile)
+ if not os.isdir(objectdir) then
+ os.mkdir(objectdir)
+ end
+ end
+
+ local fileconfig = target:fileconfig(opt.cppfile)
+ local public = fileconfig and fileconfig.public
+ local external = fileconfig and fileconfig.external
+ local from_moduleonly = external and external.moduleonly
+ local bmifile = mapped_bmi or bmifile
+ local is_mapped_bmi = mapped_bmi ~= nil
+ if external and not from_moduleonly then
+ if not mapped_bmi then
+ progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.bmi.$(mode) %s", target:fullname(), name or opt.cppfile)
+ _compile_bmi_step(target, bmifile, opt.cppfile, {std = (name == "std" or name == "std.compat")})
+ end
+ else
+ progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.module.$(mode) %s", target:fullname(), name or opt.cppfile)
+ _compile_one_step(target, bmifile, opt.cppfile, opt.objectfile, {std = (name == "std" or name == "std.compat"), is_mapped_bmi = is_mapped_bmi})
+ end
+ else
+ os.tryrm(opt.objectfile) -- force rebuild for .cpp files
+ end
+ depend.save(dependinfo, dependfile)
+ end
+ end)
+end
+
+
-- build module file for batchcmds
function make_module_buildcmds(target, batchcmds, opt)
@@ -285,7 +354,7 @@ function make_module_buildcmds(target, batchcmds, opt)
local bmifile = provide and compiler_support.get_bmi_path(provide.bmi)
local mapped_bmi
- if provide and compiler_support.memcache():get2(target:name() .. name, "reuse") then
+ if provide and compiler_support.memcache():get2(target:fullname() .. name, "reuse") then
mapped_bmi = get_from_target_mapper(target, name).bmi
end
@@ -305,11 +374,11 @@ function make_module_buildcmds(target, batchcmds, opt)
local is_mapped_bmi = mapped_bmi ~= nil
if external and not from_moduleonly then
if not mapped_bmi then
- batchcmds:show_progress(opt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.bmi.$(mode) %s", target:name(), name or opt.cppfile)
+ batchcmds:show_progress(opt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.bmi.$(mode) %s", target:fullname(), name or opt.cppfile)
_compile_bmi_step(target, bmifile, opt.cppfile, {std = (name == "std" or name == "std.compat"), batchcmds = batchcmds})
end
else
- batchcmds:show_progress(opt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.module.$(mode) %s", target:name(), name or opt.cppfile)
+ batchcmds:show_progress(opt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.module.$(mode) %s", target:fullname(), name or opt.cppfile)
_compile_one_step(target, bmifile, opt.cppfile, opt.objectfile, {std = (name == "std" or name == "std.compat"), batchcmds = batchcmds, is_mapped_bmi = is_mapped_bmi})
end
else
@@ -340,7 +409,7 @@ function make_headerunit_buildjobs(target, job_name, batchjobs, headerunit, bmif
local depvalues = {compinst:program(), compflags}
if opt.build then
- progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.headerunit.$(mode) %s", target:name(), headerunit.name)
+ progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.headerunit.$(mode) %s", target:fullname(), headerunit.name)
_compile(target, _make_headerunitflags(target, headerunit, bmifile), headerunit.path, bmifile)
end
@@ -351,6 +420,37 @@ function make_headerunit_buildjobs(target, job_name, batchjobs, headerunit, bmif
end
end
+-- build headerunit file for jobgraph
+function make_headerunit_jobgraph(target, job_name, jobgraph, headerunit, bmifile, outputdir, opt)
+ local already_exists = add_headerunit_to_target_mapper(target, headerunit, bmifile)
+ if not already_exists then
+ jobgraph:add(job_name, function(index, total, jobopt)
+ if not os.isdir(outputdir) then
+ os.mkdir(outputdir)
+ end
+
+ local compinst = compiler.load("cxx", {target = target})
+ local compflags = compinst:compflags({sourcefile = headerunit.path, target = target})
+
+ local dependfile = target:dependfile(bmifile)
+ local dependinfo = depend.load(dependfile) or {}
+ dependinfo.files = {}
+ local depvalues = {compinst:program(), compflags}
+
+ if opt.build then
+ progress.show(jobopt.progress,
+ "${color.build.target}<%s> ${clear}${color.build.object}compiling.headerunit.$(mode) %s",
+ target:fullname(), headerunit.name)
+ _compile(target, _make_headerunitflags(target, headerunit, bmifile), headerunit.path, bmifile)
+ end
+
+ table.insert(dependinfo.files, headerunit.path)
+ dependinfo.values = depvalues
+ depend.save(dependinfo, dependfile)
+ end)
+ end
+end
+
-- build headerunit file for batchcmds
function make_headerunit_buildcmds(target, batchcmds, headerunit, bmifile, outputdir, opt)
batchcmds:mkdir(outputdir)
@@ -358,7 +458,7 @@ function make_headerunit_buildcmds(target, batchcmds, headerunit, bmifile, outpu
if opt.build then
local name = headerunit.unique and headerunit.name or headerunit.path
- batchcmds:show_progress(opt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.headerunit.$(mode) %s", target:name(), name)
+ batchcmds:show_progress(opt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.headerunit.$(mode) %s", target:fullname(), name)
_batchcmds_compile(batchcmds, target, _make_headerunitflags(target, headerunit, bmifile), bmifile)
end
batchcmds:add_depfiles(headerunit.path)
diff --git a/xmake/rules/c++/modules/modules_support/clang/dependency_scanner.lua b/xmake/rules/c++/modules/modules_support/clang/dependency_scanner.lua
index 06b522ce8..715e8a07d 100644
--- a/xmake/rules/c++/modules/modules_support/clang/dependency_scanner.lua
+++ b/xmake/rules/c++/modules/modules_support/clang/dependency_scanner.lua
@@ -36,7 +36,7 @@ function generate_dependency_for(target, sourcefile, opt)
depend.on_changed(function()
if opt.progress then
- progress.show(opt.progress, "${color.build.target}<%s> generating.module.deps %s", target:name(), sourcefile)
+ progress.show(opt.progress, "${color.build.target}<%s> generating.module.deps %s", target:fullname(), sourcefile)
end
local outputdir = compiler_support.get_outputdir(target, sourcefile)
diff --git a/xmake/rules/c++/modules/modules_support/compiler_support.lua b/xmake/rules/c++/modules/modules_support/compiler_support.lua
index cf64a08bb..eed30a320 100644
--- a/xmake/rules/c++/modules/modules_support/compiler_support.lua
+++ b/xmake/rules/c++/modules/modules_support/compiler_support.lua
@@ -69,20 +69,6 @@ function strip_flags(target, flags)
return _compiler_support(target).strip_flags(target, flags)
end
--- patch sourcebatch
-function patch_sourcebatch(target, sourcebatch)
- sourcebatch.sourcekind = "cxx"
- sourcebatch.objectfiles = {}
- sourcebatch.dependfiles = {}
- for _, sourcefile in ipairs(sourcebatch.sourcefiles) do
- local objectfile = target:objectfile(sourcefile)
- table.insert(sourcebatch.objectfiles, objectfile)
-
- local dependfile = target:dependfile(sourcefile or objectfile)
- table.insert(sourcebatch.dependfiles, dependfile)
- end
-end
-
-- get bmi extension
function get_bmi_extension(target)
return _compiler_support(target).get_bmi_extension()
@@ -224,7 +210,7 @@ function modules_cachedir(target, opt)
end
function get_modulehash(target, modulepath)
- local key = path.directory(modulepath) .. target:name()
+ local key = path.directory(modulepath) .. target:fullname()
return hash.uuid(key):split("-", {plain = true})[1]:lower()
end
diff --git a/xmake/rules/c++/modules/modules_support/dependency_scanner.lua b/xmake/rules/c++/modules/modules_support/dependency_scanner.lua
index 9d552d0fd..94b8a4804 100644
--- a/xmake/rules/c++/modules/modules_support/dependency_scanner.lua
+++ b/xmake/rules/c++/modules/modules_support/dependency_scanner.lua
@@ -202,9 +202,8 @@ function _get_edges(nodes, modules)
return edges
end
-function _get_package_modules(target, package, opt)
+function _get_package_modules(target, package)
local package_modules
-
local modulesdir = path.join(package:installdir(), "modules")
local metafiles = os.files(path.join(modulesdir, "*", "*.meta-info"))
for _, metafile in ipairs(metafiles) do
@@ -213,42 +212,39 @@ function _get_package_modules(target, package, opt)
local moduleonly = not package:libraryfiles()
package_modules[name] = {file = path.join(modulesdir, modulefile), metadata = metadata, external = {moduleonly = moduleonly}}
end
-
return package_modules
end
--- generate dependency files
-function _generate_dependencies(target, sourcebatch, opt)
- local changed = false
- if opt.batchjobs then
- local jobs = option.get("jobs") or os.default_njob()
- runjobs(target:name() .. "_module_dependency_scanner", function(index)
- local sourcefile = sourcebatch.sourcefiles[index]
- changed = _dependency_scanner(target).generate_dependency_for(target, sourcefile, opt) or changed
- end, {comax = jobs, total = #sourcebatch.sourcefiles})
- else
- for _, sourcefile in ipairs(sourcebatch.sourcefiles) do
- changed = _dependency_scanner(target).generate_dependency_for(target, sourcefile, opt) or changed
- end
- end
- return changed
-end
--- get module dependencies
-function get_module_dependencies(target, sourcebatch, opt)
- local cachekey = target:name() .. "/" .. sourcebatch.rulename
- local modules = compiler_support.memcache():get2("modules", cachekey)
- if modules == nil then
- modules = compiler_support.localcache():get2("modules", cachekey)
- opt.progress = opt.progress or 0
- local changed = _generate_dependencies(target, sourcebatch, opt)
- if changed or modules == nil then
+-- generate module dependencies
+function generate_module_dependencies(target, jobgraph, sourcebatch, opt)
+ local parsejob = target:fullname() .. "/parse_module_dependencies"
+ jobgraph:add(parsejob, function (index, total, opt)
+ local changed = compiler_support.memcache():get2("modules", "dependencies_changed")
+ if changed then
+ local cachekey = target:fullname() .. "/" .. sourcebatch.rulename
local moduleinfos = compiler_support.load_moduleinfos(target, sourcebatch)
- modules = _parse_dependencies_data(target, moduleinfos)
+ local modules = _parse_dependencies_data(target, moduleinfos)
compiler_support.localcache():set2("modules", cachekey, modules)
compiler_support.localcache():save()
end
- compiler_support.memcache():set2("modules", cachekey, modules)
+ end)
+ for _, sourcefile in ipairs(sourcebatch.sourcefiles) do
+ local jobname = target:fullname() .. "/generate_module_dependencies/" .. sourcefile
+ jobgraph:add(jobname, function (index, total, opt)
+ local changed = _dependency_scanner(target).generate_dependency_for(target, sourcefile, opt)
+ if changed then
+ compiler_support.memcache():set2("modules", "dependencies_changed", true)
+ end
+ end)
+ jobgraph:add_orders(jobname, parsejob)
end
+end
+
+-- get module dependencies
+function get_module_dependencies(target, sourcebatch)
+ local cachekey = target:fullname() .. "/" .. sourcebatch.rulename
+ local modules = compiler_support.localcache():get2("modules", cachekey)
+ assert(modules, "no module dependencies!")
return modules
end
@@ -387,7 +383,7 @@ function fallback_generate_dependencies(target, jsonfile, sourcefile, preprocess
end
-- extract packages modules dependencies
-function get_all_packages_modules(target, opt)
+function get_all_packages_modules(target)
-- parse all meta-info and append their informations to the package store
local packages = target:pkgs() or {}
@@ -397,7 +393,7 @@ function get_all_packages_modules(target, opt)
local packages_modules
for _, package in table.orderpairs(packages) do
- local package_modules = _get_package_modules(target, package, opt)
+ local package_modules = _get_package_modules(target, package)
if package_modules then
packages_modules = packages_modules or {}
table.join2(packages_modules, package_modules)
@@ -415,19 +411,21 @@ function sort_modules_by_dependencies(target, objectfiles, modules, opt)
for _, e in ipairs(edges) do
dag:add_edge(e[1], e[2])
end
- local cycle = dag:find_cycle()
- if cycle then
- local names = {}
- for _, objectfile in ipairs(cycle) do
- local name, _, cppfile = compiler_support.get_provided_module(modules[objectfile])
+ local objectfiles_sorted, has_cycle = dag:topo_sort()
+ if has_cycle then
+ local cycle = dag:find_cycle()
+ if cycle then
+ local names = {}
+ for _, objectfile in ipairs(cycle) do
+ local name, _, cppfile = compiler_support.get_provided_module(modules[objectfile])
+ table.insert(names, name or cppfile)
+ end
+ local name, _, cppfile = compiler_support.get_provided_module(modules[cycle[1]])
table.insert(names, name or cppfile)
+ raise("circular modules dependency detected!\n%s", table.concat(names, "\n -> import "))
end
- local name, _, cppfile = compiler_support.get_provided_module(modules[cycle[1]])
- table.insert(names, name or cppfile)
- raise("circular modules dependency detected!\n%s", table.concat(names, "\n -> import "))
end
-
- local objectfiles_sorted = table.reverse(dag:topological_sort())
+ objectfiles_sorted = table.reverse(objectfiles_sorted)
local objectfiles_sorted_set = hashset.from(objectfiles_sorted)
for _, objectfile in ipairs(objectfiles) do
if not objectfiles_sorted_set:has(objectfile) then
@@ -465,7 +463,7 @@ function sort_modules_by_dependencies(target, objectfiles, modules, opt)
end
end
end
- if insert then
+ if insert then
table.insert(build_objectfiles, objectfile)
table.insert(link_objectfiles, objectfile)
elseif external and not external.from_moduleonly then
@@ -474,8 +472,8 @@ function sort_modules_by_dependencies(target, objectfiles, modules, opt)
objectfiles_sorted_set:remove(objectfile)
if name ~= "std" and name ~= "std.compat" then
culleds = culleds or {}
- culleds[target:name()] = culleds[target:name()] or {}
- table.insert(culleds[target:name()], format("%s -> %s", name, cppfile))
+ culleds[target:fullname()] = culleds[target:fullname()] or {}
+ table.insert(culleds[target:fullname()], format("%s -> %s", name, cppfile))
end
end
end
diff --git a/xmake/rules/c++/modules/modules_support/gcc/builder.lua b/xmake/rules/c++/modules/modules_support/gcc/builder.lua
index a0a43db5a..4033eefd5 100644
--- a/xmake/rules/c++/modules/modules_support/gcc/builder.lua
+++ b/xmake/rules/c++/modules/modules_support/gcc/builder.lua
@@ -76,7 +76,7 @@ end
function _module_map_cachekey(target)
local mode = config.mode()
- return target:name() .. "module_mapper" .. (mode or "")
+ return target:fullname() .. "module_mapper" .. (mode or "")
end
-- generate a module mapper file for build a headerunit
@@ -135,7 +135,7 @@ end
--
function _generate_modulemapper_file(target, module, cppfile)
local maplines = _get_maplines(target, module)
- local mapper_path = path.join(os.tmpdir(), target:name():replace(" ", "_"), name or cppfile:replace(" ", "_"))
+ local mapper_path = path.join(os.tmpdir(), target:fullname():replace(" ", "_"), name or cppfile:replace(" ", "_"))
local mapper_content = {}
table.insert(mapper_content, "root " .. path.unix(os.projectdir()))
for _, mapline in ipairs(maplines) do
@@ -182,11 +182,11 @@ function make_module_buildjobs(target, batchjobs, job_name, deps, opt)
return {
name = job_name,
- deps = table.join(target:name() .. "_populate_module_map", deps),
+ deps = table.join(target:fullname() .. "/module/populate_module_map", deps),
sourcefile = opt.cppfile,
- job = batchjobs:newjob(name or opt.cppfile, function(index, total, jobopt)
+ job = batchjobs:newjob(target:fullname() .. "/module/" .. (name or opt.cppfile), function(index, total, jobopt)
local mapped_bmi
- if provide and compiler_support.memcache():get2(target:name() .. name, "reuse") then
+ if provide and compiler_support.memcache():get2(target:fullname() .. name, "reuse") then
mapped_bmi = get_from_target_mapper(target, name).bmi
end
@@ -217,13 +217,13 @@ function make_module_buildjobs(target, batchjobs, job_name, deps, opt)
local sourcefile
if external and not from_moduleonly then
if not mapped_bmi then
- progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.bmi.$(mode) %s", target:name(), name or opt.cppfile)
+ progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.bmi.$(mode) %s", target:fullname(), name or opt.cppfile)
local module_onlyflag = compiler_support.get_moduleonlyflag(target)
table.insert(flags, module_onlyflag)
sourcefile = opt.cppfile
end
else
- progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.module.$(mode) %s", target:name(), name or opt.cppfile)
+ progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.module.$(mode) %s", target:fullname(), name or opt.cppfile)
sourcefile = opt.cppfile
end
if option.get("diagnosis") then
@@ -241,6 +241,70 @@ function make_module_buildjobs(target, batchjobs, job_name, deps, opt)
end)}
end
+-- build module file for jobgraph
+function make_module_jobgraph(target, jobgraph, opt)
+ local name, provide, _ = compiler_support.get_provided_module(opt.module)
+ local bmifile = provide and compiler_support.get_bmi_path(provide.bmi)
+ local module_mapperflag = compiler_support.get_modulemapperflag(target)
+
+ local jobname = target:fullname() .. "/module/" .. (name or opt.cppfile)
+ jobgraph:add(jobname, function(index, total, jobopt)
+ local mapped_bmi
+ if provide and compiler_support.memcache():get2(target:fullname() .. name, "reuse") then
+ mapped_bmi = get_from_target_mapper(target, name).bmi
+ end
+
+ -- generate and append module mapper file
+ local module_mapper
+ if provide or opt.module.requires then
+ module_mapper = _generate_modulemapper_file(target, opt.module, opt.cppfile)
+ target:fileconfig_add(opt.cppfile, {force = {cxxflags = {module_mapperflag .. module_mapper}}})
+ end
+
+ local dependfile = target:dependfile(bmifile or opt.objectfile)
+ local build, dependinfo = should_build(target, opt.cppfile, bmifile, {name = name, objectfile = opt.objectfile, requires = opt.module.requires})
+
+ -- needed to detect rebuild of dependencies
+ if provide and build then
+ mark_build(target, name)
+ end
+
+ if build then
+ -- compile if it's a named module
+ if provide or compiler_support.has_module_extension(opt.cppfile) then
+ local fileconfig = target:fileconfig(opt.cppfile)
+ local public = fileconfig and fileconfig.public
+ local external = fileconfig and fileconfig.external
+ local from_moduleonly = external and external.moduleonly
+ local bmifile = mapped_bmi or bmifile
+ local flags = {"-x", "c++"}
+ local sourcefile
+ if external and not from_moduleonly then
+ if not mapped_bmi then
+ progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.bmi.$(mode) %s", target:fullname(), name or opt.cppfile)
+ local module_onlyflag = compiler_support.get_moduleonlyflag(target)
+ table.insert(flags, module_onlyflag)
+ sourcefile = opt.cppfile
+ end
+ else
+ progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.module.$(mode) %s", target:fullname(), name or opt.cppfile)
+ sourcefile = opt.cppfile
+ end
+ if option.get("diagnosis") then
+ print("mapper file --------\n%s--------", io.readfile(module_mapper))
+ end
+ if sourcefile then
+ _compile(target, flags, sourcefile, opt.objectfile)
+ end
+ os.tryrm(module_mapper)
+ else
+ os.tryrm(opt.objectfile) -- force rebuild for .cpp files
+ end
+ depend.save(dependinfo, dependfile)
+ end
+ end)
+end
+
-- build module file for batchcmds
function make_module_buildcmds(target, batchcmds, opt)
@@ -249,7 +313,7 @@ function make_module_buildcmds(target, batchcmds, opt)
local module_mapperflag = compiler_support.get_modulemapperflag(target)
local mapped_bmi
- if provide and compiler_support.memcache():get2(target:name() .. name, "reuse") then
+ if provide and compiler_support.memcache():get2(target:fullname() .. name, "reuse") then
mapped_bmi = get_from_target_mapper(target, name).bmi
end
@@ -272,13 +336,13 @@ function make_module_buildcmds(target, batchcmds, opt)
local sourcefile
if external and not from_moduleonly then
if not mapped_bmi then
- batchcmds:show_progress(opt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.bmi.$(mode) %s", target:name(), name or opt.cppfile)
+ batchcmds:show_progress(opt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.bmi.$(mode) %s", target:fullname(), name or opt.cppfile)
local module_onlyflag = compiler_support.get_moduleonlyflag(target)
table.insert(flags, module_onlyflag)
sourcefile = opt.cppfile
end
else
- batchcmds:show_progress(opt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.module.$(mode) %s", target:name(), name or opt.cppfile)
+ batchcmds:show_progress(opt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.module.$(mode) %s", target:fullname(), name or opt.cppfile)
sourcefile = opt.cppfile
end
if option.get("diagnosis") then
@@ -297,7 +361,6 @@ end
-- build headerunit file for batchjobs
function make_headerunit_buildjobs(target, job_name, batchjobs, headerunit, bmifile, outputdir, opt)
-
local _headerunit = headerunit
_headerunit.path = headerunit.type == ":quote" and "./" .. path.relative(headerunit.path) or headerunit.path
local already_exists = add_headerunit_to_target_mapper(target, _headerunit, bmifile)
@@ -320,7 +383,7 @@ function make_headerunit_buildjobs(target, job_name, batchjobs, headerunit, bmif
if opt.build then
local headerunit_mapper = _generate_headerunit_modulemapper_file({name = path.normalize(headerunit.path), bmifile = bmifile})
- progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.headerunit.$(mode) %s", target:name(), headerunit.name)
+ progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.headerunit.$(mode) %s", target:fullname(), headerunit.name)
if option.get("diagnosis") then
print("mapper file:\n%s", io.readfile(headerunit_mapper))
end
@@ -337,9 +400,48 @@ function make_headerunit_buildjobs(target, job_name, batchjobs, headerunit, bmif
end
end
+-- build headerunit file for jobgraph
+function make_headerunit_jobgraph(target, job_name, jobgraph, headerunit, bmifile, outputdir, opt)
+ local _headerunit = headerunit
+ _headerunit.path = headerunit.type == ":quote" and "./" .. path.relative(headerunit.path) or headerunit.path
+ local already_exists = add_headerunit_to_target_mapper(target, _headerunit, bmifile)
+ if not already_exists then
+ jobgraph:add(job_name, function(index, total, jobopt)
+ if not os.isdir(outputdir) then
+ os.mkdir(outputdir)
+ end
+
+ local compinst = compiler.load("cxx", {target = target})
+ local compflags = compinst:compflags({sourcefile = headerunit.path, target = target})
+
+ local dependfile = target:dependfile(bmifile)
+ local dependinfo = depend.load(dependfile) or {}
+ dependinfo.files = {}
+ local depvalues = {compinst:program(), compflags}
+
+ if opt.build then
+ local headerunit_mapper = _generate_headerunit_modulemapper_file({name = path.normalize(headerunit.path), bmifile = bmifile})
+ progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.headerunit.$(mode) %s", target:fullname(), headerunit.name)
+ if option.get("diagnosis") then
+ print("mapper file:\n%s", io.readfile(headerunit_mapper))
+ end
+ _compile(target,
+ _make_headerunitflags(target, headerunit, headerunit_mapper, opt),
+ path.translate(path.filename(headerunit.name)), bmifile)
+ os.tryrm(headerunit_mapper)
+ end
+
+ table.insert(dependinfo.files, headerunit.path)
+ dependinfo.values = depvalues
+ depend.save(dependinfo, dependfile)
+ end)
+ end
+end
+
+
+
-- build headerunit file for batchcmds
function make_headerunit_buildcmds(target, batchcmds, headerunit, bmifile, outputdir, opt)
-
local headerunit_mapper = _generate_headerunit_modulemapper_file({name = path.normalize(headerunit.path), bmifile = bmifile})
batchcmds:mkdir(outputdir)
@@ -349,7 +451,7 @@ function make_headerunit_buildcmds(target, batchcmds, headerunit, bmifile, outpu
if opt.build then
local name = headerunit.unique and headerunit.name or headerunit.path
- batchcmds:show_progress(opt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.headerunit.$(mode) %s", target:name(), name)
+ batchcmds:show_progress(opt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.headerunit.$(mode) %s", target:fullname(), name)
if option.get("diagnosis") then
batchcmds:print("mapper file:\n%s", io.readfile(headerunit_mapper))
end
diff --git a/xmake/rules/c++/modules/modules_support/gcc/dependency_scanner.lua b/xmake/rules/c++/modules/modules_support/gcc/dependency_scanner.lua
index 11dab5669..e087c6d4e 100644
--- a/xmake/rules/c++/modules/modules_support/gcc/dependency_scanner.lua
+++ b/xmake/rules/c++/modules/modules_support/gcc/dependency_scanner.lua
@@ -40,7 +40,7 @@ function generate_dependency_for(target, sourcefile, opt)
depend.on_changed(function()
if opt.progress then
- progress.show(opt.progress, "${color.build.target}<%s> generating.module.deps %s", target:name(), sourcefile)
+ progress.show(opt.progress, "${color.build.target}<%s> generating.module.deps %s", target:fullname(), sourcefile)
end
local outputdir = compiler_support.get_outputdir(target, sourcefile)
diff --git a/xmake/rules/c++/modules/modules_support/msvc/builder.lua b/xmake/rules/c++/modules/modules_support/msvc/builder.lua
index 5998db62f..8f582438b 100644
--- a/xmake/rules/c++/modules/modules_support/msvc/builder.lua
+++ b/xmake/rules/c++/modules/modules_support/msvc/builder.lua
@@ -167,7 +167,7 @@ function _get_requiresflags(target, module, opt)
local headerunitflag = compiler_support.get_headerunitflag(target)
local name = module.name
- local cachekey = target:name() .. name
+ local cachekey = target:fullname() .. name
local requires, requires_changed = is_dependencies_changed(target, module)
local requiresflags = compiler_support.memcache():get2(cachekey, "requiresflags")
@@ -175,7 +175,7 @@ function _get_requiresflags(target, module, opt)
local deps_flags = {}
for required in requires:orderitems() do
local dep_module = get_from_target_mapper(target, required)
- assert(dep_module, "module dependency %s required for %s not found <%s>", required, name, target:name())
+ assert(dep_module, "module dependency %s required for %s not found <%s>", required, name, target:fullname())
local mapflag
local bmifile = dep_module.bmi
@@ -257,19 +257,18 @@ end
-- build module file for batchjobs
function make_module_buildjobs(target, batchjobs, job_name, deps, opt)
-
local name, provide, _ = compiler_support.get_provided_module(opt.module)
local bmifile = provide and compiler_support.get_bmi_path(provide.bmi)
local dryrun = option.get("dry-run")
return {
name = job_name,
- deps = table.join(target:name() .. "_populate_module_map", deps),
+ deps = table.join(target:fullname() .. "/module/populate_module_map", deps),
sourcefile = opt.cppfile,
- job = batchjobs:newjob(name or opt.cppfile, function(index, total, jobopt)
+ job = batchjobs:newjob(target:fullname() .. "/module/" .. (name or opt.cppfile), function(index, total, jobopt)
local mapped_bmi
- if provide and compiler_support.memcache():get2(target:name() .. name, "reuse") then
+ if provide and compiler_support.memcache():get2(target:fullname() .. name, "reuse") then
mapped_bmi = get_from_target_mapper(target, name).bmi
end
@@ -311,11 +310,11 @@ function make_module_buildjobs(target, batchjobs, job_name, deps, opt)
local bmifile = mapped_bmi or bmifile
if external and not from_moduleonly then
if not mapped_bmi then
- progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.bmi.$(mode) %s", target:name(), name or opt.cppfile)
+ progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.bmi.$(mode) %s", target:fullname(), name or opt.cppfile)
_compile_bmi_step(target, bmifile, opt.cppfile, opt.objectfile, provide)
end
else
- progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.module.$(mode) %s", target:name(), name or opt.cppfile)
+ progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.module.$(mode) %s", target:fullname(), name or opt.cppfile)
_compile_one_step(target, bmifile, opt.cppfile, opt.objectfile, provide)
end
else
@@ -326,6 +325,72 @@ function make_module_buildjobs(target, batchjobs, job_name, deps, opt)
end)}
end
+-- build module file for jobgraph
+function make_module_jobgraph(target, jobgraph, opt)
+ local name, provide, _ = compiler_support.get_provided_module(opt.module)
+ local bmifile = provide and compiler_support.get_bmi_path(provide.bmi)
+ local dryrun = option.get("dry-run")
+
+ local jobname = target:fullname() .. "/module/" .. (name or opt.cppfile)
+ jobgraph:add(jobname, function(index, total, jobopt)
+ local mapped_bmi
+ if provide and compiler_support.memcache():get2(target:fullname() .. name, "reuse") then
+ mapped_bmi = get_from_target_mapper(target, name).bmi
+ end
+
+ local build, dependinfo
+ local dependfile = target:dependfile(bmifile or opt.objectfile)
+ if provide or compiler_support.has_module_extension(opt.cppfile) then
+ build, dependinfo = should_build(target, opt.cppfile, bmifile, {name = name, objectfile = opt.objectfile, requires = opt.module.requires})
+
+ -- needed to detect rebuild of dependencies
+ if provide and build then
+ mark_build(target, name)
+ end
+ end
+
+ -- append requires flags
+ if opt.module.requires then
+ _append_requires_flags(target, opt.module, name, opt.cppfile, bmifile, opt)
+ end
+
+ -- for cpp file we need to check after appendings the flags
+ if build == nil then
+ build, dependinfo = should_build(target, opt.cppfile, bmifile, {name = name, objectfile = opt.objectfile, requires = opt.module.requires})
+ end
+
+ if build then
+ -- compile if it's a named module
+ if provide or compiler_support.has_module_extension(opt.cppfile) then
+ if not dryrun then
+ local objectdir = path.directory(opt.objectfile)
+ if not os.isdir(objectdir) then
+ os.mkdir(objectdir)
+ end
+ end
+
+ local fileconfig = target:fileconfig(opt.cppfile)
+ local public = fileconfig and fileconfig.public
+ local external = fileconfig and fileconfig.external
+ local from_moduleonly = external and external.moduleonly
+ local bmifile = mapped_bmi or bmifile
+ if external and not from_moduleonly then
+ if not mapped_bmi then
+ progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.bmi.$(mode) %s", target:fullname(), name or opt.cppfile)
+ _compile_bmi_step(target, bmifile, opt.cppfile, opt.objectfile, provide)
+ end
+ else
+ progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.module.$(mode) %s", target:fullname(), name or opt.cppfile)
+ _compile_one_step(target, bmifile, opt.cppfile, opt.objectfile, provide)
+ end
+ else
+ os.tryrm(opt.objectfile) -- force rebuild for .cpp files
+ end
+ depend.save(dependinfo, dependfile)
+ end
+ end)
+end
+
-- build module file for batchcmds
function make_module_buildcmds(target, batchcmds, opt)
@@ -333,7 +398,7 @@ function make_module_buildcmds(target, batchcmds, opt)
local bmifile = provide and compiler_support.get_bmi_path(provide.bmi)
local mapped_bmi
- if provide and compiler_support.memcache():get2(target:name() .. name, "reuse") then
+ if provide and compiler_support.memcache():get2(target:fullname() .. name, "reuse") then
mapped_bmi = get_from_target_mapper(target, name).bmi
end
@@ -353,11 +418,11 @@ function make_module_buildcmds(target, batchcmds, opt)
local bmifile = mapped_bmi or bmifile
if external and not from_moduleonly then
if not mapped_bmi then
- batchcmds:show_progress(opt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.bmi.$(mode) %s", target:name(), name or opt.cppfile)
+ batchcmds:show_progress(opt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.bmi.$(mode) %s", target:fullname(), name or opt.cppfile)
_compile_bmi_step(target, bmifile, opt.cppfile, provide, {batchcmds = batchcmds})
end
else
- batchcmds:show_progress(opt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.module.$(mode) %s", target:name(), name or opt.cppfile)
+ batchcmds:show_progress(opt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.module.$(mode) %s", target:fullname(), name or opt.cppfile)
_compile_one_step(target, bmifile, opt.cppfile, opt.objectfile, provide, {batchcmds = batchcmds})
end
else
@@ -390,7 +455,7 @@ function make_headerunit_buildjobs(target, job_name, batchjobs, headerunit, bmif
local name = headerunit.unique and headerunit.name or headerunit.path
if opt.build then
- progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.headerunit.$(mode) %s", target:name(), headerunit.name)
+ progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.headerunit.$(mode) %s", target:fullname(), headerunit.name)
_compile(target, _make_headerunitflags(target, headerunit, bmifile), name, target:objectfile(headerunit.path), true)
end
@@ -401,6 +466,37 @@ function make_headerunit_buildjobs(target, job_name, batchjobs, headerunit, bmif
end
end
+-- build headerunit file for jobgraph
+function make_headerunit_jobgraph(target, job_name, jobgraph, headerunit, bmifile, outputdir, opt)
+ local already_exists = add_headerunit_to_target_mapper(target, headerunit, bmifile)
+ if not already_exists then
+ jobgraph:add(job_name, function(index, total, jobopt)
+ if not os.isdir(outputdir) then
+ os.mkdir(outputdir)
+ end
+
+ local compinst = compiler.load("cxx", {target = target})
+ local compflags = compinst:compflags({sourcefile = headerunit.path, target = target})
+
+ local dependfile = target:dependfile(bmifile)
+ local dependinfo = depend.load(dependfile) or {}
+ dependinfo.files = {}
+ local depvalues = {compinst:program(), compflags}
+
+ local name = headerunit.unique and headerunit.name or headerunit.path
+
+ if opt.build then
+ progress.show(jobopt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.headerunit.$(mode) %s", target:fullname(), headerunit.name)
+ _compile(target, _make_headerunitflags(target, headerunit, bmifile), name, target:objectfile(headerunit.path), true)
+ end
+
+ table.insert(dependinfo.files, headerunit.path)
+ dependinfo.values = depvalues
+ depend.save(dependinfo, dependfile)
+ end)
+ end
+end
+
-- build headerunit file for batchcmds
function make_headerunit_buildcmds(target, batchcmds, headerunit, bmifile, outputdir, opt)
batchcmds:mkdir(outputdir)
@@ -408,7 +504,7 @@ function make_headerunit_buildcmds(target, batchcmds, headerunit, bmifile, outpu
if opt.build then
local name = headerunit.unique and headerunit.name or headerunit.path
- batchcmds:show_progress(opt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.headerunit.$(mode) %s", target:name(), name)
+ batchcmds:show_progress(opt.progress, "${color.build.target}<%s> ${clear}${color.build.object}compiling.headerunit.$(mode) %s", target:fullname(), name)
_batchcmds_compile(batchcmds, target, _make_headerunitflags(target, headerunit, bmifile), target:objectfile(headerunit.path))
end
batchcmds:add_depfiles(headerunit.path)
diff --git a/xmake/rules/c++/modules/modules_support/msvc/dependency_scanner.lua b/xmake/rules/c++/modules/modules_support/msvc/dependency_scanner.lua
index 491a27cbf..044510fab 100644
--- a/xmake/rules/c++/modules/modules_support/msvc/dependency_scanner.lua
+++ b/xmake/rules/c++/modules/modules_support/msvc/dependency_scanner.lua
@@ -40,7 +40,7 @@ function generate_dependency_for(target, sourcefile, opt)
local changed = false
depend.on_changed(function ()
- progress.show(opt.progress, "${color.build.target}<%s> generating.module.deps %s", target:name(), sourcefile)
+ progress.show(opt.progress, "${color.build.target}<%s> generating.module.deps %s", target:fullname(), sourcefile)
local outputdir = compiler_support.get_outputdir(target, sourcefile)
local jsonfile = path.join(outputdir, path.filename(sourcefile) .. ".module.json")
diff --git a/xmake/rules/c++/modules/xmake.lua b/xmake/rules/c++/modules/xmake.lua
index f967dd133..a27633182 100644
--- a/xmake/rules/c++/modules/xmake.lua
+++ b/xmake/rules/c++/modules/xmake.lua
@@ -37,7 +37,7 @@ rule("c++.build.modules")
-- even if some sub-targets do not contain C++ modules.
--
-- maybe we will have a more fine-grained configuration strategy to disable it in the future.
- target:set("policy", "build.across_targets_in_parallel", false)
+ target:set("policy", "build.fence", true)
-- disable ccache for this target
--
@@ -70,66 +70,48 @@ rule("c++.build.modules.builder")
set_sourcekinds("cxx")
set_extensions(".mpp", ".mxx", ".cppm", ".ixx")
- -- parallel build support to accelerate `xmake build` to build modules
- before_build_files(function(target, batchjobs, sourcebatch, opt)
+ -- generate module dependencies
+ on_prepare_files(function (target, jobgraph, sourcebatch, opt)
if target:data("cxx.has_modules") then
- import("modules_support.compiler_support")
- import("modules_support.dependency_scanner")
import("modules_support.builder")
+ import("modules_support.dependency_scanner")
- -- add target deps modules
- if target:orderdeps() then
- local deps_sourcefiles = dependency_scanner.get_targetdeps_modules(target)
- if deps_sourcefiles then
- table.join2(sourcebatch.sourcefiles, deps_sourcefiles)
- end
- end
-
- -- append std module
- local std_modules = compiler_support.get_stdmodules(target)
- if std_modules then
- table.join2(sourcebatch.sourcefiles, std_modules)
- end
-
- -- extract packages modules dependencies
- local package_modules_data = dependency_scanner.get_all_packages_modules(target, opt)
- if package_modules_data then
- -- append to sourcebatch
- for _, package_module_data in table.orderpairs(package_modules_data) do
- table.insert(sourcebatch.sourcefiles, package_module_data.file)
- target:fileconfig_set(package_module_data.file, {external = package_module_data.external, defines = package_module_data.metadata.defines})
- end
- end
+ -- patch sourcebatch
+ builder.patch_sourcebatch(target, sourcebatch)
- opt = opt or {}
- opt.batchjobs = true
+ -- generate module dependencies
+ dependency_scanner.generate_module_dependencies(target, jobgraph, sourcebatch, opt)
+ end
+ end, {jobgraph = true})
- compiler_support.patch_sourcebatch(target, sourcebatch, opt)
- local modules = dependency_scanner.get_module_dependencies(target, sourcebatch, opt)
+ -- parallel build support to accelerate `xmake build` to build modules
+ before_build_files(function(target, jobgraph, sourcebatch, opt)
+ if target:data("cxx.has_modules") then
+ import("modules_support.compiler_support")
+ import("modules_support.dependency_scanner")
+ import("modules_support.builder")
+ -- get module dependencies
+ local modules = dependency_scanner.get_module_dependencies(target, sourcebatch)
if not target:is_moduleonly() then
-- avoid building non referenced modules
local build_objectfiles, link_objectfiles = dependency_scanner.sort_modules_by_dependencies(target, sourcebatch.objectfiles, modules)
sourcebatch.objectfiles = build_objectfiles
- -- build modules
- builder.build_modules_for_batchjobs(target, batchjobs, sourcebatch, modules, opt)
-
- -- build headerunits and we need to do it before building modules
- builder.build_headerunits_for_batchjobs(target, batchjobs, sourcebatch, modules, opt)
-
+ -- build modules and headerunits
+ builder.build_modules_and_headerunits(target, jobgraph, sourcebatch, modules, opt)
sourcebatch.objectfiles = link_objectfiles
else
sourcebatch.objectfiles = {}
end
- compiler_support.localcache():set2(target:name(), "c++.modules", modules)
+ compiler_support.localcache():set2(target:fullname(), "c++.modules", modules)
compiler_support.localcache():save()
else
-- avoid duplicate linking of object files of non-module programs
sourcebatch.objectfiles = {}
end
- end, {batch = true})
+ end, {jobgraph = true, batch = true})
-- serial compilation only, usually used to support project generator
before_buildcmd_files(function(target, batchcmds, sourcebatch, opt)
@@ -138,54 +120,22 @@ rule("c++.build.modules.builder")
import("modules_support.dependency_scanner")
import("modules_support.builder")
- -- add target deps modules
- if target:orderdeps() then
- local deps_sourcefiles = dependency_scanner.get_targetdeps_modules(target)
- if deps_sourcefiles then
- table.join2(sourcebatch.sourcefiles, deps_sourcefiles)
- end
- end
-
- -- append std module
- local std_modules = compiler_support.get_stdmodules(target)
- if std_modules then
- table.join2(sourcebatch.sourcefiles, std_modules)
- end
-
- -- extract packages modules dependencies
- local package_modules_data = dependency_scanner.get_all_packages_modules(target, opt)
- if package_modules_data then
- -- append to sourcebatch
- for _, package_module_data in table.orderpairs(package_modules_data) do
- table.insert(sourcebatch.sourcefiles, package_module_data.file)
- target:fileconfig_set(package_module_data.file, {external = package_module_data.external, defines = package_module_data.metadata.defines})
- end
- end
-
- opt = opt or {}
- opt.batchjobs = false
-
- compiler_support.patch_sourcebatch(target, sourcebatch, opt)
- local modules = dependency_scanner.get_module_dependencies(target, sourcebatch, opt)
-
+ -- get module dependencies
+ local modules = dependency_scanner.get_module_dependencies(target, sourcebatch)
if not target:is_moduleonly() then
-- avoid building non referenced modules
local build_objectfiles, link_objectfiles = dependency_scanner.sort_modules_by_dependencies(target, sourcebatch.objectfiles, modules)
sourcebatch.objectfiles = build_objectfiles
- -- build headerunits
- builder.build_headerunits_for_batchcmds(target, batchcmds, sourcebatch, modules, opt)
-
- -- build modules
- builder.build_modules_for_batchcmds(target, batchcmds, sourcebatch, modules, opt)
-
+ -- build headerunits and modules
+ builder.build_modules_and_headerunits(target, batchcmds, sourcebatch, modules, opt)
sourcebatch.objectfiles = link_objectfiles
else
-- avoid duplicate linking of object files of non-module programs
sourcebatch.objectfiles = {}
end
- compiler_support.localcache():set2(target:name(), "c++.modules", modules)
+ compiler_support.localcache():set2(target:fullname(), "c++.modules", modules)
compiler_support.localcache():save()
else
sourcebatch.sourcefiles = {}
@@ -222,7 +172,7 @@ rule("c++.build.modules.install")
-- we cannot use target:data("cxx.has_modules"),
-- because on_config will be not called when installing targets
if compiler_support.contains_modules(target) then
- local modules = compiler_support.localcache():get2(target:name(), "c++.modules")
+ local modules = compiler_support.localcache():get2(target:fullname(), "c++.modules")
builder.generate_metadata(target, modules)
compiler_support.add_installfiles_for_modules(target)