CMake EXCLUDE_FROM_ALL运行"全部"时忽略的参数



简介

使用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

在这个文件树中,你可以看到我基本上有两个部分:

  1. foo库,其所有文件都位于./foo/
  2. 主可执行文件,其源代码位于./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.txtadd_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
)

相关内容

最新更新