最简单但最完整的CMake示例

tjrkku2a  于 2022-11-11  发布在  其他
关注(0)|答案(3)|浏览(170)

不知怎么的,我对CMake的工作方式感到很困惑。每当我以为我离理解CMake的编写方式越来越近的时候,我读到的下一个例子就消失了。我想知道的只是,我应该如何组织我的项目,这样我的CMake在未来需要的维护就最少。例如,当我在src树中添加一个新文件夹时,我不想更新我的CMakeList.txt,它的工作原理与所有其他src文件夹完全相同。
这是我设想的项目结构,但请这只是一个例子。如果推荐的方式不同,请告诉我,并告诉我如何做。

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

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

f0brbegy

f0brbegy1#

经过一些研究,我现在有了我自己版本的最简单但最完整的CMake示例。在这里,它试图涵盖大部分的基础知识,包括资源和打包。
它做的一件非标准的事情是资源处理。默认情况下,CMake希望将它们放在/usr/share/,/usr/local/share/和windows上的等效文件中。我希望有一个简单的zip/tar.gz,你可以在任何地方提取并运行。因此,资源是相对于可执行文件加载的。
理解CMake命令的基本规则是以下语法:<function-name>(<arg1> [<arg2> ...]),不带逗号或分号。每个参数都是一个字符串。foobar(3.0)foobar("3.0")是相同的。您可以使用set(args arg1 arg2)设置列表/变量。使用此变量集,foobar(${args})foobar(arg1 arg2)实际上是相同的。不存在的变量等效于空列表。列表内部只是一个字符串,用分号分隔元素。因此,一个只有一个元素的列表,根据定义就是这个元素,没有装箱发生。变量是全局的。内置函数提供了某种形式的 * 命名参数 *,因为它们在参数列表中期望一些id,如PUBLICDESTINATION,来对参数进行分组。但这不是一个语言特性,这些id也只是字符串。并由函数实现解析。
您可以从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)

注意:虽然file(GLOB)的上述用法在这里是适当的,但问题特别要求使用一种技术,通过添加新的源文件来最小化对CMakeLists.txt文件的编辑频率,官方文档和对这些专门问题的回答中不鼓励使用这种技术:一个一个一个的

qlvxas9a

qlvxas9a2#

最基本但完整的示例可以在CMake tutorial中找到:

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)

对于您的其他问题,一种方法是在教程中重复:创建一个包含在代码中的可配置头文件。为此,创建一个包含以下内容的文件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}")

最后,在代码中需要路径的地方,可以执行以下操作:


# include "configuration.h"

...

string resourcePath = string(RESOURCE_PATH) + "file.png";
j9per5c4

j9per5c43#

下面我写一个最简单但最完整的CMakeLists.txt文件示例。
Source Code
1.从hello world到跨平台Android/iOS/Web/桌面的教程。
1.每个平台我都发布了一个示例应用程序。
1.通过本人的工作验证了08-cross_platform文件结构
1.它可能不是完美的,但有用&对我自己的团队来说是最好的实践
在那之后,我提供了详细的文件。
如果你有任何问题,你可以联系我,我想解释一下。

相关问题