最简单但完整的CMake示例 [英] Most simple but complete CMake example

查看:77
本文介绍了最简单但完整的CMake示例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对CMake的工作方式完全感到困惑。每当我认为我越来越了解CMake的含义时,在我阅读的下一个示例中,它就消失了。我想知道的是,我应该如何构建我的项目,以便将来CMake所需的维护最少。例如,当我在src树中添加新文件夹时,我不想更新CMakeList.txt,该文件夹的工作方式与所有其他src文件夹完全一样。

Somehow I am totally confused by how CMake works. Every time I think that I am getting closer to understand how CMake is meant to be written, it vanishes in the next example I read. All I want to know is, how should I structure my project, so that my CMake requires the least amount of maintainance in the future. For example, I don't want to update my CMakeList.txt when I am adding a new folder in my src tree, that works exactly like all other src folders.

这就是我对项目结构的想象,但是请仅作为示例。如果建议的方法不同,请告诉我,并告诉我该怎么做。

This is how I imagine my project's structure, but please this is only an example. If the recommended way differs, please tell me, and tell me how to do it.

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

顺便说一句,重要的是我的程序必须知道资源在哪里。我想知道推荐的资源管理方式。经过一些研究后,我不想使用 ../ resources / file.png

By the way, it is important that my program knows where the resources are. I would like to know the recommended way of managing resources. I do not want to access my resources with "../resources/file.png"

推荐答案

访问我的资源我自己的最简单但完整的cmake示例版本。就在这里,它试图涵盖大多数基础知识,包括资源和包装。

after some research I have now my own version of the most simple but complete cmake example. Here it is, and it tries to cover most of the basics, including resources and packaging.

它做的非标准的一件事就是资源处理。默认情况下,cmake希望将它们放在/ usr / share /,/ usr / local / share /以及Windows上的等效目录中。我想要一个简单的zip / tar.gz,您可以将其提取到任何地方并运行。因此,资源是相对于可执行文件加载的。

one thing it does non-standard is resource handling. By default cmake wants to put them in /usr/share/, /usr/local/share/ and something equivalent on windows. I wanted to have a simple zip/tar.gz that you can extract anywhere and run. Therefore resources are loaded relative to the executable.

了解cmake命令的基本规则是以下语法:
< function-名称>(< arg1> [< arg2> ...]),不带逗号或半彩色。每个参数都是一个字符串。 foobar(3.0) foobar( 3.0)是相同的。您可以使用 set(args arg1 arg2)设置列表/变量。使用此变量集, foobar($ {args}) foobar(arg1 arg2)实际上是相同的。不存在的变量等效于一个空列表。列表在内部只是一个带有分号的字符串,用于分隔元素。因此,根据定义,仅包含一个元素的列表就是该元素,不会进行装箱。变量是全局的。内置函数提供某种形式的命名自变量,因为它们期望某些ID,例如 PUBLIC DESTINATION 在其参数列表中,以对参数进行分组。但这不是语言功能,这些ID也是字符串,并由函数实现进行解析。

the basic rule to understand cmake commands is the following syntax: <function-name>(<arg1> [<arg2> ...]) without comma or semicolor. Each argument is a string. foobar(3.0) and foobar("3.0") is the same. you can set lists/variables with set(args arg1 arg2). With this variable set foobar(${args}) and foobar(arg1 arg2) are effectively the same. A non existent variable is equivalent to an empty list. A list is internally just a string with semicolons to separate the elements. Therefore a list with just one element is by definition just that element, no boxing takes place. Variables are global. Builtin functions offer some form of named arguments by the fact that they expect some ids like PUBLIC or DESTINATION in their argument list, to group the arguments. But that's not a language feature, those ids are also just strings, and parsed by the function implementation.

您可以从 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示例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆