autoconf/automake:基于库存在的条件编译?

Posted

技术标签:

【中文标题】autoconf/automake:基于库存在的条件编译?【英文标题】:autoconf/automake: conditional compilation based on presence of library? 【发布时间】:2011-07-07 19:25:46 【问题描述】:

我需要根据库的存在有条件地编译一些代码。使用 autoconf/automake 似乎应该很容易,但我无法弄清楚。

例如,如果存在 PNG 库,我想包含使用它的代码。我的 configure.ac 有:

AC_CHECK_LIB([png], [png_create_write_struct_2])

我的 Makefile.am 有:

if USE_LIBPNG
libdev_la_SOURCES += png.c
endif

(将 png.c 添加到 libdev 的源列表中,以便编译)。

像 USE_LIBPNG 这样的自动生成条件需要在 configure.ac 中定义条件,所以我需要:

AM_CONDITIONAL([USE_LIBPNG], [test SOMETHINGOROTHER])

问题是,SOMETHINGOROTHER 可以测试什么? AC_CHECK_LIB 定义我可以测试什么?

AC_CHECK_LIB 的默认行为是定义一个可以在源代码中使用的符号(在 config.h 中),但这对 Makefile 没有帮助,因为 AM_CONDITIONAL 需要一个 shell 测试

我尝试像这样覆盖默认的 AC_CHECK_LIB 行为:

AC_CHECK_LIB([png], [png_create_write_struct_2], [HAS_LIBPNG=1])

之后我可以对其进行测试:

AM_CONDITIONAL([USE_LIBPNG], [test "x$HAS_LIBPNG" = "x1"])

这很难看,但适用于 Makefile...但会产生一个新问题:因为它丢弃了原始的 AC_CHECK_LIB 行为,并且我不再需要将符号添加到 config.h。

我一定遗漏了一些基本的东西,或者可能做错了。已经挖了几个小时,没有找到答案。

有人吗?

【问题讨论】:

autoconf manual gives some examples 【参考方案1】:

如果您正在检查的库提供了一个与pkg-config 一起使用的.pc 文件,那么您最好使用PKG_CHECK_MODULES 来获取正确的标志。 libpng 会:

(在configure.ac

PKG_CHECK_MODULES([libpng], [libpng12])

这使您可以访问变量$(libpng_CFLAGS)$(libpng_LIBS),您将希望将它们添加到Makefile.am(可能在AM_CFLAGS/AM_CXXFLAGSLDADD 中,或者它们的目标特定版本)。

如果找不到libpng12.pc,也会导致configure 失败并出现错误。如果您希望configure 继续,您需要向PKG_CHECK_MODULES 提供第三个和第四个参数,即ACTION-IF-FOUNDACTION-IF-NOT-FOUND

(在configure.ac

PKG_CHECK_MODULES([libpng], [libpng12], [HAVE_LIBPNG=1], [HAVE_LIBPNG=0])

现在,如果您需要 automake 条件,您可以执行以下操作:

(在configure.ac

AM_CONDITIONAL([USE_LIBPNG], [test "$HAVE_LIBPNG" -eq 1])

如果您还需要预处理器定义,您可以像这样使用AC_DEFINE

(在configure.ac

AS_IF([test "$USE_LIBPNG" -eq 1], [AC_DEFINE([USE_LIBPNG], [1], [Define if using libpng.])])

可能更好的是在Makefile.am中设置定义:

(在Makefile.am

AM_CPPFLAGS =
if USE_LIBPNG
AM_CPPFLAGS += -DUSE_LIBPNG
endif

不过,这会使您的命令行变得混乱,而如果您使用 AC_CONFIG_HEADERSAC_DEFINE 可以将定义放在标题中。我想如果你使用AM_SILENT_RULES([yes]) 或者不关心你的命令行是否整洁(老实说,automake 无论如何都会生成一些非常粗糙的命令行),这并不重要。

关于良好autoconf 风格的说明

根据检查是否成功构建可选支持被认为是糟糕的形式(有关详细信息,请参阅this gentoo doc)。下面是我如何编写对 libpng 的可选支持的代码:

(在configure.ac

# This is because the first PKG_CHECK_MODULES call is inside a conditional.
PKG_PROG_PKG_CONFIG

AC_ARG_WITH([libpng],
  [AS_HELP_STRING([--with-libpng],
    [support handling png files @<:@default=check@:>@])],
  [],
  [with_libpng=check])
AS_CASE(["$with_libpng"],
  [yes], [PKG_CHECK_MODULES([libpng], [libpng12], [HAVE_LIBPNG=1])],
  [no], [],
  [PKG_CHECK_MODULES([libpng], [libpng12], [HAVE_LIBPNG=1], [HAVE_LIBPNG=0])])
AM_CONDITIONAL([USE_LIBPNG], [test "$with_libpng" != no -a "$HAVE_LIBPNG" -eq 1])

(在Makefile.am

if USE_LIBPNG
AM_CPPFLAGS += -DUSE_LIBPNG
AM_CFLAGS += $(libpng_CFLAGS)
LDADD += $(libpng_LIBS)
libdev_la_SOURCES += png.c
endif

如果您的库没有.pc 文件

为了完整起见,下面是我检查没有.pc 文件的库的方法。我将跳过遵循良好autoconf 风格的细节。 AC_CHECK_LIB 设置了一个缓存变量,所以你可以测试它而不是替换AC_CHECK_LIBACTION-IF-FOUND

(在configure.ac

AC_CHECK_LIB([png], [png_create_write_struct_2])

# Then test:
AS_IF([test "$ac_cv_lib_png_png_create_write_struct_2" = yes], [HAVE_LIBPNG=1], [HAVE_LIBPNG=0])

# Or set conditional:
AM_CONDITIONAL([USE_LIBPNG], [test "$ac_cv_lib_png_png_create_write_struct_2" = yes])

恕我直言,只有在别无选择的情况下才应该这样做。

【讨论】:

优秀、全面的答案! @William,你要解释一下吗? @Jack 使用 PKG_CHECK_MODULES 强制用户要么在盒子上安装 pkg-config,要么手动设置 PKG_CONFIG=true 并设置 LDFLAGS 等,就像使用 AC_CHECK_LIB 而不是 PKG_CHECK_MODULES 一样。但是,由于配置依赖 PKG_CHECK_MODULES 来确定库的存在,并且用户必须覆盖 pkg-config,因此没有实际检查库是否可用。大多数主要平台都可以使用 PKG_CHECK_MODULES,但边缘情况是 autoconf 的优点……而 PKG_CHECK_MODULES 在那里不起作用……有点违背目的。 @Jack 我只建议覆盖 PKG_CONFIG 作为避免安装它的一种方式。就我个人而言,我在使用 PKG_CHECK_MODULES 时没有遇到任何问题,但我已经停止使用它,这是基于 autoconf 邮件列表中的对话,其中许多人确实报告遇到了问题。 @William:快速阅读pkg.m4,如果configure 没有找到pkg-config,这似乎并不致命,只要FOO_CFLAGSFOO_LIBS 用于每个依赖包都已在configure 命令行中设置。【参考方案2】:

感谢您的回复。

Jack:我正在努力实现最大的可移植性,所以不能假设这些库是作为包的一部分安装的(它们不在我自己的盒子上!),这意味着你建议的没有其他选项的解决方案是我已经尝试过的——手动设置一个 shell 变量——但也手动执行 AC_CHECK_LIB 已经完成的额外步骤:将库添加到 LIBS 并定义 HAVE_LIBxxx。

但有一个问题:autoheader 抱怨裸露的 AC_DEFINE:

autoheader: warning: missing template: HAVE_LIBPNG
autoheader: Use AC_DEFINE([HAVE_LIBPNG], [], [Description])

如果 autoheader 将来可以工作,我会很好,所以我不得不将 AC_DEFINE 更改为完整的 monty:

AC_CHECK_LIB([png], [png_create_write_struct_2],
    [HAS_LIBPNG=1
     LIBS="-lpng $LIBS"
     AC_DEFINE([HAVE_LIBPNG], 1, [Define to 1 if you have the `png' library (-lpng)])])

这可行,但我不太喜欢复制 AC_CHECK_LIB 的默认行为。

William:是的,我可以用 grep 查找 confdefs.h 中的符号定义,这也可以。

这两种解决方案各有利弊(什么没有?)。不知道我会走哪条路,但有选择真是太好了。

再次感谢。

【讨论】:

这感觉更像是一个评论,所以我要投票让你更接近所需的代表(离开 cmets)。 哦,还有:pkg-config 支持使用尚未安装的库,以及未安装在系统目录中的库。只需设置PKG_CONFIG_PATH 作为参考,您可以随时评论自己的帖子和自己问题的答案,即使只有 1 个代表。【参考方案3】:

对于 Jack 使用 PKG_CHECK_MODULES 的建议,我会略有不同意见。最好避免使用它。但我同意 Jack 在 AC_CHECK_LIB 的第三个参数中避​​免分配给 LIBS 的观点。如果您让 AC_CHECK_LIB 使用默认设置,生活会更轻松。

虽然 AC_CHECK_LIB 没有定义一个 shell 变量来指示是否找到了库,但是你可以在 configure.ac 中这样做:

AM_CONDITIONAL([USE_LIBPNG],[grep HAVE_LIBPNG confdefs.h > /dev/null])

可以说,这依赖于内部的 autoconf 细节,但实际上会可靠地工作。

【讨论】:

AC_CHECK_LIB 设置缓存变量,因此您可以对其进行测试:gnu.org/software/hello/manual/autoconf/Libraries.html

以上是关于autoconf/automake:基于库存在的条件编译?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 autoconf/automake 中使用协议缓冲区?

可移植地在 autoconf/automake 中包含 GLib 标头

C++学习(三五九)GNU构建系统Autotools(autoconf automake libtool autoscan autoheader aclocal automake m4)

安装 Autoconf, Automake & Libtool

autoconf,automake,libtool

使用 autoconf/automake,如何指定包含文件路径?