我正在使用CMake开始一个新的C项目,所以我创建了一个非常类似于我在Python中使用的目录结构(我的“主要”语言)。虽然它编译正确,但我不确定我是以正确的方式做到的。这是目前的结构:
.
├── CMakeLists.txt
├── dist
│ └── # project will be built here, 'cmake ..'
├── extras
│ ├── CMakeLists.txt
│ ├── extra1
│ │ ├── CMakeLists.txt
│ │ ├── extra1.h
│ │ └── extra1.c
│ └── extra2
│ ├── CMakeLists.txt
│ ├── extra2.h
│ └── extra2.c
├── src
│ ├── CMakeLists.txt
│ ├── main.c
│ ├── module1.h
│ ├── module1.c
│ ├── module2.h
│ └── module2.c
└── test
├── CMakeLists.txt
├── test_module1.c
└── test_module2.c
由于所有文件都分布在多个目录中,因此我必须找到一种方法来查找extras
中存在的库以及我需要在src
中测试的库。所以,这些是我的CMakeLists':
cmake_minimum_required(VERSION 2.8)
project(MyProject)
add_definitions(-Wall -std=c99)
# I don't know really why I need this
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/dist)
add_subdirectory(src)
add_subdirectory(test)
add_subdirectory(extras)
enable_testing()
add_test(NAME DoTestModule1 COMMAND TestModule1)
add_test(NAME DoTestModule2 COMMAND TestModule2)
macro(make_library target source)
add_library(${target} ${source})
target_include_directories(${target} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
endmacro(make_library)
make_library(Module1.o module1.c)
make_library(Module2.o module2.c)
macro(make_test target source library)
add_executable(${target} ${source})
target_link_libraries(${target} Libtap.o ${library})
target_include_directories(${target} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
endmacro(make_test)
make_test(TestModule1 test_module1.c Module1.o)
make_test(TestModule2 test_module2.c Module2.o)
# Hopefully you'll never need to change this file
foreach(subdir ${SUBDIRS})
add_subdirectory(${subdir})
endforeach()
add_library(Libtap.o tap.c)
target_include_directories(Libtap.o PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
所以,现在问题:我担心的原因是这个设置会为我正在使用的每个文件创建一个“公共”库,包括额外的库(这不是分布)。如果我在src
中有10个库,extras
中有4个依赖项(包括我用来测试的libtap)和至少相同数量的测试文件,我最终将会编译24个伪影。
add_definitions
向编译器添加标志的正确方法吗?答案 0 :(得分:1)
有没有更好的方法将库公开给链接?
不,这似乎很好。
但是,您可能需要重新考虑创建静态库的粒度。例如,如果除测试之外的所有应用程序仅组合使用Module1
和Module2
,您可能希望将它们合并到单个库目标中。当然,测试将链接到他们不使用的组件部分,但这对于降低构建复杂性来说是一个很小的代价。
我还没有编译“主要”,什么是正确的配置 那个?
将它添加到src/CMakeLists.txt
也没有错:
add_executable(my_main main.c)
target_link_libraries(my_main Module1.o Module2.o)
add_definitions是向编译器添加标志的正确方法吗?
它可以用于此目的,但可能并不理想。
较新的CMake脚本为此需要首选target_compile_options
命令。这里唯一的缺点是,如果要为项目中的所有目标重用相同的编译选项,则还必须对每个目标执行相同的target_compile_options
调用。请参阅以下有关如何解决此问题的提示。
如何让这个结构更干?
首先,与大多数程序代码不同,冗余在构建系统代码中通常不是一个大问题。值得注意的是,这些东西会妨碍可维护性。回到之前的常见编译器选项:如果您希望将来更改这些标志,您可能希望为每个目标更改它们。这里集中有关选项的知识是有意义的:在顶层引入function
,为给定目标设置选项,或将选项存储到全局变量。
在任何一种情况下,您都必须为每个目标编写一行才能获得该选项,但之后不会产生任何维护开销。作为一个额外的好处,如果你真的需要在将来只更改一个目标的选项,你仍然可以灵活地这样做。
不过,请注意不要过度工程。构建系统首先应该完成任务。
如果设置它的最简单方法意味着你复制/粘贴很多,那就去吧!如果在维护期间发现你有一些真正不必要的冗余,你可以随时重构。
你越早接受你的CMake脚本永远不会像程序代码一样漂亮的事实,那就更好了;)
最后一个小的挑剔:避免给你的目标名称扩展名。也就是说,而不是
add_library(Libtap.o tap.c)
考虑
add_library(Libtap tap.c)
CMake会根据目标平台自动附加正确的文件。