完美的Makefile

5
我想使用 make 来实现模块化构建,结合 持续集成, 自动单元测试多平台构建。类似的设置在 Java 和 .NET 中很常见,但是对于 make 和 C/C++ 我很难组合起来。如何实现这一目标?
我的要求:
  • 快速构建;非递归 make(Stack Overflow 问题 你对非递归 make 有什么经验?
  • 模块化系统(即最小依赖项,在子目录中具有组件的 makefile)
  • 多平台(通常用于单元测试的 PC,用于系统集成/发布的嵌入式目标)
  • 完整的依赖关系检查
  • 能够执行(自动)单元测试(敏捷工程)
  • 与持续集成系统连接
  • 易于使用
我已经开始使用非递归make。我仍然认为这是一个很好的起点。
目前的限制如下:
  • 没有单元测试集成
  • 基于Windows的ARM编译器与Cygwin路径不兼容
  • makefile与Windows \路径不兼容
  • 前置依赖关系
我的结构如下:
    project_root
       /algorithm
                 /src
                     /algo1.c
                     /algo2.c
                 /unit_test
                     /algo1_test.c
                     /algo2_test.c
                 /out
                     algo1_test.exe
                     algo1_test.xml
                     algo2_test.exe
                     algo2_test.xml
             headers.h
       /embunit
       /harnass
   makefile
   Rules.top
我希望保持简单;这里的单元测试(algo1_test.exe)依赖于“算法”组件(ok)和单元测试框架(在构建时可能已知也可能未知)。然而,将构建规则移动到顶部并不吸引我,因为这会在整个系统中分布组件的本地知识。
至于Cygwin路径:我正在努力使用相对路径进行构建。这解决了/cygdrive/c问题(编译器通常可以处理/路径),而不需要引入C:(这是make不喜欢的)。还有其他想法吗?

请注意,通常情况下在Windows中您可以使用/作为路径分隔符。几乎每个使用路径的API函数都会将它们透明地转换为\ - Joey
确实如此。然而,驱动器字母会引起问题。Make 无法很好地处理冒号(因为它定义了一个目标)。并且 /cygdrive/c/ 在 Windows 应用程序中无法识别。如果我将 /cygdrive/c 翻译成 c:/,则编译器生成的依赖文件将无法被 makefile 识别。 - Adriaan
2个回答

3

CMake与相关工具CTest和CDash似乎符合您的要求。 值得一看。

Bill Hoffman(CMake的首席开发人员)在CMake邮件列表的帖子中提到了递归式Makefile有害论文

...由于cmake为您创建makefile,因此避免了许多递归式make的缺点,例如您不必调试makefile或甚至思考它们的工作原理。 还有其他例子,那篇论文中的问题也被cmake解决了。

请参见stackoverflow上的这个答案:“递归式Makefile - 友还是敌?”。

- 递归式Makefile - 友还是敌?


谢谢,我会进一步研究这个组合。你的努力值得赞赏。 - Adriaan
这不是我正在寻找的答案,但我仍然接受它,因为避免问题可能确实比在 make 文件中解决问题更好。 - Adriaan

0

好的,这是我的做法:

我在根目录下使用一个Makefile和通配符模式来收集目录中的所有文件。请注意,我假设foo/*.c将组成foo.so。这使得维护Makefile最小化,因为只需将文件添加到目录中即可自动将其添加到构建中。

由于您正在使用make,我假设(我为我的项目这样做)使用了一个使用gcc(cc)兼容命令行语法的编译器。因此,MSC已经过时;但不要沮丧,我大部分开发工作(不幸的是)都在Windows上进行,并使用MinGW和MSys;效果非常好。生成本地二进制文件,但是使用Posix兼容的构建环境构建。

依赖项检查使用了一种相当标准的-MD开关。然后我将所有*.d文件包含在Makefile中。我从自动收集的源文件中构建模式。

最后,使用“标准”check目标实现了单元测试。检查目标类似于所有目标,除了它依赖于单元测试并在构建完成后执行。我这样做是为了让您可以仅构建项目或仅构建单元测试(以及项目的其余部分)。当我不开发项目时,我只想构建它并完成。

以下是我如何实现它的示例:https://github.com/rioki/c9y/blob/master/Makefile 它还具有installuninstalldist目标。

正如您所看到的,一切都是普通的make,没有递归的make调用,而且所有内容都相对简单。我曾经使用过automake和autoconf,但再也不会使用了;如果我需要安装foojam或barmake来构建某些东西,我通常会立即放弃该项目。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接