autotools中不同文件中的不同实现

时间:2011-02-20 12:43:25

标签: c autotools

假设我有一个功能“foo”,我正在为多个操作系统实现。有一种通用的方法,但如果操作系统有本机支持,那么我想使用它。

如何使用autotools有条件地编译正确的源文件?

实施例: 假设“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,它只调用system(“shutdown -i6 -g0”)。 (是的,让我们忽略不同的关闭二进制文件的语法)

在configure.ac中,我可以检查是否存在“rebo​​ot”,“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 个答案:

答案 0 :(得分:3)

  

我不喜欢这个,因为(据我所知)Makefile.am中没有“else if”,并且随着实现数量的增加,如果变得更加丑陋和丑陋。

但如果你可以保证案例HAVE_REBOOTHAVE_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

(你需要在configure.ac中定义一个HAVE_NO_REBOOT。)也没那么难,假设,例如

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

答案 1 :(得分:2)

您可以使用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
}

对于不太复杂的功能(例如上面的可移植包装器),这是具有单独源文件的IMHO清洁器。 YMMV。

编辑:为了回答larsmans和downvoter,Kernighan&amp;派克说的是,条件编译很糟糕主要是因为它使测试所有组合变得困难,如果不是不可能的话。这当然是正确的,那里没有争论,但是如果条件编译是通过在构建中包含不同的源文件比通过CPP指令的条件编译更好?嗯,显而易见的答案是它不是(明显的警告,将CPP控制流与正常控制流混合是非常令人困惑的,但是在我上面的例子中我也没有提倡),两种方法都是相同的测试的困难。

是的,显然,如果可以避免条件编译,那就好了。但是,有时候这不是一个选择,然后就必须把它搞砸了。

答案 2 :(得分:0)

根据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哲学是“测试功能,而不是平台”。