summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArthur LAURENT <[email protected]>2025-04-22 18:40:37 +0200
committerArthur LAURENT <[email protected]>2025-04-22 18:40:37 +0200
commitf49af9018f3efbcdf3d49bb30c6663b300f1a133 (patch)
treec047b0622ec6aa2b8f12a6c4dd19f2b1cbf1f768
parent40bfb6e1980d81454c9592da7eaaf0aded11f1ec (diff)
(C++ modules) cleanup module rules
-rw-r--r--xmake/rules/c++/modules/builder.lua107
-rw-r--r--xmake/rules/c++/modules/config.lua58
-rw-r--r--xmake/rules/c++/modules/scanner.lua127
-rw-r--r--xmake/rules/c++/modules/xmake.lua145
4 files changed, 215 insertions, 222 deletions
diff --git a/xmake/rules/c++/modules/builder.lua b/xmake/rules/c++/modules/builder.lua
index 1f3eec988..51de339f7 100644
--- a/xmake/rules/c++/modules/builder.lua
+++ b/xmake/rules/c++/modules/builder.lua
@@ -23,6 +23,7 @@ import("core.base.json")
import("core.base.option")
import("core.base.hashset")
import("async.runjobs")
+import("private.action.clean.remove_files")
import("private.async.buildjobs")
import("core.tool.compiler")
import("core.project.config")
@@ -257,12 +258,12 @@ function mark_build(target, name)
end
-- build batchjobs for modules
-function build_batchjobs_for_modules(modules, batchjobs, rootjob)
+function _build_batchjobs_for_modules(modules, batchjobs, rootjob)
return buildjobs(modules, batchjobs, rootjob)
end
-- build modules for batchjobs
-function build_modules_for_batchjobs(target, batchjobs, sourcebatch, modules, opt)
+function _build_modules_for_batchjobs(target, batchjobs, sourcebatch, modules, opt)
opt.rootjob = batchjobs:group_leave() or opt.rootjob
batchjobs:group_enter(target:fullname() .. "/module/build_modules", {rootjob = opt.rootjob})
@@ -287,11 +288,11 @@ function build_modules_for_batchjobs(target, batchjobs, sourcebatch, modules, op
}))
-- build batchjobs for modules
- build_batchjobs_for_modules(modulesjobs, batchjobs, opt.rootjob)
+ _build_batchjobs_for_modules(modulesjobs, batchjobs, opt.rootjob)
end
-- build modules for jobgraph
-function build_modules_for_jobgraph(target, jobgraph, sourcebatch, modules, opt)
+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"
@@ -321,7 +322,7 @@ function build_modules_for_jobgraph(target, jobgraph, sourcebatch, modules, opt)
end
-- build modules for batchcmds
-function build_modules_for_batchcmds(target, batchcmds, sourcebatch, modules, opt)
+function _build_modules_for_batchcmds(target, batchcmds, sourcebatch, modules, opt)
local depmtime = 0
opt.progress = opt.progress or 0
@@ -340,7 +341,7 @@ function build_modules_for_batchcmds(target, batchcmds, sourcebatch, modules, op
end
-- build headerunits for batchjobs
-function build_headerunits_for_batchjobs(target, batchjobs, sourcebatch, modules, opt)
+function _build_headerunits_for_batchjobs(target, batchjobs, sourcebatch, modules, opt)
local user_headerunits, stl_headerunits = scanner.get_headerunits(target, sourcebatch, modules)
if not user_headerunits and not stl_headerunits then
@@ -363,7 +364,7 @@ function build_headerunits_for_batchjobs(target, batchjobs, sourcebatch, modules
end
end
}))
- build_batchjobs_for_modules(modulesjobs, batchjobs, opt.rootjob)
+ _build_batchjobs_for_modules(modulesjobs, batchjobs, opt.rootjob)
end
-- build stl header units first as other headerunits may need them
@@ -378,7 +379,7 @@ function build_headerunits_for_batchjobs(target, batchjobs, sourcebatch, modules
end
-- build headerunits for jobgraph
-function build_headerunits_for_jobgraph(target, jobgraph, sourcebatch, modules, opt)
+function _build_headerunits_for_jobgraph(target, jobgraph, sourcebatch, modules, opt)
local user_headerunits, stl_headerunits = scanner.get_headerunits(target, sourcebatch, modules)
if not user_headerunits and not stl_headerunits then
return
@@ -416,7 +417,7 @@ function build_headerunits_for_jobgraph(target, jobgraph, sourcebatch, modules,
end
-- build headerunits for batchcmds
-function build_headerunits_for_batchcmds(target, batchcmds, sourcebatch, modules, opt)
+function _build_headerunits_for_batchcmds(target, batchcmds, sourcebatch, modules, opt)
local user_headerunits, stl_headerunits = scanner.get_headerunits(target, sourcebatch, modules)
if not user_headerunits and not stl_headerunits then
return
@@ -444,10 +445,10 @@ function build_headerunits_for_batchcmds(target, batchcmds, sourcebatch, modules
end
-- build modules and headerunits, and we need to build headerunits first
-function build_modules_and_headerunits(target, jobgraph, sourcebatch, modules, opt)
+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)
+ 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
@@ -459,11 +460,11 @@ function build_modules_and_headerunits(target, jobgraph, sourcebatch, modules, o
end
end
elseif jobgraph.runcmds then
- build_headerunits_for_batchcmds(target, jobgraph, sourcebatch, modules, opt)
- build_modules_for_batchcmds(target, jobgraph, sourcebatch, modules, opt)
+ _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)
+ _build_modules_for_batchjobs(target, jobgraph, sourcebatch, modules, opt)
+ _build_headerunits_for_batchjobs(target, jobgraph, sourcebatch, modules, opt)
end
end
@@ -576,43 +577,59 @@ function is_dependencies_changed(target, module)
return requires, changed
end
--- patch sourcebatch
-function patch_sourcebatch(target, sourcebatch, opt)
+function clean(target)
- -- add target deps modules
- if target:orderdeps() then
- local deps_sourcefiles = scanner.get_targetdeps_modules(target)
- if deps_sourcefiles then
- table.join2(sourcebatch.sourcefiles, deps_sourcefiles)
+ -- we cannot use target:data("cxx.has_modules"),
+ -- because on_config will be not called when cleaning targets
+ if support.contains_modules(target) then
+ remove_files(support.modules_cachedir(target))
+ if option.get("all") then
+ remove_files(support.stlmodules_cachedir(target))
+ support.localcache():clear()
+ support.localcache():save()
end
end
+end
+
+function install(target)
+
+ -- we cannot use target:data("cxx.has_modules"),
+ -- because on_config will be not called when installing targets
+ if support.contains_modules(target) then
+ local modules = support.localcache():get2(target:fullname(), "c++.modules")
+ generate_metadata(target, modules)
- -- append std module
- local std_modules = support.get_stdmodules(target)
- if std_modules then
- table.join2(sourcebatch.sourcefiles, std_modules)
+ support.add_installfiles_for_modules(target)
end
+end
- -- extract packages modules dependencies
- local package_modules_data = 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
+function uninstall(target)
+ if support.contains_modules(target) then
+ support.add_installfiles_for_modules(target)
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)
+function main(target, jobgraph, sourcebatch, opt)
- local dependfile = target:dependfile(sourcefile or objectfile)
- table.insert(sourcebatch.dependfiles, dependfile)
+ if target:data("cxx.has_modules") then
+ -- get module dependencies
+ local modules = scanner.get_module_dependencies(target, sourcebatch)
+ if not target:is_moduleonly() then
+ -- avoid building non referenced modules
+ local build_objectfiles, link_objectfiles = scanner.sort_modules_by_dependencies(target, sourcebatch.objectfiles, modules)
+ sourcebatch.objectfiles = build_objectfiles
+
+ -- build modules and headerunits
+ _build_modules_and_headerunits(target, jobgraph, sourcebatch, modules, opt)
+ sourcebatch.objectfiles = link_objectfiles
+ else
+ sourcebatch.objectfiles = {}
+ end
+
+ support.localcache():set2(target:fullname(), "c++.modules", modules)
+ support.localcache():save()
+ else
+ -- avoid duplicate linking of object files of non-module programs
+ sourcebatch.objectfiles = {}
end
end
-
diff --git a/xmake/rules/c++/modules/config.lua b/xmake/rules/c++/modules/config.lua
new file mode 100644
index 000000000..a39e4c4e0
--- /dev/null
+++ b/xmake/rules/c++/modules/config.lua
@@ -0,0 +1,58 @@
+--!A cross-platform build utility based on Lua
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-- Copyright (C) 2015-present, TBOOX Open Source Group.
+--
+-- @author ruki, Arthapz
+-- @file config.lua
+--
+
+import("support")
+
+function main(target)
+
+ -- we disable to build across targets in parallel, because the source files may depend on other target modules
+ -- @see https://github.com/xmake-io/xmake/issues/1858
+ if support.contains_modules(target) then
+ -- @note this will cause cross-parallel builds to be disabled for all sub-dependent targets,
+ -- 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.fence", true)
+
+ -- disable ccache for this target
+ --
+ -- Caching can affect incremental compilation, for example
+ -- by interfering with the results of depfile generation for msvc.
+ --
+ -- @see https://github.com/xmake-io/xmake/issues/3000
+ target:set("policy", "build.ccache", false)
+
+ -- load compiler support
+ support.load(target)
+
+ -- mark this target with modules
+ target:data_set("cxx.has_modules", true)
+
+ -- moduleonly modules are implicitly public
+ if target:is_moduleonly() then
+ local sourcebatch = target:sourcebatches()["c++.build.modules.builder"]
+ if sourcebatch then
+ for _, sourcefile in ipairs(sourcebatch.sourcefiles) do
+ target:fileconfig_add(sourcefile, {public = true})
+ end
+ end
+ end
+ end
+end
diff --git a/xmake/rules/c++/modules/scanner.lua b/xmake/rules/c++/modules/scanner.lua
index 020f5a954..18f90cfca 100644
--- a/xmake/rules/c++/modules/scanner.lua
+++ b/xmake/rules/c++/modules/scanner.lua
@@ -216,7 +216,7 @@ function _get_package_modules(target, package)
end
-- generate module dependencies
-function generate_module_dependencies(target, jobgraph, sourcebatch, opt)
+function _generate_module_dependencies(target, jobgraph, sourcebatch, opt)
local parsejob = target:fullname() .. "/parse_module_dependencies"
jobgraph:add(parsejob, function (index, total, opt)
local changed = support.memcache():get2("modules", "dependencies_changed")
@@ -240,6 +240,86 @@ function generate_module_dependencies(target, jobgraph, sourcebatch, opt)
end
end
+-- get source modulefile for external target deps
+function _get_targetdeps_modules(target)
+ local sourcefiles
+ for _, dep in ipairs(target:orderdeps()) do
+ local sourcebatch = dep:sourcebatches()["c++.build.modules.builder"]
+ if sourcebatch and sourcebatch.sourcefiles then
+ for _, sourcefile in ipairs(sourcebatch.sourcefiles) do
+ local fileconfig = dep:fileconfig(sourcefile)
+ local public = (fileconfig and fileconfig.public and not fileconfig.external) or false
+ if public then
+ sourcefiles = sourcefiles or {}
+ table.insert(sourcefiles, sourcefile)
+ target:fileconfig_add(sourcefile, {external = {moduleonly = dep:is_moduleonly()}})
+ end
+ end
+ end
+ end
+ return sourcefiles
+end
+
+-- extract packages modules dependencies
+function _get_all_packages_modules(target)
+
+ -- parse all meta-info and append their informations to the package store
+ local packages = target:pkgs() or {}
+ for _, deps in ipairs(target:orderdeps()) do
+ table.join2(packages, deps:pkgs())
+ end
+
+ local packages_modules
+ for _, package in table.orderpairs(packages) do
+ local package_modules = _get_package_modules(target, package)
+ if package_modules then
+ packages_modules = packages_modules or {}
+ table.join2(packages_modules, package_modules)
+ end
+ end
+ return packages_modules
+end
+
+-- patch sourcebatch
+function _patch_sourcebatch(target, sourcebatch, opt)
+
+ -- add target deps modules
+ if target:orderdeps() then
+ local deps_sourcefiles = _get_targetdeps_modules(target)
+ if deps_sourcefiles then
+ table.join2(sourcebatch.sourcefiles, deps_sourcefiles)
+ end
+ end
+
+ -- append std module
+ local std_modules = support.get_stdmodules(target)
+ if std_modules then
+ table.join2(sourcebatch.sourcefiles, std_modules)
+ end
+
+ -- extract packages modules dependencies
+ local package_modules_data = _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
+
-- get module dependencies
function get_module_dependencies(target, sourcebatch)
local cachekey = target:fullname() .. "/" .. sourcebatch.rulename
@@ -382,26 +462,6 @@ function fallback_generate_dependencies(target, jsonfile, sourcefile, preprocess
io.writefile(jsonfile, jsondata)
end
--- extract packages modules dependencies
-function get_all_packages_modules(target)
-
- -- parse all meta-info and append their informations to the package store
- local packages = target:pkgs() or {}
- for _, deps in ipairs(target:orderdeps()) do
- table.join2(packages, deps:pkgs())
- end
-
- local packages_modules
- for _, package in table.orderpairs(packages) do
- local package_modules = _get_package_modules(target, package)
- if package_modules then
- packages_modules = packages_modules or {}
- table.join2(packages_modules, package_modules)
- end
- end
- return packages_modules
-end
-
-- topological sort
function sort_modules_by_dependencies(target, objectfiles, modules, opt)
local build_objectfiles = {}
@@ -494,23 +554,12 @@ function sort_modules_by_dependencies(target, objectfiles, modules, opt)
return build_objectfiles, link_objectfiles
end
--- get source modulefile for external target deps
-function get_targetdeps_modules(target)
- local sourcefiles
- for _, dep in ipairs(target:orderdeps()) do
- local sourcebatch = dep:sourcebatches()["c++.build.modules.builder"]
- if sourcebatch and sourcebatch.sourcefiles then
- for _, sourcefile in ipairs(sourcebatch.sourcefiles) do
- local fileconfig = dep:fileconfig(sourcefile)
- local public = (fileconfig and fileconfig.public and not fileconfig.external) or false
- if public then
- sourcefiles = sourcefiles or {}
- table.insert(sourcefiles, sourcefile)
- target:fileconfig_add(sourcefile, {external = {moduleonly = dep:is_moduleonly()}})
- end
- end
- end
+function main(target, jobgraph, sourcebatch, opt)
+
+ if target:data("cxx.has_modules") then
+ -- patch sourcebatch
+ _patch_sourcebatch(target, sourcebatch)
+ -- generate module dependencies
+ _generate_module_dependencies(target, jobgraph, sourcebatch, opt)
end
- return sourcefiles
end
-
diff --git a/xmake/rules/c++/modules/xmake.lua b/xmake/rules/c++/modules/xmake.lua
index 2c7eaedff..c1b48ed41 100644
--- a/xmake/rules/c++/modules/xmake.lua
+++ b/xmake/rules/c++/modules/xmake.lua
@@ -27,43 +27,7 @@ rule("c++.build.modules")
add_deps("c++.build.modules.builder")
add_deps("c++.build.modules.install")
- on_config(function (target)
- import("support")
-
- -- we disable to build across targets in parallel, because the source files may depend on other target modules
- -- @see https://github.com/xmake-io/xmake/issues/1858
- if support.contains_modules(target) then
- -- @note this will cause cross-parallel builds to be disabled for all sub-dependent targets,
- -- 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.fence", true)
-
- -- disable ccache for this target
- --
- -- Caching can affect incremental compilation, for example
- -- by interfering with the results of depfile generation for msvc.
- --
- -- @see https://github.com/xmake-io/xmake/issues/3000
- target:set("policy", "build.ccache", false)
-
- -- load compiler support
- support.load(target)
-
- -- mark this target with modules
- target:data_set("cxx.has_modules", true)
-
- -- moduleonly modules are implicitly public
- if target:is_moduleonly() then
- local sourcebatch = target:sourcebatches()["c++.build.modules.builder"]
- if sourcebatch then
- for _, sourcefile in ipairs(sourcebatch.sourcefiles) do
- target:fileconfig_add(sourcefile, {public = true})
- end
- end
- end
- end
- end)
+ on_config("config")
-- build modules
rule("c++.build.modules.builder")
@@ -71,117 +35,22 @@ rule("c++.build.modules.builder")
set_extensions(".mpp", ".mxx", ".cppm", ".ixx")
-- generate module dependencies
- on_prepare_files(function (target, jobgraph, sourcebatch, opt)
- if target:data("cxx.has_modules") then
- import("builder")
- import("scanner")
-
- -- patch sourcebatch
- builder.patch_sourcebatch(target, sourcebatch)
-
- -- generate module dependencies
- scanner.generate_module_dependencies(target, jobgraph, sourcebatch, opt)
- end
- end, {jobgraph = true})
+ on_prepare_files("scanner", {jobgraph = true})
-- 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("support")
- import("scanner")
- import("builder")
-
- -- get module dependencies
- local modules = scanner.get_module_dependencies(target, sourcebatch)
- if not target:is_moduleonly() then
- -- avoid building non referenced modules
- local build_objectfiles, link_objectfiles = scanner.sort_modules_by_dependencies(target, sourcebatch.objectfiles, modules)
- sourcebatch.objectfiles = build_objectfiles
-
- -- build modules and headerunits
- builder.build_modules_and_headerunits(target, jobgraph, sourcebatch, modules, opt)
- sourcebatch.objectfiles = link_objectfiles
- else
- sourcebatch.objectfiles = {}
- end
-
- support.localcache():set2(target:fullname(), "c++.modules", modules)
- support.localcache():save()
- else
- -- avoid duplicate linking of object files of non-module programs
- sourcebatch.objectfiles = {}
- end
- end, {jobgraph = true, batch = true})
+ before_build_files("builder", {jobgraph = true, batch = true})
-- 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("support")
- import("scanner")
- import("builder")
-
- -- get module dependencies
- local modules = scanner.get_module_dependencies(target, sourcebatch)
- if not target:is_moduleonly() then
- -- avoid building non referenced modules
- local build_objectfiles, link_objectfiles = scanner.sort_modules_by_dependencies(target, sourcebatch.objectfiles, modules)
- sourcebatch.objectfiles = build_objectfiles
-
- -- 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
-
- support.localcache():set2(target:fullname(), "c++.modules", modules)
- support.localcache():save()
- else
- sourcebatch.sourcefiles = {}
- sourcebatch.objectfiles = {}
- sourcebatch.dependfiles = {}
- end
- end)
+ before_buildcmd_files("builder")
after_clean(function (target)
- import("core.base.option")
- import("support")
- import("private.action.clean.remove_files")
-
- -- we cannot use target:data("cxx.has_modules"),
- -- because on_config will be not called when cleaning targets
- if support.contains_modules(target) then
- remove_files(support.modules_cachedir(target))
- if option.get("all") then
- remove_files(support.stlmodules_cachedir(target))
- support.localcache():clear()
- support.localcache():save()
- end
- end
+ import("builder.clean")
end)
-- install modules
rule("c++.build.modules.install")
set_extensions(".mpp", ".mxx", ".cppm", ".ixx")
- before_install(function (target)
- import("support")
- import("builder")
-
- -- we cannot use target:data("cxx.has_modules"),
- -- because on_config will be not called when installing targets
- if support.contains_modules(target) then
- local modules = support.localcache():get2(target:fullname(), "c++.modules")
- builder.generate_metadata(target, modules)
+ before_install("builder.install")
- support.add_installfiles_for_modules(target)
- end
- end)
-
- before_uninstall(function (target)
- import("support")
- if support.contains_modules(target) then
- support.add_installfiles_for_modules(target)
- end
- end)
+ before_uninstall("builder.uninstall")