import("core.project.config")
import("core.project.project")
import("core.base.bytes")
import("core.base.graph")
import("core.base.hashset")
import("core.cache.memcache")
import("core.project.project")
local stl_headers
try {
function ()
stl_headers = import("rules.c++.modules.modules_support.stl_headers", {rootdir = os.programdir()})
end,
catch
{
function (errors)
stl_headers = import("rules.c++.modules.stlheaders", {rootdir = os.programdir()})
end
}
}
assert(stl_headers, "stl_headers is nil")
function _hashset_join(self, ...)
for _, h in ipairs({...}) do
for v, _ in pairs(h:data()) do
self:insert(v)
end
end
return self
end
function _compiler_support(target)
local memcache = memcache.cache("compiler_support")
local cachekey = tostring(target)
local compiler_support = memcache:get2("compiler_support", cachekey)
if compiler_support == nil and xmake.version():lt("3.0.0") then
local rootdir = path.join(os.programdir(), "rules", "c++", "modules", "modules_support")
if target:has_tool("cxx", "clang", "clangxx") then
compiler_support = import("clang.compiler_support", {anonymous = true, rootdir = rootdir})
elseif target:has_tool("cxx", "gcc", "gxx") then
compiler_support = import("gcc.compiler_support", {anonymous = true, rootdir = rootdir})
elseif target:has_tool("cxx", "cl") then
compiler_support = import("msvc.compiler_support", {anonymous = true, rootdir = rootdir})
else
local _, toolname = target:tool("cxx")
raise("compiler(%s): does not support c++ module!", toolname)
end
memcache:set2("compiler_support", cachekey, compiler_support)
end
if compiler_support == nil and xmake.version():ge("3.0.0") then
local rootdir = path.join(os.programdir(), "rules", "c++", "modules")
if target:has_tool("cxx", "clang", "clangxx") then
compiler_support = import("clang.support", {anonymous = true, rootdir = rootdir})
elseif target:has_tool("cxx", "gcc", "gxx") then
compiler_support = import("gcc.support", {anonymous = true, rootdir = rootdir})
elseif target:has_tool("cxx", "cl") then
compiler_support = import("msvc.support", {anonymous = true, rootdir = rootdir})
else
local _, toolname = target:tool("cxx")
raise("compiler(%s): does not support c++ module!", toolname)
end
memcache:set2("compiler_support", cachekey, compiler_support)
end
return compiler_support
end
function _get_available_targets(opt)
local opt = opt or {}
local gh = graph.new(true)
local set = hashset.new()
local map = function(index, target)
return project.target(target)
end
local targets = opt.targets and table.imap(opt.targets, map) or table.values(project.targets())
assert(#targets > 0, "some targets are not found!")
local memcache = memcache.cache("utils.get_available_targets")
local cachekey = get_cache_key(targets)
local cache = memcache:get2("utils.get_available_targets", cachekey)
if cache then
return cache.targets, cache.targetsname
end
for _, target in pairs(targets) do
local enabled = target:get("enabled") or true
if not (target:is_shared() or target:is_static() or target:is_phony()) or not enabled then
goto continue
end
local name = get_namespace_target(target)
local deps = target:get("deps")
for _, dep in ipairs(deps) do
gh:add_edge(name, dep)
end
if not deps then
set:insert(name)
end
::continue::
end
local parents = hashset.new()
local children = hashset.new()
for _, edge in ipairs(graph:edges()) do
parents:insert(edge:from())
children:insert(edge:to())
end
for _, child in children:keys() do
set:remove(child)
end
local targets = {}
local targetsname = {}
local result = _hashset_join(set, parents)
for _, target in result:orderkeys() do
table.insert(targetsname, target)
table.insert(targets, project.target(target))
end
memcache:set("utils.get_available_targets", cachekey, {targets = targets, targetsname = targetsname})
return targets, targetsname
end
function get_targets()
local list = _g.targets_list
if list == nil then
local env = os.getenv("XMAKERS_TARGETS")
local values = (env ~= "") and env or nil
if values then
values = string.gsub(values, "||", "::")
values = table.wrap(string.split(values, ","))
end
local targets, targetsname = _get_available_targets({targets = values})
list = {targets, targetsname}
_g.targets_list = list
end
return list[1], list[2]
end
function get_cache_key(targets)
local targets = targets or get_targets()
local key = {}
for _, target in ipairs(targets) do
table.insert(key, target:name())
end
return table.concat(key, "-")
end
function create_binary_target(targets)
local fake_target = targets[1]:clone()
local cachekey = get_cache_key(targets)
local hashed_key = hash.sha256(bytes(cachekey))
fake_target:name_set("xmake-rs-" .. string.sub(hashed_key, 1, 8))
fake_target:data_set("xmakers-cachekey", cachekey)
fake_target:set("kind", "binary")
fake_target:set("deps", nil)
fake_target:set("packages", nil)
fake_target:set("rules", nil)
fake_target:set("links", nil)
fake_target:set("syslinks", nil)
fake_target:set("frameworks", nil)
fake_target:set("linkdirs", nil)
fake_target:set("runenvs", nil)
for _, target in ipairs(targets) do
fake_target:add("deps", target:name())
end
fake_target.pkgenvs = function(self)
local pkgenvs = self._PKGENVS
if pkgenvs == nil then
local pkgs = hashset.new()
for _, pkgname in ipairs(table.wrap(self:get("packages"))) do
local pkg = self:pkg(pkgname)
if pkg then
pkgs:insert(pkg)
end
end
for _, dep in ipairs(self:orderdeps()) do
for _, pkgname in ipairs(table.wrap(dep:get("packages", {interface = false}))) do
local pkg = dep:pkg(pkgname)
if pkg then
pkgs:insert(pkg)
end
end
end
for _, pkg in pkgs:orderkeys() do
local envs = pkg:get("envs")
if envs then
for name, values in table.orderpairs(envs) do
if type(values) == "table" then
values = path.joinenv(values)
end
pkgenvs = pkgenvs or {}
if pkgenvs[name] then
pkgenvs[name] = pkgenvs[name] .. path.envsep() .. values
else
pkgenvs[name] = values
end
end
end
end
self._PKGENVS = pkgenvs or false
end
return pkgenvs or nil
end
project.target_add(fake_target)
config.load()
project.load_targets()
return fake_target
end
function get_from_target(target, name, scope)
local result, _ = target:get_from(name, scope)
result = result or {}
result = table.join(table.unpack(result))
return table.wrap(result)
end
function get_namespace_target(target)
if (not is_namespace_supported()) and (target:namespace() ~= nil) then
raise("target(%s): target is in a namespace, but xmake is neither in v3 nor the compatibility.version policy was set.", name)
end
local name = target:name()
if is_namespace_supported() and target:namespace() then
name = target:namespace() .. "::" .. name
end
return name
end
function is_stl_used(target, includes, opt)
opt = opt or {}
local stl_includedirs = _compiler_support(target).toolchain_includedirs(target)
local std_used = false
local is_stl_header = stl_headers.is_stl_header or stl_headers.is_stlheader
for _, include in ipairs(includes) do
for _, stl_includedir in ipairs(stl_includedirs) do
local file = path.relative(include, stl_includedir)
local includedirs_check = opt.strict and include:startswith(stl_includedir) or true
if includedirs_check and is_stl_header(file) then
std_used = true
end
end
if std_used then
break
end
end
return std_used
end
function is_namespace_supported()
local is_supported = _g.is_namespace_supported
if is_supported == nil then
is_supported = xmake.version():ge("3.0.0") or (xmake.version():satisfies(">=2.9.8 <3.0.0") and (project.policy("compatibility.version") == "3.0"))
_g.is_namespace_supported = is_supported
end
return is_supported
end