简介
使用CMake,我试图使用一个特殊的make
目标构建一个库。为此,我使用EXCLUDE_FROM_ALL
参数来确保库不是通过运行make
(默认为make all
(来构建的。不幸的是,EXCLUDE_FROM_ALL
选项似乎被cmake
忽略了。
考虑以下文件树:
.
├── CMakeLists.txt
├── foo
│ ├── CMakeLists.txt
│ ├── headers
│ │ └── foo.h
│ └── src
│ └── foo.cpp
└── src
└── main.cpp
4 directories, 5 files
在这个文件树中,你可以看到我基本上有两个部分:
- foo库,其所有文件都位于
./foo/
中 - 主可执行文件,其源代码位于
./src/main.cpp
中
下面,我将进一步解释这两个部分以及我观察到的行为。
foo库
首先,位于./foo/headers/foo.h
中的头代码是:
#ifndef _FOO_H_
#define _FOO_H_
#include <iostream>
void foo(void);
#endif // _FOO_H_
位于./foo/src/foo.cpp
中的相应源代码为:
#include "foo.h"
void foo(void) {
std::printf("Hello foo!n");
}
正如您所看到的,foo库只包含函数foo()
。此功能只是将Hello, foo!
打印到终端。为了构建foo库,我定义了以下CMakeLists.txt
文件(在./foo/CMakeLists.txt
中(:
cmake_minimum_required(VERSION 3.10)
project(foo
LANGUAGES CXX
)
# Create a foo library target
add_library(foo EXCLUDE_FROM_ALL
"src/foo.cpp"
)
target_include_directories(foo
PUBLIC "headers"
)
请注意,我在add_library()
函数中使用了EXCLUDE_FROM_ALL
参数。
为了测试EXCLUDE_FROM_ALL
参数的行为,我现在将把foo库作为一个独立的库来构建(使用前面显示的CMakeLists.txt
(。从顶部目录(.
(开始,我使用以下工作流程:
$ cd foo
$ mkdir build
$ cd build
$ cmake ..
完成后,我运行make
命令:
$ make
(nothing happens)
正如预期的那样,什么都没有发生(因为foo库被排除在all
目标之外(。现在,当我使用make foo
时,我得到以下输出:
$ make foo
Scanning dependencies of target foo
[ 50%] Building CXX object CMakeFiles/foo.dir/src/foo.cpp.o
[100%] Linking CXX static library libfoo.a
[100%] Built target foo
到目前为止,一切都很好。在构建主可执行文件之前,我完全删除了./foo/build
目录,并返回到顶级目录:
$ cd ..
$ rm -rf build
$ cd ..
主要可执行文件
主可执行文件的源代码位于./src/main.cpp
:中
#include "foo.h"
int main() {
foo();
return 0;
}
顶级CMakeLists.txt
包含:
cmake_minimum_required(VERSION 3.10)
project(TestProject
LANGUAGES CXX
)
# Include the foo library
add_subdirectory("foo" EXCLUDE_FROM_ALL)
# Create the main executable
add_executable(TestProject
"src/main.cpp"
)
target_link_libraries(TestProject
PRIVATE foo
)
请注意,我再次使用EXCLUDE_FROM_ALL
参数,但现在用于add_subdirectory()
函数。
为了生成主可执行文件的makefile,我使用以下工作流:
$ mkdir build
$ cd build
$ cmake ..
当我现在运行make
时,我得到以下输出:
$ make
Scanning dependencies of target foo
[ 25%] Building CXX object foo/CMakeFiles/foo.dir/src/foo.cpp.o
[ 50%] Linking CXX static library libfoo.a
[ 50%] Built target foo
Scanning dependencies of target TestProject
[ 75%] Building CXX object CMakeFiles/TestProject.dir/src/main.cpp.o
[100%] Linking CXX executable TestProject
[100%] Built target TestProject
正如您所看到的,它首先构建了foo库。然而,这并不是我所期望的!我明确表示要从all
目标中排除foo库。因此,我希望在运行make
之前先运行make foo
。
这就引出了我的主要问题:有人知道它为什么忽略顶级CMakeLists.txt
中add_subdirectory()
函数中的EXCLUDE_FROM_ALL
选项吗?当我将foo库作为一个独立库构建时,它确实起了作用。这是cmake
中的一个错误吗?如果没有,我如何实现预期行为(即在运行make
之前需要运行make foo
(?
这不是一个bug。CMake不直接在所有目标中包括foo
库。但是,它确实将foo
目标添加为TestProject
的依赖项,并且由于TestProject
包含在all
目标中,因此如果构建all
,也会构建foo
。
这需要这样做。否则,如何将foo
函数链接到TestProject
?
如果要使用不是作为all
的一部分构建的库,则需要使用导入的库。这样做并将lib包含在项目中似乎有点荒谬,但现在开始吧。
add_library(foo STATIC EXCLUDE_FROM_ALL
"src/foo.cpp"
)
cmake_minimum_required(VERSION 3.10)
project(TestProject
LANGUAGES CXX
)
# Include the foo library
add_subdirectory("foo" EXCLUDE_FROM_ALL)
# Create the main executable
add_executable(TestProject
"src/main.cpp"
)
# add copy of foo as imported lib
add_library(foo_imported STATIC IMPORTED)
target_include_directories(foo_imported INTERFACE $<TARGET_PROPERTY:foo,INTERFACE_INCLUDE_DIRECTORIES>)
set_target_properties(foo_imported PROPERTIES IMPORTED_LOCATION $<TARGET_FILE:foo>)
target_link_libraries(TestProject
PRIVATE foo_imported
)