完美的makefile
我想使用 make 结合 < a href="http://en.wikipedia.org/wiki/Continously_integration" rel="nofollow noreferrer">持续集成、自动单元测试和多平台构建。 类似的设置在 Java 和 .NET 中很常见,但我很难将其组合到 make 和 C/C++ 中。 如何才能实现呢?
我的要求:
- 快速构建; 非递归 make(Stack Overflow 问题您对非递归 make 的体验如何?)
- 模块化系统(即,最小依赖性,带有组件的子目录中的 makefile)
- 多平台(通常用于单元测试的 PC,用于系统集成/发布的嵌入式目标)
- 完整依赖性检查
- 执行(自动)单元测试(敏捷工程)的
- 连接到持续集成系统
- 能力轻松 为了使用,
我从non-rec make开始。 我仍然认为这是一个很好的起点。
到目前为止的限制:
- 没有集成单元测试
- 基于 Windows 的 ARM 编译器与 Cygwin 路径的不兼容性
- makefile 与 Windows \ 路径
- 前向依赖项的
不兼容性我的结构如下所示:
<前><代码> 项目根目录 /算法 /src /algo1.c /algo2.c /单元测试 /algo1_test.c /algo2_test.c /出去 算法1_测试.exe algo1_test.xml 算法2_测试.exe algo2_test.xml 头文件.h /embunit /哈纳斯 生成文件 规则.top
我想让事情变得简单; 这里的单元测试(algo1_test.exe)依赖于“算法”组件(ok)和单元测试框架(在构建这个框架时可能知道也可能不知道)。 然而,将构建规则移至顶层对我来说并不有吸引力,因为这会在整个系统中分发组件的本地知识。
至于 Cygwin 路径:我正在努力使用相对路径进行构建。 这解决了 /cygdrive/c
问题(因为编译器通常可以处理 / 路径),而无需引入 C: (这令人不喜欢)。 还有其他想法吗?
I'd like to use make to get a modular build in combination with continuous integration, automatic unit testing and multi-platform builds. Similar setups are common in Java and .NET, but I'm having a hard time putting this together for make and C/C++. How can it be achieved?
My requirements:
- fast build; non-recursive make (Stack Overflow question What is your experience with non-recursive make?)
- modular system (that is, minimal dependencies, makefile in subdirectory with components)
- multiplatform (typically PC for unit testing, embedded target for system integration/release)
- complete dependency checking
- ability to perform (automatic) unit tests (Agile engineering)
- hook into continuous integration system
- easy to use
I've started with non-rec make. I still find it a great place to start.
Limitations so far:
- no integration of unit tests
- incompatibility of windows based ARM compilers with Cygwin paths
- incompatibility of makefile with Windows \ paths
- forward dependencies
My structure looks like:
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
I'd like to keep things simple; here the unit tests (algo1_test.exe) depend on both the 'algorithm' component (ok) and the unit test framework (which may or may not be known at the time of building this). However, moving the build rules to the top make does not appeal to me as this would distribute local knowledge of components throughout the system.
As for the Cygwin paths: I'm working on making the build using relative paths. This resolves the /cygdrive/c
issue (as compilers can generally handle / paths) without bringing in C: (which make dislikes). Any other ideas?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
CMake 以及相关工具 CTest 和 CDash 似乎可以满足您的要求。 值得一看。
Bill Hoffman(首席 CMake 开发人员)提到了 Recursive Make Been Thought 有害 CMake 邮件列表中的帖子中的论文:
另请参阅此答案了解“递归生成 - 朋友还是敌人?” 这里在 stackoverflow 上。
-
递归建立 - 朋友还是敌人?
CMake together with the related tools CTest and CDash seem to answer your requirements. Worth giving it a look.
Bill Hoffman (A lead CMake developer) refers to the Recursive Make Considered Harmful paper in a post at the CMake mailing list:
See also this answer for "Recursive Make - friend or foe?" here on stackoverflow.
-
Recursive Make - friend or foe?
好的,这就是我所做的:
我在根目录使用一个 Makefile 并使用通配符模式来收集目录中的所有文件。 请注意,我假设 foo/*.c 将组成 foo.so。 这使得维护 Makefile 的工作量最小化,因为只需将文件添加到目录中就会自动将其添加到构建中。
因为它是 make 你正在使用我假设(我为我的项目这样做)使用的编译器使用 gcc (cc) 兼容的命令行语法。 所以MSC出故障了; 但不要沮丧,我的大部分开发(不幸的是)在 Windows 上进行,并使用 MinGW 和 MSys; 奇迹般有效。 生成本机二进制文件,但使用 Posix 兼容的构建环境构建。
依赖性检查是通过有点标准的
-MD
开关完成的。 然后我将所有 *.d 文件包含到 Makefile 中。 我根据自动收集的源文件构建模式。最后,单元测试是使用“标准”
check
目标实现的。 检查目标与 all 目标类似,但它取决于单元测试并在所有内容构建完成后执行。 我这样做是为了让您可以单独构建项目或构建单元测试(以及项目的其余部分)。 当我不开发项目时,我只想构建它并完成它。这是我如何做到这一点的示例: https://github.com/rioki/c9y /blob/master/Makefile
它还具有
install
、uninstall
和dist
目标。正如您所看到的,一切都是简单的 make,没有递归 make 调用,并且一切都相对简单。 我使用了 automake 和 autoconf,我再也不会这样做了; 其他构建工具也是不可能的,如果我需要安装 foojam 或 barmake 来构建某些东西,我通常会立即放弃该项目。
Ok here is what I do:
I use one Makefile at the root and wildcard patterns to collect all files in a directory. Note that I assume that foo/*.c will make up foo.so for example. This makes the maintaining the Makefile minimal, since just adding a file to the directory automatically adds it to the build.
Since it is make you are using I am assuming (I do that for my projects) that a compiler is used that uses gcc (cc) compatible command line syntax. So MSC is out of order; but don't get frustrated, I do most of my development (unfortunately) on Windows and use MinGW with MSys; works like a charm. Produces native binaries, but was built with a Posix compliant build environment.
Dependency checking is done with the somewhat standard
-MD
switch. I then include all the *.d files into the Makefile. I build the patterns out of the automatically collected source files.Finally unit tests are implemented with the "standard"
check
target. The check target is like the all target, except it depends on the unit test and executes that once everything is built. I do it this way so that you can just build the project or build the unit tests (and the rest of the project) separably. When I am not developing the project I want to just build it and be done with it.Here is an example of how I do it: https://github.com/rioki/c9y/blob/master/Makefile
It also has the
install
,uninstall
anddist
targets.As you can see everything is plain make, no recursive make calls and all is relatively simple. I used automake and autoconf and I will never do that again; also other build tools are out of the question, if I need to install foojam or barmake to build something, I normally ditch that project immediately.