Autoconf/automake: условная компиляция на основе наличия библиотеки?

Мне нужно условно скомпилировать код, основанный на наличии библиотеки. Похоже, это должно быть легко с autoconf/automake, но я не могу понять это.

Например, если есть библиотека PNG, я хочу включить код для ее использования. У моей конфигурации .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 требует проверку оболочки

Я попытался переопределить поведение 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, который мне нужен.

Я должен упустить что-то основное или возможно Неправильное. Много лет копались и не нашли ответа.

Кто-нибудь?

Ответы

Ответ 1

Если библиотека, которую вы проверяете, предоставляет файл .pc для использования с pkg-config, вам гораздо лучше использовать PKG_CHECK_MODULES для получения правильных флагов. libpng делает:

(in configure.ac)

PKG_CHECK_MODULES([libpng], [libpng12])

Это дает вам доступ к переменным $(libpng_CFLAGS) и $(libpng_LIBS), которые вы хотите добавить к Makefile.am (возможно, в AM_CFLAGS/AM_CXXFLAGS и LDADD или к конкретным версиям).

Он также приведет к ошибке configure с ошибкой, если libpng12.pc не найден. Если вы хотите, чтобы configure продолжался, вам нужно указать третий и четвертый аргументы PKG_CHECK_MODULES, которые ACTION-IF-FOUND и ACTION-IF-NOT-FOUND:

(in configure.ac)

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

Теперь, если вам нужен условный automake, вы можете сделать что-то вроде:

(in configure.ac)

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

Если вам также требуется определение препроцессора, вы можете использовать AC_DEFINE следующим образом:

(in configure.ac)

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

Возможно, лучше установить определение в Makefile.am:

(in Makefile.am)

AM_CPPFLAGS =
if USE_LIBPNG
AM_CPPFLAGS += -DUSE_LIBPNG
endif

Это будет загромождать вашу командную строку, хотя AC_DEFINE может поместить определение в заголовок, если вы используете AC_CONFIG_HEADERS. Думаю, это не имеет значения, если вы используете AM_SILENT_RULES([yes]) или не заботитесь о том, чтобы ваша командная строка была аккуратной (и пусть честно говоря, automake в любом случае генерирует некоторые довольно gnarly командные строки).

Заметка о стиле autoconf

Считается, что плохая форма для создания дополнительной поддержки основана на том, удалось ли проверить (см. этот документ gentoo). Вот как я бы закодировал дополнительную поддержку libpng:

(in 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 @<:@[email protected]:>@])],
  [],
  [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])

(in 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 задает переменную кеша, поэтому вы можете проверить, что вместо замены ACTION-IF-FOUND AC_CHECK_LIB:

(in 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])

IMHO, вы должны сделать это только в том случае, если у вас нет другого варианта.

Ответ 2

Я не соглашусь с Джеком по его рекомендации использовать PKG_CHECK_MODULES. Вероятно, лучше не использовать это. Но я соглашусь с Джеком избегать присвоения LIBS в третьем аргументе AC_CHECK_LIB. Жизнь проще, если вы позволите AC_CHECK_LIB использовать настройки по умолчанию.

Хотя AC_CHECK_LIB не определяет переменную оболочки, указывающую, была ли найдена библиотека, вы можете сделать это в файле configure.ac:

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

Возможно, это зависит от внутренних данных autoconf, но на практике они будут надежно работать.

Ответ 3

Спасибо за ответы.

Джек: Я пытаюсь обеспечить максимальную переносимость, поэтому не могу предположить, что библиотеки были установлены как часть пакета (они не на моем собственном ящике!), что означает предлагаемое вами решение для других вариантов это то, что я уже пробовал - установка переменной оболочки вручную, но также вручную выполняет дополнительные шаги, которые были бы сделаны 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 по умолчанию.

Уильям: Да, я мог бы grep для определения символа в confdefs.h, который также работает.

Оба решения имеют свои плюсы и минусы (что нет?). Не уверен, в какую сторону я пойду, но приятно иметь варианты.

Еще раз спасибо.