summaryrefslogtreecommitdiff
path: root/xmake/rules/c++/modules/modules_support/msvc.lua
diff options
context:
space:
mode:
Diffstat (limited to 'xmake/rules/c++/modules/modules_support/msvc.lua')
-rw-r--r--xmake/rules/c++/modules/modules_support/msvc.lua688
1 files changed, 688 insertions, 0 deletions
diff --git a/xmake/rules/c++/modules/modules_support/msvc.lua b/xmake/rules/c++/modules/modules_support/msvc.lua
new file mode 100644
index 000000000..5214f12df
--- /dev/null
+++ b/xmake/rules/c++/modules/modules_support/msvc.lua
@@ -0,0 +1,688 @@
+--!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 msvc.lua
+--
+
+-- imports
+import("core.tool.compiler")
+import("core.project.project")
+import("core.project.depend")
+import("core.project.config")
+import("core.base.hashset")
+import("utils.progress")
+import("private.action.build.object", {alias = "objectbuilder"})
+import("common")
+
+-- add a module or header unit into the mapper
+--
+-- e.g
+-- /headerUnit:angle Foo=build/.gens/Foo/rules/modules/cache/Foo.ifc
+-- /headerUnit:angle glm/mat4x4.hpp=Users\arthu\AppData\Local\.xmake\packages\g\glm\0.9.9+8\91454f3ee0be416cb9c7452970a2300f\include\glm\mat4x4.hpp.ifc
+--
+function _add_module_to_mapper(target, argument, name, bmifile, deps)
+ local modulemap = _get_modulemap_from_mapper(target)
+ if modulemap[name] then
+ return
+ end
+ local mapflag = {argument, name .. "=" .. bmifile}
+ modulemap[name] = {flag = mapflag, deps = deps}
+ common.localcache():set2(_mapper_cachekey(target), "modulemap", modulemap)
+end
+
+function _mapper_cachekey(target)
+ return target:name() .. "_modulemap"
+end
+
+-- flush mapper file cache
+function _flush_mapper(target)
+ -- not using set2/get2 to flush only current target mapper
+ common.localcache():save(_mapper_cachekey(target))
+end
+
+-- get modulemap from mapper
+function _get_modulemap_from_mapper(target)
+ return common.localcache():get2(_mapper_cachekey(target), "modulemap") or {}
+end
+
+-- add an objectfile to the linker args
+--
+-- e.g
+-- foo.obj
+--
+function _add_objectfile_to_link_arguments(target, objectfile)
+ local cachekey = target:name() .. "headerunit_objectfiles"
+ local cache = common.localcache():get(cachekey) or {}
+ if table.contains(cache, objectfile) then
+ return
+ end
+ table.insert(cache, objectfile)
+ common.localcache():set(cachekey, cache)
+ common.localcache():save(cachekey)
+end
+
+-- load module support for the current target
+function load(target)
+ -- get flags
+ local modulesflag = get_modulesflag(target)
+
+ -- add modules flags
+ target:add("cxxflags", modulesflag)
+
+ -- add stdifcdir in case of if the user ask for it
+ if target:values("msvc.modules.stdifcdir") then
+ local stdifcdirflag = get_stdifcdirflag(target)
+ for _, toolchain_inst in ipairs(target:toolchains()) do
+ if toolchain_inst:name() == "msvc" then
+ local vcvars = toolchain_inst:config("vcvars")
+ if vcvars.VCInstallDir and vcvars.VCToolsVersion then
+ local stdifcdir = path.join(vcvars.VCInstallDir, "Tools", "MSVC", vcvars.VCToolsVersion, "ifc", target:is_arch("x64") and "x64" or "x86")
+ if os.isdir(stdifcdir) then
+ target:add("cxxflags", {stdifcdirflag, winos.short_path(stdifcdir)}, {force = true, expand = false})
+ end
+ end
+ break
+ end
+ end
+ end
+end
+
+-- provide toolchain include dir for stl headerunit when p1689 is not supported
+function toolchain_includedirs(target)
+ for _, toolchain_inst in ipairs(target:toolchains()) do
+ if toolchain_inst:name() == "msvc" then
+ local vcvars = toolchain_inst:config("vcvars")
+ if vcvars.VCInstallDir and vcvars.VCToolsVersion then
+ return { path.join(vcvars.VCInstallDir, "Tools", "MSVC", vcvars.VCToolsVersion, "include") }
+ end
+ break
+ end
+ end
+ raise("msvc toolchain includedirs not found!")
+end
+
+-- generate dependency files
+function generate_dependencies(target, sourcebatch, opt)
+ local compinst = target:compiler("cxx")
+ local toolchain = target:toolchain("msvc")
+ local vcvars = toolchain:config("vcvars")
+ local scandependenciesflag = get_scandependenciesflag(target)
+ local common_args = {"-TP", scandependenciesflag}
+ local cachedir = common.modules_cachedir(target)
+ local changed = false
+ for _, sourcefile in ipairs(sourcebatch.sourcefiles) do
+ local dependfile = target:dependfile(sourcefile)
+ depend.on_changed(function ()
+ if opt.progress then
+ progress.show(opt.progress, "${color.build.object}generating.cxx.module.deps %s", sourcefile)
+ end
+ local outputdir = path.join(cachedir, path.directory(path.relative(sourcefile, projectdir)))
+ if not os.isdir(outputdir) then
+ os.mkdir(outputdir)
+ end
+
+ local jsonfile = path.join(outputdir, path.filename(sourcefile) .. ".json")
+ if scandependenciesflag then
+ local args = {jsonfile, sourcefile, "-Fo" .. target:objectfile(sourcefile)}
+ os.vrunv(compinst:program(), table.join(compinst:compflags({target = target}), common_args, args), {envs = vcvars})
+ else
+ common.fallback_generate_dependencies(target, jsonfile, sourcefile)
+ end
+ changed = true
+
+ local dependinfo = io.readfile(jsonfile)
+ return { moduleinfo = dependinfo }
+ end, {dependfile = dependfile, files = {sourcefile}})
+ end
+ return changed
+end
+
+-- generate target stl header units for batchjobs
+function generate_stl_headerunits_for_batchjobs(target, batchjobs, headerunits, opt)
+ local compinst = target:compiler("cxx")
+ local toolchain = target:toolchain("msvc")
+ local vcvars = toolchain:config("vcvars")
+ local stlcachedir = common.stlmodules_cachedir(target)
+
+ -- get flags
+ local exportheaderflag = get_exportheaderflag(target)
+ local headerunitflag = get_headerunitflag(target)
+ local headernameflag = get_headernameflag(target)
+ local ifcoutputflag = get_ifcoutputflag(target)
+ assert(headerunitflag and headernameflag and exportheaderflag, "compiler(msvc): does not support c++ header units!")
+
+ -- flush job
+ local flushjob = batchjobs:addjob(target:name() .. "_stl_headerunits_flush_mapper", function(index, total)
+ _flush_mapper(target)
+ end, {rootjob = opt.rootjob})
+
+ -- build headerunits
+ local common_args = {"-TP", exportheaderflag, "-c"}
+ for _, headerunit in ipairs(headerunits) do
+ local bmifile = path.join(stlcachedir, headerunit.name .. get_bmi_extension())
+ local objectfile = bmifile .. ".obj"
+ if not os.isfile(bmifile) or not os.isfile(objectfile) then
+ batchjobs:addjob(headerunit.name, function(index, total)
+ depend.on_changed(function()
+ -- don't build same header unit at the same time
+ if not common.memcache():get2(headerunit.name, "building") then
+ common.memcache():set2(headerunit.name, "building", true)
+ progress.show((index * 100) / total, "${color.build.object}generating.cxx.headerunit.bmi %s", headerunit.name)
+ local args = {headernameflag .. ":angle", headerunit.name, ifcoutputflag, headerunit.name:startswith("experimental/") and path.join(stlcachedir, "experimental") or stlcachedir, "-Fo" .. objectfile}
+ os.vrunv(compinst:program(), table.join(compinst:compflags({target = target}), common_args, args), {envs = vcvars})
+ end
+
+ end, {dependfile = target:dependfile(bmifile), files = {headerunit.path}})
+ _add_module_to_mapper(target, headerunitflag .. ":angle", headerunit.name, bmifile)
+ if os.isfile(objectfile) then
+ _add_objectfile_to_link_arguments(target, objectfile)
+ end
+ end, {rootjob = flushjob})
+ end
+ end
+end
+
+-- generate target stl header units for batchcmds
+function generate_stl_headerunits_for_batchcmds(target, batchcmds, headerunits, opt)
+ local compinst = target:compiler("cxx")
+ local toolchain = target:toolchain("msvc")
+ local vcvars = toolchain:config("vcvars")
+ local stlcachedir = common.stlmodules_cachedir(target)
+
+ -- get flags
+ local exportheaderflag = get_exportheaderflag(target)
+ local headerunitflag = get_headerunitflag(target)
+ local headernameflag = get_headernameflag(target)
+ local ifcoutputflag = get_ifcoutputflag(target)
+ assert(headerunitflag and headernameflag and exportheaderflag, "compiler(msvc): does not support c++ header units!")
+
+ -- build headerunits
+ local common_args = {"-TP", exportheaderflag, "-c"}
+ local depmtime = 0
+ for _, headerunit in ipairs(headerunits) do
+ local bmifile = path.join(stlcachedir, headerunit.name .. get_bmi_extension())
+ local objectfile = bmifile .. ".obj"
+ -- don't build same header unit at the same time
+ if not common.memcache():get2(headerunit.name, "building") then
+ common.memcache():set2(headerunit.name, "building", true)
+ local args = {
+ headernameflag .. ":angle",
+ headerunit.name,
+ ifcoutputflag,
+ path(headerunit.name:startswith("experimental/") and path.join(stlcachedir, "experimental") or stlcachedir),
+ path(objectfile, function (p) return "-Fo" .. p end)}
+ batchcmds:show_progress(opt.progress, "${color.build.object}generating.cxx.headerunit.bmi %s", headerunit.name)
+ batchcmds:vrunv(compinst:program(), table.join(compinst:compflags({target = target}), common_args, args), {envs = vcvars})
+ batchcmds:add_depfiles(headerunit.path)
+ end
+ _add_module_to_mapper(target, headerunitflag .. ":angle", headerunit.name, bmifile)
+ if os.isfile(objectfile) then
+ _add_objectfile_to_link_arguments(target, objectfile)
+ end
+ depmtime = math.max(depmtime, os.mtime(bmifile))
+ end
+ batchcmds:set_depmtime(depmtime)
+ _flush_mapper(target)
+end
+
+-- generate target user header units for batchcmds
+function generate_user_headerunits_for_batchjobs(target, batchjobs, headerunits, opt)
+ local compinst = target:compiler("cxx")
+ local toolchain = target:toolchain("msvc")
+ local vcvars = toolchain:config("vcvars")
+ local cachedir = common.modules_cachedir(target)
+
+ -- get flags
+ local exportheaderflag = get_exportheaderflag(target)
+ local headerunitflag = get_headerunitflag(target)
+ local headernameflag = get_headernameflag(target)
+ local ifcoutputflag = get_ifcoutputflag(target)
+ assert(headerunitflag and headernameflag and exportheaderflag, "compiler(msvc): does not support c++ header units!")
+
+ -- flush job
+ local flushjob = batchjobs:addjob(target:name() .. "_user_headerunits_flush_mapper", function(index, total)
+ _flush_mapper(target)
+ end, {rootjob = opt.rootjob})
+
+ -- build headerunits
+ local common_args = {"-TP", exportheaderflag, "-c"}
+ local projectdir = os.projectdir()
+ for _, headerunit in ipairs(headerunits) do
+ local file = path.relative(headerunit.path, target:scriptdir())
+ local objectfile = target:objectfile(file)
+ local outputdir
+ if headerunit.type == ":quote" then
+ outputdir = path.join(cachedir, path.directory(path.relative(headerunit.path, projectdir)))
+ else
+ -- if path is relative then its a subtarget path
+ outputdir = path.join(cachedir, path.is_absolute(headerunit.path) and path.directory(headerunit.path):sub(3) or headerunit.path)
+ end
+ local bmifilename = path.basename(objectfile) .. get_bmi_extension()
+ local bmifile = path.join(outputdir, bmifilename)
+ batchjobs:addjob(headerunit.name, function (index, total)
+ depend.on_changed(function()
+ if not common.memcache():get2(headerunit.name, "building") then
+ common.memcache():set2(headerunit.name, "building", true)
+ progress.show((index * 100) / total, "${color.build.object}generating.cxx.headerunit.bmi %s", headerunit.name)
+ local objectdir = path.directory(objectfile)
+ if not os.isdir(objectdir) then
+ os.mkdir(objectdir)
+ end
+ if not os.isdir(outputdir) then
+ os.mkdir(outputdir)
+ end
+
+ -- generate headerunit
+ local args = {headernameflag .. headerunit.type, headerunit.path, ifcoutputflag, outputdir, "/Fo" .. objectfile}
+ os.vrunv(compinst:program(), table.join(compinst:compflags({target = target}), common_args, args), {envs = vcvars})
+ end
+ _add_module_to_mapper(target, headerunitflag .. headerunit.type, headerunit.name, bmifile)
+ if os.isfile(objectfile) then
+ _add_objectfile_to_link_arguments(target, objectfile)
+ end
+ end, {dependfile = target:dependfile(bmifile), files = {headerunit.path}})
+ end, {rootjob = flushjob})
+ end
+end
+
+-- generate target user header units for batchcmds
+function generate_user_headerunits_for_batchcmds(target, batchcmds, headerunits, opt)
+ local compinst = target:compiler("cxx")
+ local toolchain = target:toolchain("msvc")
+ local vcvars = toolchain:config("vcvars")
+ local cachedir = common.modules_cachedir(target)
+
+ -- get flags
+ local exportheaderflag = get_exportheaderflag(target)
+ local headerunitflag = get_headerunitflag(target)
+ local headernameflag = get_headernameflag(target)
+ local ifcoutputflag = get_ifcoutputflag(target)
+ assert(headerunitflag and headernameflag and exportheaderflag, "compiler(msvc): does not support c++ header units!")
+
+ -- build headerunits
+ local common_args = {"-TP", exportheaderflag, "-c"}
+ local projectdir = os.projectdir()
+ local depmtime = 0
+ for _, headerunit in ipairs(headerunits) do
+ local file = path.relative(headerunit.path, target:scriptdir())
+ local objectfile = target:objectfile(file)
+ local outputdir
+ if headerunit.type == ":quote" then
+ outputdir = path.join(cachedir, path.directory(path.relative(headerunit.path, projectdir)))
+ else
+ -- if path is relative then its a subtarget path
+ outputdir = path.join(cachedir, path.is_absolute(headerunit.path) and path.directory(headerunit.path):sub(3) or headerunit.path)
+ end
+ batchcmds:mkdir(outputdir)
+
+ local bmifilename = path.basename(objectfile) .. get_bmi_extension()
+ local bmifile = path.join(outputdir, bmifilename)
+ batchcmds:mkdir(path.directory(objectfile))
+
+ local args = {headernameflag .. headerunit.type, headerunit.path, ifcoutputflag, outputdir, "/Fo" .. objectfile}
+
+ batchcmds:show_progress(opt.progress, "${color.build.object}generating.cxx.headerunit.bmi %s", headerunit.name)
+ batchcmds:vrunv(compinst:program(), table.join(compinst:compflags({target = target}), common_args, args), {envs = vcvars})
+ batchcmds:add_depfiles(headerunit.path)
+
+ _add_module_to_mapper(target, headerunitflag .. headerunit.type, headerunit.name, bmifile)
+ _add_objectfile_to_link_arguments(target, objectfile)
+
+ depmtime = math.max(depmtime, os.mtime(bmifile))
+ end
+ batchcmds:set_depmtime(depmtime)
+ _flush_mapper(target)
+end
+
+-- build module files for batchjobs
+function build_modules_for_batchjobs(target, batchjobs, objectfiles, modules, opt)
+ local compinst = target:compiler("cxx")
+ local toolchain = target:toolchain("msvc")
+ local vcvars = toolchain:config("vcvars")
+
+ -- get flags
+ local ifcoutputflag = get_ifcoutputflag(target)
+ local interfaceflag = get_interfaceflag(target)
+ local referenceflag = get_referenceflag(target)
+
+ -- flush job
+ local flushjob = batchjobs:addjob(target:name() .. "_modules", function(index, total)
+ _flush_mapper(target)
+ end, {rootjob = opt.rootjob})
+
+ local common_args = {"-TP"}
+ local modulesjobs = {}
+ for _, objectfile in ipairs(objectfiles) do
+ local module = modules[objectfile]
+ if module then
+ if module.provides then
+ -- assume there that provides is only one, until we encounter the case
+ local length = 0
+ local name, provide
+ for k, v in pairs(module.provides) do
+ length = length + 1
+ name = k
+ provide = v
+ if length > 1 then
+ raise("multiple provides are not supported now!")
+ end
+ end
+
+ local bmifile = provide.bmi
+ local moduleinfo = table.copy(provide)
+ moduleinfo.job = batchjobs:newjob(provide.sourcefile, function (index, total)
+ -- append module mapper flags first
+ -- @note we add it at the end to ensure that the full modulemap are already stored in the mapper
+ local requiresflags
+ if module.requires then
+ requiresflags = get_requiresflags(target, module.requires, {expand = true})
+ end
+ depend.on_changed(function()
+ progress.show((index * 100) / total, "${color.build.object}generating.cxx.module.bmi %s", name)
+ local objectdir = path.directory(objectfile)
+ if not os.isdir(objectdir) then
+ os.mkdir(objectdir)
+ end
+ local args = {"-c", "-Fo" .. objectfile, interfaceflag, ifcoutputflag, bmifile, provide.sourcefile}
+ os.vrunv(compinst:program(), table.join(compinst:compflags({target = target}), common_args, requiresflags or {}, args), {envs = vcvars})
+ end, {dependfile = target:dependfile(bmifile), files = {provide.sourcefile}})
+ _add_module_to_mapper(target, referenceflag, name, bmifile, requiresflags)
+ end)
+ if module.requires then
+ moduleinfo.deps = table.keys(module.requires)
+ end
+ moduleinfo.name = name
+ modulesjobs[name] = moduleinfo
+ target:add("objectfiles", objectfile)
+ else
+ if module.requires then
+ modulesjobs[module.cppfile] = {
+ name = module.cppfile,
+ deps = table.keys(module.requires),
+ sourcefile = module.cppfile,
+ job = batchjobs:newjob(module.cppfile, function(index, total)
+ function contains(t, v)
+ for _, flag in ipairs(t) do
+ if table.contains(flag, v) then
+ return true
+ end
+ end
+ return false
+ end
+ -- append module mapper flags
+ -- @note we add it at the end to ensure that the full modulemap are already stored in the mapper
+ local requiresflags = get_requiresflags(target, module.requires)
+ if requiresflags then
+ target:fileconfig_add(module.cppfile, {force = {cxxflags = requiresflags}})
+ end
+ end)
+ }
+ end
+ end
+ end
+ end
+
+ -- build batchjobs for modules
+ common.build_batchjobs_for_modules(modulesjobs, batchjobs, flushjob)
+end
+
+-- build module files for batchcmds
+function build_modules_for_batchcmds(target, batchcmds, objectfiles, modules, opt)
+ local compinst = target:compiler("cxx")
+ local toolchain = target:toolchain("msvc")
+ local vcvars = toolchain:config("vcvars")
+ local cachedir = common.modules_cachedir(target)
+
+ -- get flags
+ local ifcoutputflag = get_ifcoutputflag(target)
+ local interfaceflag = get_interfaceflag(target)
+ local referenceflag = get_referenceflag(target)
+
+ -- build modules
+ local common_args = {"-TP"}
+ local depmtime = 0
+ for _, objectfile in ipairs(objectfiles) do
+ local module = modules[objectfile]
+ if module then
+ if module.provides then
+ local name, provide
+ for k, v in pairs(module.provides) do
+ name = k
+ provide = v
+ break
+ end
+
+ -- append required modulemap flags to module
+ local requiresflags
+ if module.requires then
+ requiresflags = get_requiresflags(target, module.requires, {expand = true})
+ end
+
+ local bmifile = provide.bmi
+ local args = {"-c",
+ path(objectfile, function (p) return "-Fo" .. p end),
+ interfaceflag,
+ ifcoutputflag,
+ path(bmifile),
+ path(provide.sourcefile)}
+ batchcmds:show_progress(opt.progress, "${color.build.object}generating.cxx.module.bmi %s", name)
+ batchcmds:mkdir(path.directory(objectfile))
+ batchcmds:vrunv(compinst:program(), table.join(compinst:compflags({target = target}), common_args, requiresflags or {}, args), {envs = vcvars})
+ batchcmds:add_depfiles(provide.sourcefile)
+ _add_module_to_mapper(target, referenceflag, name, bmifile, requiresflags)
+ depmtime = math.max(depmtime, os.mtime(bmifile))
+ else
+ if module.requires then
+ local requiresflags = get_requiresflags(target, module.requires)
+ if requiresflags then
+ target:fileconfig_add(module.cppfile, {force = {cxxflags = requiresflags}})
+ end
+ end
+ end
+ end
+ end
+
+ batchcmds:set_depmtime(depmtime)
+ _flush_mapper(target)
+end
+
+function get_bmi_extension()
+ return ".ifc"
+end
+
+function get_modulesflag(target)
+ local modulesflag = _g.modulesflag
+ if modulesflag == nil then
+ local compinst = target:compiler("cxx")
+ if compinst:has_flags("-experimental:module", "cxxflags", {flagskey = "cl_experimental_module"}) then
+ modulesflag = "-experimental:module"
+ end
+ assert(modulesflag, "compiler(msvc): does not support c++ module!")
+ _g.modulesflag = modulesflag or false
+ end
+ return modulesflag or nil
+end
+
+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
+ ifcoutputflag = "-ifcOutput"
+ end
+ assert(ifcoutputflag, "compiler(msvc): does not support c++ module!")
+ _g.ifcoutputflag = ifcoutputflag or false
+ end
+ return ifcoutputflag or nil
+end
+
+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
+ ifcsearchdirflag = "-ifcSearchDir"
+ end
+ assert(ifcsearchdirflag, "compiler(msvc): does not support c++ module!")
+ _g.ifcsearchdirflag = ifcsearchdirflag or false
+ end
+ return ifcsearchdirflag or nil
+end
+
+function get_interfaceflag(target)
+ local interfaceflag = _g.interfaceflag
+ if interfaceflag == nil then
+ local compinst = target:compiler("cxx")
+ if compinst:has_flags("-interface", "cxxflags", {flagskey = "cl_interface"}) then
+ interfaceflag = "-interface"
+ end
+ assert(interfaceflag, "compiler(msvc): does not support c++ module!")
+ _g.interfaceflag = interfaceflag or false
+ end
+ return interfaceflag
+end
+
+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
+ referenceflag = "-reference"
+ end
+ assert(referenceflag, "compiler(msvc): does not support c++ module!")
+ _g.referenceflag = referenceflag or false
+ end
+ return referenceflag or nil
+end
+
+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
+ headernameflag = "-headerName"
+ end
+ _g.headernameflag = headernameflag or false
+ end
+ return headernameflag or nil
+end
+
+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
+ headerunitflag = "-headerUnit"
+ end
+ _g.headerunitflag = headerunitflag or false
+ end
+ return headerunitflag or nil
+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
+ exportheaderflag = "-exportHeader"
+ end
+ _g.exportheaderflag = exportheaderflag or false
+ end
+ return exportheaderflag or nil
+end
+
+function get_stdifcdirflag(target)
+ local stdifcdirflag = _g.stdifcdirflag
+ if stdifcdirflag == nil then
+ local compinst = target:compiler("cxx")
+ if compinst:has_flags("-stdIfcDir", "cxxflags", {flagskey = "cl_std_ifc_dir"}) then
+ stdifcdirflag = "-stdIfcDir"
+ end
+ _g.stdifcdirflag = stdifcdirflag or false
+ end
+ return stdifcdirflag or nil
+end
+
+function get_scandependenciesflag(target)
+ local scandependenciesflag = _g.scandependenciesflag
+ if scandependenciesflag == nil then
+ local compinst = target:compiler("cxx")
+ local scan_dependencies_jsonfile = os.tmpfile() .. ".json"
+ if compinst:has_flags("-scanDependencies " .. scan_dependencies_jsonfile, "cxflags", {flagskey = "cl_scan_dependencies",
+ on_check = function (ok, errors)
+ if os.isfile(scan_dependencies_jsonfile) then
+ ok = true
+ end
+ if ok and not os.isfile(scan_dependencies_jsonfile) then
+ ok = false
+ end
+ return ok, errors
+ end}) then
+ scandependenciesflag = "-scanDependencies"
+ end
+ _g.scandependenciesflag = scandependenciesflag or false
+ end
+ return scandependenciesflag or nil
+end
+
+-- get requireflags from module mapper
+function get_requiresflags(target, requires, opt)
+ opt = opt or {}
+ local flags = {}
+ local modulemap = _get_modulemap_from_mapper(target)
+ -- add deps required module flags
+ for name, _ in pairs(requires) do
+ for _, dep in ipairs(target:orderdeps()) do
+ local modulemap_ = _get_modulemap_from_mapper(dep)
+ if modulemap_[name] then
+ table.join2(flags, modulemap_[name].flag)
+ table.join2(flags, modulemap_[name].deps or {})
+ goto continue
+ end
+ end
+
+ -- append target required module mapper flags
+ if modulemap[name] then
+ table.join2(flags, modulemap[name].flag)
+ table.join2(flags, modulemap[name].deps or {})
+ goto continue
+ end
+
+ ::continue::
+ end
+ local requireflags = {}
+ local contains = {}
+ for i = 1, #flags, 2 do
+ local value = flags[i + 1]
+ if not contains[value] then
+ local key = flags[i]
+ if opt.expand then
+ table.insert(requireflags, key)
+ table.insert(requireflags, value)
+ else
+ table.insert(requireflags, {key, value})
+ end
+ contains[value] = true
+ end
+ end
+ if #requireflags > 0 then
+ return requireflags
+ end
+end