Linking golang statically
转自:https://blog.hashbangbash.com/2014/04/linking-golang-statically/ 在学习goreplay 构建的时候找到的一篇不错的文章,可能有点比较早了
If you are not familiar with Golang, do take the go tour or read some of the docs first.
There are a number of reasons that folks are in love with golang. One the most mentioned is the static linking.
As long as the source being compiled is native go, the go compiler will statically link the executable. Though when you need to use cgo, then the compiler has to use its external linker.
Pure go
// code-pure.go
package main
import "fmt"
func main() {
fmt.Println("hello, world!")
}
Straight forward example. Let’s compile it.
$> go build ./code-pure.go
$> ldd ./code-pure
not a dynamic executable
$> file ./code-pure
./code-pure: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped
cgo
Using a contrived, but that passes through the C barrier:
// code-cgo.go
package main
/*
char* foo(void) { return "hello, world!"; }
*/
import "C"
import "fmt"
func main() {
fmt.Println(C.GoString(C.foo()))
}
Seems simple enough. Let’s compile it
$> go build ./code-cgo.go
$> file ./code-cgo
./code-cgo: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), not stripped
$> ldd ./code-cgo
linux-vdso.so.1 (0x00007fff07339000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f5e62737000)
libc.so.6 => /lib64/libc.so.6 (0x00007f5e6236e000)
/lib64/ld-linux-x86-64.so.2 (0x00007f5e62996000)
$> ./code-cgo
hello, world!
wait, what?
That code that is using cgo is not statically linked. Why not?
The compile for this does not wholly use golang’s internal linker, and has to use the external linker. So, this is not surprising, since this is not unlike simple `gcc -o hello-world.c
`, which is default to dynamically linked.
// hello-world.c
int main() {
puts("hello, world!");
}
$> gcc -o ./hello-world ./hello-world.c
$> ./hello-world
hello, world!
$> file ./hello-world
./hello-world: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), not stripped
$> ldd ./hello-world
linux-vdso.so.1 (0x00007fff5f109000)
libc.so.6 => /lib64/libc.so.6 (0x00007f0906e53000)
/lib64/ld-linux-x86-64.so.2 (0x00007f090725e000)
But for that example, we just have to add the ‘-static’ flag to gcc (and ensure that glibc-static package is available).
$> gcc -o ./hello-world -static ./hello-world.c
$ file ./hello-world
./hello-world: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, not stripped
$ ldd ./hello-world
not a dynamic executable
Let’s apply that same logic to our go build
static cgo
Using same code-cgo.go
source, let’s apply that gcc flag, but using the go build
command.
$> go build --ldflags '-extldflags "-static"' ./code-cgo.go
$> file ./code-cgo
./code-cgo: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, not stripped
$> ldd ./code-cgo
not a dynamic executable
$> ./code-cgo
hello, world!
Cool! Here we’ve let the go compiler use the external linker, and that linker linked statically from libc.
An explanation of the flags here.
--ldflags
is passed to the go linker. It takes a string of arguments.
On my linux-x86_64 machine, that is the 6l
tool (5l
for arm and 8l
for ix86). To see the tools available on your host, call go tool
, and then get help on that tool with go tool 6l --help
'-extldflags ...'
is a flag for the 6l
linker, to pass additional flags to the external linker (in my situation, that is gcc
).
"-static"
is the argument to gcc
(also to ld
) to link statically.
gccgo love
Say you have a use case for using/needing the gccgo
compiler, instead of the go compiler.
Again, using our same code-cgo.go
source, let’s compile the code statically using gccgo
.
$> go build -compiler gccgo --gccgoflags "-static" ./code-cgo.go
$> file ./code-cgo
./code-cgo: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, not stripped
$> ldd ./code-cgo
not a dynamic executable
$> ./code-cgo
hello, world!
Huzzah! Still a static binary, using cgo and giving gccgo a whirl. A quick run-down of these flags.
-compiler gccgo
instructs the build to use gccgo
instead of the go compiler (gc
).
--gccgoflags ...
are additional arguments passed to the gccgo
command. See also the gccgo
man page.
"-static"
similar to gcc
, this is the same flag the instructs gccgo
to link the executable statically.
more info
If you’re curious to what is happening behind the scenes of your compile, the go build
has an -x
flag that prints out the commands that it is running. This is often helpful if you are following what is linked in, or to see the commands used during compile such that you can find where and how to insert arguments needed.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)