我正在使用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
Run Code Online (Sandbox Code Playgroud)
由于所有文件都分布在多个目录中,因此我必须找到一种方法来查找存在的库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)
Run Code Online (Sandbox Code Playgroud)
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)
Run Code Online (Sandbox Code Playgroud)
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)
Run Code Online (Sandbox Code Playgroud)
# Hopefully you'll never need to change this file
foreach(subdir ${SUBDIRS})
add_subdirectory(${subdir})
endforeach()
Run Code Online (Sandbox Code Playgroud)
add_library(Libtap.o tap.c)
target_include_directories(Libtap.o PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
Run Code Online (Sandbox Code Playgroud)
所以,现在的问题是:我担心的原因是这个设置会为我正在使用的每个文件创建一个"公共"库,包括额外的库(不应该分发).如果我有10个库src,4个依赖项extras(包括libtap,我用来测试)和至少相同数量的测试文件,我最终会得到24个编译工件.
add_definitions向编译器添加标志的正确方法吗?有没有更好的方法来公开库以进行链接?
不,这看起来不错。
然而,您可能需要重新考虑创建静态库的粒度。例如,如果除测试之外的所有应用程序都只会组合使用Module1和Module2,您可能希望将它们合并到单个库目标中。当然,测试将链接到他们不使用的组件部分,但这对于降低构建复杂性来说只是一个很小的代价。
我还没有编译“main”,正确的配置是什么?
src/CMakeLists.txt将其添加到以下也没有问题:
add_executable(my_main main.c)
target_link_libraries(my_main Module1.o Module2.o)
Run Code Online (Sandbox Code Playgroud)
add_definitions 是向编译器添加标志的正确方法吗?
它可以用于此目的,但可能并不理想。
较新的 CMake 脚本应该更喜欢使用该target_compile_options命令来实现此目的。这里唯一的缺点是,如果您想为项目中的所有目标重用相同的编译选项,则还必须target_compile_options对每个目标进行相同的调用。有关如何解决此问题的提示,请参阅下文。
我怎样才能使这个结构更加干燥?
首先,与大多数程序代码不同,冗余在构建系统代码中通常不是一个大问题。这里值得注意的是那些妨碍可维护性的东西。回到之前的常见编译器选项:如果您将来想更改这些标志,则可能需要为每个目标更改它们。在这里,集中有关选项的知识是有意义的:要么function在顶层引入为给定目标设置选项,要么将选项存储到全局变量。
在任何一种情况下,您都必须为每个目标编写一行才能获得该选项,但此后不会产生任何维护开销。作为额外的好处,如果您将来实际上只需要更改一个目标的选项,您仍然可以灵活地这样做。
不过,请注意不要过度设计。构建系统首先应该把事情做好。
如果最简单的设置方法意味着您需要进行大量复制/粘贴,那么就采用它吧!如果在以后的维护过程中发现确实存在一些不必要的冗余,那么您始终可以进行重构。
您越早接受这样一个事实,即您的 CMake 脚本永远不会像您的程序代码一样漂亮,就越好;)
最后有一点挑剔:避免给你的目标名称提供扩展名。也就是说,而不是
add_library(Libtap.o tap.c)
考虑
add_library(Libtap tap.c)
无论如何,CMake 都会根据目标平台自动附加正确的文件结尾。
| 归档时间: |
|
| 查看次数: |
480 次 |
| 最近记录: |