From b024a424af7511f2d64794b84e08aced3de935e4 Mon Sep 17 00:00:00 2001 From: Arthur LAURENT Date: Tue, 4 Nov 2025 10:07:43 +0100 Subject: (modules) add all supported platforms for clang get_cpp_library_name --- xmake/rules/c++/modules/support.lua | 226 +++++++++++++++++------------------- 1 file changed, 105 insertions(+), 121 deletions(-) (limited to 'xmake/rules/c++/modules/support.lua') diff --git a/xmake/rules/c++/modules/support.lua b/xmake/rules/c++/modules/support.lua index 0f89d4e98..4db95cb18 100644 --- a/xmake/rules/c++/modules/support.lua +++ b/xmake/rules/c++/modules/support.lua @@ -17,34 +17,33 @@ -- -- imports -import("core.base.bytes") -import("core.base.option") -import("core.base.json") -import("core.base.hashset") -import("core.cache.memcache", {alias = "_memcache"}) -import("core.cache.localcache", {alias = "_localcache"}) -import("async.runjobs") -import("lib.detect.find_file") -import("core.project.project") -import("core.project.config") - -function _support(target) - return import_implementation_of(target, "support") -end +import('core.base.bytes') +import('core.base.option') +import('core.base.json') +import('core.base.hashset') +import('core.cache.memcache', { alias = '_memcache' }) +import('core.cache.localcache', { alias = '_localcache' }) +import('core.tool.toolchain') +import('core.project.project') +import('core.project.config') +import('lib.detect.find_file') +import('async.runjobs') + +function _support(target) return import_implementation_of(target, 'support') end function import_implementation_of(target, name) local cachekey = tostring(target) local implementation = memcache():get2(name, cachekey) if implementation == nil then - if target:has_tool("cxx", "clang", "clangxx", "clang_cl") then - implementation = import("clang." .. name, {anonymous = true}) - elseif target:has_tool("cxx", "gcc", "gxx") then - implementation = import("gcc." .. name, {anonymous = true}) - elseif target:has_tool("cxx", "cl") then - implementation = import("msvc." .. name, {anonymous = true}) + if target:has_tool('cxx', 'clang', 'clangxx', 'clang_cl') then + implementation = import('clang.' .. name, { anonymous = true }) + elseif target:has_tool('cxx', 'gcc', 'gxx') then + implementation = import('gcc.' .. name, { anonymous = true }) + elseif target:has_tool('cxx', 'cl') then + implementation = import('msvc.' .. name, { anonymous = true }) else - local _, toolname = target:tool("cxx") - raise("compiler(%s): does not implementation c++ module!", toolname) + local _, toolname = target:tool('cxx') + raise('compiler(%s): does not implementation c++ module!', toolname) end memcache():set2(name, cachekey, implementation) end @@ -54,62 +53,70 @@ end -- load module support for the current target function load(target) -- At least std c++20 is required, and we should call `set_languages("c++20")` to set it - local languages = target:get("languages") + local languages = target:get('languages') local cxxlang = false for _, lang in ipairs(languages) do - if lang:find("cxx", 1, true) or lang:find("c++", 1, true) or lang:find("gnuxx", 1, true) or lang:find("gnu++", 1, true) then + if + lang:find('cxx', 1, true) + or lang:find('c++', 1, true) + or lang:find('gnuxx', 1, true) + or lang:find('gnu++', 1, true) + then cxxlang = true break end end - if not cxxlang then - target:add("languages", "c++20") - end + if not cxxlang then target:add('languages', 'c++20') end -- load module support for the specific compiler _support(target).load(target) end function get_cpplibrary_name(target) -- libc++ come first because on windows, if we use libc++ clang will still use msvc crt so MD / MT / MDd / MTd can be set - if target:has_runtime("c++_shared", "c++_static") then - return "c++" - elseif target:has_runtime("stdc++_shared", "stdc++_static") then - return "stdc++" - elseif target:has_runtime("MD", "MT", "MDd", "MTd") then - return "msstl" + if target:has_runtime('c++_shared', 'c++_static') then + return 'c++' + elseif target:has_runtime('stdc++_shared', 'stdc++_static', 'gnustl_static', 'gnustl_shared') then + return 'stdc++' + elseif target:has_runtime('stlport_static', 'stlport_shared') then + return 'stlport' + elseif target:has_runtime('MD', 'MT', 'MDd', 'MTd') then + return 'msstl' end -- if no specified runtime, fallback on native platform C++ library - if target:is_plat("macosx", "iphoneos", "appletvos") then - return "c++" - elseif target:is_plat("linux") or target:is_plat("mingw") then - return "stdc++" - elseif target:is_plat("windows") then - return "msstl" + if target:is_plat('android') then + local ndk = toolchain.load('ndk', { plat = plat, arch = arch }) + local ver = ndk:config('ndkver') + if not ver or ver > 14 then + return 'c++' + else + return 'stdc++' + end + elseif target:is_plat('macosx', 'iphoneos', 'watchos', 'appletvos', 'applexros', 'bsd', 'harmony') then + return 'c++' + elseif target:is_plat('linux', 'mingw', 'cygwin', 'msys', 'haiku') then + return 'stdc++' + elseif target:is_plat('windows') then + return 'msstl' end end -function has_two_phase_compilation_support(target) - return _support(target).has_two_phase_compilation_support(target) -end +function has_two_phase_compilation_support(target) return _support(target).has_two_phase_compilation_support(target) end -- strip flags not relevent for module reuse function strip_flags(target, flags, opt) - local strippeable_flags, splitted_strippeable_flags if not opt.requiresonly then - strippeable_flags, splitted_strippeable_flags = _support(target).strippeable_flags() - if opt and opt.strip_defines then - table.join2(splitted_strippeable_flags, {"D", "U"}) - end + strippeable_flags, splitted_strippeable_flags = _support(target).strippeable_flags() + if opt and opt.strip_defines then table.join2(splitted_strippeable_flags, { 'D', 'U' }) end else - strippeable_flags, splitted_strippeable_flags = _support(target).require_flags() + strippeable_flags, splitted_strippeable_flags = _support(target).require_flags() end local splitted_strippeable_flags_set = hashset.new() for _, flag in ipairs(splitted_strippeable_flags) do table.insert(strippeable_flags, flag) - splitted_strippeable_flags_set:insert("/" .. flag) - splitted_strippeable_flags_set:insert("-" .. flag) + splitted_strippeable_flags_set:insert('/' .. flag) + splitted_strippeable_flags_set:insert('-' .. flag) end local output = {} @@ -122,28 +129,26 @@ function strip_flags(target, flags, opt) strip_next_flag = false else for _, _flag in ipairs(strippeable_flags) do - if (flag == "/" .. _flag) or (flag == "-" .. _flag) then + if (flag == '/' .. _flag) or (flag == '-' .. _flag) then strip = true strip_next_flag = splitted_strippeable_flags_set:has(flag) break - elseif flag:startswith("/" .. _flag) or flag:startswith("-" .. _flag) then + elseif flag:startswith('/' .. _flag) or flag:startswith('-' .. _flag) then strip = true break end end end - if not strip then - table.insert(output, flag) - end + if not strip then table.insert(output, flag) end end return output end -- extract defines from flags function get_headerunit_key(target, sourcefile) - local defines = target:get("defines") or {} - local undefines = target:get("undefines") or {} + local defines = target:get('defines') or {} + local undefines = target:get('undefines') or {} local fileconfig = target:fileconfig(sourcefile) if fileconfig then table.join(defines, fileconfig.defines or {}) @@ -151,14 +156,14 @@ function get_headerunit_key(target, sourcefile) end if #defines > 0 then - defines = table.concat(defines, "-D") + defines = table.concat(defines, '-D') else - defines = "" + defines = '' end if #undefines > 0 then - undefines = table.concat(undefines, "-D") + undefines = table.concat(undefines, '-D') else - undefines = "" + undefines = '' end local key = hash.md5(bytes(defines .. undefines)) @@ -166,14 +171,12 @@ function get_headerunit_key(target, sourcefile) end -- get bmi extension -function get_bmi_extension(target) - return _support(target).get_bmi_extension() -end +function get_bmi_extension(target) return _support(target).get_bmi_extension() end -- get bmi path -- @see https://github.com/xmake-io/xmake/issues/4063 function get_bmi_path(bmifile) - bmifile = bmifile:gsub(":", "_PARTITION_") + bmifile = bmifile:gsub(':', '_PARTITION_') return path.normalize(bmifile) end @@ -182,7 +185,7 @@ function has_module_extension(sourcefile, opt) opt = opt or {} local modulexts = _g.modulexts if modulexts == nil then - modulexts = hashset.of(".cppm", ".ccm", ".cxxm", ".c++m", ".mpp", ".mxx", ".ixx") + modulexts = hashset.of('.cppm', '.ccm', '.cxxm', '.c++m', '.mpp', '.mxx', '.ixx') _g.modulexts = modulexts end local extension = opt.extension or path.extension(sourcefile) @@ -192,14 +195,12 @@ end -- this target contains module files? function contains_modules(target) -- we can not use `"c++.build.modules.builder"`, because it contains sourcekind/cxx. - local target_with_modules = target:sourcebatches()["c++.build.modules"] and true or false - if not target_with_modules then - target_with_modules = target:policy("build.c++.modules") - end + local target_with_modules = target:sourcebatches()['c++.build.modules'] and true or false + if not target_with_modules then target_with_modules = target:policy('build.c++.modules') end if not target_with_modules then for _, dep in ipairs(target:orderdeps()) do local sourcebatches = dep:sourcebatches() - if sourcebatches["c++.build.modules"] then + if sourcebatches['c++.build.modules'] then target_with_modules = true break end @@ -210,15 +211,15 @@ end -- mark that a module scan artifacts and bmifile are reused from an other target function set_reused(target, from, sourcefile) - memcache():set2(target:fullname() .. "/modules/" .. sourcefile, "reuse", from) - if option.get("diagnosis") then - print("<" .. target:fullname() .. ">", "reuse", sourcefile, "from", "<" .. from:fullname() .. ">") + memcache():set2(target:fullname() .. '/modules/' .. sourcefile, 'reuse', from) + if option.get('diagnosis') then + print('<' .. target:fullname() .. '>', 'reuse', sourcefile, 'from', '<' .. from:fullname() .. '>') end end -- query if a module scan artifacts and bmifile are reused from an other target function is_reused(target, sourcefile) - local from = memcache():get2(target:fullname() .. "/modules/" .. sourcefile, "reuse") + local from = memcache():get2(target:fullname() .. '/modules/' .. sourcefile, 'reuse') return from and true or false, from end @@ -248,20 +249,16 @@ end -- query if a module can be culled function can_be_culled(target, sourcefile) - local can_cull = target:policy("build.c++.modules.culling") + local can_cull = target:policy('build.c++.modules.culling') local fileconfig = target:fileconfig(sourcefile) local _, stdmodules_set = get_stdmodules(target) local is_stdmodule = stdmodules_set and stdmodules_set:has(sourcefile) or false - local public = target:kind() == "moduleonly" and not is_stdmodule + local public = target:kind() == 'moduleonly' and not is_stdmodule if fileconfig then public = fileconfig.public - if fileconfig.cull ~= nil then - can_cull = can_cull and fileconfig.cull - end - end - if can_cull then - can_cull = is_stdmodule or (fileconfig and fileconfig.external) + if fileconfig.cull ~= nil then can_cull = can_cull and fileconfig.cull end end + if can_cull then can_cull = is_stdmodule or (fileconfig and fileconfig.external) end return can_cull and not public end @@ -282,106 +279,93 @@ end function find_quote_header_file(sourcefile, file) local p = path.join(path.directory(path.absolute(sourcefile, project.directory())), file) - assert(os.isfile(p), "\"%s\" not found", p) + assert(os.isfile(p), '"%s" not found', p) return p end function find_angle_header_file(target, file) local headerpaths = _support(target).toolchain_includedirs(target) for _, dep in ipairs(target:orderdeps()) do - local includedirs = table.join(dep:get("sysincludedirs") or {}, dep:get("includedirs") or {}) + local includedirs = table.join(dep:get('sysincludedirs') or {}, dep:get('includedirs') or {}) table.join2(headerpaths, includedirs) end for _, pkg in ipairs(target:orderpkgs()) do - local includedirs = table.join(pkg:get("sysincludedirs") or {}, pkg:get("includedirs") or {}) + local includedirs = table.join(pkg:get('sysincludedirs') or {}, pkg:get('includedirs') or {}) table.join2(headerpaths, includedirs) end - table.join2(headerpaths, target:get("includedirs")) + table.join2(headerpaths, target:get('includedirs')) local p = find_file(file, headerpaths) - assert(p, "<%s> not found!", file) + assert(p, '<%s> not found!', file) return p end -- get stdmodules function get_stdmodules(target) local cpplib = get_cpplibrary_name(target) - local stdmodules = memcache():get2(cpplib, "c++.modules.stdmodules") - local stdmodules_set = memcache():get2(cpplib, "c++.modules.stdmodules_set") + local stdmodules = memcache():get2(cpplib, 'c++.modules.stdmodules') + local stdmodules_set = memcache():get2(cpplib, 'c++.modules.stdmodules_set') if not stdmodules or not stdmodules_set then stdmodules = _support(target).get_stdmodules(target) stdmodules_set = hashset.from(stdmodules or {}) - memcache():set2(cpplib, "c++.modules.stdmodules", stdmodules) - memcache():set2(cpplib, "c++.modules.stdmodules_set", stdmodules_set) + memcache():set2(cpplib, 'c++.modules.stdmodules', stdmodules) + memcache():set2(cpplib, 'c++.modules.stdmodules_set', stdmodules_set) end return stdmodules, stdmodules_set end -- get memcache -function memcache() - return _memcache.cache("cxxmodules") -end +function memcache() return _memcache.cache('cxxmodules') end -- get localcache -function localcache() - return _localcache.cache("cxxmodules") -end +function localcache() return _localcache.cache('cxxmodules') end -- get modules cache directory function modules_cachedir(target, opt) assert(opt and (opt.interface ~= nil or opt.headerunit or opt.scan)) local moduletype if opt.headerunit then - moduletype = "headerunits" + moduletype = 'headerunits' elseif opt.interface then - moduletype = "interfaces" + moduletype = 'interfaces' elseif opt.scan then - moduletype = "scans" + moduletype = 'scans' else - moduletype = "implementation" - end - local cachedir = path.join(target:autogendir(), "rules", "bmi", "cache", moduletype) - if opt.mkdir and not os.isdir(cachedir) then - os.mkdir(cachedir) + moduletype = 'implementation' end + local cachedir = path.join(target:autogendir(), 'rules', 'bmi', 'cache', moduletype) + if opt.mkdir and not os.isdir(cachedir) then os.mkdir(cachedir) end return cachedir end -function get_modulehash(sourcefile) - return hash.strhash64(sourcefile) -end +function get_modulehash(sourcefile) return hash.strhash64(sourcefile) end function get_metafile(target, module) -- metafile are only for named modules - local outputdir = get_outputdir(target, module.sourcefile, {interface = module.interface or false}) - return path.join(outputdir, path.filename(module.sourcefile) .. ".meta-info") + local outputdir = get_outputdir(target, module.sourcefile, { interface = module.interface or false }) + return path.join(outputdir, path.filename(module.sourcefile) .. '.meta-info') end function get_outputdir(target, sourcefile, opt) local cachedir = modules_cachedir(target, opt) local modulehash = opt.key or get_modulehash(sourcefile) local outputdir = path.join(cachedir, modulehash) - if not os.exists(outputdir) then - os.mkdir(outputdir) - end + if not os.exists(outputdir) then os.mkdir(outputdir) end return outputdir end function add_installfiles_for_modules(target, modules) - local sourcebatch = target:sourcebatches()["c++.build.modules.install"] + 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 = get_modulehash(sourcefile) - local prefixdir = path.join("modules", modulehash) - target:add("installfiles", sourcefile, {prefixdir = prefixdir}) + local prefixdir = path.join('modules', modulehash) + target:add('installfiles', sourcefile, { prefixdir = prefixdir }) local metafile = get_metafile(target, modules[sourcefile]) - if os.exists(metafile) then - target:add("installfiles", metafile, {prefixdir = prefixdir}) - end + if os.exists(metafile) then target:add('installfiles', metafile, { prefixdir = prefixdir }) end end end end end - -- cgit v1.3.1