【问题标题】:How to test a C++ library usability in configure.in?如何在 configure.in 中测试 C++ 库的可用性?
【发布时间】:2010-11-04 13:13:34
【问题描述】:

我正在 GNU/Linux 上开发一个 C++ 项目,我正在寻找一种方法来测试 IBM Informix 库的存在性和可用性与 Autotools - 即编辑 configure.in。我没有使用 Autotools 的经验,所以基本上我是从项目的 configure.inet al. 脚本中学习并复制和更改我认为需要更改的地方。 IOW,我一直在改编configure.in 中的现有文本。

到目前为止,我已经成功地使用了configure.in 中的AC_CHECK_LIB 来测试某个库是否既存在又可用。但这似乎只适用于具有 functions 的库,而不是例如类。即,在测试 Informix 的 libifc++.so 库时失败:

AC_CHECK_LIB(ifc++, ITString, 
        INFORMIX_LIB="-L$INFORMIX_LIB_LOCATION/c++ -lifc++ -L$INFORMIX_LIB_LOCATION -L$INFORMIX_LIB_LOCATION/dmi -L$INFORMIX_LIB_LOCATION/esql -lifdmi -lifsql -lifasf -lifgen -lifos -lifgls -lifglx $INFORMIX_LIB_LOCATION/esql/checkapi.o -lm -ldl -lcrypt -lnsl",
        echo "* WARNING: libifc++.so not found!"
        INFORMIX_INC=""
        INFORMIX_LIB=""
)

我也尝试过使用其他组合,例如ITString::ITString 等。

我在 Informix 的 API 中没有找到“纯”函数(即,在 C++ 类中没有上下文的函数)。所以我希望有一种方法可以在这种情况下使用AC_CHECK_LIB,或者有另一个autoconf/configure.in“命令”用于这种特定用途。

提前感谢您的反馈。

【问题讨论】:

    标签: c++ autotools configure usability autoconf


    【解决方案1】:

    您发现了 autotools 的一个缺点,但实际上是无能为力的。 Autotools 检查库二进制文件中的符号名称,与 C 中函数的符号名称与函数名称相同的 C 不同,C++ “修改”函数的符号名称以完成诸如函数重载之类的事情。更糟糕的是,C++ 甚至没有真正的“标准”修改约定,因此不同的 C++ 编译器可能会为同一个函数生成不同的符号名称。因此,自动工具无法以可靠的方式检查 C++ 符号名称。

    您尝试使用的库是否有任何用extern "C" 声明的函数?这会导致 C++ 编译器生成标准化的 C 样式符号名称,并且 autotools 将能够找到它们。

    我在尝试使用 Autotools 检测 gtestgmock(Google 单元测试和对象模拟框架)时遇到了这个问题,这就是我想出的:

    # gtest has a main function in the gtest_main library with C linkage, we can test for that.
    AC_CHECK_LIB([gtest_main], [main], [HAVE_GTEST=1] [TEST_LIBS="$TEST_LIBS -lgtest_main"], 
          AC_MSG_WARN([libgtest (Google C++ Unit Testing Framework) is not installed. Will not be able to make check.])) 
    
    # gmock has no functions with C linkage, so this is a roundabout way of testing for it. We create a small test
    # program that tries to instantiate one of gmock's objects, and try to link it with -lgmock and see if it works.
    if test "$HAVE_GTEST"                                                                 
    then                                                                                  
      saved_ldflags="${LDFLAGS}"                                                          
      LDFLAGS="${LDFLAGS} -lgtest -lgmock"                                                
      AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <gmock/gmock.h>], [testing::Cardinality dummy])],
        [TEST_LIBS="$TEST_LIBS -lgmock"] [HAVE_GMOCK=1],                                           
        [AC_MSG_WARN([libgmock (Google C++ Object Mocking Framework) is not installed. Will not be able to make check.])])
      LDFLAGS="${saved_ldflags}"                                                                                          
    fi          
    

    【讨论】:

      【解决方案2】:

      可能有一种更简洁的方法来实现这一点,但我认为您的问题是 C++ 方法被“破坏”以允许对有关方法(参数和返回类型等)的附加信息进行编码。例如; int A::foo(void) 方法将被修改为 __ZN1A3fooEv 之类的东西。

      因此,您需要在库中找到方法的错位名称。您可以通过在类 Unix 操作系统上使用 nm command 来做到这一点:

      $ nm libifc++.so | grep ITString
      

      值得一提的是,不同的编译器的准确修饰格式会有所不同;因此,通过在您的 configure.in 中嵌入某个编译器的损坏符号,它可能无法在其他平台上运行 - YMMV。

      注意:您可以使用c++filt 实用程序将名称重新组合成人类可读的形式;所以对于我之前给出的例子:

      $ c++filt __ZN1A3fooEv
      A::foo()
      

      有关更多信息,请参阅维基百科上的 Name Mangling in C++

      【讨论】:

      • 为我工作。我曾想过做这样的事情,但它似乎是一个 hack。例如,我不确定如果使用不同的 Informix 库版本重新编译代码会发生什么(我希望损坏的名称会改变)。但是,嘿,它有效! :-)
      • 这应该可以继续使用新的库版本(假设类和方法名称没有改变),但如果你的编译器版本改变可能会中断,如果其他人尝试编译几乎肯定会中断您的代码在另一个编译器或编译器版本上。
      • 太啰嗦了,认真的,在底部看我的答案。
      【解决方案3】:

      如果您正在检查的库支持pkg-config,这将变得非常容易。这是我添加到configure.in 以检查和启用gtestgmock 的所有内容:

      dnl ************************************
      dnl Check for googletest and googlemock
      dnl ************************************
      
      PKG_CHECK_MODULES(gtestmock, libgtest >= 0.4.0, libgmock >= 0.4.0)
      AC_SUBST(gtestmock_LIBS)
      AC_SUBST(gtestmock_CFLAGS)
      

      然后在我的Makefile.am 某处:

      sometarget_CXXFLAGS = $(gtestmock_CFLAGS) $(AM_CXXFLAGS)
      sometarget_LDADD    = $(gtestmock_LIBS)
      

      很简单,嗯?

      【讨论】:

      • There are problems 使用 pkg-config,不过。而且,更根本的是,pkg-config 和 autotools 以不同的方式工作。 Autoconf 检查功能,而 pkg-config 测试软件包版本。如果您尝试以 autotools 的方式做事,这应该可以为您提供最大的跨系统兼容性,我根本不建议使用 pkg-config。
      【解决方案4】:
      AC_LANG_CPLUSPLUS
      AC_CHECK_LIB(Sockets, main)
      

      警告:http://lists.gnu.org/archive/html/autoconf/2006-09/msg00019.html

      【讨论】:

      • 多一点解释会有所帮助。您的示例要求准确指定 main,并且仅检查库是否存在。但是生成的程序有UB,因为在C++中main不允许调用main。您提供的链接中提到了哪个 BTW。
      • 也许是因为链接是作为警告提供的?嗯?
      • 那么为什么不改成AC_LANG_C 允许main 调用main 呢?正如已经说过的:您只是给出了一些代码而没有任何解释,但解释确实会有所帮助。
      • 那么为什么不编辑我的答案以使其更具信息性而不是争吵呢?再见。
      猜你喜欢
      • 1970-01-01
      • 2012-03-29
      • 2012-10-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多