Different implementations in different files in autotools

烈酒焚心 提交于 2020-01-04 05:27:52

问题


Let's say I have a feature "foo" that I'm implementing for several operating systems. There is a generic way to do it, but if the OS has native support for it then I want to use that.

How do I conditionally compile only the right source files with autotools?

Example: Let's say "foo" is "reboot the machine".

On Linux I would use reboot(), and I would put that in reboot_reboot.c, where I define myreboot() do just call reboot() with the correct parameters.

On all the BSDs I would use bsd_made_up_blah_reboot(), which takes different parameters. I would put this in reboot_bsd_made_up_blah_reboot.c, which does this. (this is just an example, I know BSDs have reboot())

Else, use reboot_generic.c, which just calls system("shutdown -i6 -g0"). (Yes, let's ignore the syntax for different shutdown binaries)

In configure.ac I can check for the presence of "reboot", "bsd_made_up_blah_reboot", and then in Makefile.am do:

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

I don't like this, since (as I understand it) there is no "else if" in Makefile.am, and as the number of implementations grow it will get uglier and uglier.

What's the right way to do this? Keep in mind that I want to protect against a future system having both reboot() and bsd_made_up_blah_reboot(), so I can't just include both.


回答1:


I don't like this, since (as I understand it) there is no "else if" in Makefile.am, and as the number of implementations grow if will get uglier and uglier.

But if you can guarantee that the cases HAVE_REBOOT, HAVE_BSD_REBOOT (and whatever else might be) are pairwise disjunctive, you can simply write

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

(You would need to define a HAVE_NO_REBOOT in configure.ac.) Not that hard either, assuming, for example

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:


You can accomplish the same with autoconf tests and define preprocessor macros in config.h, and then in your code

#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
}

For features which are not very complicated (e.g. portability wrappers such as above), this is IMHO cleaner than having separate source files. YMMV.

EDIT: To answer larsmans and the downvoter, what Kernighan & Pike are saying is that conditional compilation is bad primarily because it makes testing all combinations difficult, if not impossible. That is certainly true, no argument there, but how is conditional compilation by including different source files in the build better than conditional compilation via CPP directives? Well, the obvious answer is that it isn't (with the obvious caveat that mixing CPP control flow with normal control flow is very confusing, but then I'm not advocating that in my example above either), and both methods present the same difficulties wrt testing.

And yes, obviously, if one can avoid conditional compilation, good. However, sometimes this just isn't an option, and then one has to suck it up.




回答3:


Could you AC_SUBST the sources you need into your _SOURCES line, based on what configure digs up?

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

Remember that the autoconf philosophy is "test for features, not platforms".



来源:https://stackoverflow.com/questions/5057098/different-implementations-in-different-files-in-autotools

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!