最简单但是完整的cmake例子

不知何故,我完全被CMake的工作困惑。 每次我想我越来越接近了解CMake是如何写的,在我读到的下一个例子中就消失了。 所有我想知道的是,我应该如何构build我的项目,以便我的CMake将来需要最less的维护。 例如,我不想在我的src树中添加一个新文件夹时更新我的​​CMakeList.txt,这个文件夹与所有其他src文件夹完全一样。

这就是我想象我的项目结构的方式,但是这只是一个例子。 如果推荐的方式不同,请告诉我,并告诉我如何去做。

myProject src/ module1/ module1.h module1.cpp module2/ [...] main.cpp test/ test1.cpp resources/ file.png bin [execute cmake ..] 

顺便说一下,我的程序知道资源在哪里是很重要的。 我想知道推荐的资源pipe理方式。 我不想通过“../resources/file.png”来访问我的资源

经过一番研究,我现在已经有了我自己的最简单但完整的cmake例子。 在这里,它试图涵盖大部分的基础知识,包括资源和包装。

有一点非标准是资源处理。 默认情况下,cmake希望把它们放在/ usr / share /,/ usr / local / share /和windows上的一些等价物上。 我想要一个简单的zip / tar.gz,你可以从任何地方提取并运行。 因此资源相对于可执行文件被加载。

理解cmake命令的基本规则是以下语法: <function-name>(<arg1> [<arg2> ...])不含逗号或半色。 每个参数都是一个string。 foobar(3.0)foobar("3.0")是相同的。 你可以设置列表/variablesset(args arg1 arg2) 。 使用这个variables集foobar(${args})foobar(arg1 arg2)实际上是相同的。 一个不存在的variables相当于一个空的列表。 列表在内部只是一个用分号分隔string的string。 因此,只有一个元素的列表根据定义只是该元素,不会发生装箱。 variables是全球性的。 内build函数提供某种forms的命名参数 ,因为它们在参数列表中希望使用一些像PUBLICDESTINATION这样的ID来对参数进行分组。 但是这不是一种语言function,这些ID也只是string,并由函数实现进行分析。

你可以克隆从github的一切

 cmake_minimum_required(VERSION 3.0) project(example_project) ############################################################################### ## file globbing ############################################################## ############################################################################### # these instructions search the directory tree when cmake is # invoked and put all files that match the pattern in the variables # `sources` and `data` file(GLOB_RECURSE sources src/main/*.cpp src/main/*.h) file(GLOB_RECURSE sources_test src/test/*.cpp) file(GLOB_RECURSE data resources/*) # you can use set(sources src/main.cpp) etc if you don't want to # use globing to find files automatically ############################################################################### ## target definitions ######################################################### ############################################################################### # add the data to the target, so it becomes visible in some IDE add_executable(example ${sources} ${data}) # just for example add some compiler flags target_compile_options(example PUBLIC -std=c++1y -Wall -Wfloat-conversion) # this lets me include files relative to the root src dir with a <> pair target_include_directories(example PUBLIC src/main) # this copies all resource files in the build directory # we need this, because we want to work with paths relative to the executable file(COPY ${data} DESTINATION resources) ############################################################################### ## dependencies ############################################################### ############################################################################### # this defines the variables Boost_LIBRARIES that contain all library names # that we need to link to find_package(Boost 1.36.0 COMPONENTS filesystem system REQUIRED) target_link_libraries(example PUBLIC ${Boost_LIBRARIES} # here you can add any library dependencies ) ############################################################################### ## testing #################################################################### ############################################################################### # this is for our testing framework # we don't add REQUIRED because it's just for testing find_package(GTest) if(GTEST_FOUND) add_executable(unit_tests ${sources_test} ${sources}) # we add this define to prevent collision with the main # this might be better solved by not adding the source with the main to the # testing target target_compile_definitions(unit_tests PUBLIC UNIT_TESTS) # this allows us to use our executable as a link library # therefore we can inherit all compiler options and library dependencies set_target_properties(example PROPERTIES ENABLE_EXPORTS on) target_link_libraries(unit_tests PUBLIC ${GTEST_BOTH_LIBRARIES} example ) target_include_directories(unit_tests PUBLIC ${GTEST_INCLUDE_DIRS} # doesn't do anything on Linux ) endif() ############################################################################### ## packaging ################################################################## ############################################################################### # all install commands get the same destination. this allows us to use paths # relative to the executable. install(TARGETS example DESTINATION example_destination) # this is basically a repeat of the file copy instruction that copies the # resources in the build directory, but here we tell cmake that we want it # in the package install(DIRECTORY resources DESTINATION example_destination) # now comes everything we need, to create a package # there are a lot more variables you can set, and some # you need to set for some package types, but we want to # be minimal here set(CPACK_PACKAGE_NAME "MyExample") set(CPACK_PACKAGE_VERSION "1.0.0") # we don't want to split our program up into several things set(CPACK_MONOLITHIC_INSTALL 1) # This must be last include(CPack) 

最基本但是完整的例子可以在cmake教程中find:

 cmake_minimum_required (VERSION 2.6) project (Tutorial) add_executable(Tutorial tutorial.cxx) 

对于你的项目例子,你可能有:

 cmake_minimum_required (VERSION 2.6) project (MyProject) add_executable(myexec src/module1/module1.cpp src/module2/module2.cpp src/main.cpp) add_executable(mytest test1.cpp) 

对于您的其他问题,还有一种方法是在教程中:创build一个可configuration的头文件,包含在代码中。 为此,使用以下内容创build一个文件configuration.h.in

 #define RESOURCES_PATH "@RESOURCES_PATH@" 

然后在你的CMakeLists.txt添加:

 set(RESOURCES_PATH "${PROJECT_SOURCE_DIR}/resources/" # configure a header file to pass some of the CMake settings # to the source code configure_file ( "${PROJECT_SOURCE_DIR}/configuration.h.in" "${PROJECT_BINARY_DIR}/configuration.h" ) # add the binary tree to the search path for include files # so that we will find TutorialConfig.h include_directories("${PROJECT_BINARY_DIR}") 

最后,在代码中需要path的地方,你可以这样做:

 #include "configuration.h" ... string resourcePath = string(RESOURCE_PATH) + "file.png"; 
Interesting Posts