742 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			742 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
# 属性
 | 
						|
 | 
						|
## scopeinfo
 | 
						|
 | 
						|
xmake.lua 生成属性信息,再根据类型生成
 | 
						|
 | 
						|
```lua
 | 
						|
local _instance = scopeinfo
 | 
						|
--[[
 | 
						|
	kind : scopetype {root , target , rule , package , task}
 | 
						|
	info : scopeconfig {come from xmake.lua}
 | 
						|
	opt : unknown
 | 
						|
]]
 | 
						|
-- new an instance
 | 
						|
function _instance.new(kind, info, opt)
 | 
						|
    opt = opt or {}
 | 
						|
    local instance = table.inherit(_instance)
 | 
						|
    instance._KIND = kind or "root"
 | 
						|
    instance._INFO = info
 | 
						|
    instance._INTERPRETER = opt.interpreter
 | 
						|
    instance._DEDUPLICATE = opt.deduplicate
 | 
						|
    instance._ENABLE_FILTER = opt.enable_filter
 | 
						|
    --print("scope", kind , info.__scriptdir , info.kind)
 | 
						|
    return instance
 | 
						|
end
 | 
						|
```
 | 
						|
 | 
						|
## Target
 | 
						|
 | 
						|
```lua
 | 
						|
--[[
 | 
						|
	name : scopename
 | 
						|
	info : scopeinfo
 | 
						|
]]
 | 
						|
-- new a target instance
 | 
						|
function _instance.new(name, info)
 | 
						|
    local instance     = table.inherit(_instance)
 | 
						|
    instance._NAME     = name
 | 
						|
    instance._INFO     = info
 | 
						|
    instance._CACHEID  = 1
 | 
						|
    return instance
 | 
						|
end
 | 
						|
```
 | 
						|
 | 
						|
 | 
						|
 | 
						|
## Rule
 | 
						|
 | 
						|
```lua
 | 
						|
 | 
						|
-- new a rule instance
 | 
						|
function rule.new(name, info, opt)
 | 
						|
    opt = opt or {}
 | 
						|
    local instance = table.inherit(_instance)
 | 
						|
    instance._NAME = name
 | 
						|
    instance._INFO = info
 | 
						|
    instance._PACKAGE = opt.package
 | 
						|
    if opt.package then
 | 
						|
        local deps = {}
 | 
						|
        for _, depname in ipairs(table.wrap(instance:get("deps"))) do
 | 
						|
            -- @xxx -> @package/xxx
 | 
						|
            if depname:startswith("@") and not depname:find("/", 1, true) then
 | 
						|
                depname = "@" .. opt.package:name() .. "/" .. depname:sub(2)
 | 
						|
            end
 | 
						|
            table.insert(deps, depname)
 | 
						|
        end
 | 
						|
        deps = table.unwrap(deps)
 | 
						|
        if deps and #deps > 0 then
 | 
						|
            instance:set("deps", deps)
 | 
						|
        end
 | 
						|
        for depname, extraconf in pairs(table.wrap(instance:extraconf("deps"))) do
 | 
						|
            if depname:startswith("@") and not depname:find("/", 1, true) then
 | 
						|
                depname = "@" .. opt.package:name() .. "/" .. depname:sub(2)
 | 
						|
                instance:extraconf_set("deps", depname, extraconf)
 | 
						|
            end
 | 
						|
        end
 | 
						|
    end
 | 
						|
    return instance
 | 
						|
end
 | 
						|
```
 | 
						|
 | 
						|
 | 
						|
 | 
						|
## Package
 | 
						|
 | 
						|
```lua
 | 
						|
-- new an instance
 | 
						|
function _instance.new(name, info, opt)
 | 
						|
    opt = opt or {}
 | 
						|
    local instance = table.inherit(_instance)
 | 
						|
    instance._NAME      = name
 | 
						|
    instance._INFO      = info
 | 
						|
    instance._REPO      = opt.repo
 | 
						|
    instance._SCRIPTDIR = opt.scriptdir and path.absolute(opt.scriptdir)
 | 
						|
    return instance
 | 
						|
end
 | 
						|
```
 | 
						|
 | 
						|
 | 
						|
 | 
						|
## Task
 | 
						|
 | 
						|
```lua
 | 
						|
-- new a task instance
 | 
						|
function task.new(name, info)
 | 
						|
    local instance = table.inherit(task)
 | 
						|
    instance._NAME = name
 | 
						|
    instance._INFO = info
 | 
						|
    return instance
 | 
						|
end
 | 
						|
```
 | 
						|
 | 
						|
# 事件
 | 
						|
 | 
						|
只触发一次
 | 
						|
 | 
						|
## Project
 | 
						|
 | 
						|
- targets
 | 
						|
  - _load_targets
 | 
						|
    - t:_load_before()
 | 
						|
      - r:_load_before()
 | 
						|
    - t:_load()
 | 
						|
      - r:_load()
 | 
						|
  - t:_load_after()
 | 
						|
    - r:_load_after()
 | 
						|
 | 
						|
```lua
 | 
						|
local _instance = Project
 | 
						|
function project.targets()
 | 
						|
    if project._memcache():get("targets", targets) then
 | 
						|
    	return    
 | 
						|
    end
 | 
						|
    local targets, errors = project._load_targets()
 | 
						|
    project._memcache():set("targets", targets)
 | 
						|
    for _, t in ipairs(project.ordertargets()) do
 | 
						|
        local ok, errors = t:_load_after()
 | 
						|
    end
 | 
						|
end
 | 
						|
-- load targets
 | 
						|
function project._load_targets()
 | 
						|
    -- load all requires first and reload the project file to ensure has_package() works for targets
 | 
						|
    local requires = project.required_packages()
 | 
						|
    local ok, errors = project._load(true)
 | 
						|
 | 
						|
    -- load targets
 | 
						|
    local results, errors = project._load_scope("target", true, true)
 | 
						|
 | 
						|
    -- make targets
 | 
						|
    local targets = {}
 | 
						|
    for targetname, targetinfo in pairs(results) do
 | 
						|
        local t = target.new(targetname, targetinfo)
 | 
						|
        if t and (t:get("enabled") == nil or t:get("enabled") == true) then
 | 
						|
            targets[targetname] = t
 | 
						|
        end
 | 
						|
    end
 | 
						|
 | 
						|
    -- load and attach target deps, rules and packages
 | 
						|
    for _, t in pairs(targets) do
 | 
						|
 | 
						|
        -- load rules from target and language
 | 
						|
        t._RULES = t._RULES or {}
 | 
						|
        local rulenames = {}
 | 
						|
        for _, sourcefile in ipairs(table.wrap(t:get("files"))) do
 | 
						|
            local extension = path.extension((sourcefile:gsub("|.*$", "")))
 | 
						|
            local lang = language.load_ex(extension)
 | 
						|
            table.join2(rulenames, lang:rules())
 | 
						|
        end
 | 
						|
        rulenames = table.unique(rulenames)
 | 
						|
        for _, rulename in ipairs(rulenames) do
 | 
						|
            local r = project.rule(rulename) or rule.rule(rulename)
 | 
						|
            -- only add target rules
 | 
						|
            if r:kind() == "target" then
 | 
						|
                t._RULES[rulename] = r
 | 
						|
                for _, deprule in ipairs(r:orderdeps()) do
 | 
						|
                    t._RULES[deprule:name()] = deprule
 | 
						|
                end
 | 
						|
            end
 | 
						|
            -- we need ignore `@package/rulename`, it will be loaded later
 | 
						|
        end
 | 
						|
 | 
						|
        -- @note it's deprecated, please use on_load instead of before_load
 | 
						|
        ok, errors = t:_load_before()
 | 
						|
 | 
						|
        -- we need call on_load() before building deps/rules,
 | 
						|
        -- so we can use `target:add("deps", "xxx")` to add deps in on_load
 | 
						|
        ok, errors = t:_load()
 | 
						|
    end
 | 
						|
    return targets
 | 
						|
end
 | 
						|
```
 | 
						|
 | 
						|
## Target
 | 
						|
 | 
						|
- _load_before
 | 
						|
  - _load_rules
 | 
						|
- _load
 | 
						|
  - _load_rules
 | 
						|
  - on_load
 | 
						|
- _load_after
 | 
						|
  - _load_rules
 | 
						|
- 
 | 
						|
 | 
						|
```lua
 | 
						|
local _instance = Target
 | 
						|
-- load rules  suffix = {before nil after}
 | 
						|
function _instance:_load_rules(suffix)
 | 
						|
    for k, r in ipairs(self:orderules()) do
 | 
						|
        local ok, errors = self:_load_rule(r, suffix)
 | 
						|
    end
 | 
						|
    return true
 | 
						|
end
 | 
						|
-- do before_load for rules
 | 
						|
-- @note it's deprecated, please use on_load instead of before_load
 | 
						|
function _instance:_load_before()
 | 
						|
    local ok, errors = self:_load_rules("before")
 | 
						|
    return true
 | 
						|
end
 | 
						|
-- do load target and rules
 | 
						|
function _instance:_load()
 | 
						|
 | 
						|
    -- do load with target rules
 | 
						|
    local ok, errors = self:_load_rules()
 | 
						|
 | 
						|
    -- do load for target
 | 
						|
    local on_load = self:script("load")
 | 
						|
    ok, errors = sandbox.load(on_load, self)
 | 
						|
 | 
						|
    -- mark as loaded
 | 
						|
    return true
 | 
						|
end
 | 
						|
-- do after_load target and rules
 | 
						|
function _instance:_load_after()
 | 
						|
    -- enter the environments of the target packages
 | 
						|
    local oldenvs = os.addenvs(self:pkgenvs())
 | 
						|
 | 
						|
    -- do load for target
 | 
						|
    local after_load = self:script("load_after")
 | 
						|
    if after_load then
 | 
						|
        local ok, errors = sandbox.load(after_load, self)
 | 
						|
    end
 | 
						|
    -- do after_load with target rules
 | 
						|
    local ok, errors = self:_load_rules("after")
 | 
						|
 | 
						|
    -- leave the environments of the target packages
 | 
						|
    os.setenvs(oldenvs)
 | 
						|
    return true
 | 
						|
end
 | 
						|
 | 
						|
```
 | 
						|
 | 
						|
## Language
 | 
						|
 | 
						|
# 任务
 | 
						|
 | 
						|
## Build
 | 
						|
 | 
						|
- load
 | 
						|
 | 
						|
  - before_load
 | 
						|
 | 
						|
  - on_load
 | 
						|
 | 
						|
  - after_load
 | 
						|
 | 
						|
- build
 | 
						|
 | 
						|
  - before_build
 | 
						|
 | 
						|
  - on_build
 | 
						|
 | 
						|
  - after_build
 | 
						|
 | 
						|
```lua
 | 
						|
function main()
 | 
						|
    -- lock the whole project
 | 
						|
    project.lock()
 | 
						|
 | 
						|
    -- config it first
 | 
						|
    task.run("config", {}, {disable_dump = true})
 | 
						|
 | 
						|
    -- enter project directory
 | 
						|
    local oldir = os.cd(project.directory())
 | 
						|
 | 
						|
    -- clean up temporary files once a day
 | 
						|
    cleaner.cleanup()
 | 
						|
 | 
						|
    -- do rules before building
 | 
						|
    _do_project_rules("build_before")
 | 
						|
 | 
						|
    -- do build
 | 
						|
    _do_build(targetname, group_pattern)
 | 
						|
 | 
						|
    -- dump cache stats
 | 
						|
    if option.get("diagnosis") then
 | 
						|
        build_cache.dump_stats()
 | 
						|
    end
 | 
						|
    -- do rules after building
 | 
						|
    _do_project_rules("build_after")
 | 
						|
    -- unlock the whole project
 | 
						|
    project.unlock()
 | 
						|
end
 | 
						|
```
 | 
						|
 | 
						|
## Project
 | 
						|
 | 
						|
- install
 | 
						|
 | 
						|
  - before_install
 | 
						|
 | 
						|
  - on_install
 | 
						|
 | 
						|
  - after_install
 | 
						|
 | 
						|
- load
 | 
						|
 | 
						|
  - before_load
 | 
						|
  - on_load
 | 
						|
  - after_load
 | 
						|
 | 
						|
```lua
 | 
						|
 | 
						|
-- make target info
 | 
						|
function getinfo._make_targetinfo(mode, arch, target)
 | 
						|
 | 
						|
    -- init target info
 | 
						|
    local targetinfo =
 | 
						|
    {
 | 
						|
        mode = mode
 | 
						|
    ,   arch = arch
 | 
						|
    ,   plat = config.get("plat")
 | 
						|
    ,   vsarch = vsutils.vsarch(arch)
 | 
						|
    ,   sdkver = config.get("vs_sdkver")
 | 
						|
    }
 | 
						|
 | 
						|
    -- write only if not default
 | 
						|
    -- use target:get("xxx") rather than target:xxx()
 | 
						|
 | 
						|
    -- save target kind
 | 
						|
    targetinfo.kind          = target:kind()
 | 
						|
 | 
						|
    -- is default?
 | 
						|
    targetinfo.default       = tostring(target:is_default())
 | 
						|
 | 
						|
    -- save target file
 | 
						|
    targetinfo.basename      = vsutils.escape(target:basename())
 | 
						|
    targetinfo.filename      = vsutils.escape(target:filename())
 | 
						|
 | 
						|
    -- save dirs
 | 
						|
    targetinfo.targetdir     = _make_dirs(target:get("targetdir"))
 | 
						|
    targetinfo.buildir       = _make_dirs(config.get("buildir"))
 | 
						|
    targetinfo.rundir        = _make_dirs(target:get("rundir"))
 | 
						|
    targetinfo.configdir     = _make_dirs(os.getenv("XMAKE_CONFIGDIR"))
 | 
						|
    targetinfo.configfiledir = _make_dirs(target:get("configdir"))
 | 
						|
    targetinfo.includedirs   = _make_dirs(table.join(_get_values_from_target(target, "includedirs") or {}, _get_values_from_target(target, "sysincludedirs")))
 | 
						|
    targetinfo.linkdirs      = _make_dirs(_get_values_from_target(target, "linkdirs"))
 | 
						|
    targetinfo.sourcedirs    = _make_dirs(_get_values_from_target(target, "values.project.vsxmake.sourcedirs"))
 | 
						|
    targetinfo.pcheaderfile  = target:pcheaderfile("cxx") or target:pcheaderfile("c")
 | 
						|
 | 
						|
    -- save defines
 | 
						|
    targetinfo.defines       = _make_arrs(_get_values_from_target(target, "defines"))
 | 
						|
 | 
						|
    -- save languages
 | 
						|
    targetinfo.languages     = _make_arrs(_get_values_from_target(target, "languages"))
 | 
						|
    if targetinfo.languages then
 | 
						|
        -- 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
 | 
						|
        return targetinfo
 | 
						|
    end
 | 
						|
 | 
						|
    -- save subsystem
 | 
						|
    local linkflags = linker.linkflags(target:kind(), target:sourcekinds(), {target = target})
 | 
						|
    for _, linkflag in ipairs(linkflags) do
 | 
						|
        if linkflag:lower():find("[%-/]subsystem:windows") then
 | 
						|
            targetinfo.subsystem = "windows"
 | 
						|
        end
 | 
						|
    end
 | 
						|
    if not targetinfo.subsystem then
 | 
						|
        targetinfo.subsystem = "console"
 | 
						|
    end
 | 
						|
 | 
						|
    -- save runenvs
 | 
						|
    local runenvs = {}
 | 
						|
    local addrunenvs, setrunenvs = make_runenvs(target)
 | 
						|
    for k, v in table.orderpairs(target:pkgenvs()) do
 | 
						|
        addrunenvs = addrunenvs or {}
 | 
						|
        addrunenvs[k] = table.join(table.wrap(addrunenvs[k]), path.splitenv(v))
 | 
						|
    end
 | 
						|
    for _, dep in ipairs(target:orderdeps()) do
 | 
						|
        for k, v in table.orderpairs(dep:pkgenvs()) do
 | 
						|
            addrunenvs = addrunenvs or {}
 | 
						|
            addrunenvs[k] = table.join(table.wrap(addrunenvs[k]), path.splitenv(v))
 | 
						|
        end
 | 
						|
    end
 | 
						|
    for k, v in table.orderpairs(addrunenvs) do
 | 
						|
        if k:upper() == "PATH" then
 | 
						|
            runenvs[k] = _make_dirs(v) .. ";$([System.Environment]::GetEnvironmentVariable('" .. k .. "'))"
 | 
						|
        else
 | 
						|
            runenvs[k] = path.joinenv(v) .. ";$([System.Environment]::GetEnvironmentVariable('" .. k .."'))"
 | 
						|
        end
 | 
						|
    end
 | 
						|
    for k, v in table.orderpairs(setrunenvs) do
 | 
						|
        if #v == 1 then
 | 
						|
            v = v[1]
 | 
						|
            if path.is_absolute(v) and v:startswith(project.directory()) then
 | 
						|
                runenvs[k] = _make_dirs(v)
 | 
						|
            else
 | 
						|
                runenvs[k] = v[1]
 | 
						|
            end
 | 
						|
        else
 | 
						|
            runenvs[k] = path.joinenv(v)
 | 
						|
        end
 | 
						|
    end
 | 
						|
    local runenvstr = {}
 | 
						|
    for k, v in table.orderpairs(runenvs) do
 | 
						|
        table.insert(runenvstr, k .. "=" .. v)
 | 
						|
    end
 | 
						|
    targetinfo.runenvs = table.concat(runenvstr, "\n")
 | 
						|
 | 
						|
    local runargs = target:get("runargs")
 | 
						|
    if runargs then
 | 
						|
        targetinfo.runargs = os.args(table.wrap(runargs))
 | 
						|
    end
 | 
						|
 | 
						|
    -- use mfc? save the mfc runtime kind
 | 
						|
    if target:rule("win.sdk.mfc.shared_app") or target:rule("win.sdk.mfc.shared") then
 | 
						|
        targetinfo.mfckind = "Dynamic"
 | 
						|
    elseif target:rule("win.sdk.mfc.static_app") or target:rule("win.sdk.mfc.static") then
 | 
						|
        targetinfo.mfckind = "Static"
 | 
						|
    end
 | 
						|
 | 
						|
    -- use cuda? save the cuda runtime version
 | 
						|
    if target:rule("cuda") then
 | 
						|
        local nvcc = find_tool("nvcc", { version = true })
 | 
						|
        local ver = semver.new(nvcc.version)
 | 
						|
        targetinfo.cudaver = ver:major() .. "." .. ver:minor()
 | 
						|
    end
 | 
						|
    return targetinfo
 | 
						|
end
 | 
						|
-- make vstudio project
 | 
						|
function getinfo.main(outputdir, vsinfo)
 | 
						|
 | 
						|
    -- enter project directory
 | 
						|
    local oldir = os.cd(project.directory())
 | 
						|
 | 
						|
    -- init solution directory
 | 
						|
    vsinfo.solution_dir = path.absolute(path.join(outputdir, "vsxmake" .. vsinfo.vstudio_version))
 | 
						|
    vsinfo.programdir = _make_dirs(xmake.programdir())
 | 
						|
    vsinfo.projectdir = project.directory()
 | 
						|
    vsinfo.sln_projectfile = path.relative(project.rootfile(), vsinfo.solution_dir)
 | 
						|
    local projectfile = path.filename(project.rootfile())
 | 
						|
    vsinfo.slnfile = project.name() or path.filename(project.directory())
 | 
						|
    -- write only if not default
 | 
						|
 | 
						|
    vsinfo.xmake_info = format("xmake version %s", xmake.version())
 | 
						|
    vsinfo.solution_id = hash.uuid4(project.directory() .. vsinfo.solution_dir)
 | 
						|
    vsinfo.vs_version = vsinfo.project_version .. ".0"
 | 
						|
 | 
						|
    -- init modes
 | 
						|
    vsinfo.modes = _make_vsinfo_modes()
 | 
						|
 | 
						|
    -- init archs
 | 
						|
    vsinfo.archs = _make_vsinfo_archs()
 | 
						|
 | 
						|
    -- init groups
 | 
						|
    local groups, group_deps = _make_vsinfo_groups()
 | 
						|
    vsinfo.groups            = table.orderkeys(groups)
 | 
						|
    vsinfo.group_deps        = table.orderkeys(group_deps)
 | 
						|
    vsinfo._groups           = groups
 | 
						|
    vsinfo._group_deps       = group_deps
 | 
						|
 | 
						|
    -- init config flags
 | 
						|
    local flags = {}
 | 
						|
    for k, v in table.orderpairs(localcache.get("config", "options")) do
 | 
						|
        if k ~= "plat" and k ~= "mode" and k ~= "arch" and k ~= "clean" and k ~= "buildir" then
 | 
						|
            table.insert(flags, "--" .. k .. "=" .. tostring(v))
 | 
						|
        end
 | 
						|
    end
 | 
						|
    vsinfo.configflags = os.args(flags)
 | 
						|
 | 
						|
    -- load targets
 | 
						|
    local targets = {}
 | 
						|
    vsinfo._arch_modes = {}
 | 
						|
    for _, mode in ipairs(vsinfo.modes) do
 | 
						|
        vsinfo._arch_modes[mode] = {}
 | 
						|
        for _, arch in ipairs(vsinfo.archs) do
 | 
						|
            vsinfo._arch_modes[mode][arch] = { mode = mode, arch = arch }
 | 
						|
 | 
						|
            -- trace
 | 
						|
            print("checking for %s.%s ...", mode, arch)
 | 
						|
 | 
						|
            -- reload config, project and platform
 | 
						|
            -- modify config
 | 
						|
            config.set("as", nil, {force = true}) -- force to re-check as for ml/ml64
 | 
						|
            config.set("mode", mode, {readonly = true, force = true})
 | 
						|
            config.set("arch", arch, {readonly = true, force = true})
 | 
						|
 | 
						|
            -- clear all options
 | 
						|
            for _, opt in ipairs(project.options()) do
 | 
						|
                opt:clear()
 | 
						|
            end
 | 
						|
 | 
						|
            -- clear cache
 | 
						|
            memcache.clear()
 | 
						|
            
 | 
						|
            -- check platform
 | 
						|
            platform.load(config.plat(), arch):check()
 | 
						|
 | 
						|
            -- check project options
 | 
						|
            project.check()
 | 
						|
 | 
						|
            -- install and update requires
 | 
						|
            install_requires()
 | 
						|
 | 
						|
            -- load package rules for targets
 | 
						|
            _load_package_rules_for_targets()
 | 
						|
 | 
						|
            -- config targets
 | 
						|
            _config_targets()
 | 
						|
 | 
						|
            -- update config files
 | 
						|
            generate_configfiles()
 | 
						|
            generate_configheader()
 | 
						|
 | 
						|
            -- ensure to enter project directory
 | 
						|
            os.cd(project.directory())
 | 
						|
 | 
						|
            -- save targets
 | 
						|
            for targetname, target in table.orderpairs(project.targets()) do
 | 
						|
 | 
						|
                -- https://github.com/xmake-io/xmake/issues/2337
 | 
						|
                target:data_set("plugin.project.kind", "vsxmake")
 | 
						|
 | 
						|
                -- make target with the given mode and arch
 | 
						|
                targets[targetname] = targets[targetname] or {}
 | 
						|
                local _target = targets[targetname]
 | 
						|
 | 
						|
                -- init target info
 | 
						|
                _target.target = targetname
 | 
						|
                _target.vcxprojdir = path.join(vsinfo.solution_dir, targetname)
 | 
						|
                _target.target_id = hash.uuid4(targetname)
 | 
						|
                _target.kind = target:kind()
 | 
						|
                _target.absscriptdir = target:scriptdir()
 | 
						|
                _target.scriptdir = path.relative(target:scriptdir(), _target.vcxprojdir)
 | 
						|
                _target.projectdir = path.relative(project.directory(), _target.vcxprojdir)
 | 
						|
                local targetdir = target:get("targetdir")
 | 
						|
                if targetdir then _target.targetdir = path.relative(targetdir, _target.vcxprojdir) end
 | 
						|
                _target._targets = _target._targets or {}
 | 
						|
                _target._targets[mode] = _target._targets[mode] or {}
 | 
						|
                local targetinfo = _make_targetinfo(mode, arch, target)
 | 
						|
                _target._targets[mode][arch] = targetinfo
 | 
						|
                _target.sdkver = targetinfo.sdkver
 | 
						|
                _target.default = targetinfo.default
 | 
						|
 | 
						|
                -- save all sourcefiles and headerfiles
 | 
						|
                _target.sourcefiles = table.unique(table.join(_target.sourcefiles or {}, (target:sourcefiles())))
 | 
						|
                _target.headerfiles = table.unique(table.join(_target.headerfiles or {}, (target:headerfiles())))
 | 
						|
 | 
						|
                -- sort them to stabilize generation
 | 
						|
                table.sort(_target.sourcefiles)
 | 
						|
                table.sort(_target.headerfiles)
 | 
						|
 | 
						|
                -- save file groups
 | 
						|
                _target.filegroups = target:get("filegroups")
 | 
						|
                _target.filegroups_extraconf = target:extraconf("filegroups")
 | 
						|
 | 
						|
                -- save deps
 | 
						|
                _target.deps = table.unique(table.join(_target.deps or {}, table.orderkeys(target:deps()), nil))
 | 
						|
            end
 | 
						|
        end
 | 
						|
    end
 | 
						|
    os.cd(oldir)
 | 
						|
    for _, target in table.orderpairs(targets) do
 | 
						|
        target._paths = {}
 | 
						|
        local dirs = {}
 | 
						|
        local projectdir = project.directory()
 | 
						|
        local root = target.absscriptdir or projectdir
 | 
						|
        target.sourcefiles = table.imap(target.sourcefiles, function(_, v) return path.relative(v, projectdir) end)
 | 
						|
        target.headerfiles = table.imap(target.headerfiles, function(_, v) return path.relative(v, projectdir) end)
 | 
						|
        for _, f in ipairs(table.join(target.sourcefiles, target.headerfiles)) do
 | 
						|
            local dir = _make_filter(f, target, root)
 | 
						|
            local escaped_f = vsutils.escape(f)
 | 
						|
            target._paths[f] =
 | 
						|
            {
 | 
						|
                -- @see https://github.com/xmake-io/xmake/issues/2077
 | 
						|
                path = path.is_absolute(escaped_f) and escaped_f or "$(XmakeProjectDir)\\" .. escaped_f,
 | 
						|
                dir = vsutils.escape(dir)
 | 
						|
            }
 | 
						|
            while dir and dir ~= "." do
 | 
						|
                if not dirs[dir] then
 | 
						|
                    dirs[dir] =
 | 
						|
                    {
 | 
						|
                        dir = vsutils.escape(dir),
 | 
						|
                        dir_id = hash.uuid4(dir)
 | 
						|
                    }
 | 
						|
                end
 | 
						|
                dir = path.directory(dir) or "."
 | 
						|
            end
 | 
						|
        end
 | 
						|
        target._dirs = dirs
 | 
						|
        target.dirs = table.orderkeys(dirs)
 | 
						|
        target._deps = {}
 | 
						|
        for _, v in ipairs(target.deps) do
 | 
						|
            target._deps[v] = targets[v]
 | 
						|
        end
 | 
						|
    end
 | 
						|
 | 
						|
    -- we need set startup project for default or binary target
 | 
						|
    -- @see https://github.com/xmake-io/xmake/issues/1249
 | 
						|
    local targetnames = {}
 | 
						|
    for targetname, target in table.orderpairs(project.targets()) do
 | 
						|
        if target:get("default") == true then
 | 
						|
            table.insert(targetnames, 1, targetname)
 | 
						|
        elseif target:is_binary() then
 | 
						|
            local first_target = targetnames[1] and project.target(targetnames[1])
 | 
						|
            if not first_target or first_target:is_default() then
 | 
						|
                table.insert(targetnames, 1, targetname)
 | 
						|
            else
 | 
						|
                table.insert(targetnames, targetname)
 | 
						|
            end
 | 
						|
        else
 | 
						|
            table.insert(targetnames, targetname)
 | 
						|
        end
 | 
						|
    end
 | 
						|
    vsinfo.targets = targetnames
 | 
						|
    vsinfo._targets = targets
 | 
						|
    return vsinfo
 | 
						|
end
 | 
						|
```
 | 
						|
 | 
						|
 | 
						|
 | 
						|
```lua
 | 
						|
-- make
 | 
						|
function make(version)
 | 
						|
    return function(outputdir)
 | 
						|
        -- trace
 | 
						|
        vprint("using project kind vs%d", version)
 | 
						|
 | 
						|
        -- get info and params
 | 
						|
        local info = getinfo(outputdir, vsinfo(version))
 | 
						|
        local paramsprovidersln = _buildparams(info)
 | 
						|
 | 
						|
        -- write solution file
 | 
						|
        local sln = path.join(info.solution_dir, info.slnfile .. ".sln")
 | 
						|
        _writefileifneeded(sln, render(template_sln, "#([A-Za-z0-9_,%.%*%(%)]+)#", "@([^@]+)@", paramsprovidersln))
 | 
						|
 | 
						|
        -- add solution custom file
 | 
						|
        _trycp(template_props, info.solution_dir)
 | 
						|
        _trycp(template_targets, info.solution_dir)
 | 
						|
 | 
						|
        for _, target in ipairs(info.targets) do
 | 
						|
            local paramsprovidertarget = _buildparams(info, target, "<!-- nil -->")
 | 
						|
            local proj_dir = info._targets[target].vcxprojdir
 | 
						|
 | 
						|
            -- write project file
 | 
						|
            local proj = path.join(proj_dir, target .. ".vcxproj")
 | 
						|
            _writefileifneeded(proj, render(template_vcx, "#([A-Za-z0-9_,%.%*%(%)]+)#", "@([^@]+)@", paramsprovidertarget))
 | 
						|
 | 
						|
            local projfil = path.join(proj_dir, target .. ".vcxproj.filters")
 | 
						|
            _writefileifneeded(projfil, render(template_fil, "#([A-Za-z0-9_,%.%*%(%)]+)#", "@([^@]+)@", paramsprovidertarget))
 | 
						|
 | 
						|
            -- add project custom file
 | 
						|
            _trycp(template_props, proj_dir)
 | 
						|
            _trycp(template_targets, proj_dir)
 | 
						|
            _trycp(template_items, proj_dir)
 | 
						|
            _trycp(template_itemfil, proj_dir)
 | 
						|
        end
 | 
						|
 | 
						|
        -- clear config and local cache
 | 
						|
        _clear_cache()
 | 
						|
 | 
						|
        -- save plugin arguments for autoupdate
 | 
						|
        _save_plugin_arguments()
 | 
						|
    end
 | 
						|
end
 | 
						|
-- main
 | 
						|
function main()
 | 
						|
 | 
						|
    -- in project generator?
 | 
						|
    os.setenv("XMAKE_IN_PROJECT_GENERATOR", "true")
 | 
						|
 | 
						|
    -- config it first
 | 
						|
    task.run("config")
 | 
						|
 | 
						|
    -- make project
 | 
						|
    _make[option.get("kind")](option.get("outputdir"))
 | 
						|
 | 
						|
    -- trace
 | 
						|
    cprint("${color.success}create ok!")
 | 
						|
    os.setenv("XMAKE_IN_PROJECT_GENERATOR", nil)
 | 
						|
end
 | 
						|
```
 | 
						|
 | 
						|
 | 
						|
 | 
						|
# 库依赖
 | 
						|
 | 
						|
## Package
 | 
						|
 | 
						|
```lua
 | 
						|
-- register the required local package
 | 
						|
function _register_required_package(instance, required_package)
 | 
						|
 | 
						|
    -- disable it if this package is missing
 | 
						|
    if not instance:exists() then
 | 
						|
        required_package:enable(false)
 | 
						|
    else
 | 
						|
        -- clear require info first
 | 
						|
        required_package:clear()
 | 
						|
 | 
						|
        -- add packages info with all dependencies
 | 
						|
        local envs = {}
 | 
						|
        _register_required_package_base(instance, required_package)
 | 
						|
        _register_required_package_libs(instance, required_package)
 | 
						|
        _register_required_package_envs(instance, envs)
 | 
						|
        for _, dep in ipairs(instance:librarydeps()) do
 | 
						|
            if instance:is_library() then
 | 
						|
                _register_required_package_libs(dep, required_package, true)
 | 
						|
            end
 | 
						|
        end
 | 
						|
        for _, dep in ipairs(instance:orderdeps()) do
 | 
						|
            if not dep:is_private() then
 | 
						|
                _register_required_package_envs(dep, envs)
 | 
						|
            end
 | 
						|
        end
 | 
						|
        if #table.keys(envs) > 0 then
 | 
						|
            required_package:add({envs = envs})
 | 
						|
        end
 | 
						|
 | 
						|
        -- enable this require info
 | 
						|
        required_package:enable(true)
 | 
						|
    end
 | 
						|
 | 
						|
    -- save this require info and flush the whole cache file
 | 
						|
    required_package:save()
 | 
						|
end
 | 
						|
```
 | 
						|
 |