实际上是最近遇到了一个 bug,跟以前写的一篇笔记有相关,就整理一下发出来了。 [toc]
编译一个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
就会被卸载 1
msg7086 2020-07-19 13:13:10 +08:00 2
pc 和 apt 没有关系。
apt 的包也是编译并安装,只不过是安装到临时目录中,然后把整个目录打包。 里面会有 pc 文件是因为编译安装时生成了 pc 文件而已。 这里的问题是你没有把软件编译成 deb 包,所以万事都要手动管理,包括卸载软件包,手动复制所有的文件,处理 pc 文件等等。不如修改一下打包脚本,直接打包成 deb 。 https://salsa.debian.org/debian/libgit2 不过说实话,根本问题是你 git2go 用了最新版吧。 https://packages.debian.org/buster-backports/golang-gopkg-libgit2-git2go.v28-dev git2go v28 本来就在软件源里。 |
2
ChristopherWu OP @msg7086 学习了。
> 里面会有 pc 文件是因为编译安装时生成了 pc 文件而已。 这个不知道诶,所以所有的包(链接库)都是默认放系统指定目录的? > 你没有把软件编译成 deb 包,所以万事都要手动管理,包括卸载软件包,手动复制所有的文件,处理 pc 文件等等 太高端了,手动管理不是比较麻烦? > 根本问题是你 git2go 用了最新版吧 是的,项目里用了最新版。 |
3
msg7086 2020-07-19 14:24:09 +08:00 1
Debian 打包有自己的规范,官方打包是会放在指定目录的。
https://packages.debian.org/buster-backports/amd64/libgit2-dev/filelist 可以看到默认安装在 /usr/lib/x86_64-linux-gnu/libgit2.so 这个位置。 用发行版最好所有系统软件都用 deb 包,不要手动编译安装。 只有那种无所谓有无的小程序,编译安装也无伤大雅。 |
4
nightwitch 2020-07-19 14:36:04 +08:00 1
良好的习惯是 手动编译安装软件,prefix 指定到自己的家目录,并且不要添加到环境变量,链接的时候手动指定目录或者临时 export 环境变量,不要 install 到 /usr/之类的目录去,不然和系统的起冲突是迟早的事。
|
5
chengxiao 2020-07-20 10:14:05 +08:00
既然知道是环境变量的问题.....那么解决办法不应该是
export PKG_CONFIG_PATH=/xxx/xxx (.pc 文件目录)么? |
6
ChristopherWu OP @chengxiao 不行的,你再看看文章里的那块?除非你显示的修改这个环境变量
|