summaryrefslogtreecommitdiff
path: root/xmake/core/tool
diff options
context:
space:
mode:
authorruki <[email protected]>2020-06-23 22:37:44 +0800
committerGitHub <[email protected]>2020-06-23 22:37:44 +0800
commitc18d15eb89116a0f3ce96bd56f3ccf861849f6ec (patch)
tree52b63db3274349f9a41872414208c7c30058cfd7 /xmake/core/tool
parent53df324acd9c7432336a5894ceef578daa1ce38d (diff)
parent18bded45c229f5580c13fc8b4afc5edb6f18819a (diff)
Merge pull request #857 from xmake-io/toolchain
Improve toolchain to support host and cross toolchains at same time
Diffstat (limited to 'xmake/core/tool')
-rw-r--r--xmake/core/tool/builder.lua10
-rw-r--r--xmake/core/tool/compiler.lua8
-rw-r--r--xmake/core/tool/linker.lua6
-rw-r--r--xmake/core/tool/tool.lua82
-rw-r--r--xmake/core/tool/toolchain.lua104
5 files changed, 156 insertions, 54 deletions
diff --git a/xmake/core/tool/builder.lua b/xmake/core/tool/builder.lua
index 03a9f34ed..d8a01ba2a 100644
--- a/xmake/core/tool/builder.lua
+++ b/xmake/core/tool/builder.lua
@@ -383,6 +383,16 @@ function builder:program()
return self:_tool():program()
end
+-- get toolchain of this tool
+function builder:toolchain()
+ return self:_tool():toolchain()
+end
+
+-- get the run environments
+function builder:runenvs()
+ return self:_tool():runenvs()
+end
+
-- get properties of the tool
function builder:get(name)
return self:_tool():get(name)
diff --git a/xmake/core/tool/compiler.lua b/xmake/core/tool/compiler.lua
index e56f2d300..c47ffb9e1 100644
--- a/xmake/core/tool/compiler.lua
+++ b/xmake/core/tool/compiler.lua
@@ -78,13 +78,13 @@ end
function compiler._load_tool(sourcekind, target)
-- get program from target
- local program, toolname
+ local program, toolname, toolchain_info
if target and target:type() == "target" then
- program, toolname = target:tool(sourcekind)
+ program, toolname, toolchain_info = target:tool(sourcekind)
end
-- load the compiler tool from the source kind
- local result, errors = tool.load(sourcekind, program, toolname)
+ local result, errors = tool.load(sourcekind, {program = program, toolname = toolname, toolchain_info = toolchain_info})
if not result then
return nil, errors
end
@@ -236,7 +236,7 @@ function compiler:compile(sourcefiles, objectfile, opt)
end
-- compile it
- return sandbox.load(self:_tool().compile, self:_tool(), sourcefiles, objectfile, opt.dependinfo, compflags)
+ return sandbox.load(self:_tool().compile, self:_tool(), sourcefiles, objectfile, opt.dependinfo, compflags, opt)
end
-- get the compile arguments list
diff --git a/xmake/core/tool/linker.lua b/xmake/core/tool/linker.lua
index baafde7ae..06ae051cb 100644
--- a/xmake/core/tool/linker.lua
+++ b/xmake/core/tool/linker.lua
@@ -85,13 +85,13 @@ function linker._load_tool(targetkind, sourcekinds, target)
for _, _linkerinfo in ipairs(linkerinfos) do
-- get program from target
- local program, toolname
+ local program, toolname, toolchain_info
if target and target:type() == "target" then
- program, toolname = target:tool(_linkerinfo.linkerkind)
+ program, toolname, toolchain_info = target:tool(_linkerinfo.linkerkind)
end
-- load the linker tool from the linker kind (with cache)
- linkertool, errors = tool.load(_linkerinfo.linkerkind, program, toolname)
+ linkertool, errors = tool.load(_linkerinfo.linkerkind, {program = program, toolname = toolname, toolchain_info = toolchain_info})
if linkertool then
linkerinfo = _linkerinfo
linkerinfo.program = program
diff --git a/xmake/core/tool/tool.lua b/xmake/core/tool/tool.lua
index 9e6dec6d4..b8eb29ddd 100644
--- a/xmake/core/tool/tool.lua
+++ b/xmake/core/tool/tool.lua
@@ -30,16 +30,17 @@ local table = require("base/table")
local string = require("base/string")
local config = require("project/config")
local sandbox = require("sandbox/sandbox")
+local toolchain = require("tool/toolchain")
local platform = require("platform/platform")
local import = require("sandbox/modules/import")
-- new an instance
-function _instance.new(kind, name, program)
+function _instance.new(kind, name, program, plat, arch, toolchain_inst)
-- import "core.tools.xxx"
local toolclass = nil
if os.isfile(path.join(os.programdir(), "modules", "core", "tools", name .. ".lua")) then
- toolclass = import("core.tools." .. name)
+ toolclass = import("core.tools." .. name, {nocache = true}) -- @note we need create a tool instance with unique toolclass context (_g)
end
-- not found?
@@ -51,10 +52,13 @@ function _instance.new(kind, name, program)
local instance = table.inherit(_instance, toolclass)
-- save name, kind and program
- instance._NAME = name
- instance._KIND = kind
- instance._PROGRAM = program
- instance._INFO = {}
+ instance._NAME = name
+ instance._KIND = kind
+ instance._PROGRAM = program
+ instance._PLAT = plat
+ instance._ARCH = arch
+ instance._TOOLCHAIN = toolchain_inst
+ instance._INFO = {}
-- init instance
if instance.init then
@@ -78,11 +82,31 @@ function _instance:kind()
return self._KIND
end
+-- get the tool platform
+function _instance:plat()
+ return self._PLAT
+end
+
+-- get the tool architecture
+function _instance:arch()
+ return self._ARCH
+end
+
-- get the tool program
function _instance:program()
return self._PROGRAM
end
+-- get the toolchain of this tool
+function _instance:toolchain()
+ return self._TOOLCHAIN
+end
+
+-- get run environments
+function _instance:runenvs()
+ return self:toolchain() and self:toolchain():runenvs()
+end
+
-- set the value to the platform info
function _instance:set(name, ...)
self._INFO[name] = table.unwrap({...})
@@ -123,25 +147,39 @@ function _instance:has_flags(flags, flagkind, opt)
-- import has_flags()
self._has_flags = self._has_flags or import("lib.detect.has_flags", {anonymous = true})
+ -- bind the run environments
+ opt.envs = self:runenvs()
+
-- has flags?
return self._has_flags(self:name(), flags, opt)
end
-- load the given tool from the given kind
--
--- @param kind the tool kind e.g. cc, cxx, mm, mxx, as, ar, ld, sh, ..
--- @param program the tool program, e.g. /xxx/arm-linux-gcc, [email protected], (optional)
--- @param toolname gcc, clang, .. (optional)
+-- @param kind the tool kind e.g. cc, cxx, mm, mxx, as, ar, ld, sh, ..
+-- @param opt.program the tool program, e.g. /xxx/arm-linux-gcc, [email protected], (optional)
+-- @param opt.toolname gcc, clang, .. (optional)
+-- @param opt.toolchain_info the toolchain info (optional)
--
-function tool.load(kind, program, toolname)
+function tool.load(kind, opt)
+
+ -- get tool information
+ opt = opt or {}
+ local program = opt.program
+ local toolname = opt.toolname
+ local toolchain_info = opt.toolchain_info or {}
+
+ -- get platform and architecture
+ local plat = toolchain_info.plat or config.get("plat") or os.host()
+ local arch = toolchain_info.arch or config.get("arch") or os.arch()
- -- init key
- local key = kind .. (program or "") .. (config.get("arch") or os.arch())
+ -- init cachekey
+ local cachekey = kind .. (program or "") .. plat .. arch
-- get it directly from cache dirst
tool._TOOLS = tool._TOOLS or {}
- if tool._TOOLS[key] then
- return tool._TOOLS[key]
+ if tool._TOOLS[cachekey] then
+ return tool._TOOLS[cachekey]
end
-- contain toolname? parse it, e.g. '[email protected]'
@@ -155,7 +193,11 @@ function tool.load(kind, program, toolname)
-- get the tool program and name
if not program then
- program, toolname = platform.tool(kind)
+ program, toolname, toolchain_info = platform.tool(kind, plat, arch)
+ if toolchain_info then
+ assert(toolchain_info.plat == plat)
+ assert(toolchain_info.arch == arch)
+ end
end
if not program then
return nil, string.format("cannot get program for %s", kind)
@@ -176,14 +218,20 @@ function tool.load(kind, program, toolname)
return nil, string.format("cannot find known tool script for %s", toolname or program)
end
+ -- load toolchain instance
+ local toolchain_inst
+ if toolchain_info and toolchain_info.name then
+ toolchain_inst = toolchain.load(toolchain_info.name, {plat = plat, arch = arch})
+ end
+
-- new an instance
- local instance, errors = _instance.new(kind, name, program)
+ local instance, errors = _instance.new(kind, name, program, plat, arch, toolchain_inst)
if not instance then
return nil, errors
end
-- save instance to the cache
- tool._TOOLS[key] = instance
+ tool._TOOLS[cachekey] = instance
-- ok
return instance
diff --git a/xmake/core/tool/toolchain.lua b/xmake/core/tool/toolchain.lua
index 6e48ef836..f6eafa94b 100644
--- a/xmake/core/tool/toolchain.lua
+++ b/xmake/core/tool/toolchain.lua
@@ -36,9 +36,11 @@ local sandbox = require("sandbox/sandbox")
local sandbox_module = require("sandbox/modules/import/core/sandbox/module")
-- new an instance
-function _instance.new(name, info)
+function _instance.new(name, plat, arch, info)
local instance = table.inherit(_instance)
instance._NAME = name
+ instance._PLAT = plat
+ instance._ARCH = arch
instance._INFO = info
return instance
end
@@ -50,12 +52,32 @@ end
-- get toolchain platform
function _instance:plat()
- return config.get("plat") or os.host()
+ return self._PLAT
end
-- get toolchain architecture
function _instance:arch()
- return config.get("arch") or os.arch()
+ return self._ARCH
+end
+
+-- the current platform is belong to the given platforms?
+function _instance:is_plat(...)
+ local plat = self:plat()
+ for _, v in ipairs(table.join(...)) do
+ if v and plat == v then
+ return true
+ end
+ end
+end
+
+-- the current architecture is belong to the given architectures?
+function _instance:is_arch(...)
+ local arch = self:arch()
+ for _, v in ipairs(table.join(...)) do
+ if v and arch:find("^" .. v:gsub("%-", "%%-") .. "$") then
+ return true
+ end
+ end
end
-- get toolchain info
@@ -111,6 +133,26 @@ function _instance:standalone()
return self:kind() == "standalone"
end
+-- get the run environments
+function _instance:runenvs()
+ local runenvs = self._RUNENVS
+ if runenvs == nil then
+ local toolchain_runenvs = self:get("runenvs")
+ if toolchain_runenvs then
+ runenvs = {}
+ for name, values in pairs(toolchain_runenvs) do
+ if type(values) == "table" then
+ values = path.joinenv(values)
+ end
+ runenvs[name] = values
+ end
+ end
+ runenvs = runenvs or false
+ self._RUNENVS = runenvs
+ end
+ return runenvs or nil
+end
+
-- get the program and name of the given tool kind
function _instance:tool(toolkind)
local toolpathes = self:get("toolset." .. toolkind)
@@ -139,23 +181,6 @@ function _instance:sdkdir()
return config.get("sdk") or self:get("sdkdir")
end
--- do load, @note we need load it repeatly for each architectures
-function _instance:_load()
- local info = self:info()
- if not info:get("__loaded") and not info:get("__loading") then
- local on_load = info:get("load")
- if on_load then
- info:set("__loading", true)
- local ok, errors = sandbox.load(on_load, self)
- info:set("__loading", false)
- if not ok then
- os.raise(errors)
- end
- end
- info:set("__loaded", true)
- end
-end
-
-- do check, we only check it once for all architectures
function _instance:check()
local checkok = true
@@ -174,6 +199,23 @@ function _instance:check()
return checkok
end
+-- do load, @note we need load it repeatly for each architectures
+function _instance:_load()
+ local info = self:info()
+ if not info:get("__loaded") and not info:get("__loading") then
+ local on_load = info:get("load")
+ if on_load then
+ info:set("__loading", true)
+ local ok, errors = sandbox.load(on_load, self)
+ info:set("__loading", false)
+ if not ok then
+ os.raise(errors)
+ end
+ end
+ info:set("__loaded", true)
+ end
+end
+
-- get the tool description from the tool kind
function _instance:_description(toolkind)
local descriptions = self._DESCRIPTIONS
@@ -240,7 +282,7 @@ function _instance:_checktool(toolkind, toolpath)
-- find tool program
local program, toolname
- local tool = find_tool(toolpath, {program = toolpath, pathes = self:bindir()})
+ local tool = find_tool(toolpath, {program = toolpath, pathes = self:bindir(), envs = self:get("runenvs")})
if tool then
program = tool.program
toolname = tool.name
@@ -318,24 +360,26 @@ end
-- get toolchain directories
function toolchain.directories()
-
- -- init directories
local dirs = toolchain._DIRS or { path.join(global.directory(), "toolchains")
, path.join(os.programdir(), "toolchains")
}
-
- -- save directories to cache
toolchain._DIRS = dirs
return dirs
end
-- load the given toolchain
-function toolchain.load(name)
+function toolchain.load(name, opt)
+
+ -- init cache key
+ opt = opt or {}
+ local plat = opt.plat or config.get("plat") or os.host()
+ local arch = opt.arch or config.get("arch") or os.arch()
+ local cachekey = name .. plat .. arch
-- get it directly from cache dirst
toolchain._TOOLCHAINS = toolchain._TOOLCHAINS or {}
- if toolchain._TOOLCHAINS[name] then
- return toolchain._TOOLCHAINS[name]
+ if toolchain._TOOLCHAINS[cachekey] then
+ return toolchain._TOOLCHAINS[cachekey]
end
-- find the toolchain script path
@@ -372,8 +416,8 @@ function toolchain.load(name)
end
-- save instance to the cache
- local instance = _instance.new(name, result)
- toolchain._TOOLCHAINS[name] = instance
+ local instance = _instance.new(name, plat, arch, result)
+ toolchain._TOOLCHAINS[cachekey] = instance
return instance
end