Разные реализации в разных файлах в автоинструментах - PullRequest
2 голосов
/ 20 февраля 2011

Допустим, у меня есть функция "foo", которую я реализую для нескольких операционных систем. Существует общий способ сделать это, но если ОС имеет встроенную поддержку для этого, то я хочу использовать это.

Как условно скомпилировать только нужные исходные файлы с помощью автоинструментов?

Пример: Допустим, «foo» - это «перезагрузить компьютер».

В Linux я бы использовал reboot () и поместил бы это в reboot_reboot.c, где я определяю myreboot (), просто вызовите reboot () с правильными параметрами.

На всех BSD я бы использовал bsd_made_up_blah_reboot (), который принимает разные параметры. Я бы положил это в reboot_bsd_made_up_blah_reboot.c, который делает это. (это всего лишь пример, я знаю, что BSD имеют перезагрузку ())

Иначе, используйте reboot_generic.c, который просто вызывает систему («shutdown -i6 -g0»). (Да, давайте проигнорируем синтаксис для различных двоичных файлов завершения работы)

В configure.ac я могу проверить наличие «перезагрузки», «bsd_made_up_blah_reboot», а затем в Makefile.am сделать:

if HAVE_REBOOT
 blah_SOURCES += reboot_reboot.c
else
 if HAVE_BSD_MADE_UP_BLAH_REBOOT
  blah_SOURCES += reboot_bsd_made_up_blah_reboot.c
 else
  blah_SOURCES += reboot_generic.c
 endif
endif

Мне это не нравится, так как (насколько я понимаю) в Makefile.am нет «else if», и с ростом числа реализаций он будет становиться все уродливее и уродливее.

Какой правильный способ сделать это? Имейте в виду, что я хочу защитить от будущей системы, имеющей и reboot (), и bsd_made_up_blah_reboot (), поэтому я не могу просто включить обе.

Ответы [ 3 ]

3 голосов
/ 20 февраля 2011

Мне это не нравится, поскольку (насколько я понимаю) в Makefile.am нет слова "else if", и по мере роста числа реализаций if будет становиться все уродливее.

Но если вы можете гарантировать, что случаи HAVE_REBOOT, HAVE_BSD_REBOOT (и все остальное) попарно дизъюнктивны, вы можете просто написать

if HAVE_REBOOT
x_SOURCES += reboot.c
endif
if HAVE_BSD_REBOOT
x_SOURCES += bsd_reboot.c
endif
if HAVE_NO_REBOOT
x_SOURCES += generic_reboot.c
endif

(Вам необходимо определить HAVE_NO_REBOOT в configure.ac.) Не так уж сложно, если, например,

case "$host" in
(*-linux)
    have_reboot=1;;
(*-bsd)
    have_bsd_reboot=1;;
(*)
    have_no_reboot=1;;
esac;
AM_CONDITIONAL([HAVE_REBOOT], [test "$have_reboot" = 1])
AM_CONDITIONAL([HAVE_BSD_REBOOT], [test "$have_bsd_reboot" = 1])
AM_CONDITIONAL([HAVE_NO_REBOOT], [test "$have_no_reboot" = 1])
2 голосов
/ 20 февраля 2011

Вы можете сделать то же самое с помощью тестов autoconf и определить макросы препроцессора в config.h, а затем в своем коде

#include "config.h"
#include <otherstuff.h>
void my_reboot()
{
#ifdef HAVE_REBOOT
    reboot(...);
#elif defined(HAVE_BSD_REBOOT)
    reboot(blahblah);
#else
    system("shutdown -r");
#endif
}

Для функций, которые не очень сложны (например, переносимые оболочки, такие как выше),это ИМХО чище, чем иметь отдельные исходные файлы.YMMV.

РЕДАКТИРОВАТЬ: Чтобы ответить Ларсману и пуншу, Керниган и Пайк говорят, что условная компиляция плоха в первую очередь потому, что она делает тестирование всех комбинаций трудным, если не невозможным.Это, конечно, верно, аргументов нет, но как условная компиляция путем включения различных исходных файлов в сборку лучше, чем условная компиляция с помощью директив CPP?Ну, очевидный ответ заключается в том, что это не так (с очевидным предостережением, что смешивание потока управления CPP с нормальным потоком управления очень сбивает с толку, но тогда я тоже не защищаю это в моем примере выше), и оба метода представляют одинаковотрудности при тестировании.

И да, очевидно, если можно избежать условной компиляции, хорошо.Однако иногда это просто не вариант, и тогда нужно смириться с этим.

0 голосов
/ 22 февраля 2011

Не могли бы вы AC_SUBST нужных вам источников в вашей строке _SOURCES, основываясь на том, что configure выкапывает?

configure.ac:

AS_CASE([$host],
[*-linux], [REBOOT_OBJ=reboot-linux.$OBJEXT],
[*-bsd], [REBOOT_OBJ=reboot-bsd.$OBJEXT],
[REBOOT_OBJ=reboot-generic.$OBJEXT])
AC_SUBST([REBOOT_OBJ])

Makefile.am:

foo_SOURCES = foo.c bar.c baz.c
foo_LDADD = $(REBOOT_OBJ)
foo_DEPENDENCIES = $(REBOOT_OBJ)
EXTRA_foo_SOURCES = reboot-bsd.c reboot-generic.c reboot-linux.c

Помните, что философия autoconf - это «проверка возможностей, а не платформ».

...