【CMake】CMake语法与示例

CMake官方文档

为何用Cmake?

在linux环境编写程序,因没有类似于visual studio、vs code等IDE(集成开发环境),那么如何编译、运行程序呢?一种方法是编写makefile文件,用makefile文件管理程序脚本之间的相互依赖关系,其语法相对比较复杂。另一种有效的方法就是利用cmake工具,自动生成makefile文件。

CMake是什么?

CMake是一个跨平台的安装(编译)工具,可以用简单的语句来描述所有平台的安装(编译过程)。Linux/Ubuntu上基本都预先安装好了cmake工具,用 sudo apt-get install 也可以自动安装。要使用cmake必须在工程的每个文件夹中都编写CMakeLists.txt,尤其注意C、M、L是大写,并且是复数形式。

CMake编译流程

编写文件CMakeLists.txt
执行命令“cmake PATH”或者“ccmake PATH”生成Makefile (PATH是CMakeLists.txt所在的目录)
使用make命令进行编译源码生成可执行程序或共享库(so(shared object))

cmake 指向CMakeLists.txt所在的目录,例如 cmake … 表示CMakeLists.txt在当前目录的上一级目录。cmake后会生成很多编译的中间文件以及makefile文件,所以一般建议新建一个新的目录,专门用来编译

mkdir build
cd build
cmake ..
make

make根据生成makefile文件,编译程序

示例

cmake_minimum_required

设置项目所需的cmake最低版本。

CMAKE_MINIMUM_REQUIRED(VERSION <min>[...<max>] [FATAL_ERROR])
---
cmake_minimum_required(VERSION 3.10)

project

PROJECT(projectname [CXX] [C] [Java])
---
project(proj_name LANGUAGES CXX) //proj_name是自定义的

定义工程名称并指定工程支持的语言;

隐式定义了两个cmake变量:<projectname>_BINARY_DIR以及<projectname>_SOURCE_DIR ,如果采用的是内部编译,两个变量指的将是工程所在的路径,如果是外部编译,两者所指代的内容会有所不同。

报错:CMake Error: CMAKE_LANGUAGE_COMPILER not set, after EnableLanguage
– Configuring incomplete, errors occurred!
原因: LANGUAGES误写成了LANGUAGE

option

CMake中的option用于把持编译流程,相称于C语言中的宏前提编译。
正如他名字,此命令为用户提供选择ON/OFF的选项

option(<variable> "<help_text>" [value])
第一个参数<variable>为选项变量名
第二个参数<help_text>为选项的文字描述便于只管描述其用途,类似于注释
第三个参数[value]是选项的默认值,只能为ON/OFF,如果不设定默认值则为OFF。如果已经为此变量赋值则option命令会被忽略
---
option(WITH_CUDA "Build with CUDA support" OFF)
option(BUILD_TESTS "Build tests" ON)
option(BUILD_EXAMPLES "Build examples" ON)
//上述代码定义了三个选项:WITH_CUDA、BUILD_TESTS和BUILD_EXAMPLES,分别用于控制是否加入CUDA支持、是否编译测试代码以及是否编译示例代码。

在CMakeLists.txt中读取CMake Option的值非常简单,使用${OPTION_NAME}即可,比如:

if(${WITH_CUDA})
    # do something with CUDA support
endif()

if(${BUILD_TESTS})
    # do something with tests
endif()

if(${BUILD_EXAMPLES})
    # do something with examples
endif()

深入解析CMake Option的使用

add_definitions

add_definitions(-DFOO -DBAR ...)
---
add_definitions(-Dtx2)//就是添加了一个tx2的宏定义

但是好像add_definitions没法通过cmake命令行来进行控制。所以这里在cmake中再声明一个option进行选择,如下:

cmake_minimum_required(VERSION 3.2)
project(test)

option(ONTX2 "build project on tx2" OFF)
IF(ONTX2)
    add_definitions(-Dtx2)
ENDIF(ONTX2)

set(source net.cpp)
add_executable(test ${source})

编译的时候通过以下两种方式进行选择:

cmake -DONTX2=1 ..    //注意是-Dxxxx,有个-D的前缀
or
cmake -DONTX2=0 ..

【c++】——通过cmake定义宏add_definitions

add_subdirectory

ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
---
add_subdirectory(src)

用于向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制存放的位置。EXCLUDE_FROM_ALL 参数的含义是将这个目录从编译过程中排除,比如,工程的 example,可能就需要工程构建完成后,再进入 example 目录单独进行构建(当然,你也可以通过定义依赖来解决此类问题)。

利用cmake的add_subdirectory管理内部和外部库

include_directories

INCLUDE_DIRECTORIES([AFTER|BEFORE] [SYSTEM] dir1 dir2 ...)
---
include_directories(include_1 include_2)

添加头文件路径。这条指令可以用来向工程添加多个特定的头文件路径,路径之间用空格分割,如果路径中包含了空格,可以使用双引号将它括起来,默认的行为是追加到当前的头文件搜索路径的后面,你可以通过两种方式来进行控制搜索路径添加的方式:

  1. CMAKE_INCLUDE_DIRECTORIES_BEFORE,通过 SET 这个 cmake 变量为on,可以将添加的头文件搜索路径放在已有路径的前面。
  2. 通过 AFTER 或者 BEFORE 参数,也可以控制是追加还是置前。

add_library

ADD_LIBRARY(libname [SHARED|STATIC|MODULE] [EXCLUDE_FROM_ALL] source1 source2 ... sourceN)
---
add_library(hello SHARED ./src/printhello.cpp ./src/factorial.cpp)

此指令的作用为构建库,库的类型有三种:SHARED(共享库【动态库】),STATIC(静态库),MODULE(模块);

假如创建共享库libhello.solibname项只需写hello,而不需要写全libhello.so,cmake 系统会自动为你生成libhello.X。(共享库的后缀为.so,静态库的后缀为.a

aux_source_directory

AUX_SOURCE_DIRECTORY(dir VARIABLE)
---
aux_source_directory(. SRC_LIST) //.代表当前目录
message(STATUS "source code : " ${SRC_LIST})
add_executable(main ${SRC_LIST})

发现一个目录下所有的源代码文件,并将文件路径列表存储在一个变量中,这个指令临时被用来自动构建源文件列表。因为目前 cmake 还不能自动发现新添加的源文件。
比如:AUX_SOURCE_DIRECTORY(. SRC_LIST)ADD_EXECUTABLE(main ${SRC_LIST}

file

Reading
  file(READ <filename> <out-var> [...])
  file(STRINGS <filename> <out-var> [...])
  file(<HASH> <filename> <out-var>)
  file(TIMESTAMP <filename> <out-var> [...])
 
Writing
  file({WRITE | APPEND} <filename> <content>...)
  file({TOUCH | TOUCH_NOCREATE} [<file>...])
  file(GENERATE OUTPUT <output-file> [...])
 
Filesystem
  file({GLOB | GLOB_RECURSE} <out-var> [...] [<globbing-expr>...])
  file(RENAME <oldname> <newname>)
  file({REMOVE | REMOVE_RECURSE } [<files>...])
  file(MAKE_DIRECTORY [<dir>...])
  file({COPY | INSTALL} <file>... DESTINATION <dir> [...])
  file(SIZE <filename> <out-var>)
  file(READ_SYMLINK <linkname> <out-var>)
  file(CREATE_LINK <original> <linkname> [...])
 
Path Conversion
  file(RELATIVE_PATH <out-var> <directory> <file>)
  file({TO_CMAKE_PATH | TO_NATIVE_PATH} <path> <out-var>)
 
Transfer
  file(DOWNLOAD <url> <file> [...])
  file(UPLOAD <file> <url> [...])
 
Locking
  file(LOCK <path> [...])
file(GLOB variable [RELATIVE path] [globbingexpressions]...)
---
file(GLOB C_SOURCES ./src/*.c)
file(GLOB CPP_SOURCES ./src/*.cpp)
set(SOURCES ${C_SOURCES} ${CPP_SOURCES})
add_executable(test ${SOURCES})

GLOB 会产生一个由所有匹配globbing表达式的文件组成的列表,并将其保存到变量中。Globbing 表达式与正则表达式类似,但更简单。如果指定了RELATIVE标记,返回的结果将是与指定的路径相对的路径构成的列表。
(通常不推荐使用GLOB命令来从源码树中收集源文件列表。原因是:如果CMakeLists.txt文件没有改变,即便在该源码树中添加或删除文件,产生的构建系统也不会知道何时该要求CMake重新产生构建文件。)

意思就是在该源码树中添加或删除了文件之后,识别不到。比如添加或删除了文件之后,直接make是会报错的,需要重新cmake ..之后,再make

globbing 表达式包括:

   *.cxx       - match all files with extension cxx
   *.vt?       - match all files with extension vta,...,vtz
   f[3-5].txt  - match files f3.txt,f4.txt, f5.txt

cmake的file命令

add_executable

add_executable(main main.cpp)

target_link_libraries

target_link_libraries(main hello)

target_include_directories

target_include_directories(<target> [SYSTEM] [AFTER|BEFORE]
  <INTERFACE|PUBLIC|PRIVATE> [items1...]
  [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
---
target_include_directories(hello
  PUBLIC
  ${CMAKE_CURRENT_LIST_DIR}/include
)

该命令可以指定目标(exe或者so文件)需要包含的头文件路径

命名的<目标>必须是由add_executable()add_library()之类的命令创建的,并且不能是ALIAS目标。通过显式地使用AFTERBEFORE,就可以在附加和预挂之间进行选择,而不是依赖默认值。

需要INTERFACE、PUBLICPRIVATE关键字来指定以下参数的范围。PRIVATE和PUBLIC项将填充的INCLUDE_DIRECTORIES属性。PUBLIC和INTERFACE项将填充的INTERFACE_INCLUDE_DIRECTORIES属性。具体的介绍详见private,public,interface的使用

同时,target_include_directories的参数可以使用语法为$<…>的“生成器表达式”。

target_include_directories() 的功能完全可以使用 include_directories() 实现。但是我还是建议使用 target_include_directories()。为什么?保持清晰!
include_directories(header-dir) 是一个全局包含,向下传递。什么意思呢?就是说如果某个目录的 CMakeLists.txt 中使用了该指令,其下所有的子目录默认也包含了header-dir 目录。

注意

target_include_directories()必须在add_executable()命令之后,这样才能识别到add_executable()的执行文件名,不然会报错:

CMake Error at src/CMakeLists.txt:2 (target_include_directories):
Cannot specify include directories for target "spd_test_exe" which is not
built by this project.

message

MESSAGE([SEND_ERROR | STATUS | FATAL_ERROR] "message to display"...)
---
message(STATUS "This is BINARY dir" ${xxx_BINARY_DIR})   # 这里是cmake默认隐式帮忙定义的xxx_BINARY_DIR 和 xxx_SOURCE_DIR,xxx代表proj_name
message(STATUS "This is SOURCE dir" ${xxx_SOURCE_DIR})   # message是用于向终端输出信息。 

message用于向终端输出用户定义的信息。

包含以下三种类型:

- SEND_ERROR:产生错误,生成过程被跳过
- STATUS:输出前缀为--的信息
- FATAL_ERROR:立即终止所有的CMake过程

find_file

FIND_FILE(<VAR> name1 [path1 path2 ...] [DOC "docstring"])
---
set(CMAKE_INCLUDE_PATH /home/xxx/Desktop/makefile_tuto/demo4_dynamic_lib/src/include)
find_file(MY_FUNC functions.h )
message(STATUS "MY_FUNC: " ${MY_FUNC}) 
if (MY_FUNC)
  message(STATUS "Found header file: ${MY_FUNC}")
else()
  message(STATUS "Could not find functions.h")
endif()
---
output:
-- MY_FUNC: /home/xxx/Desktop/makefile_tuto/demo4_dynamic_lib/src/include/functions.h
-- Found header file: /home/xxx/Desktop/makefile_tuto/demo4_dynamic_lib/src/include/functions.h

该命令用于查找指定文件的完整路径。
创建一个名为< VAR >的缓存条目(如果指定了NO_CACHE,则是一个普通变量)来存储此命令的结果。
如果找到文件的完整路径,则结果存储在变量中,并且搜索不会重复,除非该变量被清除。
如果没有找到,结果将是< VAR >-NOTFOUND

add_compile_options

add_compile_options(-Wall -g -std=c++11)
---
make之后会显示warning:
/home/xxx/Desktop/makefile_tuto/demo4_dynamic_lib/src/src/printhello.cpp: In function ‘void printhello():
/home/xxx/Desktop/makefile_tuto/demo4_dynamic_lib/src/src/printhello.cpp:7:6: warning: unused variable ‘i’ [-Wunused-variable]
  int i;
      ^
[ 40%] Building CXX object src/CMakeFiles/hello.dir/src/factorial.cpp.o
[ 60%] Linking CXX shared library ../lib/libhello.so
[ 60%] Built target hello
[ 80%] Building CXX object src/CMakeFiles/main.dir/main.cpp.o
[100%] Linking CXX executable ../bin/main
[100%] Built target main

install


---
//需要在顶层的CMakeLists.txt里修改安装路径
set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install)
message("CMAKE_SOURCE_DIR: " ${CMAKE_BINARY_DIR})
message("CMAKE_INSTALL_PREFIX: " ${CMAKE_INSTALL_PREFIX})
//然后在内部的CMakeLists.txt里install
install(TARGETS main hello
    ARCHIVE DESTINATION lib #静态库
    LIBRARY DESTINATION lib #动态库
    RUNTIME DESTINATION bin #可执行文件
)

以上命令会安装一个动态库,一个静态库,一个可执行文件。CMAKE会根据target类型自动推断。TARGETS 表示我们现在要安装的是TARGETS,除此之外你还可以安装FILES、DIRECTORY等。这里不讲。

通过ARCHIVE/LIBRARY/RUNTIME关键字分别指定静态库、动态库和可执行文件的属性。比如指定安装后缀DESTINATION。例如静态库安装路径就是前缀+后缀=${CMAKE_INSTALL_PREFIX}/install/lib。还可以从/开始直接指定绝对路径

其中CMAKE_INSTALL_PREFIX可以通过顶层目录中的CMakeLists.txt来定义(注意,需要是顶层目录)。你也可以通过-D CMAKE_INSTALL_PREFIX=xxx来从外部命令行传递

execute_process

execute_process命令将从当前正在执行的CMake进程中派生一个或多个子进程,从而提供了在配置项目时运行任意命令的方法。可以在一次调用execute_process时执行多个命令。但请注意,每个命令的输出将通过管道传输到下一个命令中。

execute_process(COMMAND <cmd1> [<arguments>]
                [COMMAND <cmd2> [<arguments>]]...
                [WORKING_DIRECTORY <directory>]
                [TIMEOUT <seconds>]
                [RESULT_VARIABLE <variable>]
                [RESULTS_VARIABLE <variable>]
                [OUTPUT_VARIABLE <variable>]
                [ERROR_VARIABLE <variable>]
                [INPUT_FILE <file>]
                [OUTPUT_FILE <file>]
                [ERROR_FILE <file>]
                [OUTPUT_QUIET]
                [ERROR_QUIET]
                [COMMAND_ECHO <where>]
                [OUTPUT_STRIP_TRAILING_WHITESPACE]
                [ERROR_STRIP_TRAILING_WHITESPACE]
                [ENCODING <name>]
                [ECHO_OUTPUT_VARIABLE]
                [ECHO_ERROR_VARIABLE]
                [COMMAND_ERROR_IS_FATAL <ANY|LAST>])

该命令可以一次性执行多条指令,并且每条指令执行的结果作为下一条指令的输入。下面介绍几个重要的参数:

  • WORKING_DIRECTORY:指定应该在哪个目录中执行命令;
  • TIMEOUT:超时时间。如果指令在超时时间(单位:秒)内没有执行完成,那么所有的指令会被中断。同时,参数 RESULT_VARIABLE 的值会被设置为 “timeout”;
  • RESULT_VARIABLE将包含进程运行的结果。这要么是一个整数,表示执行成功,要么是一个带有错误条件的字符串。
  • OUTPUT_VARIABLE和ERROR_VARIABLE将包含执行命令的标准输出和标准错误。由于命令的输出是通过管道传输的,因此只有最后一个命令的标准输出才会保存到OUTPUT_VARIABLE中。
  • INPUT_FILE指定标准输入重定向的文件名
  • OUTPUT_FILE指定标准输出重定向的文件名
  • ERROR_FILE指定标准错误输出重定向的文件名
  • 设置OUTPUT_QUIET和ERROR_QUIET后,CMake将静默地忽略标准输出和标准错误。
  • 设置OUTPUT_STRIP_TRAILING_WHITESPACE,可以删除运行命令的标准输出中的任何尾随空格
  • 设置ERROR_STRIP_TRAILING_WHITESPACE,可以删除运行命令的错误输出中的任何尾随空格

ex:
获取源码顶层目录中的所有文件名

cmake_minimum_required(VERSION 3.15)project(cmake-exe-test)execute_process(COMMAND ls ..
                OUTPUT_VARIABLE ls_ret)message(STATUS "ls output:\n${ls_ret}")

在这里插入图片描述
ex:

    set(_module_name "cffi")
    execute_process(
      COMMAND
          ${PYTHON_EXECUTABLE} "-c" "import ${_module_name}; print(${_module_name}.__version__)"
      OUTPUT_VARIABLE _stdout
      ERROR_VARIABLE _stderr
      OUTPUT_STRIP_TRAILING_WHITESPACE
      ERROR_STRIP_TRAILING_WHITESPACE
      )
    if(_stderr MATCHES "ModuleNotFoundError")
        message(STATUS "Module ${_module_name} not found")
    else()
      message(STATUS "Found module ${_module_name} v${_stdout}")
    endif()

该命令检查python -c "import cffi; print(cffi.__version__)"的输出。如果没有找到模块,_stderr将包含ModuleNotFoundError,我们将在if语句中对其进行检查。本例中,我们将打印Module cffi not found。如果导入成功,Python代码将打印模块的版本,该模块通过管道输入_stdout,这样就可以打印如下内容:

    message(STATUS "Found module ${_module_name} v${_stdout}")

参考:
配置时运行自定义命令

find_path、find_library、find_program

【cmake教程】find_path、find_library、find_progra

list()

cmake命令之list

CMake变量

cmake的内置变量
有个脚本打印大部分cmake内置变量。这是从CMake wiki上抄来的。
原脚本位置

# ------------------------- Begin Generic CMake Variable Logging ------------------

# /*    C++ comment style not allowed   */


# if you are building in-source, this is the same as CMAKE_SOURCE_DIR, otherwise
# this is the top level directory of your build tree
MESSAGE( STATUS "CMAKE_BINARY_DIR:         " ${CMAKE_BINARY_DIR} )

# if you are building in-source, this is the same as CMAKE_CURRENT_SOURCE_DIR, otherwise this
# is the directory where the compiled or generated files from the current CMakeLists.txt will go to
MESSAGE( STATUS "CMAKE_CURRENT_BINARY_DIR: " ${CMAKE_CURRENT_BINARY_DIR} )

# this is the directory, from which cmake was started, i.e. the top level source directory
MESSAGE( STATUS "CMAKE_SOURCE_DIR:         " ${CMAKE_SOURCE_DIR} )

# this is the directory where the currently processed CMakeLists.txt is located in
MESSAGE( STATUS "CMAKE_CURRENT_SOURCE_DIR: " ${CMAKE_CURRENT_SOURCE_DIR} )

# contains the full path to the top level directory of your build tree
MESSAGE( STATUS "PROJECT_BINARY_DIR: " ${PROJECT_BINARY_DIR} )

# contains the full path to the root of your project source directory,
# i.e. to the nearest directory where CMakeLists.txt contains the PROJECT() command
MESSAGE( STATUS "PROJECT_SOURCE_DIR: " ${PROJECT_SOURCE_DIR} )

# set this variable to specify a common place where CMake should put all executable files
# (instead of CMAKE_CURRENT_BINARY_DIR)
MESSAGE( STATUS "EXECUTABLE_OUTPUT_PATH: " ${EXECUTABLE_OUTPUT_PATH} )

# set this variable to specify a common place where CMake should put all libraries
# (instead of CMAKE_CURRENT_BINARY_DIR)
MESSAGE( STATUS "LIBRARY_OUTPUT_PATH:     " ${LIBRARY_OUTPUT_PATH} )

# tell CMake to search first in directories listed in CMAKE_MODULE_PATH
# when you use FIND_PACKAGE() or INCLUDE()
MESSAGE( STATUS "CMAKE_MODULE_PATH: " ${CMAKE_MODULE_PATH} )

# this is the complete path of the cmake which runs currently (e.g. /usr/local/bin/cmake)
MESSAGE( STATUS "CMAKE_COMMAND: " ${CMAKE_COMMAND} )

# this is the CMake installation directory
MESSAGE( STATUS "CMAKE_ROOT: " ${CMAKE_ROOT} )

# this is the filename including the complete path of the file where this variable is used.
MESSAGE( STATUS "CMAKE_CURRENT_LIST_FILE: " ${CMAKE_CURRENT_LIST_FILE} )

# this is linenumber where the variable is used
MESSAGE( STATUS "CMAKE_CURRENT_LIST_LINE: " ${CMAKE_CURRENT_LIST_LINE} )

# this is used when searching for include files e.g. using the FIND_PATH() command.
MESSAGE( STATUS "CMAKE_INCLUDE_PATH: " ${CMAKE_INCLUDE_PATH} )

# this is used when searching for libraries e.g. using the FIND_LIBRARY() command.
MESSAGE( STATUS "CMAKE_LIBRARY_PATH: " ${CMAKE_LIBRARY_PATH} )

# the complete system name, e.g. "Linux-2.4.22", "FreeBSD-5.4-RELEASE" or "Windows 5.1"
MESSAGE( STATUS "CMAKE_SYSTEM: " ${CMAKE_SYSTEM} )

# the short system name, e.g. "Linux", "FreeBSD" or "Windows"
MESSAGE( STATUS "CMAKE_SYSTEM_NAME: " ${CMAKE_SYSTEM_NAME} )

# only the version part of CMAKE_SYSTEM
MESSAGE( STATUS "CMAKE_SYSTEM_VERSION: " ${CMAKE_SYSTEM_VERSION} )

# the processor name (e.g. "Intel(R) Pentium(R) M processor 2.00GHz")
MESSAGE( STATUS "CMAKE_SYSTEM_PROCESSOR: " ${CMAKE_SYSTEM_PROCESSOR} )

# is TRUE on all UNIX-like OS's, including Apple OS X and CygWin
MESSAGE( STATUS "UNIX: " ${UNIX} )

# is TRUE on Windows, including CygWin
MESSAGE( STATUS "WIN32: " ${WIN32} )

# is TRUE on Apple OS X
MESSAGE( STATUS "APPLE: " ${APPLE} )

# is TRUE when using the MinGW compiler in Windows
MESSAGE( STATUS "MINGW: " ${MINGW} )

# is TRUE on Windows when using the CygWin version of cmake
MESSAGE( STATUS "CYGWIN: " ${CYGWIN} )

# is TRUE on Windows when using a Borland compiler
MESSAGE( STATUS "BORLAND: " ${BORLAND} )

# Microsoft compiler
MESSAGE( STATUS "MSVC: " ${MSVC} )
MESSAGE( STATUS "MSVC_IDE: " ${MSVC_IDE} )
MESSAGE( STATUS "MSVC60: " ${MSVC60} )
MESSAGE( STATUS "MSVC70: " ${MSVC70} )
MESSAGE( STATUS "MSVC71: " ${MSVC71} )
MESSAGE( STATUS "MSVC80: " ${MSVC80} )
MESSAGE( STATUS "CMAKE_COMPILER_2005: " ${CMAKE_COMPILER_2005} )


# set this to true if you don't want to rebuild the object files if the rules have changed,
# but not the actual source files or headers (e.g. if you changed the some compiler switches)
MESSAGE( STATUS "CMAKE_SKIP_RULE_DEPENDENCY: " ${CMAKE_SKIP_RULE_DEPENDENCY} )

# since CMake 2.1 the install rule depends on all, i.e. everything will be built before installing.
# If you don't like this, set this one to true.
MESSAGE( STATUS "CMAKE_SKIP_INSTALL_ALL_DEPENDENCY: " ${CMAKE_SKIP_INSTALL_ALL_DEPENDENCY} )

# If set, runtime paths are not added when using shared libraries. Default it is set to OFF
MESSAGE( STATUS "CMAKE_SKIP_RPATH: " ${CMAKE_SKIP_RPATH} )

# set this to true if you are using makefiles and want to see the full compile and link
# commands instead of only the shortened ones
MESSAGE( STATUS "CMAKE_VERBOSE_MAKEFILE: " ${CMAKE_VERBOSE_MAKEFILE} )

# this will cause CMake to not put in the rules that re-run CMake. This might be useful if
# you want to use the generated build files on another machine.
MESSAGE( STATUS "CMAKE_SUPPRESS_REGENERATION: " ${CMAKE_SUPPRESS_REGENERATION} )


# A simple way to get switches to the compiler is to use ADD_DEFINITIONS().
# But there are also two variables exactly for this purpose:

# the compiler flags for compiling C sources
MESSAGE( STATUS "CMAKE_C_FLAGS: " ${CMAKE_C_FLAGS} )

# the compiler flags for compiling C++ sources
MESSAGE( STATUS "CMAKE_CXX_FLAGS: " ${CMAKE_CXX_FLAGS} )


# Choose the type of build.  Example: SET(CMAKE_BUILD_TYPE Debug)
MESSAGE( STATUS "CMAKE_BUILD_TYPE: " ${CMAKE_BUILD_TYPE} )

# if this is set to ON, then all libraries are built as shared libraries by default.
MESSAGE( STATUS "BUILD_SHARED_LIBS: " ${BUILD_SHARED_LIBS} )

# the compiler used for C files
MESSAGE( STATUS "CMAKE_C_COMPILER: " ${CMAKE_C_COMPILER} )

# the compiler used for C++ files
MESSAGE( STATUS "CMAKE_CXX_COMPILER: " ${CMAKE_CXX_COMPILER} )

# if the compiler is a variant of gcc, this should be set to 1
MESSAGE( STATUS "CMAKE_COMPILER_IS_GNUCC: " ${CMAKE_COMPILER_IS_GNUCC} )

# if the compiler is a variant of g++, this should be set to 1
MESSAGE( STATUS "CMAKE_COMPILER_IS_GNUCXX : " ${CMAKE_COMPILER_IS_GNUCXX} )

# the tools for creating libraries
MESSAGE( STATUS "CMAKE_AR: " ${CMAKE_AR} )
MESSAGE( STATUS "CMAKE_RANLIB: " ${CMAKE_RANLIB} )

#
#MESSAGE( STATUS ": " ${} )

# ------------------------- End of Generic CMake Variable Logging ------------------

打印如下:

# xxx @ xxx-Latitude-7490 in ~/Desktop/makefile_tuto/demo5_sub_directory/build [16:11:38] 
$ cmake ..
-- The CXX compiler identification is GNU 7.5.0
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- CMAKE_BINARY_DIR:         /home/xxx/Desktop/makefile_tuto/demo5_sub_directory/build
-- CMAKE_CURRENT_BINARY_DIR: /home/xxx/Desktop/makefile_tuto/demo5_sub_directory/build/src
-- CMAKE_SOURCE_DIR:         /home/xxx/Desktop/makefile_tuto/demo5_sub_directory
-- CMAKE_CURRENT_SOURCE_DIR: /home/xxx/Desktop/makefile_tuto/demo5_sub_directory/src
-- PROJECT_BINARY_DIR: /home/xxx/Desktop/makefile_tuto/demo5_sub_directory/build
-- PROJECT_SOURCE_DIR: /home/xxx/Desktop/makefile_tuto/demo5_sub_directory
-- EXECUTABLE_OUTPUT_PATH: 
-- LIBRARY_OUTPUT_PATH:     
-- CMAKE_MODULE_PATH: 
-- CMAKE_COMMAND: /usr/bin/cmake
-- CMAKE_ROOT: /usr/share/cmake-3.10
-- CMAKE_CURRENT_LIST_FILE: /home/xxx/Desktop/makefile_tuto/demo5_sub_directory/src/CMakeLists.txt
-- CMAKE_CURRENT_LIST_LINE: 64
-- CMAKE_INCLUDE_PATH: 
-- CMAKE_LIBRARY_PATH: 
-- CMAKE_SYSTEM: Linux-5.10.76-xenomai
-- CMAKE_SYSTEM_NAME: Linux
-- CMAKE_SYSTEM_VERSION: 5.10.76-xenomai
-- CMAKE_SYSTEM_PROCESSOR: x86_64
-- UNIX: 1
-- WIN32: 
-- APPLE: 
-- MINGW: 
-- CYGWIN: 
-- BORLAND: 
-- MSVC: 
-- MSVC_IDE: 
-- MSVC60: 
-- MSVC70: 
-- MSVC71: 
-- MSVC80: 
-- CMAKE_COMPILER_2005: 
-- CMAKE_SKIP_RULE_DEPENDENCY: 
-- CMAKE_SKIP_INSTALL_ALL_DEPENDENCY: 
-- CMAKE_SKIP_RPATH: NO
-- CMAKE_VERBOSE_MAKEFILE: FALSE
-- CMAKE_SUPPRESS_REGENERATION: 
-- CMAKE_C_FLAGS: 
-- CMAKE_CXX_FLAGS: 
-- CMAKE_BUILD_TYPE: 
-- BUILD_SHARED_LIBS: 
-- CMAKE_C_COMPILER: 
-- CMAKE_CXX_COMPILER: /usr/bin/c++
-- CMAKE_COMPILER_IS_GNUCC: 
-- CMAKE_COMPILER_IS_GNUCXX : 1
-- CMAKE_AR: /usr/bin/ar
-- CMAKE_RANLIB: /usr/bin/ranlib
-- Configuring done
-- Generating done
-- Build files have been written to: /home/xxx/Desktop/makefile_tuto/demo5_sub_directory/build

补充:

${CMAKE_CURRENT_DIR}: /home/xxx/Desktop/spdlog_tuto/spdlog_test

环境变量

cmake调用系统环境变量的方式:$ENV{变量名},如:

MESSAGE(STATUS “HOME dir: $ENV{HOME})`
输出:
“HOMEdir:/home/xxx” //xxx代表用户名

设置环境变量的方式:SET(ENV{变量名} 值)

自定义变量

cmake定义与调用自定义变量的方式:定义:SET(变量名 值),调用:${变量名}

CMake中包含了大量的内置变量,这些变量的使用方法与自定义变量的是一样的。

工程路径

CMAKE_SOURCE_DIR
PROJECT_SOURCE_DIR
<projectname>_SOURCE_DIR
---
messae(STATUS "CMAKE_SOURCE_DIR: " ${CMAKE_SOURCE_DIR}) 
messae(STATUS "PROJECT_SOURCE_DIR: " ${PROJECT_SOURCE_DIR}) 
messae(STATUS "proj_name_SOURCE_DIR: " ${main_test_SOURCE_DIR}) 

output:
-- CMAKE_SOURCE_DIR: /home/xxx/Desktop/makefile_tuto/demo4_dynamic_lib
-- PROJECT_SOURCE_DIR: /home/xxx/Desktop/makefile_tuto/demo4_dynamic_lib
-- proj_name_SOURCE_DIR: /home/xxx/Desktop/makefile_tuto/demo4_dynamic_lib

这三个变量指代的内容是一致的,不论采用何种编译方式,都是工程顶层目录

CMAKE_BINARY_DIR
PROJECT_BINARY_DIR
<projectname>_BINARY_DIR
---

messae(STATUS "CMAKE_BINARY_DIR: " ${CMAKE_BINARY_DIR}) 
messae(STATUS "PROJECT_BINARY_DIR: " ${PROJECT_BINARY_DIR}) 
messae(STATUS "proj_name_BINARY_DIR: " ${main_test_BINARY_DIR}) 
output:
-- CMAKE_BINARY_DIR: /home/xxx/Desktop/makefile_tuto/demo4_dynamic_lib/build
-- PROJECT_BINARY_DIR: /home/xxx/Desktop/makefile_tuto/demo4_dynamic_lib/build
-- proj_name_BINARY_DIR: /home/xxx/Desktop/makefile_tuto/demo4_dynamic_lib/build

这三个变量指代的内容是一致的,如果是 in-source编译,指的就是工程顶层目录,如果是out-of-source编译(创建独立的build文件夹),指的是工程编译发生的目录(即buid文件夹)

CMAKE_CURRENT_SOURCE_DIR    // 指的是当前处理的 CMakeLists.txt文件所在的路径
CMAKE_CURRENT_BINARY_DIR    // 如果是in-source编译,它跟CMAKE_CURRENT_SOURCE_DIR一致,如果是out-ofsource编译,它指的将是 target 编译目录
CMAKE_CURRENT_LIST_FILE    // 输出调用这个变量的 CMakeLists.txt 的完整路径。
---
message(STATUS "CMAKE_CURRENT_SOURCE_DIR: " ${CMAKE_CURRENT_SOURCE_DIR}) 
message(STATUS "CMAKE_CURRENT_BINARY_DIR: " ${CMAKE_CURRENT_BINARY_DIR}) 
message(STATUS "CMAKE_CURRENT_LIST_FILE: " ${CMAKE_CURRENT_LIST_FILE}) 
output:
-- CMAKE_CURRENT_SOURCE_DIR: /home/xxx/Desktop/makefile_tuto/demo4_dynamic_lib/src
-- CMAKE_CURRENT_BINARY_DIR: /home/xxx/Desktop/makefile_tuto/demo4_dynamic_lib/build/src
-- CMAKE_CURRENT_LIST_FILE: /home/xxx/Desktop/makefile_tuto/demo4_dynamic_lib/src/CMakeLists.txt

编译器

CMAKE_C_COMPILER    # 指定C编译器
CMAKE_CXX_COMPILER  # 指定C++编译器
---
message(STATUS "CMAKE_C_COMPILER: " ${CMAKE_C_COMPILER}) 
message(STATUS "CMAKE_CXX_COMPILER: " ${CMAKE_CXX_COMPILER}) 
output:
-- CMAKE_C_COMPILER: /usr/bin/cc
-- CMAKE_CXX_COMPILER: /usr/bin/c++

头文件、库文件和cmake模块路径

CMAKE_INCLUDE_PATH
---
set(CMAKE_INCLUDE_PATH /home/xxx/Desktop/makefile_tuto/demo4_dynamic_lib/src/include)
find_file(MY_FUNC functions.h )
message(STATUS "MY_FUNC: " ${MY_FUNC}) 
if (MY_FUNC)
  message(STATUS "Found header file: ${MY_FUNC}")
else()
  message(STATUS "Could not find functions.h")
endif()
message(STATUS "CMAKE_INCLUDE_PATH: " ${CMAKE_INCLUDE_PATH}) 
---
output:
-- MY_FUNC: /home/xxx/Desktop/makefile_tuto/demo4_dynamic_lib/src/include/functions.h
-- Found header file: /home/xxx/Desktop/makefile_tuto/demo4_dynamic_lib/src/include/functions.h
-- CMAKE_INCLUDE_PATH: /home/xxx/Desktop/makefile_tuto/demo4_dynamic_lib/src/include

头文件路径。配合FIND_FILE()以及FIND_PATH()使用。如果头文件没有存放在如/usr/include, /usr/local/include等的常规路径中,则可以通过这个变量进行弥补。但如果不使用 FIND_FILEFIND_PATH,则变量CMAKE_INCLUDE_PATH是没有任何作用的。

CMAKE_LIBRARY_PATH

CMAKE_LIBRARY_PATH

库文件路径。配合FIND_LIBRARY()使用,否则将没有任何作用。

CMAKE_MODULE_PATH

CMAKE_MODULE_PATH

cmake模块路径。cmake为上百个软件包提供了查找器(finder):FindXXXX.cmake。当使用非cmake自带的finder时,需要指定finder的路径,这就是CMAKE_MODULE_PATH,配合FIND_PACKAGE()使用
CMAKE_MODULE_PATH 与 CMAKE_PREFIX_PATH的区别

程序安装

CMAKE_INSTALL_PREFIX
---
//需要在顶层的CMakeLists.txt里修改安装路径
set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install)
message("CMAKE_SOURCE_DIR: " ${CMAKE_BINARY_DIR})
message("CMAKE_INSTALL_PREFIX: " ${CMAKE_INSTALL_PREFIX})

控制make install,把make产生的文件安装到指定的地方。此变量默认的程序安装路径前缀为/usr/local%PROGRAMFILES%

可执行文件与库文件存放的路径:LIBRARY_OUTPUT_PATH、EXECUTABLE_OUTPUT_PATH

set(LIBRARY_OUTPUT_PATH ${xxx_BINARY_DIR}/lib)
set(EXECUTABLE_OUTPUT_PATH ${xxx_BINARY_DIR}/bin)

分别用来重新定义最终结果(可执行文件和库文件)的存放目录。

private、public、interface

具体的介绍详见private,public,interface的使用

编译类型(Debug & Release)

#设定编译类型为Debug,调试时需要选择为Debug
set(CMAKE_BUILD_TYPE Debug)
#设定编译类型为Release,调试时需要选择为Release
set(CMAKE_BUILD_TYPE Release)

指令解析

cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/home/OpenCV ..

此指令分四部分:
一是cmake,
二是-D CMAKE_BUILD_TYPE=RELEASE,
三是-D CMAKE_INSTALL_PREFIX=/home/OpenCV,
四是…
cmake表示对项目进行分析构建,-D相当于定义,-D可以理解为告诉cmake后边要设置一个属性的值,每设置一个属性,就需在属性前面加上一个-D。CMAKE_BUILD_TYPE表示要编译的类型,类型有debug,release。CMAKE_INSTALL_PREFIX是安装路径。…表示要分析的CMakeLists.txt文件在上一层目录中。

所谓安装,即是是将需要的头文件和库文件拷贝到指定的目录中,默认情况下,会是/usr目录下,有时是/usr/local目录下。

参考

make的基础用法

一知半解学 CMake

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值