summaryrefslogtreecommitdiff
path: root/xmake/modules
diff options
context:
space:
mode:
authorruki <[email protected]>2025-12-05 22:36:39 +0800
committerruki <[email protected]>2025-12-05 22:36:39 +0800
commite688a7bd853c49ec10aa8656e704c2115ea5e14c (patch)
treeea514a602e65bec18b18e4037df605357bd95443 /xmake/modules
parent6d803e27d205bc7282597ac4db2a105f2a79d5ad (diff)
rewrite golang support
Diffstat (limited to 'xmake/modules')
-rw-r--r--xmake/modules/core/tools/go.lua93
-rw-r--r--xmake/modules/core/tools/go/has_flags.lua95
-rw-r--r--xmake/modules/private/tools/go/goenv.lua84
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