我有一个C ++ autoconf托管项目,我正在适应在FreeBSD主机上编译。 原来的系统是Linux所以我做了一个AM_CONDITIONAL来区分我正在构建的主机并将代码分成系统特定的文件。
configure.ac
AC_CANONICAL_HOST AM_CONDITIONAL([IS_FREEBSD],false) case $host in *free*) AC_DEFINE([IS_FREEBSD],[1],[FreeBSD Host]) AM_CONDITIONAL([IS_FREEBSD],true) BP_ADD_LDFLAG([-L/usr/local/lib]) ;; esac
Makefile.am
lib_LTLIBRARIES=mylib.la mylib_la_SOURCES=a.cpp \ b.cpp if IS_FREEBSD mylib_la_SOURCES+=freebsd/c.cpp else mylib_la_SOURCES+=linux/c.cpp endif
当我运行automake时,它失败并显示以下消息:
Makefile.am: object `c.lo' created by `linux/c.cpp' and `freebsd/c.cpp'
有关如何配置automake以尊重此条件的任何想法,即使在Makefile.in构建过程中也是如此?
如果文件的名称不同,我的工作正常,但它是c ++代码,我试图保持文件名与类名相同。
提前致谢!
答案 0 :(得分:11)
您可以使用
请求在各自的子目录中构建对象AUTOMAKE_OPTIONS = subdir-objects
答案 1 :(得分:7)
除了 subdir-objects 之外,另一个选项是为每个子项目提供一些自定义的每个项目构建标志。执行此操作时,automake会更改其* .o命名规则,以将目标名称添加到模块名称之前。例如,这个:
mylib_la_CXXFLAGS=$(AM_CXXFLAGS)
mylib_la_SOURCES=a.cpp b.cpp
将导致输出文件mylib_la-a.o和mylib_la-b.o,而不是a.o和b.o.因此,您可以拥有两个具有相同输出目录的不同项目,每个项目都有一个b.cpp文件,并且它们的输出不会发生冲突。
请注意,我是通过将特定于项目的CXXFLAGS设置为automake已经使用的值AM_CXXFLAGS来实现的。 Automake不够聪明,无法检测到这个技巧并使用较短的* .o名称。如果碰巧你确实需要每个项目的构建选项,你当然可以这样做,而不是这个黑客。
有一个whole list的automake变量,当基于每个可执行文件设置时,会产生同样的效果。因此,例如,也许一个子项目已经需要特殊的链接标记,所以你给它类似的东西:
mylib_la_LDFLAGS=-lfoo
这将为您提供前缀* .o文件,就像AM_CXXFLAGS技巧一样,只有现在您“合法地”使用此功能,而不是欺骗automake进行此操作。
顺便说一下,改变你的程序如何构建完全基于它正在构建的操作系统的方式是不好的autoconf风格。良好的autoconf风格是仅检查特定平台功能,而不是整个平台,因为平台会发生变化。 FreeBSD今天可能是某种方式,但也许在下一个版本中它将复制Linux中的一个功能,这将消除您以两种不同的方式构建程序的需要。或者,您今天使用的功能可能已弃用,并将在下一版本中删除。
在autotools,蚱蜢中有四十年的便携式Unix编程智慧。我上面给出的“maybes”有过去发生过,并且肯定会再次发生。测试各个功能是应对不断变化的平台的最灵敏的方式。
你也可以通过这种方法获得意想不到的奖金。例如,您的程序可能需要两个不可移植的功能才能完成其工作。比如在FreeBSD上,这些是A和B的功能,在Linux上,它们是X和Y的功能; A和X是类似的机制,但是具有不同的接口,并且对于B和Y是相同的。可能是特征A来自原始BSD,并且在Solaris中,因为它在80年代具有来自SunOS的BSD根,并且Solaris也具有功能Y来自它在90年代早期基于System V的重新设计。通过测试这些功能,您的程序也可以在Solaris上运行,因为它具有您的程序所需的功能,而不是与FreeBSD和Linux相同的组合。