cmake:复制 boost-build 的 "build everything in Jamfile" 行为?
cmake: replicate boost-build's "build everything in Jamfile" behaviour?
我正在将 boost-build
构建系统转换为 cmake。
boost-build 的一个特点是您可以指定 Jamfile
的路径(相当于 CMakeLists.txt
文件),其中指定的所有目标都将被构建。
例如,具有以下项目结构:
root
|
+--- foo
| |
| +--- test
|
+--- bar
| |
| +--- test
|
+--- app
如果输入以下命令:
$ b2 foo
root/foo
下的 Jamfile
将被执行,导致构建 foo
库,构建 test
测试和 运行
增强构建示例
这是一个使用 boost-build
:
的简单构建配置
Jamroot
:
using gcc ;
project proj : requirements
<link>static
<include>.
;
build-project foo ;
foo/Jamfile
:
lib foo : [ glob *.cpp ] ;
build-project test ;
foo/test/Jamfile
:
import testing ;
unit-test foo-tests
: [ glob *.cpp ]
..//foo
;
你会注意到在 foo's Jamfile
中有一个指令 build-project test
这意味着如果我键入 b2 foo
那么 lib/Jamfile
中的所有内容都将被执行,导致 foo
和 foo/test
正在建设中。
此外,在 Jamroot
中有一个指令 build-project foo
这意味着,如果我只键入 b2
,那么 Jamroot
中的所有内容都会被执行,从而导致构建 foo
和 foo/test
。
因此很容易构建整个项目并获得构建的所有源代码和所有测试。
也很容易构建只是一个子目录并获得只有它的源代码和测试构建。
我正试图复制这种行为。
cmake 示例
root/CMakeLists.txt
:
cmake_minimum_required(VERSION 3.2.2)
project(proj CXX)
add_subdirectory(foo)
foo/CMakeLists.txt
:
file(GLOB src "*.cpp")
add_library(foo STATIC ${src})
add_subdirectory(test)
foo/test/CMakeLists.txt
:
file(GLOB src "*.cpp")
add_executable(foo_test ${src})
add_test(foo_test foo_test foo)
# run tests if foo_test.passed is missing or outdated
add_custom_command(
OUTPUT foo_test.passed
COMMAND foo_test
COMMAND ${CMAKE_COMMAND} -E touch foo_test.passed
DEPENDS foo_test
)
# make tests run as part of ALL target
add_custom_target(run_foo_test
ALL
DEPENDS foo_test.passed)
上面的 CMakeLists.txt
结构允许我 make
并同时构建 foo
和 foo_test
。
但是,如果我指定 make foo
,只会构建 foo
,但不会构建 foo_test
,并且测试不会 运行.
问题:
- 如何在输入
make foo
时构建 foo/CMakeLists.txt
中的所有内容?
- 或者,如何使目标
foo_test.passed
作为更新目标 foo
的一部分构建 AND 作为 [=56= 的一部分构建] 目标?
这是一个实现要求的实现。
它有点复杂,因为它需要几个虚假目标和依赖链。
第 1 步:
- 创建一个虚假目标,"module" 的所有其他目标都将收集在
下
- 将虚假目标添加到
ALL
,以便将其构建为全局构建过程的一部分
foo/CMakeLists.txt
:
# create a phony target which all 'foo' related items will be added to
add_custom_target(foo
ALL
)
第 2 步:
- 将 "module" 中的每个目标添加为该虚假目标的依赖项
libfoo
:
- 请注意,我已将
foo
重命名为 libfoo
,因为我们现在将 foo
用于我们之前的虚假目标。
- (这实际上会导致生成的库被调用
liblibfoo.a
,有点难看)
foo/CMakeLists.txt
:
add_library(libfoo STATIC ${src})
# add libfoo as a dependency of foo, so 'make foo' will build libfoo
add_dependencies(foo
libfoo)
foo_test
:
作为构建的一部分自动进行测试 运行 有点复杂。
你必须:
- 创建测试可执行文件
- 添加一个
custom_command
用于 运行 测试并生成标记文件 (foo_test.passed
) 如果它们通过
- 添加一个
custom_target
(foo_test.run
) 取决于哨兵 (foo_test.passed
)
- 在
foo
和foo_test.run
之间添加依赖关系
foo_test/CMakeLists.txt
:
add_executable (foo_test main.cpp)
target_link_libraries(foo_test libfoo ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
# create foo_test.passed command which generates the sentinel file when the tests pass
add_custom_command(
OUTPUT foo_test.passed
COMMAND foo_test
COMMAND ${CMAKE_COMMAND} -E touch foo_test.passed
DEPENDS foo_test
)
# create foo_test.run target which depends on foo_test.passed
add_custom_target(foo_test.run
DEPENDS foo_test.passed
)
# add foo_test.run as a dependency of foo, so 'make foo' will build foo_test.run
add_dependencies(foo
foo_test.run
)
因此,目标 foo
具有 libfoo
和 foo_test.run
作为依赖项。
因此,make
和 make foo
都构建了 libfoo
并构建了 运行 foo_test
(通过 foo_test.run
和 foo_test.passed
)
感知笨拙:
foo
-> foo_test.run
-> foo_test.passed
-> foo_test
依赖链。
在 boost-build
中,您可以将库命名为 foo
,而不会导致 foo
虚假目标与 foo
库(和 b2 foo
构建 foo
库及其测试)
然而,它有效,并且在没有更优雅的解决方案的情况下,会给我我想要的。
我正在将 boost-build
构建系统转换为 cmake。
boost-build 的一个特点是您可以指定 Jamfile
的路径(相当于 CMakeLists.txt
文件),其中指定的所有目标都将被构建。
例如,具有以下项目结构:
root
|
+--- foo
| |
| +--- test
|
+--- bar
| |
| +--- test
|
+--- app
如果输入以下命令:
$ b2 foo
root/foo
下的 Jamfile
将被执行,导致构建 foo
库,构建 test
测试和 运行
增强构建示例
这是一个使用 boost-build
:
Jamroot
:
using gcc ;
project proj : requirements
<link>static
<include>.
;
build-project foo ;
foo/Jamfile
:
lib foo : [ glob *.cpp ] ;
build-project test ;
foo/test/Jamfile
:
import testing ;
unit-test foo-tests
: [ glob *.cpp ]
..//foo
;
你会注意到在 foo's Jamfile
中有一个指令 build-project test
这意味着如果我键入 b2 foo
那么 lib/Jamfile
中的所有内容都将被执行,导致 foo
和 foo/test
正在建设中。
此外,在 Jamroot
中有一个指令 build-project foo
这意味着,如果我只键入 b2
,那么 Jamroot
中的所有内容都会被执行,从而导致构建 foo
和 foo/test
。
因此很容易构建整个项目并获得构建的所有源代码和所有测试。
也很容易构建只是一个子目录并获得只有它的源代码和测试构建。
我正试图复制这种行为。
cmake 示例
root/CMakeLists.txt
:
cmake_minimum_required(VERSION 3.2.2)
project(proj CXX)
add_subdirectory(foo)
foo/CMakeLists.txt
:
file(GLOB src "*.cpp")
add_library(foo STATIC ${src})
add_subdirectory(test)
foo/test/CMakeLists.txt
:
file(GLOB src "*.cpp")
add_executable(foo_test ${src})
add_test(foo_test foo_test foo)
# run tests if foo_test.passed is missing or outdated
add_custom_command(
OUTPUT foo_test.passed
COMMAND foo_test
COMMAND ${CMAKE_COMMAND} -E touch foo_test.passed
DEPENDS foo_test
)
# make tests run as part of ALL target
add_custom_target(run_foo_test
ALL
DEPENDS foo_test.passed)
上面的 CMakeLists.txt
结构允许我 make
并同时构建 foo
和 foo_test
。
但是,如果我指定 make foo
,只会构建 foo
,但不会构建 foo_test
,并且测试不会 运行.
问题:
- 如何在输入
make foo
时构建foo/CMakeLists.txt
中的所有内容? - 或者,如何使目标
foo_test.passed
作为更新目标foo
的一部分构建 AND 作为 [=56= 的一部分构建] 目标?
这是一个实现要求的实现。
它有点复杂,因为它需要几个虚假目标和依赖链。
第 1 步:
- 创建一个虚假目标,"module" 的所有其他目标都将收集在 下
- 将虚假目标添加到
ALL
,以便将其构建为全局构建过程的一部分
foo/CMakeLists.txt
:
# create a phony target which all 'foo' related items will be added to
add_custom_target(foo
ALL
)
第 2 步:
- 将 "module" 中的每个目标添加为该虚假目标的依赖项
libfoo
:
- 请注意,我已将
foo
重命名为libfoo
,因为我们现在将foo
用于我们之前的虚假目标。 - (这实际上会导致生成的库被调用
liblibfoo.a
,有点难看)
foo/CMakeLists.txt
:
add_library(libfoo STATIC ${src})
# add libfoo as a dependency of foo, so 'make foo' will build libfoo
add_dependencies(foo
libfoo)
foo_test
:
作为构建的一部分自动进行测试 运行 有点复杂。
你必须:
- 创建测试可执行文件
- 添加一个
custom_command
用于 运行 测试并生成标记文件 (foo_test.passed
) 如果它们通过 - 添加一个
custom_target
(foo_test.run
) 取决于哨兵 (foo_test.passed
) - 在
foo
和foo_test.run
之间添加依赖关系
foo_test/CMakeLists.txt
:
add_executable (foo_test main.cpp)
target_link_libraries(foo_test libfoo ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
# create foo_test.passed command which generates the sentinel file when the tests pass
add_custom_command(
OUTPUT foo_test.passed
COMMAND foo_test
COMMAND ${CMAKE_COMMAND} -E touch foo_test.passed
DEPENDS foo_test
)
# create foo_test.run target which depends on foo_test.passed
add_custom_target(foo_test.run
DEPENDS foo_test.passed
)
# add foo_test.run as a dependency of foo, so 'make foo' will build foo_test.run
add_dependencies(foo
foo_test.run
)
因此,目标 foo
具有 libfoo
和 foo_test.run
作为依赖项。
因此,make
和 make foo
都构建了 libfoo
并构建了 运行 foo_test
(通过 foo_test.run
和 foo_test.passed
)
感知笨拙:
foo
->foo_test.run
->foo_test.passed
->foo_test
依赖链。在
boost-build
中,您可以将库命名为foo
,而不会导致foo
虚假目标与foo
库(和b2 foo
构建foo
库及其测试)
然而,它有效,并且在没有更优雅的解决方案的情况下,会给我我想要的。