diff options
| author | Arthur Laurent <[email protected]> | 2023-01-08 15:55:56 +0100 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-01-08 15:55:56 +0100 |
| commit | 8749422a005d5150fccbfe807fbc618361a2afa1 (patch) | |
| tree | 51809e3b148bcf03bb4514e837f253ca5dc92808 | |
| parent | c394913eafbc3a24485a0c88b0d891e9954b302b (diff) | |
| parent | 476f1c3592aa55cd10a6986c045f1be834cf2a83 (diff) | |
Merge branch 'dev' into improve-clang-modules-support-with-libc++
33 files changed, 432 insertions, 89 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 849816da3..5f0fc2148 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,16 @@ ### New features +* [#3228](https://github.com/xmake-io/xmake/pull/3228): Add support of importing modules from packages + +### Bugs fixed + +* [#3229](https://github.com/xmake-io/xmake/issues/3229): Fix find rc.exe for vs2015 + +## v2.7.5 + +### New features + * [#3201](https://github.com/xmake-io/xmake/pull/3201): Add completer and xrepo complete * [#3233](https://github.com/xmake-io/xmake/issues/3233): Add MASM32 sdk toolchain @@ -1487,6 +1497,16 @@ ### 新特性 +* [#3228](https://github.com/xmake-io/xmake/pull/3228): C++ modules 的安装发布,以及从包中导入 C++ modules 支持 + +### Bugs 修复 + +* [#3229](https://github.com/xmake-io/xmake/issues/3229): 修复 vs2015 下找不到 rc.exe 问题 + +## v2.7.5 + +### 新特性 + * [#3201](https://github.com/xmake-io/xmake/pull/3201): 为 xrepo 添加命令自动补全 * [#3233](https://github.com/xmake-io/xmake/issues/3233): 添加 MASM32 sdk 工具链 @@ -3290,12 +3290,21 @@ _check_cxxsnippets() { # check option _check_option() { local name="${1}" - _get_option_item "${name}" "before_check"; local before_check="${_ret}" - if test_nz "${before_check}"; then - eval ${before_check} - fi - if _check_csnippets "${name}" && _check_cxxsnippets "${name}"; then - return 0 + _get_option_value "${name}"; local value="${_ret}" + if test_nz "${value}"; then + if _is_enabled "${value}"; then + return 0 + else + return 1 + fi + else + _get_option_item "${name}" "before_check"; local before_check="${_ret}" + if test_nz "${before_check}"; then + eval ${before_check} + fi + if _check_csnippets "${name}" && _check_cxxsnippets "${name}"; then + return 0 + fi fi return 1 } diff --git a/core/src/xmake/os/syserror.c b/core/src/xmake/os/syserror.c index c93a4eeda..1ab6afb23 100644 --- a/core/src/xmake/os/syserror.c +++ b/core/src/xmake/os/syserror.c @@ -45,6 +45,7 @@ tb_int_t xm_os_syserror(lua_State* lua) { case TB_STATE_SYSERROR_NOT_PERM: err = 1; break; case TB_STATE_SYSERROR_NOT_FILEDIR: err = 2; break; + case TB_STATE_SYSERROR_NOT_ACCESS: err = 3; break; case TB_STATE_SYSERROR_UNKNOWN_ERROR: err = -1; break; } lua_pushinteger(lua, err); diff --git a/core/xmake.lua b/core/xmake.lua index a9f8a1066..d1eeb20b4 100644 --- a/core/xmake.lua +++ b/core/xmake.lua @@ -2,7 +2,7 @@ set_project("xmake") -- version -set_version("2.7.4", {build = "%Y%m%d%H%M"}) +set_version("2.7.5", {build = "%Y%m%d%H%M"}) -- set xmake min version set_xmakever("2.2.3") diff --git a/core/xmake.sh b/core/xmake.sh index 39a279b25..5de724427 100755 --- a/core/xmake.sh +++ b/core/xmake.sh @@ -1,7 +1,7 @@ #!/bin/sh set_project "xmake" -set_version "2.7.4" "%Y%m%d%H%M" +set_version "2.7.5" "%Y%m%d%H%M" # set warning all set_warnings "all" diff --git a/scripts/archlinux/PKGBUILD b/scripts/archlinux/PKGBUILD index 5ff7eed6a..d7a555c3f 100755 --- a/scripts/archlinux/PKGBUILD +++ b/scripts/archlinux/PKGBUILD @@ -2,7 +2,7 @@ # PKGBuild Create By: lumpyzhu <[email protected]> pkgname=xmake -pkgver=2.7.3 +pkgver=2.7.5 pkgrel=1 pkgdesc="A cross-platform build utility based on Lua" depends=('bash') @@ -14,12 +14,12 @@ source=("https://github.com/xmake-io/xmake/releases/download/v${pkgver}/xmake-v$ sha256sums=('3e71437ad2a59d1fbbc9fba75ab4ca8d428c49beefcce86c11f6c4710dd4b6f2') build() { - cd "$srcdir" + cd "${_realname}-${pkgver}" ./configure make } package() { - cd "$srcdir" - make install PREFIX="${pkgdir}/usr" + cd "${_realname}-${pkgver}" + make install DESTDIR="${pkgdir}" PREFIX="usr" } diff --git a/scripts/get.ps1 b/scripts/get.ps1 index 4cfa51416..3efb6b6a5 100755 --- a/scripts/get.ps1 +++ b/scripts/get.ps1 @@ -11,7 +11,7 @@ param ( ) & { - $LastRelease = "v2.7.3" + $LastRelease = "v2.7.5" $ErrorActionPreference = 'Stop' function writeErrorTip($msg) { diff --git a/scripts/msys/PKGBUILD b/scripts/msys/PKGBUILD index 847b2f268..0dcb90b81 100644 --- a/scripts/msys/PKGBUILD +++ b/scripts/msys/PKGBUILD @@ -16,12 +16,12 @@ source=("${_realname}-${pkgver}.tar.gz"::"https://github.com/xmake-io/${_realnam sha256sums=('c927efad5412c3bdb8bad1be5b1b2ea40a998dff2a252edb443782865b7472b9') build() { - cd "$srcdir" + cd "${_realname}-${pkgver}" ./configure make } package() { - cd "$srcdir" + cd "${_realname}-${pkgver}" make install PREFIX="${pkgdir}/usr" } diff --git a/scripts/rpmbuild/SPECS/xmake.spec b/scripts/rpmbuild/SPECS/xmake.spec index 528f84d67..c530598f8 100644 --- a/scripts/rpmbuild/SPECS/xmake.spec +++ b/scripts/rpmbuild/SPECS/xmake.spec @@ -1,5 +1,5 @@ -%define xmake_revision 69f7fc412e8a270d9019446fe20e150e0ed806cb -%define tbox_revision 1c6fcb6b7732b6c632f501dbd1ac4ea622220e7d +%define xmake_revision 5b527d486b2a08c0cc4c721fbf673f8bd1c8551f +%define tbox_revision 513f0f36384c540002787c7362ede4efaf104d8a %define sv_revision 035262773da0500367cb88e6f30197908159a348 %define lua_cjson_revision ddcecf3b24b71421e7b4a2962f1fbcc0297e0c1e %define luajit_revision e9af1abec542e6f9851ff2368e7f196b6382a44c diff --git a/tests/projects/c++/modules/packages/my-repo/packages/b/bar/src/bar.cpp b/tests/projects/c++/modules/packages/my-repo/packages/b/bar/src/bar.cpp new file mode 100644 index 000000000..5bbb5e5c1 --- /dev/null +++ b/tests/projects/c++/modules/packages/my-repo/packages/b/bar/src/bar.cpp @@ -0,0 +1,5 @@ +module bar; + +const char *bar() { + return "Hello world"; +}
\ No newline at end of file diff --git a/tests/projects/c++/modules/packages/my-repo/packages/b/bar/src/bar.mpp b/tests/projects/c++/modules/packages/my-repo/packages/b/bar/src/bar.mpp new file mode 100644 index 000000000..a13487fea --- /dev/null +++ b/tests/projects/c++/modules/packages/my-repo/packages/b/bar/src/bar.mpp @@ -0,0 +1,3 @@ +export module bar; + +export const char *bar();
\ No newline at end of file diff --git a/tests/projects/c++/modules/packages/my-repo/packages/b/bar/src/xmake.lua b/tests/projects/c++/modules/packages/my-repo/packages/b/bar/src/xmake.lua new file mode 100644 index 000000000..345dd2db4 --- /dev/null +++ b/tests/projects/c++/modules/packages/my-repo/packages/b/bar/src/xmake.lua @@ -0,0 +1,7 @@ +add_rules("mode.release", "mode.debug") +set_languages("c++20") + +target("bar") + set_kind("static") + add_files("*.cpp") + add_files("*.mpp", { install = true }) diff --git a/tests/projects/c++/modules/packages/my-repo/packages/b/bar/xmake.lua b/tests/projects/c++/modules/packages/my-repo/packages/b/bar/xmake.lua new file mode 100644 index 000000000..301166807 --- /dev/null +++ b/tests/projects/c++/modules/packages/my-repo/packages/b/bar/xmake.lua @@ -0,0 +1,6 @@ +package("bar") + set_sourcedir(path.join(os.scriptdir(), "src")) + + on_install(function(package) + import("package.tools.xmake").install(package, {}) + end)
\ No newline at end of file diff --git a/tests/projects/c++/modules/packages/my-repo/packages/f/foo/src/foo.cpp b/tests/projects/c++/modules/packages/my-repo/packages/f/foo/src/foo.cpp new file mode 100644 index 000000000..f46c7119a --- /dev/null +++ b/tests/projects/c++/modules/packages/my-repo/packages/f/foo/src/foo.cpp @@ -0,0 +1,9 @@ +module foo; + +import <cstdio>; + +namespace foo { + void say(const char *msg) { + std::printf("%s", msg); + } +}
\ No newline at end of file diff --git a/tests/projects/c++/modules/packages/my-repo/packages/f/foo/src/foo.mpp b/tests/projects/c++/modules/packages/my-repo/packages/f/foo/src/foo.mpp new file mode 100644 index 000000000..4cab3d977 --- /dev/null +++ b/tests/projects/c++/modules/packages/my-repo/packages/f/foo/src/foo.mpp @@ -0,0 +1,5 @@ +export module foo; + +export namespace foo { + void say(const char *); +}
\ No newline at end of file diff --git a/tests/projects/c++/modules/packages/my-repo/packages/f/foo/src/xmake.lua b/tests/projects/c++/modules/packages/my-repo/packages/f/foo/src/xmake.lua new file mode 100644 index 000000000..d79b2ac54 --- /dev/null +++ b/tests/projects/c++/modules/packages/my-repo/packages/f/foo/src/xmake.lua @@ -0,0 +1,7 @@ +add_rules("mode.release", "mode.debug") +set_languages("c++20") + +target("foo") + set_kind("static") + add_files("*.cpp") + add_files("*.mpp", { install = true }) diff --git a/tests/projects/c++/modules/packages/my-repo/packages/f/foo/xmake.lua b/tests/projects/c++/modules/packages/my-repo/packages/f/foo/xmake.lua new file mode 100644 index 000000000..19c87d866 --- /dev/null +++ b/tests/projects/c++/modules/packages/my-repo/packages/f/foo/xmake.lua @@ -0,0 +1,6 @@ +package("foo") + set_sourcedir(path.join(os.scriptdir(), "src")) + + on_install(function(package) + import("package.tools.xmake").install(package, {}) + end)
\ No newline at end of file diff --git a/tests/projects/c++/modules/packages/src/main.cpp b/tests/projects/c++/modules/packages/src/main.cpp new file mode 100644 index 000000000..10c501c4a --- /dev/null +++ b/tests/projects/c++/modules/packages/src/main.cpp @@ -0,0 +1,7 @@ +import foo; +import bar; + +int main() { + foo::say(bar()); + return 0; +} diff --git a/tests/projects/c++/modules/packages/test.lua b/tests/projects/c++/modules/packages/test.lua new file mode 100644 index 000000000..c18e5a1d0 --- /dev/null +++ b/tests/projects/c++/modules/packages/test.lua @@ -0,0 +1 @@ +inherit(".test_headerunits") diff --git a/tests/projects/c++/modules/packages/xmake.lua b/tests/projects/c++/modules/packages/xmake.lua new file mode 100644 index 000000000..fe3cc7dc5 --- /dev/null +++ b/tests/projects/c++/modules/packages/xmake.lua @@ -0,0 +1,11 @@ +add_rules("mode.release", "mode.debug") +set_languages("c++20") + +add_repositories("my-repo my-repo") +add_requires("foo", "bar") + +target("packages") + set_kind("binary") + add_files("src/*.cpp") + add_packages("foo", "bar") + set_policy("build.c++.modules", true) diff --git a/tests/projects/c++/modules/test_headerunits.lua b/tests/projects/c++/modules/test_headerunits.lua index 747ec6535..6a942e583 100644 --- a/tests/projects/c++/modules/test_headerunits.lua +++ b/tests/projects/c++/modules/test_headerunits.lua @@ -15,26 +15,27 @@ function main(t) if is_subhost("windows") then local vs = find_vstudio() if vs and vs["2022"] then - os.exec("xmake f -c") + os.exec("xmake f -c --yes") _build() end elseif is_host("linux") then local gcc = find_tool("gcc", {version = true}) if gcc and gcc.version and semver.compare(gcc.version, "11.0") >= 0 then - os.exec("xmake f -c") + os.exec("xmake f -c --yes") _build() end local clang = find_tool("clang", {version = true}) - if clang and clang.version and semver.compare(clang.version, "16.0") >= 0 then - if is_host("linux") then + if clang and clang.version then + if semver.compare(clang.version, "15.0") >= 0 then os.exec("xmake clean -a") os.exec("xmake f --toolchain=clang -c") _build() - end + -- elseif semver.compare(clang.version, "15.0") >= 0 then -- there is currently a bug on llvm git that prevent to build STL header units https://github.com/llvm/llvm-project/issues/58540 -- os.exec("xmake clean -a") -- os.exec("xmake f --toolchain=clang --cxxflags=\"-stdlib=libc++\" -c") -- _build() + end end end end diff --git a/xmake/actions/install/main.lua b/xmake/actions/install/main.lua index 4f59c2b79..5d15a4c40 100644 --- a/xmake/actions/install/main.lua +++ b/xmake/actions/install/main.lua @@ -118,8 +118,11 @@ function main() cprint("${color.success}install ok!") ok = true end - if not ok and os.syserror() == os.SYSERR_NOT_PERM then - wprint("please pass the --admin parameter to `xmake install` to request administrator permissions!") + if not ok then + local syserror = os.syserror() + if syserror == os.SYSERR_NOT_PERM or syserror == os.SYSERR_NOT_ACCESS then + wprint("please pass the --admin parameter to `xmake install` to request administrator permissions!") + end end assert(ok, "install failed, %s", errors or "unknown reason") end diff --git a/xmake/actions/uninstall/main.lua b/xmake/actions/uninstall/main.lua index 67bb36a83..3132a3456 100644 --- a/xmake/actions/uninstall/main.lua +++ b/xmake/actions/uninstall/main.lua @@ -75,8 +75,11 @@ function main() cprint("${color.success}uninstall ok!") ok = true end - if not ok and os.syserror() == os.SYSERR_NOT_PERM then - wprint("please pass the --admin parameter to `xmake uninstall` to request administrator permissions!") + if not ok then + local syserror = os.syserror() + if syserror == os.SYSERR_NOT_PERM or syserror == os.SYSERR_NOT_ACCESS then + wprint("please pass the --admin parameter to `xmake uninstall` to request administrator permissions!") + end end assert(ok, "uninstall failed, %s", errors or "unknown reason") end diff --git a/xmake/core/base/os.lua b/xmake/core/base/os.lua index b28381ccd..dcd7cca8b 100644 --- a/xmake/core/base/os.lua +++ b/xmake/core/base/os.lua @@ -50,6 +50,7 @@ os.SYSERR_UNKNOWN = -1 os.SYSERR_NONE = 0 os.SYSERR_NOT_PERM = 1 os.SYSERR_NOT_FILEDIR = 2 +os.SYSERR_NOT_ACCESS = 3 -- copy single file or directory function os._cp(src, dst, rootdir, opt) diff --git a/xmake/core/sandbox/modules/os.lua b/xmake/core/sandbox/modules/os.lua index 28eba4471..ac860eac8 100644 --- a/xmake/core/sandbox/modules/os.lua +++ b/xmake/core/sandbox/modules/os.lua @@ -83,6 +83,7 @@ sandbox_os.SYSERR_UNKNOWN = os.SYSERR_UNKNOWN sandbox_os.SYSERR_NONE = os.SYSERR_NONE sandbox_os.SYSERR_NOT_PERM = os.SYSERR_NOT_PERM sandbox_os.SYSERR_NOT_FILEDIR = os.SYSERR_NOT_FILEDIR +sandbox_os.SYSERR_NOT_ACCESS = os.SYSERR_NOT_ACCESS -- copy file or directory function sandbox_os.cp(srcpath, dstpath, opt) diff --git a/xmake/core/tool/toolchain.lua b/xmake/core/tool/toolchain.lua index 66321dfa4..87a28cb69 100644 --- a/xmake/core/tool/toolchain.lua +++ b/xmake/core/tool/toolchain.lua @@ -449,7 +449,11 @@ function _instance:_checktool(toolkind, toolpath) end -- find tool program - local tool = find_tool(toolpath, {toolchain = self, cachekey = cachekey, program = program or toolpath, paths = self:bindir(), envs = self:get("runenvs")}) + local tool = find_tool(toolpath, {toolchain = self, + cachekey = cachekey, + program = program or toolpath, + paths = self:bindir(), + envs = self:get("runenvs")}) if tool then program = tool.program toolname = toolname or tool.name diff --git a/xmake/modules/detect/tools/find_rc.lua b/xmake/modules/detect/tools/find_rc.lua index 6e04ac950..08db8fb87 100644 --- a/xmake/modules/detect/tools/find_rc.lua +++ b/xmake/modules/detect/tools/find_rc.lua @@ -59,6 +59,8 @@ function main(opt) -- local envs = opt.envs if envs and envs.WindowsSdkDir and envs.WindowsSDKVersion then + local toolchain = opt.toolchain + local arch = toolchain and toolchain:arch() or config.arch() local bindir = path.join(envs.WindowsSdkDir, "bin", envs.WindowsSDKVersion, arch) if os.isdir(bindir) then opt.paths = opt.paths or {} diff --git a/xmake/rules/c++/modules/modules_support/clang.lua b/xmake/rules/c++/modules/modules_support/clang.lua index 34ee9a2ac..0e91aadae 100644 --- a/xmake/rules/c++/modules/modules_support/clang.lua +++ b/xmake/rules/c++/modules/modules_support/clang.lua @@ -20,6 +20,7 @@ -- imports import("core.base.option") +import("core.base.json") import("core.tool.compiler") import("core.project.project") import("core.project.depend") @@ -481,6 +482,24 @@ function build_modules_for_batchjobs(target, batchjobs, objectfiles, modules, op end end local moduleinfo = table.copy(provide) or {} + + if provide then + local fileconfig = target:fileconfig(cppfile) + if fileconfig and fileconfig.install then + batchjobs:addjob(name .. "_metafile", function(index, total) + local cachedir = common.modules_cachedir(target) + local metafilepath = path.join(cachedir, path.filename(cppfile) .. ".meta-info") + depend.on_changed(function() + progress.show(opt.progress, "${color.build.object}generating.module.metadata %s", name) + local metadata = common.generate_meta_module_info(target, name, cppfile, module.requires) + json.savefile(metafilepath, metadata) + + end, {dependfile = target:dependfile(metafilepath), files = {cppfile}}) + + end, {rootjob = flushjob}) + end + end + table.join2(moduleinfo, { name = name or cppfile, deps = table.keys(module.requires or {}), @@ -494,20 +513,34 @@ function build_modules_for_batchjobs(target, batchjobs, objectfiles, modules, op if provide or common.has_module_extension(cppfile) then local bmifile = provide and provide.bmi - _build_modulefile(target, provide and provide.sourcefile or cppfile, { - objectfile = objectfile, - dependfile = target:dependfile(bmifile or objectfile), - provide = provide and {bmifile = bmifile, name = name}, - common_args = common_args, - requiresflags = requiresflags, - progress = (index * 100) / total}) + if not common.memcache():get2(name or cppfile, "compiling") then + if name and module.external then + common.memcache():set2(name or cppfile, "compiling", true) + end + _build_modulefile(target, provide and provide.sourcefile or cppfile, { + objectfile = objectfile, + dependfile = target:dependfile(bmifile or objectfile), + provide = provide and {bmifile = bmifile, name = name}, + common_args = common_args, + requiresflags = requiresflags, + progress = (index * 100) / total}) + end target:add("objectfiles", objectfile) if provide then _add_module_to_mapper(target, name, bmifile, requiresflags) end elseif requiresflags then - target:fileconfig_add(cppfile, {force = {cxxflags = requiresflags}}) + local cxxflags = {} + for _, flag in ipairs(requiresflags) do + -- we need wrap flag to support flag with space + if type(flag) == "string" and flag:find(" ", 1, true) then + table.insert(cxxflags, {flag}) + else + table.insert(cxxflags, flag) + end + end + target:fileconfig_add(cppfile, {force = {cxxflags = cxxflags}}) end end)}) modulesjobs[name or cppfile] = moduleinfo @@ -563,7 +596,16 @@ function build_modules_for_batchcmds(target, batchcmds, objectfiles, modules, op not provide and {"-x", "c++"} or {}, {"-c", file, "-o", path(objectfile)})) target:add("objectfiles", objectfile) elseif requiresflags then - target:fileconfig_add(cppfile, {force = {cxxflags = requiresflags}}) + local cxxflags = {} + for _, flag in ipairs(requiresflags) do + -- we need wrap flag to support flag with space + if type(flag) == "string" and flag:find(" ", 1, true) then + table.insert(cxxflags, {flag}) + else + table.insert(cxxflags, flag) + end + end + target:fileconfig_add(cppfile, {force = {cxxflags = cxxflags}}) end batchcmds:add_depfiles(cppfile) @@ -725,8 +767,10 @@ function get_requiresflags(target, requires) local modulemap_ = _get_modulemap_from_mapper(dep, name) if modulemap_ then already_mapped_modules[name] = true - table.join2(flags, modulemap_.flag) - table.join2(flags, modulemap_.deps or {}) + table.insert(flags, modulemap_.flag) + if modulemap_.deps then + table.shallow_join2(flags, modulemap_.deps) + end goto continue end end @@ -735,8 +779,10 @@ function get_requiresflags(target, requires) local modulemap = _get_modulemap_from_mapper(target, name) if modulemap then already_mapped_modules[name] = true - table.join2(flags, modulemap.flag) - table.join2(flags, modulemap.deps or {}) + table.insert(flags, modulemap.flag) + if modulemap.deps then + table.shallow_join2(flags, modulemap.deps) + end goto continue end diff --git a/xmake/rules/c++/modules/modules_support/common.lua b/xmake/rules/c++/modules/modules_support/common.lua index 1c3b2f0b1..32c1b7be8 100644 --- a/xmake/rules/c++/modules/modules_support/common.lua +++ b/xmake/rules/c++/modules/modules_support/common.lua @@ -102,6 +102,86 @@ function patch_sourcebatch(target, sourcebatch) end end +function parse_meta_info(target, metafile) + local metadata = json.loadfile(metafile) + if metadata._VENDOR_extension.xmake then + return metadata._VENDOR_extension.xmake.file, metadata._VENDOR_extension.xmake.name, metadata + end + + local filename = path.basename(metafile) + local metadir = path.directory(metafile) + for _, ext in ipairs({".mpp", ".mxx", ".cppm", ".ixx"}) do + if os.isfile(path.join(metadir, filename .. ext)) then + filename = filename .. ext + break + end + end + + local sourcecode = io.readfile(path.join(path.directory(metafile), filename)) + sourcecode = sourcecode:gsub("//.-\n", "\n") + sourcecode = sourcecode:gsub("/%*.-%*/", "") + + local name + for _, line in ipairs(sourcecode:split("\n", {plain = true})) do + name = line:match("export%s+module%s+(.+)%s*;") or line:match("export%s+__preprocessed_module%s+(.+)%s*;") + if name then + break + end + end + + return filename, name, metadata +end + +-- extract packages modules dependencies +function get_all_package_modules(target, modules, opt) + local package_modules + + -- parse all meta-info and append their informations to the package store + for name, package in pairs(target:pkgs()) do + package_modules = package_modules or {} + local modules_dir = path.join(package:installdir(), "modules", name) + local metafiles = os.files(path.join(modules_dir, "**.meta-info")) + for _, metafile in ipairs(metafiles) do + local modulefile, name, metadata = parse_meta_info(target, metafile) + package_modules[name] = { + file = path.join(modules_dir, modulefile), + metadata = metadata + } + end + end + + return package_modules +end + +-- cull unused modules +function cull_unused_modules(target, modules, package_modules_data) + local needed_modules = {} + -- append all target dependencies + for _, module in pairs(modules) do + if module.requires then + for required, _ in pairs(module.requires) do + table.insert(needed_modules, required) + end + end + end + + -- append all package dependencies + local culled + local module_names = table.keys(package_modules_data) + for _, name in ipairs(module_names) do + culled = culled or {} + if table.find(needed_modules, name) and package_modules_data[name] and not culled[name] then + culled[name] = package_modules_data[name] + + if culled[name].metadata.imports then + table.join2(needed_modules, culled[name].metadata.imports) + table.join2(module_names, culled[name].metadata.imports) + end + end + end + return culled +end + -- get modules support function modules_support(target) local cachekey = tostring(target) @@ -510,7 +590,7 @@ end function get_module_dependencies(target, sourcebatch, opt) local cachekey = target:name() .. "/" .. sourcebatch.rulename local modules = memcache():get2("modules", cachekey) - if modules == nil then + if modules == nil or opt.regenerate then modules = localcache():get2("modules", cachekey) opt.progress = opt.progress or 0 local changed = modules_support(target).generate_dependencies(target, sourcebatch, opt) @@ -564,11 +644,71 @@ function append_dependency_objectfiles(target) local cache = localcache():get(cachekey) if cache then if target:is_binary() then - target:add("ldflags", cache, {force = true}) + target:add("ldflags", cache, {force = true, expand = false}) elseif target:is_static() then - target:add("arflags", cache, {force = true}) + target:add("arflags", cache, {force = true, expand = false}) elseif target:is_shared() then - target:add("shflags", cache, {force = true}) + target:add("shflags", cache, {force = true, expand = false}) + end + end +end + +-- generate meta module informations for package / other buildsystems import +-- based on https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2473r1.pdf +-- +-- e.g +-- { +-- "include_paths": ["foo/", "bar/"] +-- "definitions": ["FOO=BAR"] +-- "imports": ["std", "bar"] +-- "_VENDOR_extension": {} +-- } +function generate_meta_module_info(target, name, sourcefile, requires) + local module_metadata = {} + + -- add include paths + module_metadata.include_paths = table.wrap(target:get("includedirs")) or {} + for _, deps in ipairs(target:orderdeps()) do + table.join2(module_metadata.include_paths, deps:get("includedirs") or {}) + end + + -- add definitions + module_metadata.definitions = table.wrap(target:get("defines")) or {} + for _, deps in ipairs(target:orderdeps()) do + table.join2(module_metadata.definitions, deps:get("defines") or {}) + end + + -- add imports + if requires then + for name, _ in pairs(requires) do + module_metadata.imports = module_metadata.imports or {} + table.append(module_metadata.imports, name) + end + end + + module_metadata._VENDOR_extension = { xmake = { name = name, file = path.filename(sourcefile) }} + + return module_metadata +end + +function install_module_target(target) + local sourcebatch = target:sourcebatches()["c++.build.modules.install"] + local cachedir = modules_cachedir(target) + if sourcebatch and sourcebatch.sourcefiles then + for _, sourcefile in ipairs(sourcebatch.sourcefiles) do + local prefixdir = path.join("modules", target:name()) + local fileconfig = target:fileconfig(sourcefile) + if fileconfig and fileconfig.prefixdir then + prefixdir = fileconfig.prefixdir + end + local install = (fileconfig and not fileconfig.install) and false or true + if install then + target:add("installfiles", sourcefile, {prefixdir = prefixdir}) + local metafile = path.join(cachedir, path.filename(sourcefile) .. ".meta-info") + if os.exists(metafile) then + target:add("installfiles", metafile, {prefixdir = prefixdir}) + end + end end end end diff --git a/xmake/rules/c++/modules/modules_support/gcc.lua b/xmake/rules/c++/modules/modules_support/gcc.lua index f178e550a..5d0f9182f 100644 --- a/xmake/rules/c++/modules/modules_support/gcc.lua +++ b/xmake/rules/c++/modules/modules_support/gcc.lua @@ -20,6 +20,7 @@ -- imports import("core.base.option") +import("core.base.json") import("core.tool.compiler") import("core.project.project") import("core.project.depend") @@ -424,6 +425,24 @@ function build_modules_for_batchjobs(target, batchjobs, objectfiles, modules, op end local moduleinfo = table.copy(provide) or {} local dependfile = (provide and provide.bmi) and target:dependfile(provide.bmi) or target:dependfile(objectfile) + + if provide then + local fileconfig = target:fileconfig(cppfile) + if fileconfig and fileconfig.install then + batchjobs:addjob(name .. "_metafile", function(index, total) + local cachedir = common.modules_cachedir(target) + local metafilepath = path.join(cachedir, path.filename(cppfile) .. ".meta-info") + depend.on_changed(function() + progress.show(opt.progress, "${color.build.object}generating.module.metadata %s", name) + local metadata = common.generate_meta_module_info(target, name, cppfile, module.requires) + json.savefile(metafilepath, metadata) + + end, {dependfile = target:dependfile(metafilepath), files = {cppfile}}) + + end, {rootjob = opt.rootjob}) + end + end + table.join2(moduleinfo, { name = name or cppfile, deps = table.keys(module.requires or {}), @@ -445,11 +464,16 @@ function build_modules_for_batchjobs(target, batchjobs, objectfiles, modules, op end if provide or common.has_module_extension(cppfile) then - _build_modulefile(target, cppfile, { - objectfile = objectfile, - dependfile = dependfile, - name = name or cppfile, - progress = (index * 100) / total}) + if not common.memcache():get2(name or cppfile, "compiling") then + if name and module.external then + common.memcache():set2(name or cppfile, "compiling", true) + end + _build_modulefile(target, cppfile, { + objectfile = objectfile, + dependfile = dependfile, + name = name or cppfile, + progress = (index * 100) / total}) + end target:add("objectfiles", objectfile) end end)}) diff --git a/xmake/rules/c++/modules/modules_support/msvc.lua b/xmake/rules/c++/modules/modules_support/msvc.lua index a902721c0..d0895490a 100644 --- a/xmake/rules/c++/modules/modules_support/msvc.lua +++ b/xmake/rules/c++/modules/modules_support/msvc.lua @@ -20,6 +20,7 @@ -- imports import("core.base.option") +import("core.base.json") import("core.tool.compiler") import("core.project.project") import("core.project.depend") @@ -450,6 +451,7 @@ function build_modules_for_batchjobs(target, batchjobs, objectfiles, modules, op for objectfile, module in pairs(get_stdmodules(target)) do table.insert(objectfiles, objectfile) modules[objectfile] = module + modules[objectfile].external = true end end @@ -480,6 +482,21 @@ function build_modules_for_batchjobs(target, batchjobs, objectfiles, modules, op if provide then table.join2(flags, {ifcoutputflag, path(provide.bmi), provide.interface and interfaceflag or internalpartitionflag}) dependfile = target:dependfile(provide.bmi) + + local fileconfig = target:fileconfig(cppfile) + if fileconfig and fileconfig.install then + batchjobs:addjob(name .. "_metafile", function(index, total) + local cachedir = common.modules_cachedir(target) + local metafilepath = path.join(cachedir, path.filename(cppfile) .. ".meta-info") + depend.on_changed(function() + progress.show(opt.progress, "${color.build.object}generating.module.metadata %s", name) + local metadata = common.generate_meta_module_info(target, name, cppfile, module.requires) + json.savefile(metafilepath, metadata) + + end, {dependfile = target:dependfile(metafilepath), files = {cppfile}}) + + end, {rootjob = flushjob}) + end end table.join2(moduleinfo, { @@ -497,17 +514,17 @@ function build_modules_for_batchjobs(target, batchjobs, objectfiles, modules, op if provide or common.has_module_extension(cppfile) then if not common.memcache():get2(name or cppfile, "compiling") then - if name and name:match("std") then - common.memcache():set2(name or cppfile, "compiling", true) + if name and module.external then + common.memcache():set2(name or cppfile, "compiling", true) end - _build_modulefile(target, cppfile, { - objectfile = objectfile, - dependfile = dependfile, - name = name or module.cppfile, - flags = _flags, - progress = (index * 100) / total}) - _add_objectfile_to_link_arguments(target, path(objectfile)) + _build_modulefile(target, cppfile, { + objectfile = objectfile, + dependfile = dependfile, + name = name or module.cppfile, + flags = _flags, + progress = (index * 100) / total}) end + _add_objectfile_to_link_arguments(target, objectfile) elseif requiresflags then requiresflags = get_requiresflags(target, module.requires) target:fileconfig_add(cppfile, {force = {cxxflags = table.join(flags, requiresflags)}}) @@ -577,7 +594,7 @@ function build_modules_for_batchcmds(target, batchcmds, objectfiles, modules, op batchcmds:mkdir(path.directory(objectfile)) _batchcmds_compile(batchcmds, target, table.join(flags, requiresflags or {})) batchcmds:add_depfiles(cppfile) - _add_objectfile_to_link_arguments(target, path(objectfile)) + _add_objectfile_to_link_arguments(target, path.translate(objectfile)) if provide then _add_module_to_mapper(target, referenceflag, name, name, objectfile, provide.bmi, requiresflags) end @@ -642,10 +659,10 @@ function get_ifcoutputflag(target) local ifcoutputflag = _g.ifcoutputflag if ifcoutputflag == nil then local compinst = target:compiler("cxx") - if compinst:has_flags("-ifcOutput", "cxxflags", {flagskey = "cl_ifc_output"}) then + if compinst:has_flags({"-ifcOutput", os.tmpfile()}, "cxxflags", {flagskey = "cl_ifc_output"}) then ifcoutputflag = "-ifcOutput" end - assert(ifcoutputflag, "compiler(msvc): does not support c++ module!") + assert(ifcoutputflag, "compiler(msvc): does not support c++ module flag(/ifcOutput)!") _g.ifcoutputflag = ifcoutputflag or false end return ifcoutputflag or nil @@ -655,10 +672,10 @@ function get_ifcsearchdirflag(target) local ifcsearchdirflag = _g.ifcsearchdirflag if ifcsearchdirflag == nil then local compinst = target:compiler("cxx") - if compinst:has_flags("-ifcSearchDir", "cxxflags", {flagskey = "cl_ifc_search_dir"}) then + if compinst:has_flags({"-ifcSearchDir", os.tmpdir()}, "cxxflags", {flagskey = "cl_ifc_search_dir"}) then ifcsearchdirflag = "-ifcSearchDir" end - assert(ifcsearchdirflag, "compiler(msvc): does not support c++ module!") + assert(ifcsearchdirflag, "compiler(msvc): does not support c++ module flag(/ifcSearchDir)!") _g.ifcsearchdirflag = ifcsearchdirflag or false end return ifcsearchdirflag or nil @@ -671,7 +688,7 @@ function get_interfaceflag(target) if compinst:has_flags("-interface", "cxxflags", {flagskey = "cl_interface"}) then interfaceflag = "-interface" end - assert(interfaceflag, "compiler(msvc): does not support c++ module!") + assert(interfaceflag, "compiler(msvc): does not support c++ module flag(/interface)!") _g.interfaceflag = interfaceflag or false end return interfaceflag @@ -681,10 +698,10 @@ function get_referenceflag(target) local referenceflag = _g.referenceflag if referenceflag == nil then local compinst = target:compiler("cxx") - if compinst:has_flags("-reference", "cxxflags", {flagskey = "cl_reference"}) then + if compinst:has_flags({"-reference", "Foo=" .. os.tmpfile()}, "cxxflags", {flagskey = "cl_reference"}) then referenceflag = "-reference" end - assert(referenceflag, "compiler(msvc): does not support c++ module!") + assert(referenceflag, "compiler(msvc): does not support c++ module flag(/reference)!") _g.referenceflag = referenceflag or false end return referenceflag or nil @@ -694,8 +711,8 @@ function get_headernameflag(target) local headernameflag = _g.headernameflag if headernameflag == nil then local compinst = target:compiler("cxx") - if compinst:has_flags("-headerName:quote", "cxxflags", {flagskey = "cl_header_name_quote"}) and - compinst:has_flags("-headerName:angle", "cxxflags", {flagskey = "cl_header_name_angle"}) then + if compinst:has_flags({"-std:c++latest", "-exportHeader", "-headerName:quote"}, "cxxflags", {flagskey = "cl_header_name_quote"}) and + compinst:has_flags({"-std:c++latest", "-exportHeader", "-headerName:angle"}, "cxxflags", {flagskey = "cl_header_name_angle"}) then headernameflag = "-headerName" end _g.headernameflag = headernameflag or false @@ -707,8 +724,9 @@ function get_headerunitflag(target) local headerunitflag = _g.headerunitflag if headerunitflag == nil then local compinst = target:compiler("cxx") - if compinst:has_flags("-headerUnit:quote", "cxxflags", {flagskey = "cl_header_unit_quote"}) and - compinst:has_flags("-headerUnit:angle", "cxxflags", {flagskey = "cl_header_unit_angle"}) then + local ifcfile = os.tmpfile() + if compinst:has_flags({"-std:c++latest", "-headerUnit:quote", "foo.h=" .. ifcfile}, "cxxflags", {flagskey = "cl_header_unit_quote"}) and + compinst:has_flags({"-std:c++latest", "-headerUnit:angle", "foo.h=" .. ifcfile}, "cxxflags", {flagskey = "cl_header_unit_angle"}) then headerunitflag = "-headerUnit" end _g.headerunitflag = headerunitflag or false @@ -717,11 +735,9 @@ function get_headerunitflag(target) end function get_exportheaderflag(target) - local modulesflag = get_modulesflag(target) local exportheaderflag = _g.exportheaderflag if exportheaderflag == nil then - local compinst = target:compiler("cxx") - if compinst:has_flags(modulesflag .. " -exportHeader", "cxxflags", {flagskey = "cl_export_header"}) then + if get_headernameflag(target) then exportheaderflag = "-exportHeader" end _g.exportheaderflag = exportheaderflag or false diff --git a/xmake/rules/c++/modules/xmake.lua b/xmake/rules/c++/modules/xmake.lua index 3a7c7129d..b62ec0f36 100644 --- a/xmake/rules/c++/modules/xmake.lua +++ b/xmake/rules/c++/modules/xmake.lua @@ -67,6 +67,24 @@ rule("c++.build.modules.builder") common.patch_sourcebatch(target, sourcebatch, opt) local modules = common.get_module_dependencies(target, sourcebatch, opt) + -- extract packages modules dependencies + local package_modules_data = common.get_all_package_modules(target, modules, opt) + if package_modules_data then + -- cull unused modules + package_modules_data = common.cull_unused_modules(target, modules, package_modules_data) + if package_modules_data then + -- append to sourcebatch + for name, package_module_data in pairs(package_modules_data) do + table.insert(sourcebatch.sourcefiles, package_module_data.file) + end + + -- we need to repatch and regenerate dependencies at this point + common.patch_sourcebatch(target, sourcebatch, opt) + opt.regenerate = true + modules = common.get_module_dependencies(target, sourcebatch, opt) + end + end + -- build modules common.build_modules_for_batchjobs(target, batchjobs, sourcebatch, modules, opt) @@ -147,19 +165,6 @@ rule("c++.build.modules.install") -- we cannot use target:data("cxx.has_modules"), -- because on_config will be not called when installing targets if common.contains_modules(target) then - local sourcebatch = target:sourcebatches()["c++.build.modules.install"] - if sourcebatch then - for _, sourcefile in sourcebatch.sourcefiles do - local prefixdir = "modules" - local fileconfig = target:fileconfig(sourcefile) - if fileconfig and fileconfig.prefixdir then - prefixdir = fileconfig.prefixdir - end - local install = (fileconfig and not fileconfig.install) and false or true - if install then - target:add("installfiles", sourcefile, {prefixdir = prefixdir}) - end - end - end + common.install_module_target(target) end end) diff --git a/xmake/toolchains/zig/xmake.lua b/xmake/toolchains/zig/xmake.lua index 2f97b0340..d6d3e1de2 100644 --- a/xmake/toolchains/zig/xmake.lua +++ b/xmake/toolchains/zig/xmake.lua @@ -96,8 +96,8 @@ toolchain("zig") -- xmake f -p cross --toolchain=zig --cross=mips64el-linux-gnuabi64 target = toolchain:cross() elseif toolchain:is_plat("macosx") then - -- zig 0.10 will raise `unable to find or provide libc for target 'x86_64-macos.11.7.1...13-gnu'` - --target = arch .. "-macos-gnu" + --@see https://github.com/ziglang/zig/issues/14226 + target = arch .. "-macos-none" elseif toolchain:is_plat("linux") then if arch == "arm" then target = "arm-linux-gnueabi" |
