Article directory
-
- 1. Background
- 2. Overview of static compilation
- 3. Detailed investigation process
-
- 1. Download the bpf troubleshooting tools bcc, bcc-tools, python-bcc
- 2. Use opensnoop to troubleshoot the compilation process and find the paths for shared libraries.
- 3. Download the opus package from pacman
- 4. Check the current version of libopus.so file
- 5. Download libopus.a
- 6. Decompress the .deb file
- 7. Add LD_LIBRARY_PATH
- 8. Add LIBRARY_PATH as the current directory
- 9. The difference between LD_LIBRARY_PATH and LIBRARY_PATH
1. Background
A simple audio and video parsing go
program needs to be run on a go
machine without an environment. It is all linux
an environment, and I thought it could be migrated seamlessly. But in fact, I found that the running error was reported and glibc
the version was inconsistent. . .
Therefore, I plan to directly compile a purely static executable program, and compile all dependent libraries directly into it, so that I can truly ignore platform restrictions. Who knew that static compilation directly reports errors? Well, let’s summarize the relevant knowledge points of static compilation and record the troubleshooting process.
premise
The blogger is using manjaro
version linux
, the target server is ubuntu
version and the version is older.
2. Overview of static compilation
go
The default is to use static compilation if go
the library used in the code does not depend on C
the library. However, the packages used by more complex go
programs are likely to rely on system C
libraries, so the compiled files are dynamic. For example, you can ldd
view the files from the executable program through commands .so
.
ldd 可执行程序
linux-vdso.so.1 (0x00007ffeeaee7000)
libresolv.so.2 => /usr/lib/libresolv.so.2 (0x00007ff3838a6000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007ff3836bf000)
/lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007ff3838d3000)
Specifically why dynamic compilation occurs, please refer to the principle:
[External dependencies of go executable files]
1. Perform static compilation
There are two ways to statically compile
Set CGO_ENABLED mode
By default, go
the runtime
environment variable CGO_ENABLED=1
, that is, the default start cgo
, allows you go
to call C
the code in the code, and the files go
of pre-compiled
the standard library .a
are also compiled in this case.
We can CGO_ENABLED=0
statically compile by specifying it on the command line
CGO_ENABLED=0 go build .
Specify link method
go
The default is to use it internal linking
without starting externally external linker(如:gcc、clang等)
. The external linking
mechanism cmd/link
is to type all the generated .o
files into a .o
file, and then hand it over to an external linker, such as gcc
or clang
for final link processing.
If we want to compile statically, we need to -ldflags
specify linkmode
the parameters in external
and specify static linking.
-ldflags '-linkmode "external" -extldflags "-static"'
忽略'-linkmode "external" ,只设置-extldflags 也是ok的
To statically compile a project, compile the command:
go build -o myapp -ldflags '-w -s -extldflags "-static"'
Compilation error
/usr/lib/go/pkg/tool/linux_amd64/link: running gcc failed: exit status 1
/usr/bin/ld: cannot find -lopus: No such file or directory
collect2: error: ld returned 1 exit status
2. Compilation error analysis
/usr/bin/ld 是 Linux 系统中的链接器(linker),用于将目标文件和库文件等链接起
来,生成最终的可执行文件或共享库。在大多数情况下,这个链接器已经默认设置
好,并且可以自动被编译器调用。
而对于 Go 语言的静态编译过程,我们需要在编译命令中加入相应的选项,指定使用
外部链接模式和静态链接方式,并将必要的库文件链接到生成的二进制文件中。具体
来说,可以使用 -ldflags 选项传递参数给链接器,包括 -linkmode external 表示启用
外部链接模式、-extldflags "-static" 表示启用静态链接方式等。
It seems that it is not found libopus
. Let’s first confirm whether it is installed on this machine.libopus
(1) Confirm whether libopus is installed on the system
ldconfig -p | grep libopus
Query via package managerlibopus
pacman -Ql opus | grep libopus
opus /usr/lib/libopus.so
opus /usr/lib/libopus.so.0
opus /usr/lib/libopus.so.0.8.0
(2) Set LD_LIBRARY_PATH
This environment variable is used to specify the path that the program searches when dynamically loading shared libraries (also called dynamic link libraries) at runtime. When a program needs to load a shared library, it searches the path in the following order:
程序中已经指定的库路径(如使用 -L 参数指定的路径)
LD_LIBRARY_PATH 中指定的路径
export LD_LIBRARY_PATH=/usr/lib:$LD_LIBRARY_PATH
Continue static compilation, but the search still libopus
fails. Ok, it’s starting to look interesting. Let’s check it out in detail below.
3. Detailed investigation process
1. Download the bpf troubleshooting tools bcc, bcc-tools, python-bcc
If you need to specify the version, use this command:
sudo /usr/bin/pip install -i https://pypi.org/simple bcc==0.27.0
bcc
is a cross-platform toolset for Linux
dynamic tracing and probing on systems. Tools opensnoop
can be used to monitor the system calls an application makes to open, read, or write files to understand which files in the system are accessed and how they are accessed. Mainly monitors open()、read()、write()
system calls related to file operations.
strace
You can also view the system call function, which is used here opensnoop
for troubleshooting.
2. Use opensnoop to troubleshoot the compilation process and find the paths for shared libraries.
# 开启一个窗口,输入这个命令
sudo opensnoop
# 开启另一个窗口,进行编译
go build -o myapp -ldflags '-w -s -extldflags "-static -lm"'
# 查看opensnoop的输出
结果发现编译过程中查找的是libopus.a文件,我们只有libopus.so文件
3. Download the opus package from pacman
# 查看安装opus都会安装什么东西
sudo pacman -Ql opus
# 结果是没有.a文件
It seems that you can only compile .a
the file yourself or download it from other package management platforms. . .
4. Check the current version of libopus.so file
# 查看.so的版本
sudo pacman -Qo /usr/lib/libopus.so
/usr/lib/libopus.so is owned by opus 1.3.1-3
5. Download libopus.a
https://ubuntu.pkgs.org/20.04/ubuntu-main-amd64/libopus-dev_1.3.1-0ubuntu1_amd64.deb.html
ubuntu
The package found in the query libopus
contains libopus.a
files. The version is also compatible, just download it.
6. Decompress the .deb file
# 下载地址
https://www.cyberciti.biz/faq/how-to-extract-a-deb-file-without-opening-it-on-debian-or-ubuntu-linux/
# 查看下载的.deb包
file libopus-dev_1.3.1-0ubuntu1_amd64.deb
libopus-dev_1.3.1-0ubuntu1_amd64.deb: Debian binary package (format 2.0), with control.tar.xz, data compression xz
# 解压缩deb包
ar x libopus-dev_1.3.1-0ubuntu1_amd64.deb
# 解压完毕后会出现几个文件,主要用到data.tar.gz包,这个是存放二进制文件的压缩包
# 解压缩tar
tar -xvf data.tar.xz
# 可以发现libopus.a文件
./usr/lib/x86_64-linux-gnu/libopus.a
7. Add LD_LIBRARY_PATH
Directly put libopus.a
the file into the current directory and set the search shared library path.
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
Executing compilation still reports an error, and it seems that it does not take effect.
8. Add LIBRARY_PATH as the current directory
# 执行静态编译成功
# 查看静态编译文件
file myapp
myapp: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, BuildID[sha1]=8afbe7cba97e5f860ac49cfb6692e5eb5ec18cd5, for GNU/Linux 4.4.0, stripped
9. The difference between LD_LIBRARY_PATH and LIBRARY_PATH
LD_LIBRARY_PATH
and LIBRARY_PATH
are both environment variables used to specify shared library search paths, but there are some subtle differences.
LD_LIBRARY_PATH
It is mainly used to control the path for loading shared libraries when the program is running,
while LIBRARY_PATH
it is mainly used to control the path for the compiler to find shared libraries during compilation.
Static compilation needs to link .a
files, LD_LIBRARY_PATH
mainly to set .so
the search path of files, so it will not take effect.
end