【问题标题】:How do I set up a CMake project with subfolders?如何设置带有子文件夹的 CMake 项目?
【发布时间】:2022-01-27 23:03:24
【问题描述】:

我是 CMake 新手,所以如果我的问题被证明是菜鸟问题,我深表歉意。

我正在尝试在 C++ 中建立一个项目,其目录结构类似于我在 Java 中编码时 Maven 将创建的目录结构(src 目录和 build 目录):

root
├── build (where to build)
├── CMakeLists.txt (main one)
├── compile_commands.json -> ./build/compile_commands.json
├── doc
├── Doxyfile
└── src
    ├── CMakeLists.txt
    ├── common
    │   └── Terminal.hpp
    ├── fsa
    │   ├── CMakeLists.txt
    │   ├── Machine.cpp
    │   ├── Machine.hpp
    │   └── MachineState.hpp
    └── main.cpp

我不知道如何正确设置 CMake 以识别、编译和链接所有文件。特别是,我认为我应该使用(混合使用)add_subdirectory()add_executable()link_directories()target_link_libraries()add_library()target_include_directories(),但我不确定我知道如何。

我稍后提供我的CMakeLists.txt 文件,但是当我配置和编译时,我得到:

/usr/bin/ld: fsa/libfsalib.a(Machine.cpp.o): in function `Machine::addState(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, bool)':
Machine.cpp:(.text+0xd1): undefined reference to `MachineState::MachineState(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool)'
collect2: error: ld returned 1 exit status
make[2]: *** [src/CMakeFiles/elr1.dir/build.make:98: src/elr1] Error 1
make[1]: *** [CMakeFiles/Makefile2:115: src/CMakeFiles/elr1.dir/all] Error 2
make: *** [Makefile:91: all] Error 2

我做错了什么? 编辑: 原来这是我的一个非常愚蠢的错误,我忘了添加一个实现。但是,仍然存在一些问题:

  • 如果这个项目/cmake 结构是最佳实践,您能告诉我吗?
  • 我不知道应该在哪里使用 link_directories()target_include_directories()
  • 更一般地说,如何保持代码库整洁并编译我的项目? 提前致谢

我的命令是

to configure: "cmake -S /path_to_root_project -B /path_to_root_project/build -D CMAKE_EXPORT_COMPILE_COMMANDS=ON"
to compile: "cmake --build /path_to_root_project/build"

root_project/CMakeLists.txt:

cmake_minimum_required(VERSION 3.10)

# set the project name
project(elr1 VERSION 0.1)

set(CMAKE_CXX_STANDARD 11)

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

add_subdirectory(src)

root_project/src/CMakeLists.txt:

add_subdirectory(fsa)

# add the executable
add_executable(elr1 main.cpp)

link_directories(fsa)

target_link_libraries(elr1 #target in which link
  fsalib #library name
  )

root_project/src/fsa/CMakeLists.txt:

add_library(fsalib #name
   Machine.cpp #files
   MachineState.hpp
   )

 target_include_directories(fsalib PUBLIC
  ${CMAKE_CURRENT_SOURCE_DIR}
  )

【问题讨论】:

  • 那么MachineState::MachineState(std::string, bool)定义在哪里呢?没有MachineState.cpp吗?
  • 你是对的,没有,我的错。现在错误消失了。我的错!我非常专注于构建项目,以至于我忘记了它可能是真正的链接器错误。我将编辑我的问题,但关于 CMake 命令和最佳实践的问题仍然存在。
  • “关于 CMake 命令和最佳实践的问题仍然存在。” - 组织项目没有“最佳实践”。在 CMake 中,您几乎可以使用任何项目文件布局。
  • 可能不是最好的,但也有好的,例如除非绝对必须,否则不要创建文件夹,同时让CMakeLists.txt 只处理一个文件夹,并且只在更深层次上使用add_subdirectory而不是从不同的地方引用一堆文件。示例:project/tests/CMakeLists.txtproject/CMakeLists.txt 现在可以向可选的add_subdirectory(tests) 添加一个选项,这会导致测试构建生成器运行或完全忽略,甚至不被 CMake 解析。
  • (target_)link_directories() 只能在极少数情况下使用。它为链接器添加目录以搜索库文件。对于同一个项目构建的链接目标,这是不必要的;对于提供 cmake 导入脚本的外部项目,这也不是必需的。对于不提供 cmake 配置文件的外部库,这可能是一个选项,但通常我更喜欢创建一个导入的目标...

标签: c++ cmake build linker configuration-files


【解决方案1】:

如果这个项目/cmake 结构是最佳实践,你能告诉我吗?

没有或无穷无尽的最佳实践,每天都有人发明新的。特别是关于如何构建你的项目,这与 CMake 无关。以您想要的方式构建它,并且您认为它是最好的。你的结构看起来完全没问题。

看看无穷无尽的谷歌搜索结果。 What's a good directory structure for larger C++ projects using Makefile?http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1204r0.html 项目。

至于 CMake 你可以看看终极版的 https://github.com/friendlyanon/cmake-init , https://github.com/cmake-lint/cmake-lint , https://gist.github.com/mbinna/c61dbb39bca0e4fb7d1f73b0d66a4fd1

我应该在哪里使用 link_directories() 和 target_include_directories()。

通常你应该更喜欢target的东西,即target_link_directories而不是非目标。

使用target_include_directories 将路径添加到#include &lt;thishere&gt; 搜索路径。

使用target_link_directories 路径添加到搜索路径target_link_libraries(... this_library_here)。通常你想使用add_library(... IMPORTED),然后是find_library,而不是target_link_directories。见man ld

在您的项目中,没有外部共享 .so 也没有静态 .a 库。我完全没有理由使用link_directories

如何保持我的代码库整洁并编译我的项目?

好吧,您可以努力工作并经常清理您的项目。记住定期锻炼、睡眠和健康饮食。


而不是set(CMAKE_CXX_STANDARD 11) 更喜欢target_set_properties(. .. CXX_STANDARD 11)

【讨论】:

  • 非常感谢!只是一件小事:在脚注中,你的意思是set_target_properties吗?
  • 此外@KamilCuk,你会说find_librarytarget_link_directories 更好吗?如果是,为什么?如果我看起来很迂腐,我很抱歉,但我发现 CMake 文档没有提供真正的最佳实践。
  • did you mean set_target_properties?find_library is better than target_link_directories? 确保该库确实存在,并且您链接到正确的库。很少需要导入 20 个库 - 通常是一个第三方库。
  • 非常感谢,这很有意义。这是处理导入库时的最佳实践。在我的项目中,我只用它来模块化编译:实际上,所有的源代码都是我写的,所以我没有“导入”的库。我简单地为每个子目录创建一个库,然后将所有内容链接到主可执行文件。在这种情况下,我认为target_link_libraries 是最好的选择,我什至不需要target_link_directories,因为该位置由CMake 管理。
猜你喜欢
  • 1970-01-01
  • 2019-10-13
  • 1970-01-01
  • 1970-01-01
  • 2014-07-09
  • 1970-01-01
  • 1970-01-01
  • 2016-09-17
  • 1970-01-01
相关资源
最近更新 更多