diff options
| author | Arthur LAURENT <[email protected]> | 2025-04-22 18:40:37 +0200 |
|---|---|---|
| committer | Arthur LAURENT <[email protected]> | 2025-04-22 18:40:37 +0200 |
| commit | f49af9018f3efbcdf3d49bb30c6663b300f1a133 (patch) | |
| tree | c047b0622ec6aa2b8f12a6c4dd19f2b1cbf1f768 | |
| parent | 40bfb6e1980d81454c9592da7eaaf0aded11f1ec (diff) | |
(C++ modules) cleanup module rules
| -rw-r--r-- | xmake/rules/c++/modules/builder.lua | 107 | ||||
| -rw-r--r-- | xmake/rules/c++/modules/config.lua | 58 | ||||
| -rw-r--r-- | xmake/rules/c++/modules/scanner.lua | 127 | ||||
| -rw-r--r-- | xmake/rules/c++/modules/xmake.lua | 145 |
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") |
