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_CXXFLAGS
和LDADD
中,或者它们的目标特定版本)。
如果找不到libpng12.pc
,也会导致configure
失败并出现错误。如果您希望configure
继续,您需要向PKG_CHECK_MODULES
提供第三个和第四个参数,即ACTION-IF-FOUND
和ACTION-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_HEADERS
,AC_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_LIB
的ACTION-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_CFLAGS
和FOO_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)