前两篇博客弄明白了cmake的基本command 和variable 。
现在看看别人怎么写CMakeLists.txt 的。
下面是美国德克萨斯大学(奥斯汀分校)的一个研究生写的,源码在github上。
cmake_minimum_required(VERSION 2.8)
project(UTAustinVillaBase CXX C)
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/)
find_package(Threads REQUIRED)
find_package(Boost COMPONENTS system REQUIRED)
find_package(Rcssnet3d REQUIRED)
if(NOT CMAKE_BUILD_TYPE)
message(STATUS "No build type selected, default to Release")
set (CMAKE_BUILD_TYPE Release)
endif(NOT CMAKE_BUILD_TYPE)
if(NOT CMAKE_CXX_FLAGS)
set(CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-unused ")
endif(NOT CMAKE_CXX_FLAGS)
set(CORE_PATH utwalk)
include_directories(
${CORE_PATH}
${RCSSNET3D_INCLUDE_DIR}
)
set(CORE_FILES
${CORE_PATH}/MotionCore.cpp
${CORE_PATH}/Module.cpp
${CORE_PATH}/common/NMatrix.cpp
${CORE_PATH}/math/MVTools.cpp
${CORE_PATH}/math/RotationMatrix.cpp
${CORE_PATH}/memory/Lock.cpp
${CORE_PATH}/memory/Logger.cpp
${CORE_PATH}/memory/Memory.cpp
${CORE_PATH}/memory/MemoryBlock.cpp
${CORE_PATH}/memory/PrivateMemory.cpp
${CORE_PATH}/memory/SharedMemory.cpp
${CORE_PATH}/motion/MotionModule.cpp
${CORE_PATH}/motion/UTWalkEngine.cpp
${CORE_PATH}/sensor/SensorModule.cpp
${CORE_PATH}/sensor/InertialFilter.cpp
${CORE_PATH}/kinematics/InverseKinematics.cpp
${CORE_PATH}/kinematics/ForwardKinematics.cpp
${CORE_PATH}/kinematics/KinematicsModule.cpp
${CORE_PATH}/math/Geometry.cpp
${CORE_PATH}/common/PIDController.cpp
${CORE_PATH}/motion/WalkEngineParameters.cpp
)
set(SRCS
main.cc
behaviors/behavior.cc
behaviors/naobehavior.cc
behaviors/checkfall.cc
behaviors/kicking.cc
behaviors/strategy.cc
behaviors/pkbehaviors.cc
behaviors/gazebobehavior.cc
servercomm/primitives.cc
parser/parser.cc
math/hctmatrix.cc
math/vecposition.cc
math/Geometry.cc
worldmodel/worldmodel.cc
bodymodel/bodymodel.cc
particlefilter/PFLocalization.cc
particlefilter/Particle.cc
skills/skill.cc
skills/curve3d.cc
ikfast/ikfast.cpp
headers/headers.cc
audio/audio.cc
rvdraw/rvdraw.cc
${CORE_FILES}
kalman/BallKF.cpp
kalman/PlayerKF.cpp
kalman/OrigKalmanFilter.cpp
optimization/optimizationbehaviors.cc
)
add_executable(agentspark
${SRCS}
)
target_link_libraries(agentspark
${RCSSNET3D_LIBRARY}
${Boost_SYSTEM_LIBRARY}
dl
${CMAKE_THREAD_LIBS_INIT}
rt
)
如果从头读到这,都没有问题。那么,说明你的水平已不是小学水平了,就不用往下看了==#
1. project
project(UTAustinVillaBase CXX C)
这个project和之前我们写的project有点不同,它多了两个参数 CXX 和 C
CXX是语言,表示C/C++,C是语言名 指代前面的CXX
帮助文档的解释:
Set a name, version, and enable languages for the entire project.
project(<PROJECT-NAME> [LANGUAGES] [<language-name>...])
Optionally you can specify which languages your project supports.
Example languages are ``C``, ``CXX`` (i.e. C++), ``Fortran``, etc.
By default ``C`` and ``CXX`` are enabled if no language options are
given.
注:默认就是CXX,看来UT Austin大佬多此一举了==
2. CMAKE_MODULE_PATH
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/)
${CMAKE_SOURCE_DIR}/cmake/ 这个路径就是当前项目
顶层目录下的cmake目录
之所以把这个cmake目录加到CMAKE_MODULE_PATH中,是因为,有一个module(Rcssnet3d)不在cmake自带的Modules路径下(不在默认的CMAKE_MODULE_PATH中)。Rcssnet3d是UT Austin自己写的module,要想让自己写的module能被find_package()找到,必须把它添加到CMAKE_MODULE_PATH。
帮助文档:
List of directories to search for CMake modules. 说明CMAKE_MODULE_PATH是一个目录列表。
Commands like include() and find_package() search for files indirectories listed by this variable before checking the defaultmodules that come with CMake.
3. find_package()
find_package(Threads REQUIRED)
find_package(Boost COMPONENTS system REQUIRED)
find_package(Rcssnet3d REQUIRED)
这三个find_package(),我们知道是找包(module,第三方库)的,
其中Threads 和Boost 都在/usr/share/cmake-3.5/Modules中,Rcssnet3d在<project_path>/cmake中。
那么,REQUIRED和COMPONENTS是什么呢?
帮助文档:
find_package(<package> [version] [EXACT] [QUIET] [MODULE]
[REQUIRED] [[COMPONENTS] [components...]]
[OPTIONAL_COMPONENTS components...]
[NO_POLICY_SCOPE])
Finds and loads settings from an external project. ``<package>_FOUND``
will be set to indicate whether the package was found. When the
package is found package-specific information is provided through
variables and :ref:`Imported Targets` documented by the package itself. The
``QUIET`` option disables messages if the package cannot be found. The
``MODULE`` option disables the second signature documented below. The
``REQUIRED`` option stops processing with an error message if the package
cannot be found.
REQUIRED参数作用:在package 没有找到的情况下,停止处理并报错。
A package-specific list of required components may be listed after the
``COMPONENTS`` option (or after the ``REQUIRED`` option if present).
Additional optional components may be listed after
``OPTIONAL_COMPONENTS``. Available components and their influence on
whether a package is considered to be found are defined by the target
package.
COMPONENTS参数作用:找 指定包(package-specific)的组件(required components)。不要整个包,要组件。
vim /usr/share/cmake-3.5/Modules/FindBoost.cmake,看看Boost关于system组件的介绍。
Implicit dependencies such as Boost::filesystem
requiring Boost::system will be automatically detected and satisfied,
even if system is not specified when using find_package
and if Boost::system is not added to target_link_libraries.
If using Boost::thread, then Thread::Thread will also be added automatically.
这里自动检测并满足是什么鬼????身为小白的我,心很累==。。。
有时间再学习Boost库,一样一样学,啊...
4. if(Not CMAKE_BUILD_TYPE)
if(NOT CMAKE_BUILD_TYPE)
message(STATUS "No build type selected, default to Release")
set (CMAKE_BUILD_TYPE Release)
endif(NOT CMAKE_BUILD_TYPE)
if 简介:
if(expression)
# then section.
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
...
elseif(expression2)
# elseif section.
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
...
else(expression3)
# else section.
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
...
endif(expression)
一个if() 必须对应一个 endif() 。if嵌套在if里,也必须要有对应的endif。
elseif() 不需要对应。else() 不需要对应。
帮助文档:
Evaluates the given expression. If the result is true, the commands
in the THEN section are invoked. Otherwise, the commands in the else
section are invoked. The elseif and else sections are optional. You
may have multiple elseif clauses(从句). Note that the expression in the
else and endif clause is optional.
Long expressions can be used and there is a traditional order of precedence(优先权).
Parenthetical expressions(插入的表达式) are evaluated first followed by unary(一元的)
tests such as ``EXISTS``, ``COMMAND``, and ``DEFINED``.
Then any binary tests such as ``EQUAL``, ``LESS``, ``GREATER``,
``STRLESS``, ``STRGREATER``, ``STREQUAL``, and ``MATCHES`` will be evaluated.
Then boolean ``NOT`` operators and finally boolean ``AND`` and
then ``OR`` operators will be evaluated.
Possible expressions are:
``if(<constant>)``
True if the constant is ``1``, ``ON``, ``YES``, ``TRUE``, ``Y``,
or a non-zero number. False if the constant is ``0``, ``OFF``,
``NO``, ``FALSE``, ``N``, ``IGNORE``, ``NOTFOUND``, the empty string,
or ends in the suffix ``-NOTFOUND``. Named boolean constants are
case-insensitive. If the argument is not one of these specific
constants, it is treated as a variable or string and the following
signature is used.
``if(<variable|string>)``
True if given a variable that is defined to a value that is not a false
constant(变量被定义了,且定义值为真). False otherwise.
(Note macro arguments are not variables.)
``if(NOT <expression>)``
在if(NOT CMAKE_BUILD_TYPE) 里,CMAKE_BUILD_TYPE是cmake自带的变量,默认为empty。
这里set (CMAKE_BUILD_TYPE Release) 把CMAKE_BUILD_TYPE设置为Release(发布)。
CMAKE_BUILD_TYPE可取的值(了解即可):
empty, ``Debug``, ``Release``, ``RelWithDebInfo`` and ``MinSizeRel``.
再看看这里的message:比之前多了一个STATUS。
message([<mode>] "message to display" ...)
The optional ``<mode>`` keyword determines the type of message:
(none) = Important information
STATUS = Incidental(附带的,次要的) information
多了一个STATUS,在输出效果上看,就多了两个dash(-)。
5. CMAKE_CXX_FLAGS
if(NOT CMAKE_CXX_FLAGS)
set(CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-unused")
endif(NOT CMAKE_CXX_FLAGS)
CMAKE_CXX_FLAGS属于CMAKE_<LANG>_FLAGS变量。
CMAKE_CXX_FLAGS 可以取哪些值,我还不清楚,只知道它可以把compiler flags设置为C++。(在网上找了半天,都没找到关于这个变量详细说明)。
想要在CMakeLists.txt 里设置C++支持C++11标准,可以用以下语句[1]:
#只要这一条语句,不用设置CMAKE_CXX_FLAGS
set (CMAKE_CXX_STANDARD 11)
奇怪的是,set (CMAKE_CXX_STANDARD 11)加到ut的CMakeLists中,会报关于share_ptr错。
6. include_directories
set(CORE_PATH utwalk)
include_directories(
${CORE_PATH}
${RCSSNET3D_INCLUDE_DIR})
${CORE_PATH}就是顶层目录下的utwalk目录,utwalk目录下是一些关于机器人行走的源码。
${RCSSNET3D_INCLUDE_DIR} 是在module里定义的(<name>_INCLUDE_DIR),
find_package(Rcssnet3d REQUIRED)以后,就可以直接拿来用了。
FindRcssnet3d.cmake里有这样一句说明:RCSSNET3D_INCLUDE_DIR - where to find rcssnet include files
7. 其他内容
最后两个长长的set 定义了两个列表,里面都是源文件。
add_executable(agentspark ${SRCS})
target_link_libraries(agentspark
${RCSSNET3D_LIBRARY}
${Boost_SYSTEM_LIBRARY}
dl
${CMAKE_THREAD_LIBS_INIT}
rt
)
把${SRCS} 下的所有源文件编译成一个可执行文件agentspark,
把五个库链接到agentspark。
8. 总结
现在看懂CMakeLists 文件已经没问题了。
下一步该考虑:
- 如何自己写module,使用find_package()调用自己写的module
- CMakeCache.txt 查看和编辑
- cmake 的单元测试部分 ctest