实际上是最近遇到了一个 bug,跟以前写的一篇笔记有相关,就整理一下发出来了。
编译一个golang
的项目时,提示:缺少git_index_add_from_buffer
的动态库。
# github.com/libgit2/git2go/v30
/tmp/go-build349513601/b205/_x019.o: In function `_cgo_eec00726eb8d_Cfunc_git_index_add_from_buffer':
/tmp/go-build/cgo-gcc-prolog:161: undefined reference to `git_index_add_from_buffer'
collect2: error: ld returned 1 exit status
Makefile:21: recipe for target 'binary' failed
make: *** [binary] Error 2
项目时依赖了libgit
这个库,搜索git_index_add_from_buffer
也可以确认函数是来自libgit
。
但是我之前因为版本问题,在apt install libgit
因为版本不对(最新是 0.08 )后,看到项目 Makefile 里有编译安装的方法,就跑了一下,升级到1.0.1
:
cd /tmp
rm -fr libgit2-1.0.1.tar.gz libgit2-1.0.1
curl -Lv -O https://github.com/libgit2/libgit2/releases/download/v1.0.1/libgit2-1.0.1.tar.gz
tar xvfz libgit2-1.0.1.tar.gz
mkdir -p libgit2-1.0.1/build
cd libgit2-1.0.1/build
cmake ..
cmake --build .
sudo cp libgit2.pc /usr/lib/pkgconfig/
sudo cp libgit2.so.1.0.1 /usr/lib
sudo ln -s /usr/lib/libgit2.so.1.0.1 /usr/lib/libgit2.so
sudo cp -aR ../include/* /usr/local/include/
解决了问题的了,但为何在链接时还提示缺少git_index_add_from_buffer
的引用呢。
root@localhost:/# readelf -s /usr/lib/libgit2.so.1.0 2>&1 | grep git_index_add_from_buffer
782: 000000000006d9c0 426 FUNC GLOBAL DEFAULT 12 git_index_add_from_buffer
2680: 000000000006d9c0 426 FUNC GLOBAL DEFAULT 12 git_index_add_from_buffer
可以看到,动态链接库里确实有这两个符号
root@localhost:/# cat /usr/lib/pkgconfig/libgit2.pc
prefix="/home/cloud/go_dir/src/github.com/git2go/dynamic-build/install"
libdir="/home/cloud/go_dir/src/github.com/git2go/dynamic-build/install/lib"
includedir="/home/cloud/go_dir/src/github.com/git2go/dynamic-build/install/include"
Name: libgit2
Description: The git library, take 2
Version: 1.0.0
Libs: -L${libdir} -lgit2
Libs.private: -lrt -lpthread -lssh2
Requires.private: openssl zlib
Cflags: -I${includedir}
pc 文件
就是给pkg-config
用的 meta 信息。
可以看到,libgit2.pc
文件里的 Version 确实是1.0.0
。
但是pkg-config
里记录的 version 确实0.08
root@localhost:/# pkg-config --modversion libgit2
0.08
可见,问题的根源就是这个了,在使用 libgit2 时,pkg-config
读取了 0.08 的动态链接库,结果没有git_index_add_from_buffer
。
pkg-config is a helper tool used when compiling applications and libraries.
It helps you insert the correct compiler options on the command line so an application can use
gcc -o test test.c
pkg-config --libs --cflags glib-2.0`` for instance, rather than hard-coding values on where to find glib (or other libraries). It is language-agnostic, so it can be used for defining the location of documentation tools, for instance.
pkg-config
: 是一个软件,跟make
一样都是软件。linux 在编译与链接程序时需要用到它来找到必要的动态链接库,例子:
gcc -o test test.c `pkg-config --libs --cflags glib-2.0`
pkg-config --libs --cflags glib-2.0 就是找到所有的 glib 依赖:
$ pkg-config --libs --cflags glib-2.0
-I/usr/local/Cellar/glib/2.64.3/include/glib-2.0 -I/usr/local/Cellar/glib/2.64.3/lib/glib-2.0/include -I/usr/local/opt/gettext/include -I/usr/local/Cellar/pcre/8.44/include -L/usr/local/Cellar/glib/2.64.3/lib -L/usr/local/opt/gettext/lib -lglib-2.0 -lintl
接上, 问题根源就是 golang 编译时,去找libgit2
的库时,在pkg-config
里,读的 pc 文件不是指向0.08
动态链接库的版本库。
找一下pkg-config
读 pc 文件的规则,就发现pkg-config
找 pc 文件,是根据环境变量来找的:
pkg-config --variable pc_path pkg-config
/usr/local/lib/x86_64-linux-gnu/pkgconfig:
/usr/local/lib/pkgconfig:
/usr/local/share/pkgconfig:
/usr/lib/x86_64-linux-gnu/pkgconfig:
/usr/lib/pkgconfig:/usr/share/pkgconfig
然后就是从上往下找libgit2
的 pc 文件.
而Makefile
在拷 libgit2 的配置时,拷到了sudo cp libgit2.pc /usr/lib/pkgconfig/
。
但是刚好,我之前用 apt install
装过,所以在/user/local/lib/pkgconfig
里就有了 libgit2 的配置了。。所以一直用了 28 版本的动态链接库,就没这个符号了。
/user/local/lib/pkgconfig
就会被卸载这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.