跳至主要內容
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?

4563博客

全新的繁體中文 WordPress 網站
  • 首頁
  • golang 编译问题让我搞懂 apt install 是怎么运行的
未分類
15 7 月 2020

golang 编译问题让我搞懂 apt install 是怎么运行的

golang 编译问题让我搞懂 apt install 是怎么运行的

資深大佬 : ChristopherWu 4

实际上是最近遇到了一个 bug,跟以前写的一篇笔记有相关,就整理一下发出来了。 golang 编译问题让我搞懂 apt install 是怎么运行的 [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的引用呢。

调查

[email protected]:/#  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 

可以看到,动态链接库里确实有这两个符号

[email protected]:/# 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

[email protected]:/# 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.cpkg-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 版本的动态链接库,就没这个符号了。

解决方法

  • 卸载 apt install 的 libgit2,这样子/user/local/lib/pkgconfig就会被卸载
  • 将“sudo cp libgit2.pc /usr/lib/pkgconfig/` 改成拷到优先读目录(不推荐,复写了 apt 安装的版本)

golang 编译问题让我搞懂 apt install 是怎么运行的

大佬有話說 (6)

  • 資深大佬 : msg7086

    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 本来就在软件源里。

  • 主 資深大佬 : ChristopherWu

    @msg7086 学习了。

    > 里面会有 pc 文件是因为编译安装时生成了 pc 文件而已。

    这个不知道诶,所以所有的包(链接库)都是默认放系统指定目录的?

    > 你没有把软件编译成 deb 包,所以万事都要手动管理,包括卸载软件包,手动复制所有的文件,处理 pc 文件等等

    太高端了,手动管理不是比较麻烦?

    > 根本问题是你 git2go 用了最新版吧
    是的,项目里用了最新版。

  • 資深大佬 : msg7086

    Debian 打包有自己的规范,官方打包是会放在指定目录的。
    https://packages.debian.org/buster-backports/amd64/libgit2-dev/filelist
    可以看到默认安装在 /usr/lib/x86_64-linux-gnu/libgit2.so 这个位置。

    用发行版最好所有系统软件都用 deb 包,不要手动编译安装。
    只有那种无所谓有无的小程序,编译安装也无伤大雅。

  • 資深大佬 : nightwitch

    良好的习惯是 手动编译安装软件,prefix 指定到自己的家目录,并且不要添加到环境变量,链接的时候手动指定目录或者临时 export 环境变量,不要 install 到 /usr/之类的目录去,不然和系统的起冲突是迟早的事。

  • 資深大佬 : chengxiao

    既然知道是环境变量的问题…..那么解决办法不应该是
    export PKG_CONFIG_PATH=/xxx/xxx (.pc 文件目录)么?

  • 主 資深大佬 : ChristopherWu

    @chengxiao 不行的,你再看看文章里的那块?除非你显示的修改这个环境变量

文章導覽

上一篇文章
下一篇文章

AD

其他操作

  • 登入
  • 訂閱網站內容的資訊提供
  • 訂閱留言的資訊提供
  • WordPress.org 台灣繁體中文

51la

4563博客

全新的繁體中文 WordPress 網站
返回頂端
本站採用 WordPress 建置 | 佈景主題採用 GretaThemes 所設計的 Memory
4563博客
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?
在這裡新增小工具