Autoconf:链接器错误链接到自定义库

Posted

技术标签:

【中文标题】Autoconf:链接器错误链接到自定义库【英文标题】:Autoconf: linker error linking against custom library 【发布时间】:2012-02-24 16:37:49 【问题描述】:

1) 我有一个项目包含一个链接到一些外部库(即gcryptgpg-errorzssh2)的共享库。让我们称之为“mylib”。 这个库构建完美,我可以看到libtool 正确链接了依赖项。

libtool: link: ppc-linux-gcc -shared  -fPIC -DPIC  .libs/mylib1.o .libs/mylib2.o .libs/mylib3.o
     -Wl,-rpath -Wl,/opt/ELDK/ppc_8xx/lib -Wl,-rpath \
     -Wl,/opt/ELDK/ppc_8xx/lib /opt/ELDK/ppc_8xx/lib/libssh2.so \
     -L/opt/ELDK/ppc_8xx/lib -lz /opt/ELDK/ppc_8xx/lib/libgcrypt.so \
     /opt/ELDK/ppc_8xx/lib/libgpg-error.so -lpthread  -O2 \
     -Wl,-soname -Wl,mylib.so.0 -o .libs/mylib.so.0.0.0

2) 同一个项目有几个链接到“mylib”的程序。 但是,当我尝试链接它们时,我收到了关于相同先前库的链接器错误:

/opt/ELDK-3.1/usr/bin/../lib/gcc-lib/ppc-linux/3.3.3/../../../../ppc-linux/bin/ld: \
     warning: libssh2.so.1, needed by ./../myLib/.libs/mylib.so, not found (try using -rpath or -rpath-link)
/opt/ELDK-3.1/usr/bin/../lib/gcc-lib/ppc-linux/3.3.3/../../../../ppc-linux/bin/ld: \
     warning: libz.so.1, needed by ./../myLib/.libs/mylib.so, not found (try using -rpath or -rpath-link)
/opt/ELDK-3.1/usr/bin/../lib/gcc-lib/ppc-linux/3.3.3/../../../../ppc-linux/bin/ld: \
     warning: libgcrypt.so.11, needed by ./../myLib/.libs/mylib.so, not found (try using -rpath or -rpath-link)
/opt/ELDK-3.1/usr/bin/../lib/gcc-lib/ppc-linux/3.3.3/../../../../ppc-linux/bin/ld: \
     warning: libgpg-error.so.0, needed by ./../myLib/.libs/mylib.so, not found (try using -rpath or -rpath-link)
./../myLib/.libs/mylib.so: undefined reference to `libssh2_channel_process_startup'
./../myLib/.libs/mylib.so: undefined reference to `libssh2_scp_send_ex'

在“mylib”configure.ac 我明确搜索库:

AC_SEARCH_LIBS(gpg_err_set_errno,[gpg-error])
AC_SEARCH_LIBS(gcry_check_version,[gcrypt])
AC_SEARCH_LIBS(deflate,[z])
AC_SEARCH_LIBS(libssh2_init,[ssh2])

我还必须使用“mylib”在每个项目中明确包含所有这些库吗? 当我第一次在“mylib”中链接它们时,它不应该已经解决了吗?

有没有更好的方法来做到这一点?

谢谢。

P.S.:我在autoconf这件事上不是很聪明,对不起。

注意:我正在使用(还很旧的)ELDK 3.1 为 PowerPC 进行交叉编译。

【问题讨论】:

您是否覆盖了 Makefile.am 中程序的任何指令? 我有类似program1_CPPFLAGS = -I$(top_srcdir) $(MYLIB_CFLAGS) 的东西,其中MYLIB_CFLAGSMYLIB_LIBS 在“program1”的configure.ac 中定义为AC_ARG_WITH,以允许我链接到本地​​“mylib”而不是一个系统安装了一个(请告诉我这是否是一种更好的方法)。 CPPFLAGS 应该不相关,但是如何在 Makefile.am 中使用 MYLIB_LIBS?在您的最终 Makefile 中,应该有一个包含 $(LINK) 命令的 program1$(EXEEXT) 的目标,并且该命令应该有 $(LIBS),如果 AC_SEARCH_LIBS 成功找到给定的库,则它应该包含库。 在 mylib.so 上运行 ldd 的输出会很有用,尽管我不确定在交叉编译时这样做有多容易。同样有趣的是检查 readelf -a 以确保 RPATH 确实按照您的要求添加。 【参考方案1】:

注意:由于我在 2 年后收到了答复,但这并没有解决我的问题,我认为最好与大家分享我所做的事情。


回答:

我发现在基于autoconf 的项目中自动包含链接器依赖项的更好方法是将pkg-config 信息添加到我的库中。

更改为configure.ac

export PKG_CONFIG_PATH=../MyLibPath:$PKG_CONFIG_PATH
PKG_CHECK_MODULES([DEPS], [libssh2 >= 1.3.0])

# Output configuration files.
AC_CONFIG_FILES([Makefile libMyLib-1.0.pc libMyLib-1.0-uninstalled.pc])

第二个输出文件libMyLib-1.0-uninstalled.pc 是为了让我可以继续使用卸载版本的 MyLib 开发我的项目。

更改为Makefile.am

libMyLib_la_CPPFLAGS  = $(DEPS_CPPFLAGS)
libMyLib_la_CFLAGS    = $(DEPS_CFLAGS)
libMyLib_la_CXXFLAGS  = $(DEPS_CXXFLAGS)
libMyLib_la_LIBADD    = $(DEPS_LIBS)

pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libMyLib-1.0.pc

添加到项目libMyLib-1.0.pc:

prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@

Name: MyLib
Description: My library.
Requires: libssh2
Requires.private:
Version: @PACKAGE_VERSION@
Libs: -L$libdir -lMyLib -lstdc++ -lm -lslog -lpthread
Libs.private:
Cflags: -I$includedir/libMyLib-1.0

libMyLib-1.0-uninstalled.pc

prefix=@abs_builddir@
exec_prefix=@exec_prefix@
libdir=$prefix/.libs
includedir=$prefix

Name: MyLib
Description: My library.
Requires: libssh2
Requires.private:
Version: @PACKAGE_VERSION@
Libs: -Wl,-rpath-link,$libdir -L$libdir -lMyLib -lstdc++ -lm -lslog -lpthread
Libs.private:
Cflags: -I$includedir/

在每个依赖项目中:

configure.ac:

export PKG_CONFIG_PATH=../MyLibPath:$PKG_CONFIG_PATH
PKG_CHECK_MODULES([MYLIB], [libMyLib-1.0 >= 1.0.0])

Makefile.am:

dependent_CPPFLAGS  = $(MYLIB_CPPFLAGS)
dependent_CFLAGS    = $(MYLIB_CFLAGS)
dependent_CXXFLAGS  = $(MYLIB_CXXFLAGS)
dependent_LIBADD    = $(MYLIB_LIBS)

【讨论】:

除非libslog 或标准库也位于不同的路径中,否则您不需要在 Libs 条目中使用 -rpath-link 是的,它位于 uninstalled 配置文件中的不同路径中。谢谢!【参考方案2】:

如果不知道 Makefile.amconfigure.ac 中的内容,就很难准确判断您在做什么,但由于我看到您使用的是 -Wl,-rpath,因此我假设您将其传递为 LDFLAGS当您拨打 ./configure 时,从外部。

发生的情况是libtool 通常不会存储-rpath 值,但它会存储-L;所以我通常的建议是同时传递-L-rpath,这样.la 文件将包含找到要链接到它的库的路径。

虽然您不必在每个二进制文件上都传递它,但 libtool 会,然后让链接编辑器正确解析它。

【讨论】:

非常感谢您回答 Diego。最后我把pkgconfig 玩了,它解决了我的问题。现在我不必为每个依赖项重复链接库。不过,令人失望的是,autoconf 无法自动“级联”这种依赖关系...... 您只能级联共享对象依赖项,但不能级联静态存档,但在这种情况下,在我看来,您似乎有一些额外的依赖项完全位于不同的路径中,这更棘手,因为它的搜索路径改变。 恼人的想法是我不得不在共享项目中不断重复依赖(共享)库。尽管MyLib 已经动态链接,但如果我省略(已在 MyLib 中链接)依赖项,最终程序/库会给出链接器错误。 这些是系统库的一部分还是在单独的路径中?链接编辑器似乎不知道在哪里寻找它们。

以上是关于Autoconf:链接器错误链接到自定义库的主要内容,如果未能解决你的问题,请参考以下文章

静态和共享库链接器错误

链接器错误:“ff_log2_tab”的多个定义

使用 C++ 的 SOIL 库链接器错误问题

为啥链接器链接了错误的函数?

链接器忽略库链接

静态库的c ++链接器错误