summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2016-04-14 09:24:24 +0800
committerruki <[email protected]>2016-04-14 09:24:24 +0800
commit9e736d8b83930330edaee2958b4c66093ca87e37 (patch)
treecefcd89bbc72f1aac02535699f97626560be12ab
parent733935aec221c1bce476e7cfea7b5e64d280f71e (diff)
reimpl compiler and linker
-rwxr-xr-xxmake/actions/config/makefile.lua6
-rw-r--r--xmake/core/platform/compiler.lua588
-rw-r--r--xmake/core/platform/linker.lua391
-rw-r--r--xmake/core/project/option.lua51
-rw-r--r--xmake/core/project/project.lua1
-rw-r--r--xmake/core/project/target.lua38
-rw-r--r--xmake/core/tool/compiler.lua88
-rw-r--r--xmake/core/tool/linker.lua358
-rw-r--r--xmake/core/tool/tool.lua39
-rwxr-xr-xxmake/tools/compiler/gcc.lua4
-rw-r--r--xmake/tools/linker/ar.lua44
-rwxr-xr-xxmake/tools/linker/clang++.lua33
-rwxr-xr-xxmake/tools/linker/clang.lua40
-rwxr-xr-xxmake/tools/linker/g++.lua33
-rwxr-xr-xxmake/tools/linker/gcc.lua95
-rw-r--r--xmake/tools/make.lua76
16 files changed, 842 insertions, 1043 deletions
diff --git a/xmake/actions/config/makefile.lua b/xmake/actions/config/makefile.lua
index b65b8a7b0..fa7525a79 100755
--- a/xmake/actions/config/makefile.lua
+++ b/xmake/actions/config/makefile.lua
@@ -21,7 +21,7 @@
--
-- imports
-import("core.platform.tool")
+import("core.tool.tool")
import("core.project.project")
-- get log makefile
@@ -157,12 +157,12 @@ function _make_target(makefile, target)
-- make the command
local linker = target:linker()
- local cmd = linker:makecmd(target, objfiles, targetfile, _logfile())
+ local cmd = linker:command(target, objfiles, targetfile, _logfile())
-- make the verbose info
local verbose = cmd:encode()
if verbose and #verbose > 256 then
- verbose = linker:makecmd(target, {target.filename("*", "object")}, targetfile)
+ verbose = linker:command(target, target.filename("*", "object"), targetfile)
verbose = verbose:encode()
end
diff --git a/xmake/core/platform/compiler.lua b/xmake/core/platform/compiler.lua
deleted file mode 100644
index e703ef933..000000000
--- a/xmake/core/platform/compiler.lua
+++ /dev/null
@@ -1,588 +0,0 @@
---!The Automatic Cross-platform Build Tool
---
--- XMake is free software; you can redistribute it and/or modify
--- it under the terms of the GNU Lesser General Public License as published by
--- the Free Software Foundation; either version 2.1 of the License, or
--- (at your option) any later version.
---
--- XMake is distributed in the hope that it will be useful,
--- but WITHOUT ANY WARRANTY; without even the implied warranty of
--- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
--- GNU Lesser General Public License for more details.
---
--- You should have received a copy of the GNU Lesser General Public License
--- along with XMake;
--- If not, see <a href="http://www.gnu.org/licenses/"> http://www.gnu.org/licenses/</a>
---
--- Copyright (C) 2015 - 2016, ruki All rights reserved.
---
--- @author ruki
--- @file compiler.lua
---
-
--- define module
-local compiler = compiler or {}
-
--- load modules
-local io = require("base/io")
-local path = require("base/path")
-local utils = require("base/utils")
-local table = require("base/table")
-local string = require("base/string")
-local option = require("base/option")
-local config = require("project/config")
-local tool = require("platform/tool")
-local platform = require("platform/platform")
-
--- map gcc flag to the given compiler flag
-function compiler._mapflag(self, flag)
-
- -- check
- assert(self._TOOL.mapflags and flag)
-
- -- attempt to map it directly
- local flag_mapped = self._TOOL.mapflags[flag]
- if flag_mapped and type(flag_mapped) == "string" then
- return flag_mapped
- end
-
- -- find and replace it using pattern
- for k, v in pairs(self._TOOL.mapflags) do
- local flag_mapped, count = flag:gsub("^" .. k .. "$", function (w)
- if type(v) == "function" then
- return v(self, w)
- else
- return v
- end
- end)
- if flag_mapped and count ~= 0 then
- return utils.ifelse(#flag_mapped ~= 0, flag_mapped, nil)
- end
- end
-
- -- return it directly
- return flag
-end
-
--- map gcc flags to the given compiler flags
-function compiler._mapflags(self, flags)
-
- -- check
- assert(self)
-
- -- wrap flags first
- flags = table.wrap(flags)
-
- -- need not map flags? return it directly
- if not self._TOOL.mapflags then
- return flags
- end
-
- -- map flags
- local flags_mapped = {}
- for _, flag in pairs(flags) do
- -- map it
- local flag_mapped = compiler._mapflag(self, flag)
- if flag_mapped then
- table.insert(flags_mapped, flag_mapped)
- end
- end
-
- -- ok?
- return flags_mapped
-end
-
--- get the compiler flags from names
-function compiler._getflags(self, names, flags)
-
- -- check
- assert(flags)
-
- -- the mapped flags
- local flags_mapped = {}
-
- -- wrap it first
- names = table.wrap(names)
- for _, name in ipairs(names) do
- table.join2(flags_mapped, compiler._mapflags(self, flags[name]))
- end
-
- -- get it
- return flags_mapped
-end
-
--- add flags from the compiler
-function compiler._addflags_from_compiler(self, flags, flagnames, kind)
-
- -- check
- assert(self and flags and flagnames)
-
- -- done
- for _, flagname in ipairs(flagnames) do
-
- -- add compiler.xxflags
- table.join2(flags, self._TOOL[flagname])
-
- -- add compiler.kind.xxflags
- if kind ~= nil and self._TOOL[kind] ~= nil then
- table.join2(flags, self._TOOL[kind][flagname])
- end
- end
-end
-
--- add flags from the configure
-function compiler._addflags_from_config(self, flags, flagnames)
-
- -- check
- assert(self and flags and flagnames)
-
- -- done
- for _, flagname in ipairs(flagnames) do
- table.join2(flags, config.get(flagname))
- end
-end
-
--- add flags from the platform
-function compiler._addflags_from_platform(self, flags, flagnames)
-
- -- check
- assert(self and flags and flagnames)
-
- -- add flags
- for _, flagname in ipairs(flagnames) do
- table.join2(flags, compiler._mapflags(self, platform.get(flagname)))
- end
-
- -- add the includedirs flags
- if self._TOOL.flag_includedir then
- for _, includedir in ipairs(table.wrap(platform.get("includedirs"))) do
- table.join2(flags, self._TOOL:flag_includedir(includedir))
- end
- end
-
- -- add the defines flags
- if self._TOOL.flag_define then
- for _, define in ipairs(table.wrap(platform.get("defines"))) do
- table.join2(flags, self._TOOL:flag_define(define))
- end
- end
-
- -- append the undefines flags
- if self._TOOL.flag_undefine then
- for _, undefine in ipairs(table.wrap(platform.get("undefines"))) do
- table.join2(flags, self._TOOL:flag_undefine(undefine))
- end
- end
-end
-
--- TODO optimize speed, cache it
--- add flags from the target
-function compiler._addflags_from_target(self, flags, flagnames, target)
-
- -- check
- assert(self and flags and flagnames and target)
-
- -- add the target flags from the current project
- for _, flagname in ipairs(flagnames) do
- table.join2(flags, compiler._mapflags(self, target:get(flagname)))
- end
-
- -- add the symbols flags from the current project
- table.join2(flags, compiler._getflags(self, target:get("symbols"), { debug = "-g"
- , hidden = "-fvisibility=hidden"
- }))
-
- -- add the warning flags from the current project
- table.join2(flags, compiler._getflags(self, target:get("warnings"), { none = "-w"
- , less = "-W1"
- , more = "-W3"
- , all = "-Wall"
- , error = "-Werror"
- }))
-
- -- add the optimize flags from the current project
- table.join2(flags, compiler._getflags(self, target:get("optimize"), { none = "-O0"
- , fast = "-O1"
- , faster = "-O2"
- , fastest = "-O3"
- , smallest = "-Os"
- , aggressive = "-Ofast"
- }))
-
- -- add the vector extensions flags from the current project
- table.join2(flags, compiler._getflags(self, target:get("vectorexts"), { mmx = "-mmmx"
- , sse = "-msse"
- , sse2 = "-msse2"
- , sse3 = "-msse3"
- , ssse3 = "-mssse3"
- , avx = "-mavx"
- , avx2 = "-mavx2"
- , neon = "-mfpu=neon"
- }))
-
- -- add the language flags from the current project
- local languages = {}
- for _, flagname in ipairs(flagnames) do
- if flagname == "cflags" or flagname == "mflags" then
- table.join2(languages, { ansi = "-ansi"
- , c89 = "-std=c89"
- , gnu89 = "-std=gnu89"
- , c99 = "-std=c99"
- , gnu99 = "-std=gnu99"
- , c11 = "-std=c11"
- , gnu11 = "-std=gnu11"
- })
- elseif flagname == "cxxflags" or flagname == "mxxflags" then
- table.join2(languages, { cxx98 = "-std=c++98"
- , gnuxx98 = "-std=gnu++98"
- , cxx11 = "-std=c++11"
- , gnuxx11 = "-std=gnu++11"
- , cxx14 = "-std=c++14"
- , gnuxx14 = "-std=gnu++14"
- })
- end
- end
- table.join2(flags, compiler._getflags(self, target:get("languages"), languages))
-
- -- add the includedirs flags from the current project
- if self._TOOL.flag_includedir then
- for _, includedir in ipairs(table.wrap(target:get("includedirs"))) do
- table.join2(flags, self._TOOL:flag_includedir(includedir))
- end
- end
-
- -- add the defines flags from the current project
- if self._TOOL.flag_define then
- for _, define in ipairs(table.wrap(target:get("defines"))) do
- table.join2(flags, self._TOOL:flag_define(define))
- end
- end
-
- -- append the undefines flags from the current project
- if self._TOOL.flag_undefine then
- for _, undefine in ipairs(table.wrap(target:get("undefines"))) do
- table.join2(flags, self._TOOL:flag_undefine(undefine))
- end
- end
-
- -- is target?
- if target.options then
-
- -- add the flags for the target options
- for name, opt in pairs(target:options()) do
-
- -- add the flags from the option
- self:_addflags_from_target(flags, flagnames, opt)
-
- -- append the defines flags
- if self._TOOL.flag_define then
- for _, define in ipairs(table.wrap(opt:get("defines_if_ok"))) do
- table.join2(flags, self._TOOL:flag_define(define))
- end
- end
-
- -- append the undefines flags
- if self._TOOL.flag_undefine then
- for _, undefine in ipairs(table.wrap(opt:get("undefines_if_ok"))) do
- table.join2(flags, self._TOOL:flag_undefine(undefine))
- end
- end
- end
- end
-end
-
--- add flags from the option
-function compiler._addflags_from_option(self, flags, flagnames, opt)
-
- -- check
- assert(self and flags and flagnames and opt)
-
- -- add the flags from the option
- self:_addflags_from_target(flags, flagnames, opt)
-
-end
-
--- make the compile command for option
-function compiler._make_for_option(self, opt, srcfile, objfile, logfile)
-
- -- check
- assert(self and self._TOOL and opt)
-
- -- the flag names
- local flagnames = compiler._flagnames(self._KIND)
- assert(flagnames)
-
- -- init flags
- local flags = {}
-
- -- add flags from the configure
- compiler._addflags_from_config(self, flags, flagnames)
-
- -- add flags from the option
- compiler._addflags_from_option(self, flags, flagnames, opt)
-
- -- add flags from the platform
- compiler._addflags_from_platform(self, flags, flagnames)
-
- -- add flags from the compiler
- compiler._addflags_from_compiler(self, flags, flagnames)
-
- -- remove repeat
- flags = table.unique(flags)
-
- -- execute the compile command
- return self._TOOL:command_compile(srcfile, objfile, table.concat(flags, " "):trim(), logfile)
-end
-
--- get the flag names from the given compiler name
-function compiler._flagnames(name)
-
- -- check
- assert(name)
-
- -- the flag names
- local flagnames = nil
- if name == "cc" then flagnames = { "cxflags", "cflags" }
- elseif name == "cxx" then flagnames = { "cxflags", "cxxflags" }
- elseif name == "mm" then flagnames = { "mxflags", "mflags" }
- elseif name == "mxx" then flagnames = { "mxflags", "mxxflags" }
- elseif name == "as" then flagnames = { "asflags" }
- elseif name == "sc" then flagnames = { "scflags" }
- else
- -- error
- utils.error("unknown compiler: %s", name)
- return
- end
-
- -- ok
- return flagnames
-end
-
--- get the compiler kind from the source file type
-function compiler._kind(srcfile)
-
- -- get the source file type
- local filetype = path.extension(srcfile)
- if not filetype then
- return nil
- end
-
- -- get the lower file type
- filetype = filetype:lower()
-
- -- get the compiler kind
- local kind = nil
- if filetype == ".c" then kind = "cc"
- elseif filetype == ".cpp" or filetype == ".cc" then kind = "cxx"
- elseif filetype == ".m" then kind = "mm"
- elseif filetype == ".mm" then kind = "mxx"
- elseif filetype == ".s" or filetype == ".asm" then kind = "as"
- elseif filetype == ".swift" then kind = "sc"
- elseif filetype == ".a" or filetype == ".lib" then kind = "lib"
- elseif filetype == ".o" or filetype == ".obj" then kind = "obj"
- end
-
- -- ok
- return kind
-end
-
--- init the compiler from the given source file
-function compiler.init(srcfile)
-
- -- get the compiler kind
- local kind = compiler._kind(srcfile)
- if not kind then
- return nil, string.format("unknown source file: %s", srcfile)
- end
-
- -- init instance
- local instance = table.inherit(compiler)
-
- -- ignore "*.a/lib" and "*.o/obj" kind
- if kind == "lib" or kind == "obj" then
- return instance
- end
-
- -- get compiler tool from the source file type
- instance._TOOL, errors = tool.get(kind)
- if instance._TOOL then
-
- -- invalid compiler
- if not instance._TOOL.command_compile then
- return nil, string.format("invalid compiler for %s", kind)
- end
-
- -- save kind
- instance._KIND = kind
- else
- return nil, errors
- end
-
- -- ok
- return instance
-end
-
--- get flags from the given flag names
-function compiler.flags(self, flagnames, target)
-
- -- init flags
- local flags = {}
-
- -- add flags from the configure
- self:_addflags_from_config(flags, flagnames)
-
- -- add flags from the target
- self:_addflags_from_target(flags, flagnames, target)
-
- -- add flags from the platform
- self:_addflags_from_platform(flags, flagnames)
-
- -- add flags from the compiler
- self:_addflags_from_compiler(flags, flagnames, target:get("kind"))
-
- -- remove repeat
- flags = table.unique(flags)
-
- -- ok?
- return flags
-end
-
--- make the compile command
-function compiler.makecmd(self, target, srcfile, objfile, logfile)
-
- -- check
- assert(self and self._TOOL and target)
-
- -- the flag names
- local flagnames = compiler._flagnames(self._KIND)
- assert(flagnames)
-
- -- get flags
- local flags = self:flags(flagnames, target)
-
- -- make the compile command
- return self._TOOL:command_compile(srcfile, objfile, table.concat(flags, " "):trim(), logfile)
-end
-
--- check include for the project option
-function compiler.check_include(opt, include, srcpath, objpath)
-
- -- check
- assert(opt and srcpath and objpath)
-
- -- open the checking source file
- local srcfile = io.open(srcpath, "w")
- if not srcfile then return end
-
- -- make include
- if include then
- srcfile:print("#include <%s>\n", include)
- end
-
- -- make the main function header
- srcfile:print("int main(int argc, char** argv)")
- srcfile:print("{")
- srcfile:print(" return 0;")
- srcfile:print("}")
-
- -- exit this file
- srcfile:close()
-
- -- get the compiler
- local self = compiler.init(srcpath)
- if not self then return end
-
- -- execute the compile command
- return self._TOOL:main(self:_make_for_option(opt, srcpath, objpath, utils.ifelse(option.get("verbose"), nil, xmake._NULDEV)))
-end
-
--- check function for the project option
-function compiler.check_function(opt, interface, srcpath, objpath)
-
- -- check
- assert(opt and interface)
-
- -- open the checking source file
- local srcfile = io.open(srcpath, "w")
- if not srcfile then return end
-
- -- get the compiler
- local self = compiler.init(srcpath)
- if not self then return end
-
- -- make includes
- local includes = nil
- if self._KIND == "cc" then includes = opt:get("cincludes")
- elseif self._KIND == "cxx" then includes = opt:get("cxxincludes")
- end
- if includes then
- for _, include in ipairs(table.wrap(includes)) do
- srcfile:print("#include <%s>", include)
- end
- srcfile:print("")
- end
-
- -- make the main function header
- srcfile:print("int main(int argc, char** argv)")
- srcfile:print("{")
-
- -- make interfaces
- srcfile:print(" volatile void* p%s = (void*)&%s;\n", interface, interface)
-
- -- make the main function tailer
- srcfile:print(" return 0;")
- srcfile:print("}")
-
- -- exit this file
- srcfile:close()
-
- -- execute the compile command
- return self._TOOL:main(self:_make_for_option(opt, srcpath, objpath, utils.ifelse(option.get("verbose"), nil, xmake._NULDEV)))
-end
-
--- check typedef for the project option
-function compiler.check_typedef(opt, typedef, srcpath, objpath)
-
- -- check
- assert(opt and typedef)
-
- -- open the checking source file
- local srcfile = io.open(srcpath, "w")
- if not srcfile then return end
-
- -- get the compiler
- local self = compiler.init(srcpath)
- if not self then return end
-
- -- make includes
- local includes = nil
- if self._KIND == "cc" then includes = opt:get("cincludes")
- elseif self._KIND == "cxx" then includes = opt:get("cxxincludes")
- end
- if includes then
- for _, include in ipairs(table.wrap(includes)) do
- srcfile:print("#include <%s>", include)
- end
- srcfile:print("")
- end
-
- -- make the main function header
- srcfile:print("int main(int argc, char** argv)")
- srcfile:print("{")
-
- -- make interfaces
- srcfile:print(" typedef %s __type_xxx;\n", typedef)
-
- -- make the main function tailer
- srcfile:print(" return 0;")
- srcfile:print("}")
-
- -- exit this file
- srcfile:close()
-
- -- execute the compile command
- return self._TOOL:main(self:_make_for_option(opt, srcpath, objpath, utils.ifelse(option.get("verbose"), nil, xmake._NULDEV)))
-end
-
--- return module
-return compiler
diff --git a/xmake/core/platform/linker.lua b/xmake/core/platform/linker.lua
deleted file mode 100644
index 7849ed638..000000000
--- a/xmake/core/platform/linker.lua
+++ /dev/null
@@ -1,391 +0,0 @@
---!The Automatic Cross-platform Build Tool
---
--- XMake is free software; you can redistribute it and/or modify
--- it under the terms of the GNU Lesser General Public License as published by
--- the Free Software Foundation; either version 2.1 of the License, or
--- (at your option) any later version.
---
--- XMake is distributed in the hope that it will be useful,
--- but WITHOUT ANY WARRANTY; without even the implied warranty of
--- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
--- GNU Lesser General Public License for more details.
---
--- You should have received a copy of the GNU Lesser General Public License
--- along with XMake;
--- If not, see <a href="http://www.gnu.org/licenses/"> http://www.gnu.org/licenses/</a>
---
--- Copyright (C) 2015 - 2016, ruki All rights reserved.
---
--- @author ruki
--- @file linker.lua
---
-
--- define module
-local linker = linker or {}
-
--- load modules
-local utils = require("base/utils")
-local table = require("base/table")
-local string = require("base/string")
-local option = require("base/option")
-local config = require("project/config")
-local compiler = require("platform/compiler")
-local tool = require("platform/tool")
-local platform = require("platform/platform")
-
--- map gcc flag to the given linker flag
-function linker._mapflag(self, flag)
-
- -- check
- assert(self._TOOL.mapflags and flag)
-
- -- attempt to map it directly
- local flag_mapped = self._TOOL.mapflags[flag]
- if flag_mapped and type(flag_mapped) == "string" then
- return flag_mapped
- end
-
- -- find and replace it using pattern
- for k, v in pairs(self._TOOL.mapflags) do
- local flag_mapped, count = flag:gsub("^" .. k .. "$", function (w)
- if type(v) == "function" then
- return v(self, w)
- else
- return v
- end
- end)
- if flag_mapped and count ~= 0 then
- return utils.ifelse(#flag_mapped ~= 0, flag_mapped, nil)
- end
- end
-
- -- return it directly
- return flag
-end
-
--- map gcc flags to the given linker flags
-function linker._mapflags(self, flags)
-
- -- check
- assert(self)
-
- -- wrap flags first
- flags = table.wrap(flags)
-
- -- need not map flags? return it directly
- if not self._TOOL.mapflags then
- return flags
- end
-
- -- map flags
- local flags_mapped = {}
- for _, flag in pairs(flags) do
- -- map it
- local flag_mapped = linker._mapflag(self, flag)
- if flag_mapped then
- table.insert(flags_mapped, flag_mapped)
- end
- end
-
- -- ok?
- return flags_mapped
-end
-
--- get the linker flags from names
-function linker._getflags(self, names, flags)
-
- -- check
- assert(flags)
-
- -- the mapped flags
- local flags_mapped = {}
-
- -- wrap it first
- names = table.wrap(names)
- for _, name in ipairs(names) do
- table.join2(flags_mapped, linker._mapflags(self, flags[name]))
- end
-
- -- get it
- return flags_mapped
-end
-
-
--- add flags from the links
-function linker._addflags_from_links(self, flags, links)
-
- -- check
- assert(self and flags and links)
-
- -- done
- if self._TOOL.flag_link then
- for _, link in ipairs(table.wrap(links)) do
- table.join2(flags, self._TOOL:flag_link(link))
- end
- end
-end
-
--- add flags from the linker
-function linker._addflags_from_linker(self, flags, flagname)
-
- -- check
- assert(self and flags and flagname)
-
- -- done
- table.join2(flags, self._TOOL[flagname])
-end
-
--- add flags from the compiler
-function linker._addflags_from_compiler(self, flags, flagname, srcfiles)
-
- -- check
- assert(self and flags and flagname)
-
- -- add the flags for compiler
- local flags_for_compiler = {}
- if srcfiles then
- for _, srcfile in ipairs(table.wrap(srcfiles)) do
-
- -- init a compiler instance
- local c, errors = compiler.init(srcfile)
- if not c then
- -- error
- utils.error(errors)
- return
- end
-
- -- add flags
- table.join2(flags_for_compiler, c[flagname])
- end
- end
-
- -- done
- table.join2(flags, table.unique(flags_for_compiler))
-end
-
--- add flags from the configure
-function linker._addflags_from_config(self, flags, flagname)
-
- -- check
- assert(self and flags and flagname)
-
- -- done
- table.join2(flags, config.get(flagname))
-end
-
--- add flags from the platform
-function linker._addflags_from_platform(self, flags, flagname)
-
- -- check
- assert(self and flags and flagname)
-
- -- add flags
- table.join2(flags, linker._mapflags(self, platform.get(flagname)))
-
- -- add the linkdirs flags
- if self._TOOL.flag_linkdir then
- for _, linkdir in ipairs(table.wrap(platform.get("linkdirs"))) do
- table.join2(flags, self._TOOL:flag_linkdir(linkdir))
- end
- end
-
- -- add the links flags
- if self._TOOL.flag_link then
- for _, link in ipairs(table.wrap(platform.get("links"))) do
- table.join2(flags, self._TOOL:flag_link(link))
- end
- end
-end
-
--- add flags from the target
-function linker._addflags_from_target(self, flags, flagname, target)
-
- -- check
- assert(self and flags and flagname and target)
-
- -- add the target flags from the current project
- table.join2(flags, linker._mapflags(self, target[flagname]))
-
- -- add the linkdirs flags from the current project
- if self._TOOL.flag_linkdir then
- for _, linkdir in ipairs(table.wrap(target:get("linkdirs"))) do
- table.join2(flags, self._TOOL:flag_linkdir(linkdir))
- end
- end
-
- -- add the links flags from the current project
- if self._TOOL.flag_link then
- for _, link in ipairs(table.wrap(target:get("links"))) do
- table.join2(flags, self._TOOL:flag_link(link))
- end
- end
-
- -- add the flags for the target options
- for _, opt in pairs(target:options()) do
-
- -- add the flags from the option
- table.join2(flags, linker._mapflags(self, opt:get(flagname)))
-
- -- add the linkdirs flags from the option
- if self._TOOL.flag_linkdir then
- for _, linkdir in ipairs(table.wrap(opt:get("linkdirs"))) do
- table.join2(flags, self._TOOL:flag_linkdir(linkdir))
- end
- end
-
- -- add the links flags from the option
- if self._TOOL.flag_link then
- for _, link in ipairs(table.wrap(opt:get("links"))) do
- table.join2(flags, self._TOOL:flag_link(link))
- end
- end
- end
-
- -- add the flags from the configure
- table.join2(flags, linker._mapflags(self, config.get(flagname)))
-
- -- add the strip flags from the current project
- table.join2(flags, linker._getflags(self, target:get("strip"), { debug = "-S"
- , all = "-s"
- }))
-end
-
--- add flags from the option
-function linker._addflags_from_option(self, flags, flagname, opt)
-
- -- check
- assert(self and flags and flagname and opt)
-
- -- append the option flags
- table.join2(flags, linker._mapflags(self, opt:get("flagname")))
-
- -- append the linkdirs flags
- if opt:get("linkdirs") and self._TOOL.flag_linkdir then
- for _, linkdir in ipairs(table.wrap(opt:get("linkdirs"))) do
- table.join2(flags, self._TOOL:flag_linkdir(linkdir))
- end
- end
-end
-
--- init a linker instance from the given kind
-function linker.init(kind)
-
- -- check
- assert(kind)
-
- -- get the linker name from the kind
- local name = nil
- if kind == "binary" then name = "ld"
- elseif kind == "static" then name = "ar"
- elseif kind == "shared" then name = "sh"
- else
- return nil, string.format("unknown kind: %s for linker", kind)
- end
-
- -- init instance
- local instance = table.inherit(linker)
-
- -- get the linker tool
- instance._TOOL, errors = tool.get(name)
- if not instance._TOOL then
- return nil, errors
- end
-
- -- ok?
- return instance
-end
-
--- get flags from the given flag name
-function linker.flags(self, flagname, target)
-
- -- init flags
- local flags = {}
-
- -- add flags from the configure
- self:_addflags_from_config(flags, flagname)
-
- -- add flags from the target
- self:_addflags_from_target(flags, flagname, target)
-
- -- add flags from the platform
- self:_addflags_from_platform(flags, flagname)
-
- -- add flags from the compiler
- self:_addflags_from_compiler(flags, flagname, target:sourcefiles())
-
- -- add flags from the linker
- self:_addflags_from_linker(flags, flagname)
-
- -- remove repeat
- flags = table.unique(flags)
-
- -- ok?
- return flags
-end
-
--- make the link command
-function linker.makecmd(self, target, objfiles, targetfile, logfile)
-
- -- check
- assert(self and self._TOOL and target)
-
- -- the target kind
- local kind = target:get("kind") or ""
-
- -- the flag name
- local flagname = nil
- if kind == "binary" then flagname = "ldflags"
- elseif kind == "static" then flagname = "arflags"
- elseif kind == "shared" then flagname = "shflags"
- else
- -- error
- os.raise("unknown type for linker: %s", kind)
- end
-
- -- get flags
- local flags = self:flags(flagname, target)
-
- -- make the link command
- return self._TOOL:command_link(table.concat(objfiles, " "), targetfile, table.concat(flags, " "):trim(), logfile)
-end
-
--- check link for the project option
-function linker.check_links(opt, sourcefile, objectfile, targetfile)
-
- -- check
- assert(opt and objectfile and targetfile)
-
- -- init the linker
- local self = linker.init("binary")
- assert(self and self._TOOL)
-
- -- init flags
- local flags = {}
-
- -- add flags from the configure
- linker._addflags_from_config(self, flags, "ldflags")
-
- -- add flags from the option
- linker._addflags_from_option(self, flags, "ldflags", opt)
-
- -- add flags from the platform
- linker._addflags_from_platform(self, flags, "ldflags")
-
- -- add flags from the links
- linker._addflags_from_links(self, flags, opt:get("links"))
-
- -- add flags from the compiler
- linker._addflags_from_compiler(self, flags, "ldflags", sourcefile)
-
- -- add flags from the linker
- linker._addflags_from_linker(self, flags, "ldflags")
-
- -- remove repeat
- flags = table.unique(flags)
-
- -- execute the link command
- return self._TOOL:main(self._TOOL:command_link(objectfile, targetfile, table.concat(flags, " "):trim(), utils.ifelse(option.get("verbose"), nil, xmake._NULDEV)))
-end
-
--- return module
-return linker
diff --git a/xmake/core/project/option.lua b/xmake/core/project/option.lua
index 4cea021c4..c74fc4279 100644
--- a/xmake/core/project/option.lua
+++ b/xmake/core/project/option.lua
@@ -31,9 +31,34 @@ local table = require("base/table")
local utils = require("base/utils")
local option_ = require("base/option")
local cache = require("project/cache")("local.option")
-local linker = require("platform/linker")
+local linker = require("tool/linker")
local compiler = require("tool/compiler")
+-- check link
+function option:_check_link(sourcefile, objectfile, targetfile)
+
+ -- check
+ assert(sourcefile and objectfile and targetfile)
+
+ -- update source kinds
+ self._SOURCEKINDS = compiler.kind_of_file(sourcefile)
+
+ -- load the linker instance
+ local instance = linker.load("binary")
+ if not instance then
+ return false
+ end
+
+ -- attempt to run this command
+ local ok, errors = instance:run(instance:command(self, objectfile, targetfile))
+ if not ok and option_.get("verbose") then
+ print(errors)
+ end
+
+ -- ok?
+ return ok
+end
+
-- check include
function option:_check_include(include, srcpath, objpath)
@@ -61,7 +86,7 @@ function option:_check_include(include, srcpath, objpath)
srcfile:close()
-- load the compiler instance
- local instance = compiler.load(srcpath)
+ local instance = compiler.load(compiler.kind_of_file(srcpath))
if not instance then
return false
end
@@ -89,7 +114,7 @@ function option:_check_function(interface, srcpath, objpath)
end
-- load the compiler instance
- local instance = compiler.load(srcpath)
+ local instance = compiler.load(compiler.kind_of_file(srcpath))
if not instance then
return false
end
@@ -143,7 +168,7 @@ function option:_check_typedef(typedef, srcpath, objpath)
end
-- load the compiler instance
- local instance = compiler.load(srcpath)
+ local instance = compiler.load(compiler.kind_of_file(srcpath))
if not instance then
return false
end
@@ -206,7 +231,7 @@ function option:_check_links(cfile, objectfile, targetfile)
local ok = self:_check_include(nil, cfile, objectfile)
-- check link
- if ok then ok = linker.check_links(self, cfile, objectfile, targetfile) end
+ if ok then ok = self:_check_link(cfile, objectfile, targetfile) end
-- trace
utils.printf("checking for the links %s ... %s", links_str, utils.ifelse(ok, "ok", "no"))
@@ -282,7 +307,7 @@ function option:_check_cfuncs(cfile, objectfile, targetfile)
local ok = self:_check_function(cfunc, cfile, objectfile)
-- check link
- if ok and self:get("links") then ok = linker.check_links(self, cfile, objectfile, targetfile) end
+ if ok and self:get("links") then ok = self:_check_link(cfile, objectfile, targetfile) end
-- trace
utils.printf("checking for the c function %s ... %s", cfunc, utils.ifelse(ok, "ok", "no"))
@@ -305,7 +330,7 @@ function option:_check_cxxfuncs(cxxfile, objectfile, targetfile)
local ok = self:_check_function(cxxfunc, cxxfile, objectfile)
-- check link
- if ok and self:get("links") then ok = linker.check_links(self, cxxfile, objectfile, targetfile) end
+ if ok and self:get("links") then ok = self:_check_link(cxxfile, objectfile, targetfile) end
-- trace
utils.printf("checking for the c++ function %s ... %s", cxxfunc, utils.ifelse(ok, "ok", "no"))
@@ -441,5 +466,17 @@ function option.load(name)
return instance
end
+-- get the kinds of sourcefiles
+function option:sourcekinds()
+
+ -- cached? return it directly
+ if self._SOURCEKINDS then
+ return self._SOURCEKINDS
+ end
+
+ -- ok?
+ return {"cc", "cxx"}
+end
+
-- return module
return option
diff --git a/xmake/core/project/project.lua b/xmake/core/project/project.lua
index c52b52a05..252e75ab6 100644
--- a/xmake/core/project/project.lua
+++ b/xmake/core/project/project.lua
@@ -35,7 +35,6 @@ local target = require("project/target")
local config = require("project/config")
local option = require("project/option")
local deprecated_project = require("project/deprecated/project")
-local linker = require("platform/linker")
local platform = require("platform/platform")
-- the current os is belong to the given os?
diff --git a/xmake/core/project/target.lua b/xmake/core/project/target.lua
index 42a4df4bf..ef170fa4f 100644
--- a/xmake/core/project/target.lua
+++ b/xmake/core/project/target.lua
@@ -29,7 +29,7 @@ local path = require("base/path")
local table = require("base/table")
local option = require("project/option")
local config = require("project/config")
-local linker = require("platform/linker")
+local linker = require("tool/linker")
local compiler = require("tool/compiler")
local platform = require("platform/platform")
@@ -70,7 +70,7 @@ function target:linker()
assert(self)
-- init the linker from the given kind
- local result, errors = linker.init(self:get("kind"))
+ local result, errors = linker.load(self:get("kind"))
if not result then
os.raise(errors)
end
@@ -87,7 +87,7 @@ function target:compiler(srcfile)
assert(self and srcfile)
-- load the compiler
- local result, errors = compiler.load(srcfile)
+ local result, errors = compiler.load(compiler.kind_of_file(srcfile))
if not result then
os.raise(errors)
end
@@ -311,6 +311,38 @@ function target:headerfiles()
return srcheaders, dstheaders
end
+-- get the kinds of sourcefiles
+--
+-- .e.g cc cxx mm mxx as ...
+--
+function target:sourcekinds()
+
+ -- cached? return it directly
+ if self._SOURCEKINDS then
+ return self._SOURCEKINDS
+ end
+
+ -- make kinds
+ local kinds = {}
+ for _, sourcefile in pairs(self:sourcefiles()) do
+
+ -- get kind
+ local kind = compiler.kind_of_file(sourcefile)
+ if kind then
+ table.insert(kinds, kind)
+ end
+ end
+
+ -- remove repeat
+ kinds = table.unique(kinds)
+
+ -- cache it
+ self._SOURCEKINDS = kinds
+
+ -- ok?
+ return kinds
+end
+
-- return module
return target
diff --git a/xmake/core/tool/compiler.lua b/xmake/core/tool/compiler.lua
index 294a9c6c0..34510efd0 100644
--- a/xmake/core/tool/compiler.lua
+++ b/xmake/core/tool/compiler.lua
@@ -30,8 +30,8 @@ local utils = require("base/utils")
local table = require("base/table")
local string = require("base/string")
local config = require("project/config")
-local tool = require("tool/tool")
local platform = require("platform/platform")
+local tool = require("tool/tool")
-- get the current tool
function compiler:_tool()
@@ -47,32 +47,6 @@ function compiler:_flagnames()
return self._FLAGNAMES
end
--- get the compiler kind of the source file
-function compiler._kind_of_file(srcfile)
-
- -- get the source file type
- local filetype = path.extension(srcfile)
- if not filetype then
- return nil
- end
-
- -- the kinds
- local kinds =
- {
- [".c"] = "cc"
- , [".cc"] = "cxx"
- , [".cpp"] = "cxx"
- , [".m"] = "mm"
- , [".mm"] = "mxx"
- , [".s"] = "as"
- , [".asm"] = "as"
- , [".swift"] = "sc"
- }
-
- -- get kind
- return kinds[filetype:lower()]
-end
-
-- get the flags
function compiler:_flags(target)
@@ -280,7 +254,7 @@ function compiler:_addflags_from_target(flags, target)
if target.options then
-- add the flags for the target options
- for name, opt in pairs(target:options()) do
+ for _, opt in pairs(target:options()) do
-- add the flags from the option
self:_addflags_from_target(flags, opt)
@@ -344,6 +318,32 @@ function compiler:_addflags_from_compiler(flags, kind)
end
end
+-- get the compiler kind of the source file
+function compiler.kind_of_file(srcfile)
+
+ -- get the source file type
+ local filetype = path.extension(srcfile)
+ if not filetype then
+ return nil
+ end
+
+ -- the kinds
+ local kinds =
+ {
+ [".c"] = "cc"
+ , [".cc"] = "cxx"
+ , [".cpp"] = "cxx"
+ , [".m"] = "mm"
+ , [".mm"] = "mxx"
+ , [".s"] = "as"
+ , [".asm"] = "as"
+ , [".swift"] = "sc"
+ }
+
+ -- get kind
+ return kinds[filetype:lower()]
+end
+
-- get the current kind
function compiler:kind()
@@ -351,26 +351,23 @@ function compiler:kind()
return self._KIND
end
--- load the compiler from the given source file
-function compiler.load(srcfile)
+-- load the compiler from the given source kind
+function compiler.load(sourcekind)
- -- get the compiler kind
- local kind = compiler._kind_of_file(srcfile)
- if not kind then
- return nil, string.format("unknown source file: %s", srcfile)
- end
+ -- check
+ assert(sourcekind)
-- get it directly from cache dirst
compiler._INSTANCES = compiler._INSTANCES or {}
- if compiler._INSTANCES[kind] then
- return compiler._INSTANCES[kind]
+ if compiler._INSTANCES[sourcekind] then
+ return compiler._INSTANCES[sourcekind]
end
-- new instance
local instance = table.inherit(compiler)
-- load the compiler tool from the source file type
- local result, errors = tool.load(kind)
+ local result, errors = tool.load(sourcekind)
if not result then
return nil, errors
end
@@ -379,7 +376,7 @@ function compiler.load(srcfile)
instance._TOOL = result
-- save kind
- instance._KIND = kind
+ instance._KIND = sourcekind
-- save flagnames
local flagnames =
@@ -391,20 +388,27 @@ function compiler.load(srcfile)
, as = { "asflags" }
, sc = { "scflags" }
}
- instance._FLAGNAMES = flagnames[kind]
+ instance._FLAGNAMES = flagnames[sourcekind]
-- check
if not instance._FLAGNAMES then
- return nil, string.format("unknown compiler for kind: %s", kind)
+ return nil, string.format("unknown compiler for kind: %s", sourcekind)
end
-- save this instance
- compiler._INSTANCES[kind] = instance
+ compiler._INSTANCES[sourcekind] = instance
-- ok
return instance
end
+-- get properties of the tool
+function compiler:get(name)
+
+ -- get it
+ return self:_tool():get(name)
+end
+
-- run the command
function compiler:run(cmd)
diff --git a/xmake/core/tool/linker.lua b/xmake/core/tool/linker.lua
new file mode 100644
index 000000000..482c3c8a3
--- /dev/null
+++ b/xmake/core/tool/linker.lua
@@ -0,0 +1,358 @@
+--!The Automatic Cross-platform Build Tool
+--
+-- XMake is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU Lesser General Public License as published by
+-- the Free Software Foundation; either version 2.1 of the License, or
+-- (at your option) any later version.
+--
+-- XMake is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU Lesser General Public License for more details.
+--
+-- You should have received a copy of the GNU Lesser General Public License
+-- along with XMake;
+-- If not, see <a href="http://www.gnu.org/licenses/"> http://www.gnu.org/licenses/</a>
+--
+-- Copyright (C) 2015 - 2016, ruki All rights reserved.
+--
+-- @author ruki
+-- @file linker.lua
+--
+
+-- define module
+local linker = linker or {}
+
+-- load modules
+local io = require("base/io")
+local path = require("base/path")
+local utils = require("base/utils")
+local table = require("base/table")
+local string = require("base/string")
+local config = require("project/config")
+local platform = require("platform/platform")
+local tool = require("tool/tool")
+local compiler = require("tool/compiler")
+
+-- get the current tool
+function linker:_tool()
+
+ -- get it
+ return self._TOOL
+end
+
+-- get the current flag name
+function linker:_flagname()
+
+ -- get it
+ return self._FLAGNAME
+end
+
+-- get the link kind of the target kind
+function linker._kind_of_target(targetkind)
+
+ -- the kinds
+ local kinds =
+ {
+ ["binary"] = "ld"
+ , ["static"] = "ar"
+ , ["shared"] = "sh"
+ }
+
+ -- get kind
+ return kinds[targetkind]
+end
+
+-- get the flags
+function linker:_flags(target)
+
+ -- get the target key
+ local key = tostring(target)
+
+ -- get it directly from cache dirst
+ self._FLAGS = self._FLAGS or {}
+ if self._FLAGS[key] then
+ return self._FLAGS[key]
+ end
+
+ -- add flags from the configure
+ local flags = {}
+ self:_addflags_from_config(flags)
+
+ -- add flags from the target
+ self:_addflags_from_target(flags, target)
+
+ -- add flags from the platform
+ self:_addflags_from_platform(flags)
+
+ -- add flags from the compiler
+ self:_addflags_from_compiler(flags, target:sourcekinds())
+
+ -- add flags from the linker
+ self:_addflags_from_linker(flags)
+
+ -- remove repeat
+ flags = table.unique(flags)
+
+ -- merge flags
+ flags = table.concat(flags, " "):trim()
+
+ -- save flags
+ self._FLAGS[key] = flags
+
+ -- get it
+ return flags
+end
+
+-- map gcc flag to the given linker flag
+function linker:_mapflag(flag, mapflags)
+
+ -- attempt to map it directly
+ local flag_mapped = mapflags[flag]
+ if flag_mapped then
+ return flag_mapped
+ end
+
+ -- find and replace it using pattern
+ for k, v in pairs(mapflags) do
+ local flag_mapped, count = flag:gsub("^" .. k .. "$", function (w) return v end)
+ if flag_mapped and count ~= 0 then
+ return utils.ifelse(#flag_mapped ~= 0, flag_mapped, nil)
+ end
+ end
+
+ -- check it
+ if self:_tool():check(flag) then
+ return flag
+ end
+end
+
+-- map gcc flags to the given linker flags
+function linker:_mapflags(flags)
+
+ -- wrap flags first
+ flags = table.wrap(flags)
+
+ -- the linker tool
+ local ctool = self:_tool()
+
+ -- done
+ local results = {}
+ local mapflags = ctool:get("mapflags")
+ if mapflags then
+
+ -- map flags
+ for _, flag in pairs(flags) do
+ local flag_mapped = self:_mapflag(flag, mapflags)
+ if flag_mapped then
+ table.insert(results, flag_mapped)
+ end
+ end
+
+ else
+
+ -- check flags
+ for _, flag in pairs(flags) do
+ if ctool:check(flag) then
+ table.insert(results, flag)
+ end
+ end
+
+ end
+
+ -- ok?
+ return results
+end
+
+-- get the named flags
+function linker:_named_flags(names, flags)
+
+ -- map it
+ local flags_mapped = {}
+ for _, name in ipairs(table.wrap(names)) do
+ table.join2(flags_mapped, self:_mapflags(flags[name]))
+ end
+
+ -- get it
+ return flags_mapped
+end
+
+-- add flags from the configure
+function linker:_addflags_from_config(flags)
+
+ -- done
+ table.join2(flags, config.get(self:_flagname()))
+end
+
+-- add flags from the target
+function linker:_addflags_from_target(flags, target)
+
+ -- the compiler tool
+ local ctool = self:_tool()
+
+ -- add the target flags
+ table.join2(flags, self:_mapflags(target:get(self:_flagname())))
+
+ -- add the linkdirs flags
+ for _, linkdir in ipairs(table.wrap(target:get("linkdirs"))) do
+ table.join2(flags, ctool:linkdir(linkdir))
+ end
+
+ -- add the links flags
+ for _, link in ipairs(table.wrap(target:get("links"))) do
+ table.join2(flags, ctool:link(link))
+ end
+
+ -- for target options?
+ if target.options then
+
+ -- add the flags for the target options
+ for _, opt in pairs(target:options()) do
+
+ -- add the flags from the option
+ table.join2(flags, self:_mapflags(opt:get(self:_flagname())))
+
+ -- add the linkdirs flags from the option
+ for _, linkdir in ipairs(table.wrap(opt:get("linkdirs"))) do
+ table.join2(flags, ctool:linkdir(linkdir))
+ end
+
+ -- add the links flags from the option
+ for _, link in ipairs(table.wrap(opt:get("links"))) do
+ table.join2(flags, ctool:link(link))
+ end
+ end
+ end
+
+ -- add the strip flags
+ table.join2(flags, self:_named_flags(target:get("strip"), { debug = "-S"
+ , all = "-s"
+ }))
+end
+
+-- add flags from the platform
+function linker:_addflags_from_platform(flags)
+
+ -- the compiler tool
+ local ctool = self:_tool()
+
+ -- add flags
+ table.join2(flags, self:_mapflags(platform.get(self:_flagname())))
+
+ -- add the linkdirs flags
+ for _, linkdir in ipairs(table.wrap(platform.get("linkdirs"))) do
+ table.join2(flags, ctool:linkdir(linkdir))
+ end
+
+ -- add the links flags
+ for _, link in ipairs(table.wrap(platform.get("links"))) do
+ table.join2(flags, ctool:link(link))
+ end
+end
+
+-- add flags from the compiler
+function linker:_addflags_from_compiler(flags, srckinds)
+
+ -- done
+ local flags_of_compiler = {}
+ for _, srckind in ipairs(table.wrap(srckinds)) do
+
+ -- load compiler
+ local instance, errors = compiler.load(srckind)
+ if instance then
+ table.join2(flags_of_compiler, instance:get(self:_flagname()))
+ end
+ end
+
+ -- add flags
+ table.join2(flags, table.unique(flags_of_compiler))
+end
+
+-- add flags from the linker
+function linker:_addflags_from_linker(flags)
+
+ -- done
+ table.join2(flags, self:_tool():get(self:_flagname()))
+end
+
+-- get the current kind
+function linker:kind()
+
+ -- get it
+ return self._KIND
+end
+
+-- load the linker from the given target kind
+function linker.load(targetkind)
+
+ -- get the linker kind
+ local kind = linker._kind_of_target(targetkind)
+ if not kind then
+ return nil, string.format("unknown target kind: %s", targetkind)
+ end
+
+ -- get it directly from cache dirst
+ linker._INSTANCES = linker._INSTANCES or {}
+ if linker._INSTANCES[kind] then
+ return linker._INSTANCES[kind]
+ end
+
+ -- new instance
+ local instance = table.inherit(linker)
+
+ -- load the linker tool from the source file type
+ local result, errors = tool.load(kind)
+ if not result then
+ return nil, errors
+ end
+
+ -- save tool
+ instance._TOOL = result
+
+ -- save kind
+ instance._KIND = kind
+
+ -- save flagname
+ local flagname =
+ {
+ ld = "ldflags"
+ , ar = "arflags"
+ , sh = "shflags"
+ }
+ instance._FLAGNAME = flagname[kind]
+
+ -- check
+ if not instance._FLAGNAME then
+ return nil, string.format("unknown linker for kind: %s", kind)
+ end
+
+ -- save this instance
+ linker._INSTANCES[kind] = instance
+
+ -- ok
+ return instance
+end
+
+-- get properties of the tool
+function linker:get(name)
+
+ -- get it
+ return self:_tool():get(name)
+end
+
+-- run the command
+function linker:run(cmd)
+
+ -- get it
+ return self:_tool():run(cmd)
+end
+
+-- get the command
+function linker:command(target, objfiles, targetfile, logfile)
+
+ -- get it
+ return self:_tool():command(table.concat(table.wrap(objfiles), " "), targetfile, self:_flags(target), logfile)
+end
+
+-- return module
+return linker
diff --git a/xmake/core/tool/tool.lua b/xmake/core/tool/tool.lua
index bca361388..75ef33a22 100644
--- a/xmake/core/tool/tool.lua
+++ b/xmake/core/tool/tool.lua
@@ -100,6 +100,39 @@ function _module:includedir(dir)
return interface.includedir(dir)
end
+-- make the link flag
+function _module:link(lib)
+
+ -- the interface
+ local interface = self._INTERFACE
+ assert(interface)
+
+ -- check
+ if not interface.link then
+ return
+ end
+
+ -- make it
+ return interface.link(lib)
+end
+
+-- TODO wrap dynamic
+-- make the linkdir flag
+function _module:linkdir(dir)
+
+ -- the interface
+ local interface = self._INTERFACE
+ assert(interface)
+
+ -- check
+ if not interface.linkdir then
+ return
+ end
+
+ -- make it
+ return interface.linkdir(dir)
+end
+
-- make the command
function _module:command(srcfile, objfile, flags, logfile)
@@ -174,15 +207,13 @@ function tool._directories(name)
, mm = "compiler"
, mxx = "compiler"
, sc = "compiler"
- , ar = "archiver"
+ , ar = "linker"
, sh = "linker"
, ld = "linker"
- , make = "other"
}
-- get kind sub-directory
- local subdir = kinds[name]
- assert(subdir)
+ local subdir = kinds[name] or ""
-- the directories
return { path.join(path.join(config.directory(), "tools"), subdir)
diff --git a/xmake/tools/compiler/gcc.lua b/xmake/tools/compiler/gcc.lua
index 9d6e8a484..437948610 100755
--- a/xmake/tools/compiler/gcc.lua
+++ b/xmake/tools/compiler/gcc.lua
@@ -45,10 +45,6 @@ function init(shellname)
["-W1"] = "-Wall"
, ["-W2"] = "-Wall"
, ["-W3"] = "-Wall"
-
- -- strip
- , ["-s"] = "-s"
- , ["-S"] = "-S"
}
end
diff --git a/xmake/tools/linker/ar.lua b/xmake/tools/linker/ar.lua
new file mode 100644
index 000000000..12beaab0a
--- /dev/null
+++ b/xmake/tools/linker/ar.lua
@@ -0,0 +1,44 @@
+--!The Automatic Cross-platform Build Tool
+--
+-- XMake is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU Lesser General Public License as published by
+-- the Free Software Foundation; either version 2.1 of the License, or
+-- (at your option) any later version.
+--
+-- XMake is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU Lesser General Public License for more details.
+--
+-- You should have received a copy of the GNU Lesser General Public License
+-- along with XMake;
+-- If not, see <a href="http://www.gnu.org/licenses/"> http://www.gnu.org/licenses/</a>
+--
+-- Copyright (C) 2015 - 2016, ruki All rights reserved.
+--
+-- @author ruki
+-- @file ar.lua
+--
+
+-- init it
+function init(shellname)
+
+ -- save the shell name
+ _g.shellname = shellname or "ar"
+
+ -- init arflags
+ _g.arflags = { "-crs" }
+
+end
+
+-- make the command
+function command(objfiles, targetfile, flags, logfile)
+
+ -- redirect
+ local redirect = ""
+ if logfile then redirect = format(" > %s 2>&1", logfile) end
+
+ -- make it
+ return format("%s %s %s %s%s", _g.shellname, flags, targetfile, objfiles, redirect)
+end
+
diff --git a/xmake/tools/linker/clang++.lua b/xmake/tools/linker/clang++.lua
new file mode 100755
index 000000000..6b2feaa2f
--- /dev/null
+++ b/xmake/tools/linker/clang++.lua
@@ -0,0 +1,33 @@
+--!The Automatic Cross-platform Build Tool
+--
+-- XMake is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU Lesser General Public License as published by
+-- the Free Software Foundation; either version 2.1 of the License, or
+-- (at your option) any later version.
+--
+-- XMake is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU Lesser General Public License for more details.
+--
+-- You should have received a copy of the GNU Lesser General Public License
+-- along with XMake;
+-- If not, see <a href="http://www.gnu.org/licenses/"> http://www.gnu.org/licenses/</a>
+--
+-- Copyright (C) 2015 - 2016, ruki All rights reserved.
+--
+-- @author ruki
+-- @file clang++.lua
+--
+
+-- inherit clang
+inherit("clang")
+
+-- init it
+function init(shellname)
+
+ -- init super
+ _super.init(shellname or "clang++")
+
+end
+
diff --git a/xmake/tools/linker/clang.lua b/xmake/tools/linker/clang.lua
new file mode 100755
index 000000000..712b578e3
--- /dev/null
+++ b/xmake/tools/linker/clang.lua
@@ -0,0 +1,40 @@
+--!The Automatic Cross-platform Build Tool
+--
+-- XMake is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU Lesser General Public License as published by
+-- the Free Software Foundation; either version 2.1 of the License, or
+-- (at your option) any later version.
+--
+-- XMake is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU Lesser General Public License for more details.
+--
+-- You should have received a copy of the GNU Lesser General Public License
+-- along with XMake;
+-- If not, see <a href="http://www.gnu.org/licenses/"> http://www.gnu.org/licenses/</a>
+--
+-- Copyright (C) 2015 - 2016, ruki All rights reserved.
+--
+-- @author ruki
+-- @file clang.lua
+--
+
+-- inherit gcc
+inherit("gcc")
+
+-- init it
+function init(shellname)
+
+ -- init super
+ _super.init(shellname or "clang")
+
+ -- init shflags
+ _super._g.shflags = { "-dynamiclib", "-fPIC" }
+
+ -- init flags map
+ _super._g.mapflags["-s"] = "-Wl,-S"
+ _super._g.mapflags["-S"] = "-Wl,-S"
+
+end
+
diff --git a/xmake/tools/linker/g++.lua b/xmake/tools/linker/g++.lua
new file mode 100755
index 000000000..7b2837b8e
--- /dev/null
+++ b/xmake/tools/linker/g++.lua
@@ -0,0 +1,33 @@
+--!The Automatic Cross-platform Build Tool
+--
+-- XMake is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU Lesser General Public License as published by
+-- the Free Software Foundation; either version 2.1 of the License, or
+-- (at your option) any later version.
+--
+-- XMake is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU Lesser General Public License for more details.
+--
+-- You should have received a copy of the GNU Lesser General Public License
+-- along with XMake;
+-- If not, see <a href="http://www.gnu.org/licenses/"> http://www.gnu.org/licenses/</a>
+--
+-- Copyright (C) 2015 - 2016, ruki All rights reserved.
+--
+-- @author ruki
+-- @file g++.lua
+--
+
+-- inherit gcc
+inherit("gcc")
+
+-- init it
+function init(shellname)
+
+ -- init super
+ _super.init(shellname or "g++")
+
+end
+
diff --git a/xmake/tools/linker/gcc.lua b/xmake/tools/linker/gcc.lua
new file mode 100755
index 000000000..6bc839768
--- /dev/null
+++ b/xmake/tools/linker/gcc.lua
@@ -0,0 +1,95 @@
+--!The Automatic Cross-platform Build Tool
+--
+-- XMake is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU Lesser General Public License as published by
+-- the Free Software Foundation; either version 2.1 of the License, or
+-- (at your option) any later version.
+--
+-- XMake is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU Lesser General Public License for more details.
+--
+-- You should have received a copy of the GNU Lesser General Public License
+-- along with XMake;
+-- If not, see <a href="http://www.gnu.org/licenses/"> http://www.gnu.org/licenses/</a>
+--
+-- Copyright (C) 2015 - 2016, ruki All rights reserved.
+--
+-- @author ruki
+-- @file gcc.lua
+--
+
+-- init it
+function init(shellname)
+
+ -- save the shell name
+ _g.shellname = shellname or "gcc"
+
+ -- init shflags
+ _g.shflags = { "-shared", "-fPIC" }
+
+ -- init flags map
+ _g.mapflags =
+ {
+ -- strip
+ ["-s"] = "-s"
+ , ["-S"] = "-S"
+
+ }
+end
+
+-- get the property
+function get(name)
+
+ -- get it
+ return _g[name]
+end
+
+-- make the link flag
+function link(lib)
+
+ -- make it
+ return "-l" .. lib
+end
+
+-- make the linkdir flag
+function linkdir(dir)
+
+ -- make it
+ return "-L" .. dir
+end
+
+-- make the command
+function command(objfiles, targetfile, flags, logfile)
+
+ -- redirect
+ local redirect = ""
+ if logfile then redirect = format(" > %s 2>&1", logfile) end
+
+ -- make it
+ return format("%s -o %s %s %s%s", _g.shellname, targetfile, objfiles, flags, redirect)
+end
+
+-- check the given flags
+function check(flags)
+
+ -- done
+ local ok = false
+ try
+ {
+ function ()
+
+ -- check it
+ os.run("%s %s -S -o $(nuldev) -xc $(nuldev) > $(nuldev) 2>&1", _g.shellname, flags)
+
+ -- ok
+ ok = true
+
+ end
+ }
+
+ -- ok?
+ return ok
+end
+
diff --git a/xmake/tools/make.lua b/xmake/tools/make.lua
new file mode 100644
index 000000000..8cab41067
--- /dev/null
+++ b/xmake/tools/make.lua
@@ -0,0 +1,76 @@
+--!The Automatic Cross-platform Build Tool
+--
+-- XMake is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU Lesser General Public License as published by
+-- the Free Software Foundation; either version 2.1 of the License, or
+-- (at your option) any later version.
+--
+-- XMake is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU Lesser General Public License for more details.
+--
+-- You should have received a copy of the GNU Lesser General Public License
+-- along with XMake;
+-- If not, see <a href="http://www.gnu.org/licenses/"> http://www.gnu.org/licenses/</a>
+--
+-- Copyright (C) 2015 - 2016, ruki All rights reserved.
+--
+-- @author ruki
+-- @file make.lua
+--
+
+-- imports
+import("core.base.option")
+
+-- init it
+function init(shellname)
+
+ -- save name
+ _g.shellname = shellname or "make"
+
+end
+
+-- run it
+function run(makefile, target, jobs)
+
+ -- enable jobs?
+ if jobs ~= nil then
+ if tonumber(jobs) ~= 0 then
+ jobs = "-j" .. jobs
+ else
+ jobs = "-j"
+ end
+ else
+ jobs = ""
+ end
+
+ -- is verbose?
+ local verbose = ifelse(option.get("verbose"), "-v", "")
+
+ -- run it
+ local ok = nil
+ if makefile and os.isfile(makefile) then
+ ok = os.execute("%s -r %s -f %s %s VERBOSE=%s", _g.shellname, jobs, makefile, target or "", verbose)
+ else
+ ok = os.execute("%s -r %s %s VERBOSE=%s", _g.shellname, jobs, target or "", verbose)
+ end
+
+ -- failed
+ if ok ~= 0 then
+
+ -- attempt to run it again for getting the error logs without jobs
+ if makefile and os.isfile(makefile) then
+ ok = os.execute("%s -r -f %s %s VERBOSE=%s", _g.shellname, makefile, target or "", verbose)
+ else
+ ok = os.execute("%s -r %s VERBOSE=%s", _g.shellname, target or "", verbose)
+ end
+
+ end
+
+ -- always failed?
+ if ok ~= 0 then
+ raise(ok)
+ end
+
+end