Как настроить autotools для создания дополнительных компонентов только при наличии зависимостей? - PullRequest
1 голос
/ 04 апреля 2020

У меня есть проект C ++, использующий autotools в качестве системы сборки.

Моя программа использует абстрактный интерфейс, в котором есть несколько реализаций, каждая из которых находится в отдельном исходном файле. Эти реализации зависят от библиотек, которые могут или не могут быть установлены, в зависимости от предпочтений пользователя и платформы.

Я хотел бы настроить автоинструменты, чтобы пропустить создание реализаций, в которых отсутствуют базовые зависимости. Я хотел бы сделать это так, как того ожидают пользователи и сопровождающие.

В качестве примера, скажем, моя программа выводит звук, и это можно сделать с помощью OSS, ALSA или JACK . Они реализованы в oss_output.cc, alsa_output.cc и jack_output.cc, соответственно.

В настоящее время мой Makefile.am содержит (среди прочего):

myprog_SOURCES = \
    src/oss_output.cc \
    src/alsa_output.cc \
    src/jack_output.cc

myprog_LDFLAGS = [...some other stuff...] -ljack

К сожалению, попытка построить эту программу в системе без установленного JACK не удается, потому что компоновщик не может найти libjack и / или не удается выполнить компилятор из-за отсутствия заголовочных файлов JACK. В случае, если JACK не установлен, я бы вместо этого хотел удалить src/jack_output.cc из myprog_SOURCES и удалить -ljack из myprog_LDFLAGS. И аналогично, для ALSA и OSS.

Из этих зависимостей (OSS, ALSA и JACK) некоторые из этих библиотек используют pkg-config. Некоторые этого не делают, но я все еще могу обнаружить их присутствие по наличию заголовочного файла и библиотеки.

Как это достигается с помощью автоинструментов, при этом соблюдая передовые методы и соглашения?

Ответы [ 2 ]

3 голосов
/ 05 апреля 2020

Как это достигается с помощью автоинструментов, следуя рекомендациям и соглашениям?

Есть две части:

  1. Определение требуемых подсистем / поддерживается и
  2. Ограничение сборки только выбранными подсистемами.

Идентификация подсистем для поддержки

Первая часть - это хлеб и масло Autoconf. Как правило, проверяет наличие библиотеки каждого подсистемы (-ies) через AC_CHECK_LIB() или AC_SEARCH_LIBS(), чтобы определить, доступна ли она, а также проверяет основной заголовочный файл (ы). ) через AC_CHECK_HEADER() или AC_CHECK_HEADERS().

Было бы удобно также настроить механизм отказа от поддержки здания для некоторых доступных подсистем. Это могло бы принять форму установки --without или --disable аргументов (какой из них выбрать часто неоднозначен). Это не обязательно, но я бы посчитал это хорошим тоном. Тем не менее, обратите внимание, что это требует некоторого внимания и осторожности, чтобы не включать в ссылку все найденные библиотеки.

Версия Cadilla c, кроме того, предоставит поддержку пользователю, указывающему, где найти нужные библиотеки и заголовки. в случае, если они не находятся в пути поиска по умолчанию. Я часто вижу подобные вещи в хорошо поддерживаемых проектах, но это поднимает сложность на уровень, и я не считаю это никоим образом обязательным.

Детали реализации могут варьироваться довольно широко, но обычно конечный результат для каждой подсистемы будет

  • переменной оболочки, указывающей, включать ли подсистему в сборку (например, build_oss) и
  • ( (необязательно) выходные переменные (созданные с помощью AC_SUBST()), передающие флаги препроцессора / компилятора / и / или компоновщика, которые будут использоваться для построения в соответствии с соответствующей внутренней библиотекой. Например, некоторые или все из OSS_CPPFLAGS, OSS_CXXFLAGS, OSS_LIBS для части OSS.

Ограничение сборки выбранными подсистемами

Automake и Autoconf работают вместе на это. Ключевым инструментом является условное Automake . Automake предоставляет макрос Autoconf, AM_CONDITIONAL, для их определения и назначения их значений, и поддерживает конструкцию if / then / else в Makefile.am файлах на их основе. (Обратите внимание, что они полностью отделены от условных выражений GNU make, хотя и имеют сходный синтаксис.)

Раздел руководства Automake, который я связал, относится к нескольким другим, в которых обсуждается, как следует использовать условные выражения в различных Scenar ios, и не совсем понятно, какие из них относятся к вам. Однако я думаю, что все, что вам действительно нужно, это условные источники , поэтому я сосредоточусь на этом.

Часть Autoconf будет следовать из битов, которые я уже обсуждал. Это может быть так просто, как

AM_CONDITIONAL([oss], [test "$build_oss" = "1"])
AM_CONDITIONAL([alsa], [test "$build_alsa" = "1"])
AM_CONDITIONAL([jack], [test "$build_jack" = "1"])

В руководстве Automake приведены другие примеры.

На стороне Makefile.am это может совпадать с чем-то вроде этого:

myprog_SOURCES = \
  src/main.cc \
  src/another.cc \
  ...

if oss
  myprog_SOURCES += src/oss_output.cc
endif
if alsa
  myprog_SOURCES += src/alsa_output.cc
endif
if jack
  myprog_SOURCES += src/jack_output.cc
endif

Вам также необходимо позаботиться о применении флагов и библиотек для каждой подсистемы. Вы можете использовать тот же подход (и даже использовать те же самые if блоки), что и для источников, и это было бы просто замечательно, или вы могли бы позволить configure взять контроль над тем, как (независимо) ли он определяет какие-либо флаги для каждой подсистемы во-первых.

Вы заметите, что я замалчивал многие детали. Это довольно общий ответ на вопрос, который я должен принять как вопрос высокого уровня. Если я возьму вопрос по-другому, то он слишком широк для этого места.

0 голосов
/ 11 апреля 2020

Способ выборочной компиляции с помощью автоинструментов заключается в обнаружении в configure.a c и определении в Makefile.am. Используя этот метод, обнаружение доступных библиотек выполняется при выполнении начальной команды configure, и это условно создает Makefile, который компилирует исходный код, только если установлены его зависимости.

Например, из конфигурации программного обеспечения gtkIOStream. c обнаруживает наличие гнезда . Затем он определяет переменную HAVE_JACK, если она присутствует, например:

# jack
PKG_CHECK_MODULES([JACK], [jack], HAVE_JACK="yes", HAVE_JACK="no")
AC_SUBST(JACK_CFLAGS)
AC_SUBST(JACK_LIBS)
AM_CONDITIONAL(HAVE_JACK, test x$HAVE_JACK = xyes)
if test "x$HAVE_JACK" == xyes ; then
    AC_DEFINE(HAVE_JACK, [], [whether to build in Jack support])
fi

Makefile.am проверяет переменную HAVE_JACK и, если она существует, изменяет компиляцию. В вашем случае это должно работать:

if HAVE_JACK
    myprog_SOURCES += src/jack_output.cc
endif

Теперь, если configure обнаружит джек, ваш Makefile добавляет его к источникам для сборки.

Если вы хотите ограничить создание амплификаций, тогда вы захотите добавить другую переменную (как в ранее упомянутом примере gtkIOStream), которая выглядит следующим образом:

if HAVE_JACK
bin_PROGRAMS += I2SEndianTest CrossoverTester
endif

gtkIOStream также обнаруживает ALSA следующим образом:

# alsa
PKG_CHECK_MODULES(ALSA, alsa, HAVE_ALSA="yes", HAVE_ALSA="no")
AC_SUBST(ALSA_CFLAGS)
AC_SUBST(ALSA_LIBS)
AM_CONDITIONAL(HAVE_ALSA, test x$HAVE_ALSA = xyes)
if test "x$HAVE_ALSA" == xyes ; then
    AC_DEFINE(HAVE_ALSA, [], [whether to build in Alsa support])
fi
...