diff --git a/tests/projects/c++/modules/link_order/xmake.lua b/tests/projects/c++/modules/link_order/xmake.lua index b062dbe66f4..4cb2af87f45 100644 --- a/tests/projects/c++/modules/link_order/xmake.lua +++ b/tests/projects/c++/modules/link_order/xmake.lua @@ -2,14 +2,12 @@ add_rules("mode.release", "mode.debug") set_languages("c++20") target("foo") - add_rules("c++") - set_kind("static") - add_files("src/foo.mpp", {public = true}) + set_kind("moduleonly") + add_files("src/foo.mpp") target("bar") - add_rules("c++") - set_kind("static") - add_files("src/bar.mpp", {public = true}) + set_kind("moduleonly") + add_files("src/bar.mpp") target("link_order_1") set_kind("binary") diff --git a/tests/projects/c++/modules/staticlib_without_cpp/src/mod.mpp b/tests/projects/c++/modules/moduleonly/src/mod.mpp similarity index 100% rename from tests/projects/c++/modules/staticlib_without_cpp/src/mod.mpp rename to tests/projects/c++/modules/moduleonly/src/mod.mpp diff --git a/tests/projects/c++/modules/staticlib_without_cpp/test.lua b/tests/projects/c++/modules/moduleonly/test.lua similarity index 100% rename from tests/projects/c++/modules/staticlib_without_cpp/test.lua rename to tests/projects/c++/modules/moduleonly/test.lua diff --git a/tests/projects/c++/modules/staticlib_without_cpp/xmake.lua b/tests/projects/c++/modules/moduleonly/xmake.lua similarity index 79% rename from tests/projects/c++/modules/staticlib_without_cpp/xmake.lua rename to tests/projects/c++/modules/moduleonly/xmake.lua index a0609141429..54c681cc870 100644 --- a/tests/projects/c++/modules/staticlib_without_cpp/xmake.lua +++ b/tests/projects/c++/modules/moduleonly/xmake.lua @@ -2,5 +2,5 @@ add_rules("mode.release", "mode.debug") set_languages("c++20") target("mod") - set_kind("static") + set_kind("moduleonly") add_files("src/mod.mpp") diff --git a/tests/projects/c++/modules/packages/my-repo/packages/b/bar2/src/bar.mpp b/tests/projects/c++/modules/packages/my-repo/packages/b/bar2/src/bar.mpp new file mode 100644 index 00000000000..ee9fb2c7805 --- /dev/null +++ b/tests/projects/c++/modules/packages/my-repo/packages/b/bar2/src/bar.mpp @@ -0,0 +1,8 @@ +export module bar2; + +export namespace bar { + const char *hello2() { + return "Hello world"; + } +} + diff --git a/tests/projects/c++/modules/packages/my-repo/packages/b/bar2/src/xmake.lua b/tests/projects/c++/modules/packages/my-repo/packages/b/bar2/src/xmake.lua new file mode 100644 index 00000000000..0324fa93188 --- /dev/null +++ b/tests/projects/c++/modules/packages/my-repo/packages/b/bar2/src/xmake.lua @@ -0,0 +1,6 @@ +add_rules("mode.release", "mode.debug") +set_languages("c++20") + +target("bar2") + set_kind("moduleonly") + add_files("*.mpp") diff --git a/tests/projects/c++/modules/packages/my-repo/packages/b/bar2/xmake.lua b/tests/projects/c++/modules/packages/my-repo/packages/b/bar2/xmake.lua new file mode 100644 index 00000000000..ffa208234fb --- /dev/null +++ b/tests/projects/c++/modules/packages/my-repo/packages/b/bar2/xmake.lua @@ -0,0 +1,7 @@ +package("bar2") + set_kind("library") + set_sourcedir(path.join(os.scriptdir(), "src")) + + on_install(function(package) + import("package.tools.xmake").install(package, {}) + end) diff --git a/tests/projects/c++/modules/packages/src/main.cpp b/tests/projects/c++/modules/packages/src/main.cpp index d12361c453a..d6f2218c07d 100644 --- a/tests/projects/c++/modules/packages/src/main.cpp +++ b/tests/projects/c++/modules/packages/src/main.cpp @@ -1,7 +1,9 @@ import foo; import bar; +import bar2; int main() { foo::say(bar::hello()); + foo::say(bar::hello2()); return 0; } diff --git a/tests/projects/c++/modules/packages/xmake.lua b/tests/projects/c++/modules/packages/xmake.lua index f772d666850..62dba119b23 100644 --- a/tests/projects/c++/modules/packages/xmake.lua +++ b/tests/projects/c++/modules/packages/xmake.lua @@ -2,10 +2,10 @@ add_rules("mode.release", "mode.debug") set_languages("c++2b") add_repositories("my-repo my-repo") -add_requires("foo", "bar") +add_requires("foo", "bar", "bar2") target("packages") set_kind("binary") add_files("src/*.cpp") - add_packages("foo", "bar") + add_packages("foo", "bar", "bar2") set_policy("build.c++.modules", true) diff --git a/tests/projects/c++/modules/staticlib/xmake.lua b/tests/projects/c++/modules/staticlib/xmake.lua index d353774e455..9e1cf422174 100644 --- a/tests/projects/c++/modules/staticlib/xmake.lua +++ b/tests/projects/c++/modules/staticlib/xmake.lua @@ -3,7 +3,8 @@ set_languages("c++20") target("mod") set_kind("static") - add_files("src/mod.mpp", "src/mod.cpp", {public = true}) + add_files("src/mod.mpp", {public = true}) + add_files("src/mod.cpp") target("hello") set_kind("binary") diff --git a/tests/projects/c++/modules/user_headerunit2/a/xmake.lua b/tests/projects/c++/modules/user_headerunit2/a/xmake.lua index 3225b2814cd..a3c5906fcef 100644 --- a/tests/projects/c++/modules/user_headerunit2/a/xmake.lua +++ b/tests/projects/c++/modules/user_headerunit2/a/xmake.lua @@ -1,4 +1,5 @@ target("a") + set_kind("moduleonly") + add_headerfiles("*.hpp") + add_files("a.mpp") set_languages("cxxlatest") - set_kind("object") - add_files("a.mpp", {public = true}) diff --git a/tests/projects/c++/modules/user_headerunit2/b/xmake.lua b/tests/projects/c++/modules/user_headerunit2/b/xmake.lua index 24f9c9b1ffd..7a353ec26a3 100644 --- a/tests/projects/c++/modules/user_headerunit2/b/xmake.lua +++ b/tests/projects/c++/modules/user_headerunit2/b/xmake.lua @@ -1,5 +1,5 @@ target("b") add_deps("a") + set_kind("moduleonly") + add_files("b.mpp") set_languages("cxxlatest") - set_kind("object") - add_files("b.mpp", {public = true}) diff --git a/xmake/actions/build/build.lua b/xmake/actions/build/build.lua index bb0b61cc149..1db197cd602 100644 --- a/xmake/actions/build/build.lua +++ b/xmake/actions/build/build.lua @@ -65,7 +65,7 @@ function _add_batchjobs_builtin(batchjobs, rootjob, target) end -- uses the builtin target script - if not job and (target:is_static() or target:is_binary() or target:is_shared() or target:is_object()) then + if not job and (target:is_static() or target:is_binary() or target:is_shared() or target:is_object() or target:is_moduleonly()) then job, job_leaf = import("kinds." .. target:kind(), {anonymous = true})(batchjobs, rootjob, target) end job = job or rootjob diff --git a/xmake/actions/build/kinds/moduleonly.lua b/xmake/actions/build/kinds/moduleonly.lua new file mode 100644 index 00000000000..d177b8b97d6 --- /dev/null +++ b/xmake/actions/build/kinds/moduleonly.lua @@ -0,0 +1,22 @@ +--!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 moduleonly.lua +-- + +-- imports +inherit("object") diff --git a/xmake/actions/package/local/main.lua b/xmake/actions/package/local/main.lua index 90495dae484..f27cbd0911c 100644 --- a/xmake/actions/package/local/main.lua +++ b/xmake/actions/package/local/main.lua @@ -25,6 +25,8 @@ import("core.project.rule") import("core.project.config") import("core.project.project") import("core.base.bit") +import("rules.c++.modules.modules_support.compiler_support", {alias = "module_compiler_support", rootdir = os.programdir()}) +import("rules.c++.modules.modules_support.builder", {alias = "module_builder", rootdir = os.programdir()}) -- get library deps function _get_librarydeps(target) @@ -95,6 +97,7 @@ function _package_library(target) local binarydir = path.join(packagedir, target:plat(), target:arch(), config.mode(), "bin") local librarydir = path.join(packagedir, target:plat(), target:arch(), config.mode(), "lib") local headerdir = path.join(packagedir, target:plat(), target:arch(), config.mode(), "include") + local modulesdir = path.join(packagedir, target:plat(), target:arch(), config.mode(), "modules") -- copy the library file to the output directory local targetfile = target:targetfile() @@ -142,6 +145,30 @@ function _package_library(target) end end + -- copy modules + if target:data("cxx.has_modules") then + + local modules = module_compiler_support.localcache():get2(target:name(), "c++.modules") + module_builder.generate_metadata(target, modules) + + local sourcebatch = target:sourcebatches()["c++.build.modules.install"] + if sourcebatch and sourcebatch.sourcefiles then + for _, sourcefile in ipairs(sourcebatch.sourcefiles) do + local fileconfig = target:fileconfig(sourcefile) + local install = fileconfig and fileconfig.public or false + if install then + local modulehash = module_compiler_support.get_modulehash(target, sourcefile) + local prefixdir = path.join(modulesdir, modulehash) + os.vcp(sourcefile, path.join(prefixdir, path.filename(sourcefile))) + local metafile = module_compiler_support.get_metafile(target, sourcefile) + if os.exists(metafile) then + os.vcp(metafile, path.join(prefixdir, path.filename(metafile))) + end + end + end + end + end + -- generate xmake.lua local file = io.open(path.join(packagedir, "xmake.lua"), "w") if file then @@ -261,6 +288,78 @@ function _package_headeronly(target) print("package(%s): %s generated", packagename, packagedir) end +function _package_moduleonly(target) + + -- get the output directory + local packagedir = target:packagedir() + local packagename = target:name():lower() + local headerdir = path.join(packagedir, target:plat(), target:arch(), config.mode(), "include") + local modulesdir = path.join(packagedir, target:plat(), target:arch(), config.mode(), "modules") + + local modules = module_compiler_support.localcache():get2(target:name(), "c++.modules") + module_builder.generate_metadata(target, modules) + + -- copy headers + local srcheaders, dstheaders = target:headerfiles(headerdir) + if srcheaders and dstheaders then + local i = 1 + for _, srcheader in ipairs(srcheaders) do + local dstheader = dstheaders[i] + if dstheader then + os.vcp(srcheader, dstheader) + end + i = i + 1 + end + end + + -- copy modules + local sourcebatch = target:sourcebatches()["c++.build.modules.install"] + if sourcebatch and sourcebatch.sourcefiles then + for _, sourcefile in ipairs(sourcebatch.sourcefiles) do + local modulehash = module_compiler_support.get_modulehash(target, sourcefile) + local prefixdir = path.join(modulesdir, modulehash) + os.vcp(sourcefile, path.join(prefixdir, path.filename(sourcefile))) + local metafile = module_compiler_support.get_metafile(target, sourcefile) + if os.exists(metafile) then + os.vcp(metafile, path.join(prefixdir, path.filename(metafile))) + end + end + end + + -- generate xmake.lua + local file = io.open(path.join(packagedir, "xmake.lua"), "w") + if file then + local deps = _get_librarydeps(target) + file:print("package(\"%s\")", packagename) + local homepage = option.get("homepage") + if homepage then + file:print(" set_homepage(\"%s\")", homepage) + end + local description = option.get("description") or ("The " .. packagename .. " package") + file:print(" set_description(\"%s\")", description) + if target:license() then + file:print(" set_license(\"%s\")", target:license()) + end + if #deps > 0 then + file:print(" add_deps(\"%s\")", table.concat(deps, "\", \"")) + end + file:print("") + file:print([[ + on_load(function (package) + package:set("installdir", path.join(os.scriptdir(), package:plat(), package:arch(), package:mode())) + end) + + on_fetch(function (package) + local result = {} + result.includedirs = package:installdir("include") + return result + end)]]) + file:close() + end + + -- show tips + print("package(%s): %s generated", packagename, packagedir) +end -- do package target function _do_package_target(target) if not target:is_phony() then @@ -269,6 +368,7 @@ function _do_package_target(target) binary = _package_binary , static = _package_library , shared = _package_library + , moduleonly = _package_moduleonly , headeronly = _package_headeronly } local kind = target:kind() diff --git a/xmake/core/project/target.lua b/xmake/core/project/target.lua index 8cc2ff824ca..b6835a277ad 100644 --- a/xmake/core/project/target.lua +++ b/xmake/core/project/target.lua @@ -1201,9 +1201,14 @@ function _instance:is_headeronly() return self:kind() == "headeronly" end +-- is moduleonly target? +function _instance:is_moduleonly() + return self:kind() == "moduleonly" +end + -- is library target? function _instance:is_library() - return self:is_static() or self:is_shared() or self:is_headeronly() + return self:is_static() or self:is_shared() or self:is_headeronly() or self:is_moduleonly() end -- is default target? @@ -1555,7 +1560,7 @@ end function _instance:filename() -- no target file? - if self:is_object() or self:is_phony() or self:is_headeronly() then + if self:is_object() or self:is_phony() or self:is_headeronly() or self:is_moduleonly() then return end diff --git a/xmake/modules/private/check/checkers/api/target/kind.lua b/xmake/modules/private/check/checkers/api/target/kind.lua index 127f78ad5c1..5d716b1295a 100644 --- a/xmake/modules/private/check/checkers/api/target/kind.lua +++ b/xmake/modules/private/check/checkers/api/target/kind.lua @@ -23,5 +23,5 @@ import(".api_checker") function main(opt) opt = opt or {} - api_checker.check_targets("kind", table.join(opt, {values = {"object", "binary", "static", "shared", "headeronly", "phony"}})) + api_checker.check_targets("kind", table.join(opt, {values = {"object", "binary", "static", "shared", "headeronly", "moduleonly", "phony"}})) end diff --git a/xmake/modules/target/action/uninstall/main.lua b/xmake/modules/target/action/uninstall/main.lua index cc5feb3ac6c..daa23917cf8 100644 --- a/xmake/modules/target/action/uninstall/main.lua +++ b/xmake/modules/target/action/uninstall/main.lua @@ -26,6 +26,12 @@ function _uninstall_files(target) end end +-- uninstall modules +function _uninstall_modules(target, opt) + local moduledir = path.join(target:installdir(), opt and opt.moduledir or "modules") + os.vrm(moduledir) +end + -- the builtin uninstall main entry function main(target, opt) @@ -47,6 +53,9 @@ function main(target, opt) end end + -- remove modules + _uninstall_modules(target, opt) + -- uninstall the other files _uninstall_files(target) end diff --git a/xmake/plugins/project/cmake/cmakelists.lua b/xmake/plugins/project/cmake/cmakelists.lua index 6fcf38313bb..4402f080fd7 100644 --- a/xmake/plugins/project/cmake/cmakelists.lua +++ b/xmake/plugins/project/cmake/cmakelists.lua @@ -68,6 +68,7 @@ end function _escape_path(filepath) if is_host("windows") then filepath = filepath:gsub('\\', '/') + filepath = filepath:gsub(' ', '\\ ') end return filepath end @@ -323,6 +324,11 @@ function _add_target_headeronly(cmakelists, target) cmakelists:print("add_library(%s INTERFACE)", target:name()) end +-- add target: headeronly +function _add_target_moduleonly(cmakelists, target) + cmakelists:print("add_custom_target(%s)", target:name()) +end + -- add target dependencies function _add_target_dependencies(cmakelists, target) local deps = target:get("deps") @@ -340,8 +346,8 @@ function _add_target_sources(cmakelists, target, outputdir) local has_cuda = false cmakelists:print("target_sources(%s PRIVATE", target:name()) local sourcebatches = target:sourcebatches() - for _, sourcebatch in table.orderpairs(sourcebatches) do - if _sourcebatch_is_built(sourcebatch) then + for name, sourcebatch in table.orderpairs(sourcebatches) do + if _sourcebatch_is_built(sourcebatch) and not name:startswith("c++.build.modules") then for _, sourcefile in ipairs(sourcebatch.sourcefiles) do cmakelists:print(" " .. _get_relative_unix_path(sourcefile, outputdir)) end @@ -1003,6 +1009,9 @@ function _add_target(cmakelists, target, outputdir) _add_target_headeronly(cmakelists, target) _add_target_include_directories(cmakelists, target, outputdir) return + elseif targetkind == 'moduleonly' then + _add_target_moduleonly(cmakelists, target) + return else raise("unknown target kind %s", target:kind()) end diff --git a/xmake/plugins/project/vstudio/impl/vs201x.lua b/xmake/plugins/project/vstudio/impl/vs201x.lua index a8b48dada5f..b3c6f84c251 100644 --- a/xmake/plugins/project/vstudio/impl/vs201x.lua +++ b/xmake/plugins/project/vstudio/impl/vs201x.lua @@ -185,7 +185,6 @@ function _make_custom_commands_for_objectrules(commands, target, sourcebatch, vc scriptname = "buildcmd_file" .. (suffix and ("_" .. suffix) or "") script = ruleinst:script(scriptname) if script then - local sourcekind = sourcebatch.sourcekind for _, sourcefile in ipairs(sourcebatch.sourcefiles) do local batchcmds_ = batchcmds.new({target = target}) script(target, batchcmds_, sourcefile, {}) @@ -219,7 +218,7 @@ function _make_custom_commands(target, vcxprojdir) for _, sourcebatch in table.orderpairs(sourcebatches) do local rulename = sourcebatch.rulename local sourcekind = sourcebatch.sourcekind - if rulename ~= "c.build" and rulename ~= "c++.build" and rulename ~= "asm.build" and rulename ~= "cuda.build" and sourcekind ~= "mrc" then + if rulename ~= "c.build" and rulename ~= "c++.build" and not rulename:startswith("c++.build.modules") and rulename ~= "asm.build" and rulename ~= "cuda.build" and sourcekind ~= "mrc" then _make_custom_commands_for_objectrules(commands, target, sourcebatch, vcxprojdir, "before") _make_custom_commands_for_objectrules(commands, target, sourcebatch, vcxprojdir, nil) _make_custom_commands_for_objectrules(commands, target, sourcebatch, vcxprojdir, "after") @@ -256,6 +255,9 @@ function _make_targetinfo(mode, arch, target, vcxprojdir) -- save symbols targetinfo.symbols = target:get("symbols") + -- has modules + targetinfo.has_modules = target:data("cxx.has_modules") + -- save target kind targetinfo.targetkind = target:kind() if target:is_phony() or target:is_headeronly() then @@ -268,9 +270,6 @@ function _make_targetinfo(mode, arch, target, vcxprojdir) -- save symbol file targetinfo.symbolfile = target:symbolfile() - -- save sourcebatches - targetinfo.sourcebatches = target:sourcebatches() - -- save sourcekinds targetinfo.sourcekinds = target:sourcekinds() @@ -289,9 +288,9 @@ function _make_targetinfo(mode, arch, target, vcxprojdir) local sourcekind = sourcebatch.sourcekind local rulename = sourcebatch.rulename if sourcekind then - for idx, sourcefile in ipairs(sourcebatch.sourcefiles) do + for _, sourcefile in ipairs(sourcebatch.sourcefiles) do local compflags = compiler.compflags(sourcefile, {target = target, sourcekind = sourcekind}) - if not firstcompflags and (rulename == "c.build" or rulename == "c++.build" or rulename == "cuda.build") then + if not firstcompflags and (rulename == "c.build" or rulename == "c++.build" or rulename == "c++.build.modules" or rulename == "cuda.build") then firstcompflags = compflags end targetinfo.compflags[sourcefile] = compflags @@ -309,8 +308,11 @@ function _make_targetinfo(mode, arch, target, vcxprojdir) end end + -- save sourcebatches + targetinfo.sourcebatches = target:sourcebatches() + -- save linker flags - local linkflags = linker.linkflags(target:kind(), target:sourcekinds(), {target = target}) + local linkflags = linker.linkflags(target:is_moduleonly() and 'static' or target:kind(), target:sourcekinds(), {target = target}) targetinfo.linkflags = linkflags if table.contains(target:sourcekinds(), "cu") then @@ -323,7 +325,7 @@ function _make_targetinfo(mode, arch, target, vcxprojdir) end -- save execution dir (when executed from VS) - targetinfo.rundir = target:rundir() + targetinfo.rundir = target:is_moduleonly() and "" or target:rundir() -- save runenvs local targetrunenvs = {} @@ -544,6 +546,13 @@ function make(outputdir, vsinfo) -- save file groups _target.filegroups = table.unique(table.join(_target.filegroups or {}, target:get("filegroups"))) + -- save references to deps + for _, dep in ipairs(target:orderdeps()) do + _target.deps = _target.deps or {} + local dep_name = dep:name() + _target.deps[dep_name] = path.relative(path.join(vsinfo.solution_dir, dep_name, dep_name .. ".vcxproj"), _target.project_dir) + end + for filegroup, groupconf in pairs(target:extraconf("filegroups")) do _target.filegroups_extraconf = _target.filegroups_extraconf or {} local mergedconf = _target.filegroups_extraconf[filegroup] diff --git a/xmake/plugins/project/vstudio/impl/vs201x_vcxproj.lua b/xmake/plugins/project/vstudio/impl/vs201x_vcxproj.lua index f5bb88d738c..ee21e88b193 100644 --- a/xmake/plugins/project/vstudio/impl/vs201x_vcxproj.lua +++ b/xmake/plugins/project/vstudio/impl/vs201x_vcxproj.lua @@ -218,6 +218,17 @@ function _make_header(vcxprojfile, vsinfo) vcxprojfile:enter("", assert(vsinfo.project_version)) end +-- make references +function _make_references(vcxprojfile, vsinfo, target) + vcxprojfile:print("") + for dep_name, dep_vcxprojfile in pairs(target.deps) do + vcxprojfile:print("", dep_vcxprojfile) + vcxprojfile:print("{%s}", hash.uuid4(dep_name)) + vcxprojfile:print("") + end + vcxprojfile:print("") +end + -- make tailer function _make_tailer(vcxprojfile, vsinfo, target) vcxprojfile:print("") @@ -242,6 +253,7 @@ function _make_configurations(vcxprojfile, vsinfo, target) binary = "Application" , shared = "DynamicLibrary" , static = "StaticLibrary" + , moduleonly = "StaticLibrary" -- emulate moduleonly with staticlib } -- make ProjectConfigurations @@ -307,8 +319,10 @@ function _make_configurations(vcxprojfile, vsinfo, target) vcxprojfile:enter("", targetinfo.mode, targetinfo.arch) vcxprojfile:print("%s\\", _make_dirs(targetinfo.targetdir, target.project_dir)) vcxprojfile:print("%s\\", _make_dirs(targetinfo.objectdir, target.project_dir)) - vcxprojfile:print("%s", path.basename(targetinfo.targetfile)) - vcxprojfile:print("%s", path.extension(targetinfo.targetfile)) + if targetinfo.targetfile then + vcxprojfile:print("%s", path.basename(targetinfo.targetfile)) + vcxprojfile:print("%s", path.extension(targetinfo.targetfile)) + end if target.kind == "binary" then vcxprojfile:print("true") @@ -723,7 +737,7 @@ endlocal & call :xmErrorLevel %errorlevel% & goto :xmDone exit /b %1 :xmDone if %errorlevel% neq 0 goto :VCEnd]] - vcxprojfile:print("%s", cmdstr) + vcxprojfile:print("%s", cmdstr:replace("<", " <"):replace(">", ">"):replace("/Fo ", "/Fo")) if suffix == "after" or suffix == "after_link" then vcxprojfile:print("") elseif suffix == "before" then @@ -742,12 +756,12 @@ end -- make common item function _make_common_item(vcxprojfile, vsinfo, target, targetinfo) - -- init the linker kinds local linkerkinds = { binary = "Link" , static = "Lib" + , moduleonly = "Lib" -- emulate moduleonly with staticlib , shared = "Link" } if not linkerkinds[targetinfo.targetkind] then @@ -892,6 +906,10 @@ function _make_common_item(vcxprojfile, vsinfo, target, targetinfo) vcxprojfile:print("%s", cstandard) end + if targetinfo.has_modules then + vcxprojfile:enter("true") + end + -- use c or c++ precompiled header local pcheader = target.pcxxheader or target.pcheader if pcheader then @@ -959,9 +977,8 @@ function _build_common_items(vsinfo, target) for _, sourcebatch in pairs(targetinfo.sourcebatches) do local sourcekind = sourcebatch.sourcekind local rulename = sourcebatch.rulename - if (rulename == "c.build" or rulename == "c++.build" or rulename == "asm.build" or sourcekind == "mrc") then + if (rulename == "c.build" or rulename == "c++.build" or rulename == "c++.build.modules" or rulename == "asm.build" or sourcekind == "mrc") then for _, sourcefile in ipairs(sourcebatch.sourcefiles) do - -- make compiler flags local flags = _make_compflags(sourcefile, targetinfo, target.project_dir) @@ -1028,7 +1045,7 @@ function _build_common_items(vsinfo, target) for _, sourcefile in ipairs(sourcebatch.sourcefiles) do sourceflags[sourcefile] = targetinfo.sourceflags[sourcefile] end - elseif rulename == "c.build" or rulename == "c++.build" then -- sourcekind maybe bind multiple rules, e.g. c++modules + elseif rulename == "c.build" or rulename == "c++.build" or rulename == "c++.build.modules" then -- sourcekind maybe bind multiple rules, e.g. c++modules for _, sourcefile in ipairs(sourcebatch.sourcefiles) do local flags = targetinfo.sourceflags[sourcefile] local otherflags = {} @@ -1062,7 +1079,7 @@ function _make_common_items(vcxprojfile, vsinfo, target) -- for each mode and arch for _, targetinfo in ipairs(target.info) do -- make common item - _make_common_item(vcxprojfile, vsinfo, target, targetinfo, target.project_dir) + _make_common_item(vcxprojfile, vsinfo, target, targetinfo) end end @@ -1325,6 +1342,19 @@ function _make_source_files(vcxprojfile, vsinfo, target) sourceinfos[sourcefile] = sourceinfos[sourcefile] or {} table.insert(sourceinfos[sourcefile], {targetinfo = targetinfo, mode = targetinfo.mode, arch = targetinfo.arch, sourcekind = sourcekind, objectfile = objectfile, flags = flags, compargv = targetinfo.compargvs[sourcefile]}) end + elseif rulename == "c++.build.modules" then + local builder_batch = targetinfo.sourcebatches["c++.build.modules.builder"] + table.sort(builder_batch.objectfiles) + local objectfiles = builder_batch.objectfiles + for idx, sourcefile in ipairs(sourcebatch.sourcefiles) do + local is_named_module = table.contains(builder_batch.sourcefiles, sourcefile) + if is_named_module then + local objectfile = objectfiles[idx] + local flags = targetinfo.sourceflags[sourcefile] + sourceinfos[sourcefile] = sourceinfos[sourcefile] or {} + table.insert(sourceinfos[sourcefile], {targetinfo = targetinfo, mode = targetinfo.mode, arch = targetinfo.arch, sourcekind = "cxx", objectfile = objectfile, flags = flags, compargv = targetinfo.compargvs[sourcefile]}) + end + end end end end @@ -1386,6 +1416,9 @@ function make(vsinfo, target) -- make source files _make_source_files(vcxprojfile, vsinfo, target) + -- make deps references + _make_references(vcxprojfile, vsinfo, target) + -- make tailer _make_tailer(vcxprojfile, vsinfo, target) diff --git a/xmake/plugins/project/vsxmake/getinfo.lua b/xmake/plugins/project/vsxmake/getinfo.lua index e992c1bd488..af88b51f6c7 100644 --- a/xmake/plugins/project/vsxmake/getinfo.lua +++ b/xmake/plugins/project/vsxmake/getinfo.lua @@ -154,7 +154,7 @@ function _make_targetinfo(mode, arch, target) -- fix c++17 to cxx17 for Xmake.props targetinfo.languages = targetinfo.languages:replace("c++", "cxx", {plain = true}) end - if target:is_phony() or target:is_headeronly() then + if target:is_phony() or target:is_headeronly() or target:is_moduleonly() then return targetinfo end diff --git a/xmake/rules/c++/modules/modules_support/builder.lua b/xmake/rules/c++/modules/modules_support/builder.lua index 4ceb67b0baa..936f904142e 100644 --- a/xmake/rules/c++/modules/modules_support/builder.lua +++ b/xmake/rules/c++/modules/modules_support/builder.lua @@ -21,6 +21,7 @@ -- imports import("core.base.json") import("core.base.option") +import("async.runjobs") import("private.async.buildjobs") import("core.tool.compiler") import("core.project.config") @@ -31,8 +32,7 @@ import("dependency_scanner") -- build target modules function _build_modules(target, sourcebatch, modules, opt) - local objectfiles = dependency_scanner.sort_modules_by_dependencies(sourcebatch.objectfiles, modules) - + local objectfiles = sourcebatch.objectfiles _builder(target).populate_module_map(target, modules) -- build modules @@ -42,22 +42,15 @@ function _build_modules(target, sourcebatch, modules, opt) goto CONTINUE end - local name, provide, cppfile = compiler_support.get_provided_module(module) + local name, _, cppfile = compiler_support.get_provided_module(module) cppfile = cppfile or module.cppfile - local fileconfig = target:fileconfig(cppfile) - local bmifile = provide and compiler_support.get_bmi_path(provide.bmi) - -- add objectfile if module is not from external dep - if not (fileconfig and fileconfig.external) then - target:add("objectfiles", objectfile) - end - local deps = {} for _, dep in ipairs(table.keys(module.requires or {})) do table.insert(deps, opt.batchjobs and target:name() .. dep or dep) end - opt.build_module(deps, module, name, provide, objectfile, cppfile, fileconfig) + opt.build_module(deps, module, name, objectfile, cppfile) ::CONTINUE:: end @@ -198,21 +191,10 @@ function build_modules_for_batchjobs(target, batchjobs, sourcebatch, modules, op local modulesjobs = {} _build_modules(target, sourcebatch, modules, table.join(opt, { - build_module = function(deps, module, name, provide, objectfile, cppfile, fileconfig) + 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}) - - if provide and fileconfig and fileconfig.public then - batchjobs:addjob(name .. "_metafile", function(index, total) - local metafilepath = compiler_support.get_metafile(target, cppfile) - depend.on_changed(function() - progress.show((index * 100) / total, "${color.build.target}<%s> generating.module.metadata %s", target:name(), name) - local metadata = _generate_meta_module_info(target, name, cppfile, module.requires) - json.savefile(metafilepath, metadata) - end, {dependfile = target:dependfile(metafilepath), files = {cppfile}, changed = target:is_rebuilt()}) - end, {rootjob = opt.rootjob}) - end end })) @@ -228,17 +210,8 @@ function build_modules_for_batchcmds(target, batchcmds, sourcebatch, modules, op -- build modules _build_modules(target, sourcebatch, modules, table.join(opt, { - build_module = function(_, module, name, provide, objectfile, cppfile, fileconfig) + 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})) - - if provide and fileconfig and fileconfig.public then - local metafilepath = compiler_support.get_metafile(target, cppfile) - depend.on_changed(function() - progress.show(opt.progress, "${color.build.target}<%s> generating.module.metadata %s", target:name(), name) - local metadata = _generate_meta_module_info(target, name, cppfile, module.requires) - json.savefile(metafilepath, metadata) - end, {dependfile = target:dependfile(metafilepath), files = {cppfile}, changed = target:is_rebuilt()}) - end end })) @@ -312,6 +285,33 @@ function build_headerunits_for_batchcmds(target, batchcmds, sourcebatch, modules end end +function generate_metadata(target, modules) + local public_modules + for _, module in table.orderpairs(modules) do + local _, _, cppfile = compiler_support.get_provided_module(module) + local fileconfig = target:fileconfig(cppfile) + local public = fileconfig and fileconfig.public + if public then + public_modules = public_modules or {} + table.insert(public_modules, module) + end + end + + if not public_modules then + return + end + + local jobs = option.get("jobs") or os.default_njob() + runjobs(target:name() .. "_install_modules", function(index) + local module = public_modules[index] + local name, _, cppfile = compiler_support.get_provided_module(module) + local metafilepath = compiler_support.get_metafile(target, cppfile) + progress.show((index * 100) / #public_modules, "${color.build.target}<%s> generating.module.metadata %s", target:name(), name) + local metadata = _generate_meta_module_info(target, name, cppfile, module.requires) + json.savefile(metafilepath, metadata) + end, {comax = jobs, total = #public_modules}) +end + -- flush target module mapper keys function flush_target_module_mapper_keys(target) local memcache = compiler_support.memcache() diff --git a/xmake/rules/c++/modules/modules_support/clang/builder.lua b/xmake/rules/c++/modules/modules_support/clang/builder.lua index 15a53c00ba5..0e5f0b5bd43 100644 --- a/xmake/rules/c++/modules/modules_support/clang/builder.lua +++ b/xmake/rules/c++/modules/modules_support/clang/builder.lua @@ -38,12 +38,12 @@ function _make_modulebuildflags(target, provide, bmifile, opt) local flags local precompile = false - if module_outputflag and provide and not opt.external then -- one step compilation of named module, clang >= 16 + if module_outputflag and provide and opt.build_objectfile then -- one step compilation of named module, clang >= 16 flags = {{"-x", "c++-module", module_outputflag .. bmifile}} elseif provide then -- two step compilation of named module precompile = true flags = {{"-x", "c++-module", "--precompile"}} - if not opt.external then + if opt.build_objectfile then table.insert(flags, {}) end else -- internal module, no bmi needed @@ -199,7 +199,7 @@ function make_module_buildjobs(target, batchjobs, job_name, deps, opt) return { name = job_name, deps = deps, - sourcefile = cppfile, + sourcefile = opt.cppfile, job = batchjobs:newjob(name or opt.cppfile, function(index, total) local compinst = compiler.load("cxx", {target = target}) @@ -242,10 +242,12 @@ function make_module_buildjobs(target, batchjobs, job_name, deps, opt) end end - local fileconfig = target:fileconfig(opt.cppfile) - local external = fileconfig and fileconfig.external + local fileconfig = target:fileconfig(opt.cppfile) + local public = fileconfig and fileconfig.public + local external = fileconfig and fileconfig.external + local build_objectfile = target:kind() == "binary" or (not public and not external) - local precompile, first_step, second_step = _make_modulebuildflags(target, provide, bmifile, {sourcefile = opt.cppfile, external = external, name = name}) + local precompile, first_step, second_step = _make_modulebuildflags(target, provide, bmifile, {sourcefile = opt.cppfile, build_objectfile = build_objectfile, name = name}) _compile(target, first_step, opt.cppfile, precompile and bmifile or opt.objectfile) @@ -289,6 +291,7 @@ function make_module_buildcmds(target, batchcmds, opt) build = should_build(target, opt.cppfile, bmifile, {objectfile = opt.objectfile, requires = opt.module.requires}) end + local build_objectfile = target:kind() == "binary" if build then -- compile if it's a named module if provide or compiler_support.has_module_extension(opt.cppfile) then @@ -296,9 +299,11 @@ function make_module_buildcmds(target, batchcmds, opt) batchcmds:mkdir(path.directory(opt.objectfile)) local fileconfig = target:fileconfig(opt.cppfile) + local public = fileconfig and fileconfig.public local external = fileconfig and fileconfig.external + local build_objectfile = target:kind() == "binary" or (not public and not external) - local precompile, first_step, second_step = _make_modulebuildflags(target, provide, bmifile, {batchcmds = true, sourcefile = opt.cppfile, external = external, name = name}) + local precompile, first_step, second_step = _make_modulebuildflags(target, provide, bmifile, {batchcmds = true, sourcefile = opt.cppfile, build_objectfile = build_objectfile, name = name}) _batchcmds_compile(batchcmds, target, first_step, opt.cppfile, precompile and bmifile or opt.objectfile) if second_step then diff --git a/xmake/rules/c++/modules/modules_support/compiler_support.lua b/xmake/rules/c++/modules/modules_support/compiler_support.lua index 52ee86a57e5..d11e833fd83 100644 --- a/xmake/rules/c++/modules/modules_support/compiler_support.lua +++ b/xmake/rules/c++/modules/modules_support/compiler_support.lua @@ -64,14 +64,26 @@ function patch_sourcebatch(target, sourcebatch) end -- cull sourcebatch objectfiles -function cull_objectfiles(target, sourcebatch) +function cull_objectfiles(target, modules, sourcebatch) + + -- don't cull for executables + if target:is_binary() then + return + end - sourcebatch.sourcekind = "cxx" sourcebatch.objectfiles = {} for _, sourcefile in ipairs(sourcebatch.sourcefiles) do - local fileconfig = target:fileconfig(sourcefile) - if not (fileconfig and fileconfig.external) then - local objectfile = target:objectfile(sourcefile) + local objectfile = target:objectfile(sourcefile) + local module = modules[objectfile] + local _, provide, _ = get_provided_module(module) + if provide then + local fileconfig = target:fileconfig(sourcefile) + local public = fileconfig and fileconfig.public + local external = fileconfig and fileconfig.external + if not public and not external then + table.insert(sourcebatch.objectfiles, objectfile) + end + else table.insert(sourcebatch.objectfiles, objectfile) end end diff --git a/xmake/rules/c++/modules/modules_support/dependency_scanner.lua b/xmake/rules/c++/modules/modules_support/dependency_scanner.lua index 7ad34475006..0b02292ef85 100644 --- a/xmake/rules/c++/modules/modules_support/dependency_scanner.lua +++ b/xmake/rules/c++/modules/modules_support/dependency_scanner.lua @@ -182,7 +182,7 @@ function _get_edges(nodes, modules) for _, required_node in ipairs(nodes) do local name, _, _ = compiler_support.get_provided_module(modules[required_node]) if name and name == required_name then - table.insert(edges, {node, required_node}) + table.insert(edges, {required_node, node}) break end end @@ -396,9 +396,9 @@ function get_all_packages_modules(target, opt) end -- topological sort -function sort_modules_by_dependencies(objectfiles, modules) +function sort_modules_by_dependencies(target, objectfiles, modules) local result = {} - local edges, nodeps_nodes = _get_edges(objectfiles, modules) + local edges = _get_edges(objectfiles, modules) local dag = graph.new(true) for _, e in ipairs(edges) do dag:add_edge(e[1], e[2]) @@ -418,10 +418,17 @@ function sort_modules_by_dependencies(objectfiles, modules) for _, objectfile in ipairs(objectfiles_sorted) do table.insert(result, objectfile) end + local objectfiles_sorted_set = hashset.from(objectfiles_sorted) for _, objectfile in ipairs(objectfiles) do if not objectfiles_sorted_set:has(objectfile) then - table.insert(result, objectfile) + -- cull unreferenced non-public named module but add non-module files and implementation modules + local _, provide, cppfile = compiler_support.get_provided_module(modules[objectfile]) + local fileconfig = target:fileconfig(cppfile) + local public = fileconfig and fileconfig.public + if not provide or public then + table.insert(result, objectfile) + end end end return result diff --git a/xmake/rules/c++/modules/modules_support/gcc/builder.lua b/xmake/rules/c++/modules/modules_support/gcc/builder.lua index 7e96c3fcc59..c4c9871e212 100644 --- a/xmake/rules/c++/modules/modules_support/gcc/builder.lua +++ b/xmake/rules/c++/modules/modules_support/gcc/builder.lua @@ -99,31 +99,14 @@ end function _get_maplines(target, module) local maplines = {} - local m_name, m = compiler_support.get_provided_module(module) + local m_name, m, cppfile = compiler_support.get_provided_module(module) if m then table.insert(maplines, m_name .. " " .. compiler_support.get_bmi_path(m.bmi)) end for required, _ in table.orderpairs(module.requires) do - local dep_module - local dep_target - for _, dep in ipairs(target:orderdeps()) do - dep_module = get_from_target_mapper(dep, required) - if dep_module then - dep_target = dep - break - end - end - - -- if not in target dep - if not dep_module then - dep_module = get_from_target_mapper(target, required) - if dep_module then - dep_target = target - end - end - - assert(dep_module, "module dependency %s required for %s not found", required, m_name) + local dep_module = get_from_target_mapper(target, required) + assert(dep_module, "module dependency %s required for %s not found", required, m_name or module.cppfile) local bmifile = dep_module.bmi local mapline @@ -143,7 +126,7 @@ function _get_maplines(target, module) -- append deps if dep_module.opt and dep_module.opt.deps then - local deps = _get_maplines(dep_target, { name = dep_module.name, bmi = bmifile, requires = dep_module.opt.deps }) + local deps = _get_maplines(target, {name = dep_module.name, bmi = bmifile, requires = dep_module.opt.deps}) table.join2(maplines, deps) end end @@ -173,16 +156,6 @@ end -- populate module map function populate_module_map(target, modules) - - -- append all modules - for _, module in pairs(modules) do - local name, provide = compiler_support.get_provided_module(module) - if provide then - add_module_to_target_mapper(target, name, provide.sourcefile, compiler_support.get_bmi_path(provide.bmi)) - end - end - - -- then update their deps for _, module in pairs(modules) do local name, provide = compiler_support.get_provided_module(module) if provide then diff --git a/xmake/rules/c++/modules/modules_support/gcc/compiler_support.lua b/xmake/rules/c++/modules/modules_support/gcc/compiler_support.lua index a598f39f582..c365a107a27 100644 --- a/xmake/rules/c++/modules/modules_support/gcc/compiler_support.lua +++ b/xmake/rules/c++/modules/modules_support/gcc/compiler_support.lua @@ -99,7 +99,6 @@ end -- not supported atm function get_stdmodules(target) - return {} end function get_bmi_extension() diff --git a/xmake/rules/c++/modules/modules_support/msvc/builder.lua b/xmake/rules/c++/modules/modules_support/msvc/builder.lua index 10a0ad409c7..3fc86b36975 100644 --- a/xmake/rules/c++/modules/modules_support/msvc/builder.lua +++ b/xmake/rules/c++/modules/modules_support/msvc/builder.lua @@ -37,11 +37,11 @@ function _make_modulebuildflags(target, provide, bmifile, opt) local ifconlyflag = compiler_support.get_ifconlyflag(target) local interfaceflag = compiler_support.get_interfaceflag(target) local internalpartitionflag = compiler_support.get_internalpartitionflag(target) - local ifconly = (opt.external and ifconlyflag) + local ifconly = (not opt.build_objectfile and ifconlyflag) local flags if provide then -- named module - flags = table.join({"-TP", ifcoutputflag, bmifile, provide.interface and interfaceflag or internalpartitionflag}, ifconly or {}) + flags = table.join({"-TP", ifcoutputflag, path(bmifile), provide.interface and interfaceflag or internalpartitionflag}, ifconly or {}) else flags = {"-TP"} end @@ -102,8 +102,8 @@ function _batchcmds_compile(batchcmds, target, flags, sourcefile, outputfile) opt = opt or {} local compinst = target:compiler("cxx") local compflags = compinst:compflags({sourcefile = sourcefile, target = target}) - flags = table.join("-c", compflags or {}, flags, {"/Fo", outputfile, sourcefile}) - batchcmds:compilev(flags, {compiler = compinst, sourcekind = "cxx"}) + flags = table.join(compflags or {}, flags) + batchcmds:compile(sourcefile, outputfile, {sourcekind = "cxx", compflags = flags}) end -- get module requires flags @@ -260,8 +260,10 @@ function make_module_buildjobs(target, batchjobs, job_name, deps, opt) end local fileconfig = target:fileconfig(opt.cppfile) + local public = fileconfig and fileconfig.public local external = fileconfig and fileconfig.external - local flags = _make_modulebuildflags(target, provide, bmifile, {external = external}) + local build_objectfile = target:kind() == "binary" or (not public and not external) + local flags = _make_modulebuildflags(target, provide, bmifile, {build_objectfile = build_objectfile}) _compile(target, flags, opt.cppfile, opt.objectfile) else @@ -276,7 +278,7 @@ function make_module_buildjobs(target, batchjobs, job_name, deps, opt) end -- build module file for batchcmds -function make_module_buildcmds(target, batchcmds, should_build, mark_build, opt) +function make_module_buildcmds(target, batchcmds, opt) local name, provide, _ = compiler_support.get_provided_module(opt.module) local bmifile = provide and compiler_support.get_bmi_path(provide.bmi) @@ -308,9 +310,11 @@ function make_module_buildcmds(target, batchcmds, should_build, mark_build, opt) batchcmds:mkdir(path.directory(opt.objectfile)) local fileconfig = target:fileconfig(opt.cppfile) - local external = fileconfig and fileconfig.external - local flags = _make_modulebuildflags(target, provide, bmifile, opt.cppfile, opt.objectfile, {batchcmds = true, external = external}) - _batchcmds_compile(batchcmds, target, flags, opt.cppfile, objectfile) + local public = fileconfig and fileconfig.public + local external = fileconfig and fileconfig.external + local build_objectfile = target:kind() == "binary" or (not public and not external) + local flags = _make_modulebuildflags(target, provide, bmifile, {build_objectfile = build_objectfile}) + _batchcmds_compile(batchcmds, target, flags, opt.cppfile, opt.objectfile) else batchcmds:rm(opt.objectfile) -- force rebuild for .cpp files end diff --git a/xmake/rules/c++/modules/modules_support/msvc/compiler_support.lua b/xmake/rules/c++/modules/modules_support/msvc/compiler_support.lua index 662fd603e8b..e65effa1110 100644 --- a/xmake/rules/c++/modules/modules_support/msvc/compiler_support.lua +++ b/xmake/rules/c++/modules/modules_support/msvc/compiler_support.lua @@ -88,7 +88,6 @@ function get_stdmodules(target) end end end - return {} end function get_bmi_extension() diff --git a/xmake/rules/c++/modules/xmake.lua b/xmake/rules/c++/modules/xmake.lua index ecb79f65b7c..922841cd1d0 100644 --- a/xmake/rules/c++/modules/xmake.lua +++ b/xmake/rules/c++/modules/xmake.lua @@ -52,6 +52,14 @@ rule("c++.build.modules") -- 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"] + for _, sourcefile in ipairs(sourcebatch.sourcefiles) do + target:fileconfig_add(sourcefile, {public = true}) + end + end end end) @@ -76,7 +84,12 @@ rule("c++.build.modules.builder") end -- append std module - table.join2(sourcebatch.sourcefiles, compiler_support.get_stdmodules(target) or {}) + local std_modules = compiler_support.get_stdmodules(target) + if std_modules then + table.join2(sourcebatch.sourcefiles, std_modules) + target:fileconfig_set(std_modules[1], {external = true}) + target:fileconfig_set(std_modules[2], {external = true}) + end -- extract packages modules dependencies local package_modules_data = dependency_scanner.get_all_packages_modules(target, opt) @@ -84,23 +97,34 @@ rule("c++.build.modules.builder") -- append to sourcebatch for _, package_module_data in table.orderpairs(package_modules_data) do table.insert(sourcebatch.sourcefiles, package_module_data.file) - target:fileconfig_add(package_module_data.file, {external = true, defines = package_module_data.metadata.defines}) + target:fileconfig_set(package_module_data.file, {external = true, defines = package_module_data.metadata.defines}) end end + opt = opt or {} opt.batchjobs = true compiler_support.patch_sourcebatch(target, sourcebatch, opt) local modules = dependency_scanner.get_module_dependencies(target, sourcebatch, opt) - -- build modules - builder.build_modules_for_batchjobs(target, batchjobs, sourcebatch, modules, opt) + if not target:is_moduleonly() then + -- avoid building non referenced modules + sourcebatch.objectfiles = dependency_scanner.sort_modules_by_dependencies(target, sourcebatch.objectfiles, modules) - -- build headerunits and we need to do it before building modules - builder.build_headerunits_for_batchjobs(target, batchjobs, sourcebatch, modules, opt) + -- 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) + + -- cull external modules objectfile + compiler_support.cull_objectfiles(target, modules, sourcebatch) + else + sourcebatch.objectfiles = {} + end - -- cull external modules objectfile - compiler_support.cull_objectfiles(target, sourcebatch) + compiler_support.localcache():set2(target:name(), "c++.modules", modules) + compiler_support.localcache():save() else -- avoid duplicate linking of object files of non-module programs sourcebatch.objectfiles = {} @@ -123,7 +147,12 @@ rule("c++.build.modules.builder") end -- append std module - table.join2(sourcebatch.sourcefiles, compiler_support.get_stdmodules(target) or {}) + local std_modules = compiler_support.get_stdmodules(target) + if std_modules then + table.join2(sourcebatch.sourcefiles, std_modules) + target:fileconfig_set(std_modules[1], {external = true}) + target:fileconfig_set(std_modules[2], {external = true}) + end -- extract packages modules dependencies local package_modules_data = dependency_scanner.get_all_packages_modules(target, opt) @@ -131,26 +160,39 @@ rule("c++.build.modules.builder") -- append to sourcebatch for _, package_module_data in table.orderpairs(package_modules_data) do table.insert(sourcebatch.sourcefiles, package_module_data.file) - target:fileconfig_add(package_module_data.file, {external = true, defines = package_module_data.metadata.defines}) + target:fileconfig_set(package_module_data.file, {external = true, 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) - -- build headerunits - builder.build_headerunits_for_batchcmds(target, batchcmds, sourcebatch, modules, opt) + if not target:is_moduleonly() then + -- avoid building non referenced modules + sourcebatch.objectfiles = dependency_scanner.sort_modules_by_dependencies(target, sourcebatch.objectfiles, modules) + + -- 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 modules - builder.build_modules_for_batchcmds(target, batchcmds, sourcebatch, modules, opt) + -- cull external modules objectfile + compiler_support.cull_objectfiles(target, modules, sourcebatch) + else + -- avoid duplicate linking of object files of non-module programs + sourcebatch.objectfiles = {} + end - -- cull external modules objectfile - compiler_support.cull_objectfiles(target, sourcebatch) + compiler_support.localcache():set2(target:name(), "c++.modules", modules) + compiler_support.localcache():save() else - -- avoid duplicate linking of object files of non-module programs + sourcebatch.sourcefiles = {} sourcebatch.objectfiles = {} + sourcebatch.dependfiles = {} end end) @@ -177,10 +219,14 @@ rule("c++.build.modules.install") before_install(function (target) import("modules_support.compiler_support") + import("modules_support.builder") -- 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") + builder.generate_metadata(target, modules) + compiler_support.install_module_target(target) end end) diff --git a/xmake/scripts/vsxmake/vsproj/Xmake.props b/xmake/scripts/vsxmake/vsproj/Xmake.props index 3e3a3329825..990a9505684 100644 --- a/xmake/scripts/vsxmake/vsproj/Xmake.props +++ b/xmake/scripts/vsxmake/vsproj/Xmake.props @@ -94,6 +94,11 @@ Unknown + + + Unknown + +