@@ -42,6 +42,124 @@ go1.13.9 download 下载源码到用户目录下的sdk/go1.13.9 下
42
42
43
43
` -w, --workdir string ` 指定工作目录
44
44
45
+
46
+ ## 动态链接和静态链接
47
+ ```
48
+ $file helloworld-default
49
+ helloworld-default: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped
50
+ $ldd helloworld-default
51
+ 不是动态可执行文件
52
+ ```
53
+
54
+ 开启 CGO_ENABLED=1
55
+ ```
56
+ // go-compilation/main-with-os-user.go
57
+
58
+ package main
59
+
60
+ import (
61
+ "fmt"
62
+ _ "os/user"
63
+ )
64
+
65
+ func main() {
66
+ fmt.Println("hello, world")
67
+ }
68
+ ```
69
+
70
+ ```
71
+ $file helloworld-with-os-user
72
+ helloworld-with-os-user: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), not stripped
73
+
74
+ $ldd helloworld-with-os-user
75
+ linux-vdso.so.1 => (0x00007ffcb8fd4000)
76
+ libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fb5d6fce000)
77
+ libc.so.6 => /lib64/libc.so.6 (0x00007fb5d6c00000)
78
+ /lib64/ld-linux-x86-64.so.2 (0x00007fb5d71ea000)
79
+ ```
80
+ 通过nm命令我们还可以查看Go程序依赖了哪些C库的符号:
81
+ ```
82
+ $nm -a helloworld-with-os-user |grep " U "
83
+ U abort
84
+ U __errno_location
85
+ U fprintf
86
+ U fputc
87
+ U free
88
+ U fwrite
89
+ U malloc
90
+ U mmap
91
+ U munmap
92
+ U nanosleep
93
+ U pthread_attr_destroy
94
+ U pthread_attr_getstack
95
+ U pthread_attr_getstacksize
96
+ U pthread_attr_init
97
+ U pthread_cond_broadcast
98
+ U pthread_cond_wait
99
+ U pthread_create
100
+ U pthread_detach
101
+ U pthread_getattr_np
102
+ U pthread_key_create
103
+ U pthread_mutex_lock
104
+ U pthread_mutex_unlock
105
+ U pthread_self
106
+ U pthread_setspecific
107
+ U pthread_sigmask
108
+ U setenv
109
+ U sigaction
110
+ U sigaddset
111
+ U sigemptyset
112
+ U sigfillset
113
+ U sigismember
114
+ U stderr
115
+ U strerror
116
+ U unsetenv
117
+ U vfprintf
118
+ ```
119
+
120
+ ### 依赖使用cgo的外部go包(静态链接)
121
+ 要想实现静态链接,我们需要找出外部go依赖的所有c库的.a文件(静态共享库)。以我们的go-sqlite3示例为例,go-sqlite3是sqlite库的go binding,它依赖sqlite库,同时所有第三方c库都依赖libc,我们还要准备一份libc的.a文件,下面我们就先安装这些:
122
+ ```
123
+ $yum install -y gcc glibc-static sqlite-devel
124
+ ... ...
125
+
126
+ 已安装:
127
+ sqlite-devel.x86_64 0:3.7.17-8.el7_7.1
128
+
129
+ 更新完毕:
130
+ glibc-static.x86_64 0:2.17-326.el7_9.3
131
+ ```
132
+ 接下来,我们就来以静态链接的方式在go-compilation/go-sqlite3-static下编译一下:
133
+ ```
134
+ $go build -tags 'sqlite_omit_load_extension' -ldflags '-linkmode external -extldflags "-static"' demo
135
+
136
+ $file ./demo
137
+ ./demo: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=c779f5c3eaa945d916de059b56d94c23974ce61c, not stripped
138
+ ```
139
+ 这里命令行中的` -tags 'sqlite_omit_load_extension' ` 用于禁用SQLite3的动态加载功能,确保更好的静态链接兼容性。而` -ldflags '-linkmode external -extldflags "-static"' ` 的含义是使用外部链接器(比如gcc linker),并强制静态链接所有库。
140
+
141
+ ### 优化可执行文件的大小
142
+ - 去除符号表和调试信息
143
+ 在编译时使用-ldflags="-s -w"标志可以去除符号表和调试符号,其中-s用于去掉符号表和调试信息,-w用于去掉DWARF调试信息,这样能显著减小文件体积。
144
+ ```
145
+ $go build -ldflags="-s -w" -o helloworld-default-nosym main.go
146
+ ```
147
+
148
+
149
+ - 使用tinygo
150
+ [ TinyGo] ( https://github.com/tinygo-org/tinygo ) 是一个Go语言的编译器,它专为资源受限的环境而设计,例如微控制器、WebAssembly和其他嵌入式设备。TinyGo的目标是提供一个轻量级的、能在小型设备上运行的Go运行时,同时尽可能支持Go语言的特性。tinygo的一大优点就是生成的二进制文件通常比标准Go编译器生成的文件小得多:
151
+ ```
152
+ $tinygo build -o helloworld-tinygo main.go
153
+ ```
154
+
155
+ ### 依赖CGO依赖CGO
156
+ ```
157
+ go list -deps -f '{{.ImportPath}}: {{.CgoFiles}}' ./... | grep -v '\[\]'
158
+
159
+ go list -deps -f '{{.ImportPath}}: {{.CgoFiles}}' main-with-os-user.go | grep -v '\[\]'
160
+ ```
161
+
162
+
45
163
## 其它
46
164
https://go.dev/
47
165
0 commit comments