diff options
| author | ruki <[email protected]> | 2025-12-05 22:36:39 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2025-12-05 22:36:39 +0800 |
| commit | e688a7bd853c49ec10aa8656e704c2115ea5e14c (patch) | |
| tree | ea514a602e65bec18b18e4037df605357bd95443 /xmake/modules | |
| parent | 6d803e27d205bc7282597ac4db2a105f2a79d5ad (diff) | |
rewrite golang support
Diffstat (limited to 'xmake/modules')
| -rw-r--r-- | xmake/modules/core/tools/go.lua | 93 | ||||
| -rw-r--r-- | xmake/modules/core/tools/go/has_flags.lua | 95 | ||||
| -rw-r--r-- | xmake/modules/private/tools/go/goenv.lua | 84 |
3 files changed, 176 insertions, 96 deletions
diff --git a/xmake/modules/core/tools/go.lua b/xmake/modules/core/tools/go.lua index 70e667ad9..90431320c 100644 --- a/xmake/modules/core/tools/go.lua +++ b/xmake/modules/core/tools/go.lua @@ -18,6 +18,7 @@ -- @file go.lua -- + -- imports import("core.base.option") import("core.project.config") @@ -26,45 +27,39 @@ import("core.language.language") -- init it function init(self) - self:set("gcarflags", "grc") + self:set("gcarflags", "") end -- make the optimize flag function nf_optimize(self, level) - -- only for source kind - local kind = self:kind() - if language.sourcekinds()[kind] then - local maps = { - none = "-N" - } - return maps[level] - end + -- Go build flags for optimization + local maps = { + none = "-gcflags=-N" + } + return maps[level] end -- make the symbol flag function nf_symbol(self, level, opt) - local targetkind = opt.targetkind - if targetkind ~= "object" then - return - end - local maps = { - debug = "-E" - } - return maps[level] + -- Go doesn't use separate symbol flags like C/C++ + return end -- make the strip flag function nf_strip(self, level) + -- Go uses -ldflags="-s -w" for stripping + -- -ldflags needs to be passed as separate arguments: -ldflags and the value local maps = { - debug = "-s" - , all = "-s" + debug = {"-ldflags", "-s"} + , all = {"-ldflags", "-s -w"} } return maps[level] end -- make the includedir flag function nf_includedir(self, dir) - return {"-I", dir} + -- Go doesn't use -I flags, but we can use build tags or build constraints + return end -- make the sysincludedir flag @@ -74,34 +69,50 @@ end -- make the linkdir flag function nf_linkdir(self, dir) - return {"-L", dir} + -- Go uses -L flag for linker search paths via -ldflags + -- -ldflags needs to be passed as separate arguments: -ldflags and the value + -- Note: -L must be inside the -ldflags value, not as a separate argument + return {"-ldflags", "-L " .. dir} end --- make the link arguments list -function linkargv(self, objectfiles, targetkind, targetfile, flags) +-- make the build arguments list +-- Modern Go uses "go build" command for both compilation and linking +function buildargv(self, sourcefiles, targetkind, targetfile, flags) + local argv = {"build"} + + -- add build flags + if flags then + table.join2(argv, flags) + end + + -- set output file + table.insert(argv, "-o") + table.insert(argv, targetfile) + + -- for static library, use buildmode=archive if targetkind == "static" then - return self:program(), table.join("tool", "pack", flags, targetfile, objectfiles) + table.insert(argv, "-buildmode=archive") + end + + -- add source files (Go supports building from source file list) + -- The caller should change to the source directory before calling build + if sourcefiles and #sourcefiles > 0 then + -- convert source files to relative paths from current directory + -- or use absolute paths if needed + for _, sourcefile in ipairs(sourcefiles) do + table.insert(argv, sourcefile) + end else - return self:program(), table.join("tool", "link", flags, "-o", targetfile, objectfiles) + -- fallback to current package if no source files + table.insert(argv, ".") end + + return self:program(), argv end --- link the target file -function link(self, objectfiles, targetkind, targetfile, flags) +-- build the target file (compile and link in one step) +function build(self, sourcefiles, targetkind, targetfile, flags) os.mkdir(path.directory(targetfile)) - local program, argv = linkargv(self, objectfiles, targetkind, targetfile, flags) - os.runv(program, argv, {envs = self:runenvs()}) -end - --- make the compile arguments list -function compargv(self, sourcefiles, objectfile, flags) - return self:program(), table.join("tool", "compile", flags, "-o", objectfile, sourcefiles) -end - --- compile the source file -function compile(self, sourcefiles, objectfile, dependinfo, flags) - os.mkdir(path.directory(objectfile)) - local program, argv = compargv(self, sourcefiles, objectfile, flags) + local program, argv = buildargv(self, sourcefiles, targetkind, targetfile, flags) os.runv(program, argv, {envs = self:runenvs()}) end - diff --git a/xmake/modules/core/tools/go/has_flags.lua b/xmake/modules/core/tools/go/has_flags.lua index 1e84ac279..d3df6bf89 100644 --- a/xmake/modules/core/tools/go/has_flags.lua +++ b/xmake/modules/core/tools/go/has_flags.lua @@ -24,24 +24,31 @@ import("core.language.language") -- is linker? function _islinker(flags, opt) - -- the tool kind is gcld or gcsh? local toolkind = opt.toolkind or "" return toolkind:endswith("ld") or toolkind:endswith("sh") end -- try running -function _try_running(...) - - local argv = {...} +function _try_running(program, argv, opt) local errors = nil - return try { function () os.runv(table.unpack(argv)); return true end, catch { function (errs) errors = (errs or ""):trim() end }}, errors + local ok = try { + function () + os.runv(program, argv, opt) + return true + end, + catch { + function (errs) + errors = (errs or ""):trim() + end + } + } + return ok, errors end -- attempt to check it from the argument list function _check_from_arglist(flags, opt, islinker) - - -- only for compiler + -- only for compiler and single flag if islinker or #flags > 1 then return end @@ -55,66 +62,67 @@ function _check_from_arglist(flags, opt, islinker) -- get all flags from argument list local allflags = detectcache:get2(key, flagskey) if not allflags then - - -- attempt to get argument list from the error info (help menu) allflags = {} - try - { - function () os.runv(opt.program, {"tool", "compile", "--help"}) end, - catch - { - function (errors) - local arglist = errors - if arglist then - for arg in arglist:gmatch("%s+(%-[%-%a%d]+)%s+") do - allflags[arg] = true - end - end - end - } + + -- try to get help from "go help build" + local help_output = try { + function () + return os.iorunv(opt.program, {"help", "build"}, {envs = opt.envs}) + end + } + + if help_output then + -- parse flags from help output + for flag in help_output:gmatch("%s+(%-[%-%a%d=]+)%s+") do + allflags[flag] = true + end + end + + -- also try "go build -h" for more detailed flags + local build_help = try { + function () + return os.iorunv(opt.program, {"build", "-h"}, {envs = opt.envs}) + end } + + if build_help then + for flag in build_help:gmatch("%s+(%-[%-%a%d=]+)%s+") do + allflags[flag] = true + end + end -- save cache detectcache:set2(key, flagskey, allflags) end + return allflags[flags[1]] end -- try running to check flags function _check_try_running(flags, opt, islinker) - -- make an stub source file local sourcefile = path.join(os.tmpdir(), "detect", "go_has_flags.go") - local objectfile = path.join(os.tmpdir(), "detect", "go_has_flags.o") - local targetfile = path.join(os.tmpdir(), "detect", "go_has_flags.bin") if not os.isfile(sourcefile) then - io.writefile(sourcefile, "package main\nfunc main() {\n}") - end - - -- check flags for linker - if islinker then - - -- compile a object file first - if not os.isfile(objectfile) and not _try_running(opt.program, table.join("tool", "compile", "-o", objectfile, sourcefile)) then - return false - end - - -- check it - return _try_running(opt.program, table.join("tool", "link", flags, "-o", targetfile, objectfile)) + io.writefile(sourcefile, "package main\n\nfunc main() {\n}\n") end - -- check flags for compiler - return _try_running(opt.program, table.join("tool", "compile", flags, "-o", objectfile, sourcefile)) + -- check flags for linker or compiler + -- Modern Go uses "go build" for both compilation and linking + local argv = {"build", "-o", os.tmpfile()} + table.join2(argv, flags) + table.insert(argv, sourcefile) + + local ok, errors = _try_running(opt.program, argv, {envs = opt.envs}) + return ok == true end -- has_flags(flags)? -- --- @param opt the argument options, e.g. {toolname = "", program = "", programver = "", toolkind = "[cc|cxx|ld|ar|sh|gc|mm|mxx]"} +-- @param opt the argument options, e.g. {toolname = "", program = "", programver = "", toolkind = "[gc|gcld|gcar]"} -- -- @return true or false -- function main(flags, opt) - -- is linker? local islinker = _islinker(flags, opt) @@ -126,4 +134,3 @@ function main(flags, opt) -- try running to check it return _check_try_running(flags, opt, islinker) end - diff --git a/xmake/modules/private/tools/go/goenv.lua b/xmake/modules/private/tools/go/goenv.lua index 278146a6c..1a448e6f3 100644 --- a/xmake/modules/private/tools/go/goenv.lua +++ b/xmake/modules/private/tools/go/goenv.lua @@ -21,26 +21,88 @@ -- imports import("lib.detect.find_tool") +-- Map xmake platform to Go OS function GOOS(plat) - local goos - if plat == "windows" or plat == "mingw" or plat == "msys" or plat == "cygwin" then - goos = "windows" - elseif plat == "linux" then - goos = "linux" - elseif plat == "macosx" then - goos = "darwin" - end - return goos + local goos_map = { + windows = "windows", + mingw = "windows", + msys = "windows", + cygwin = "windows", + linux = "linux", + macosx = "darwin", + android = "android", + ios = "ios", + freebsd = "freebsd", + netbsd = "netbsd", + openbsd = "openbsd", + dragonfly = "dragonfly", + solaris = "solaris", + aix = "aix", + plan9 = "plan9" + } + return goos_map[plat] end +-- Map xmake architecture to Go architecture function GOARCH(arch) - return (arch == "x86" or arch == "i386") and "386" or "amd64" + local goarch_map = { + x86 = "386", + i386 = "386", + x64 = "amd64", + x86_64 = "amd64", + amd64 = "amd64", + arm = "arm", + armv7 = "arm", + armv7s = "arm", + arm64 = "arm64", + aarch64 = "arm64", + mips = "mips", + mips64 = "mips64", + mips64le = "mips64le", + mipsle = "mipsle", + ppc = "ppc", + ppc64 = "ppc64", + ppc64le = "ppc64le", + riscv64 = "riscv64", + s390x = "s390x", + wasm = "wasm" + } + + -- try direct match first + if goarch_map[arch] then + return goarch_map[arch] + end + + -- try pattern matching for arm variants + if arch:match("^arm") then + if arch:match("64") or arch:match("aarch64") then + return "arm64" + else + return "arm" + end + end + + -- try pattern matching for x86 variants + if arch:match("^x86") or arch:match("^i386") or arch:match("^i686") then + return "386" + end + + if arch:match("^x64") or arch:match("^amd64") or arch:match("^x86_64") then + return "amd64" + end + + return nil end +-- Get GOROOT from Go installation function GOROOT(toolchain) local go = find_tool("go") if go then - local gorootdir = try { function() return os.iorunv(go.program, {"env", "GOROOT"}) end } + local gorootdir = try { + function() + return os.iorunv(go.program, {"env", "GOROOT"}, {envs = toolchain and toolchain:get("runenvs") or nil}) + end + } if gorootdir then return gorootdir:trim() end |
