--!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, Xmake Open Source Community. -- -- @author ruki, OpportunityLiu, SirLynix -- @file runenvs.lua -- -- imports import("core.base.hashset") -- add search directories for all dependent shared libraries on windows function _make_runpath_on_windows(target) local pathenv = {} local searchdirs = hashset.new() local function insert(dir) if not path.is_absolute(dir) then dir = path.absolute(dir, os.projectdir()) end if searchdirs:insert(dir) then table.insert(pathenv, dir) end end -- recursively add targets and dep targets linkdirs local seentargets = hashset.new() local function insert_target(target) if seentargets:insert(target) then for _, linkdir in ipairs(target:get("linkdirs")) do insert(linkdir) end for _, opt in ipairs(target:orderopts()) do for _, linkdir in ipairs(opt:get("linkdirs")) do insert(linkdir) end end for _, pkg in ipairs(target:orderpkgs()) do for _, linkdir in ipairs(pkg:get("linkdirs")) do insert(linkdir) end end for _, dep in ipairs(target:orderdeps()) do if dep:kind() == "shared" then insert(dep:targetdir()) end insert_target(dep) end for _, toolchain in ipairs(target:toolchains()) do local runenvs = toolchain:runenvs() if runenvs and runenvs.PATH then for _, env in ipairs(path.splitenv(runenvs.PATH)) do insert(env) end end end end end insert_target(target) return pathenv end -- flatten envs ({PATH = {"A", "B"}} => {PATH = "A;B"}) function _flatten_envs(envs) local flatten_envs = {} for name, values in pairs(envs) do flatten_envs[name] = path.joinenv(values) end return flatten_envs end -- join addenvs and setenvs in a common envs table function join(addenvs, setenvs) local envs = os.joinenvs(addenvs and _flatten_envs(addenvs) or {}) if setenvs then envs = os.joinenvs(envs, _flatten_envs(setenvs)) end return envs end -- recursively add package envs function _add_target_pkgenvs(addenvs, target, targets_added) if targets_added[target:name()] then return end targets_added[target:name()] = true local pkgenvs = target:pkgenvs() if pkgenvs then for name, values in pairs(pkgenvs) do local values = path.splitenv(values) local oldenvs = addenvs[name] if oldenvs then table.join2(oldenvs, values) else addenvs[name] = values end end end for _, dep in ipairs(target:orderdeps()) do _add_target_pkgenvs(addenvs, dep, targets_added) end end -- deduplicate envs -- @see https://github.com/xmake-io/xmake/issues/5184 function _dedup_envs(envs) local envs_new = {} for k, v in pairs(envs) do if type(v) == "table" then envs_new[k] = table.unique(v) else envs_new[k] = v end end return envs_new end function make(target) -- add run environments local setenvs = {} local addenvs = {} local runenvs = target:get("runenvs") if runenvs then for name, values in pairs(runenvs) do addenvs[name] = table.wrap(values) end end local runenv = target:get("runenv") if runenv then for name, value in pairs(runenv) do setenvs[name] = table.wrap(value) if addenvs[name] then utils.warning(format("both add_runenvs and set_runenv called on environment variable \"%s\", the former one will be ignored.", name)) addenvs[name] = nil end end end -- add package run environments _add_target_pkgenvs(addenvs, target, {}) -- add search directories for all dependent shared libraries on windows if target:is_plat("windows") or (target:is_plat("mingw") and is_host("windows")) then local pathenv = addenvs["PATH"] or setenvs["PATH"] local runpath = _make_runpath_on_windows(target) if pathenv == nil then addenvs["PATH"] = runpath else table.join2(pathenv, runpath) end end -- deduplicate envs if addenvs then addenvs = _dedup_envs(addenvs) end if setenvs then setenvs = _dedup_envs(setenvs) end return addenvs, setenvs end