cmake & CMakeLists.txt

文章目录

    • 前言
    • 先从体验开始
      • 1.一个最简单的例子:
      • 2.例子升级,将hello.c生成为一个库:
      • 3.例子升级,将源代码和库分开放:
      • 4.让可执行文件在 bin 目录,库文件在 lib 目录:
      • 5.动态库:
      • 6.应用:
    • 部分常用命令
      • include_directories,link_directories,link_libraries和target_link_libraries区别:
    • 工程路径
    • 各种参数
    • find_package
      • 基本使用
      • 如何编写自己的cmake module

前言

cmake官网:https://cmake.org/documentation/
其中的tutorial讲的很好:https://cmake.org/cmake/help/latest/guide/tutorial/index.html


先从体验开始

1.一个最简单的例子:

cmake执行的流程:

#其中directory为CMakeList.txt所在目录
$> ccmake directory		#配置编译选项,如VTK_DIR目录 ,一般这一步不需要配置,直接执行第二条语句即可,但当出现错误时,这里就需要认为配置了,这一步才真正派上用场;
$> cmake directory		#根据CMakeLists.txt生成Makefile文件;
$> make					#执行Makefile文件,编译程序,生成可执行文件;

hello.h 头文件

#ifndef DBZHANG_HELLO_
#define DBZHANG_HELLO_
void hello(const char* name);
#endif //DBZHANG_HELLO_

hello.c

#include 
#include "hello.h"
void hello(const char * name)
{
printf ("Hello %s!/n", name);
}

main.c

#include "hello.h"
int main()
{
hello("World");
return 0;
}

CMakeList.txt

project(HELLO)
set(SRC_LIST main.c hello.c)
add_executable(hello ${SRC_LIST})

由于执行cmake的时候会产生很多中间文件,我们采用out of source(外部编译)方式进行构建:建立一个build目录储存中间执行过程。

进入build目录,执行cmake . . ,cmake执行指向上一个目录,也就是存储CMakeLists.txt的目录,完成后就会看到makefile文件,make过后就会看到执行文件。

#第一个行project不是强制性的,最好加上,这会引入两个变量:
HELLO_BINARY_DIR, HELLO_SOURCE_DIR
#同时也会定义两个等价的变量:
PROJECT_BINARY_DIR, PROJECT_SOURCE_DIR
#外部编译要时刻区分这两个变量对应的目录:
#可以通过message进行输出

message(${PROJECT_SOURCE_DIR})
#set 命令用来设置变量

#add_exectuable 告诉工程生成一个可执行文件。
#add_library 则告诉生成一个库文件。
#注意:CMakeList.txt 文件中,命令名字是不区分大小写的,而参数和变量是大小写相关的。

2.例子升级,将hello.c生成为一个库:

改写一下前面的CMakeList.txt文件试试:

project(HELLO)
set(LIB_SRC hello.c)
set(APP_SRC main.c)
add_library(libhello ${LIB_SRC})
add_executable(hello ${APP_SRC})
target_link_libraries(hello libhello)

和前面相比,我们添加了一个新的目标 libhello,并将其链接进hello程序

因为可执行程序占据了 hello 这个名字,所以 add_library 就不能使用这个名字了
然后,我们取了个libhello 的名字,这将导致生成的库为 libhello.lib(或 liblibhello.a),很不爽
想生成 hello.lib(或libhello.a) 怎么办?

添加一行

set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")

就可以了
但是上面将源代码和库放在同一个目录下,工程变大后会很乱,怎么办?

3.例子升级,将源代码和库分开放:

顶层的CMakeList.txt 文件

project(HELLO)
add_subdirectory(src)
add_subdirectory(libhello)

src 中的 CMakeList.txt 文件

include_directories(${PROJECT_SOURCE_DIR}/libhello)
set(APP_SRC main.c)
add_executable(hello ${APP_SRC})
target_link_libraries(hello libhello)

libhello 中的 CMakeList.txt 文件

set(LIB_SRC hello.c)
add_library(libhello ${LIB_SRC})
set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")

目录结构如下:

├── build
├── CMakeLists.txt
├── libhello
│   ├── CMakeLists.txt
│   ├── hello.c
│   └── hello.h
└── src
    ├── CMakeLists.txt
    └── main.c

编译之后生成的库文件在build/libhello中,生成的可执行文件在build/src中

回头看看,这次多了点什么,顶层的 CMakeList.txt 文件中使用 add_subdirectory 告诉cmake去子目录寻找新的CMakeList.txt 子文件
在 src 的 CMakeList.txt 文件中,新增加了include_directories,用来指明头文件所在的路径。
通常编译后生成的可执行文件放在bin目录下,库文件放在lib目录下,所以:

4.让可执行文件在 bin 目录,库文件在 lib 目录:

**一种办法:**修改顶级的 CMakeList.txt 文件,指定名字

project(HELLO)
add_subdirectory(src bin)
add_subdirectory(libhello lib)

可是这样除了 hello.exe,中间产物也进来了。还不是我们最想要的。
另一种办法:
不修改顶级的文件,修改其他两个文件
src/CMakeList.txt 文件

include_directories(${PROJECT_SOURCE_DIR}/libhello)
#link_directories(${PROJECT_BINARY_DIR}/lib)
set(APP_SRC main.c)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
add_executable(hello ${APP_SRC})target_link_libraries(hello libhello)

libhello/CMakeList.txt 文件

set(LIB_SRC hello.c)
add_library(libhello ${LIB_SRC})
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")

上面的例子中都是生成的静态库,下面用动态库代替静态库

5.动态库:

如果不考虑windows下,这个例子应该是很简单的,只需要在上个例子的 libhello/CMakeList.txt 文件中的
add_library命令中加入一个SHARED参数:

add_library(libhello SHARED ${LIB_SRC})

通过例子我们已经学习到了以下变量:

HELLO_BINARY_DIR, HELLO_SOURCE_DIR
PROJECT_BINARY_DIR, PROJECT_SOURCE_DIR

EXECUTABLE_OUTPUT_PATH
LIBRARY_OUTPUT_PATH 

SHARED 

6.应用:

(1)添加版本号和配置头文件 :
在源代码中提供版本号如果要修改就很麻烦,可以写到CMakeLists.txt中:

cmake_minimum_required (VERSION 2.6)
project (Tutorial)
# The version number.
set (Tutorial_VERSION_MAJOR 1)
set (Tutorial_VERSION_MINOR 0)
 
# configure a header file to pass some of the CMake settings
# to the source code
configure_file (
  "${PROJECT_SOURCE_DIR}/TutorialConfig.h.in"
  "${PROJECT_BINARY_DIR}/TutorialConfig.h"
  )
 
# add the binary tree to the search path for include files
# so that we will find TutorialConfig.h
include_directories("${PROJECT_BINARY_DIR}")
 
# add the executable
add_executable(Tutorial tutorial.cxx)

另创建“TutorialConfig.h.in”文件,内容如下:

// the configured options and settings for Tutorial
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@

tutorial.cxx:

// A simple program that computes the square root of a number
#include 
#include 
#include 
#include "TutorialConfig.h"
 
int main (int argc, char *argv[])
{
  if (argc < 2)
    {
    fprintf(stdout,"%s Version %d.%d\n",
            argv[0],
            Tutorial_VERSION_MAJOR,
            Tutorial_VERSION_MINOR);
    fprintf(stdout,"Usage: %s number\n",argv[0]);
    return 1;
    }
  double inputValue = atof(argv[1]);
  double outputValue = sqrt(inputValue);
  fprintf(stdout,"The square root of %g is %g\n",
          inputValue, outputValue);
  return 0;
}

(2)”EXTRA_LIBS”变量是用来收集每一个可选库的,以便他们链接到可执行程序中.这是一个保持大项目工程可选库清洁的通用方法

# add the MathFunctions library?
#
if (USE_MYMATH)
  include_directories ("${PROJECT_SOURCE_DIR}/MathFunctions")
  add_subdirectory (MathFunctions)
  set (EXTRA_LIBS ${EXTRA_LIBS} MathFunctions)
endif (USE_MYMATH)
# add the executable
add_executable (Tutorial tutorial.cxx)
target_link_libraries (Tutorial  ${EXTRA_LIBS})

部分常用命令

set
SET( VAR value [CACHE TYPE DOCSTRING [FORCE]])
#set(VAR ${VAR} value)相当于VAR = VAR + value

add_executable

add_library
#添加SHARED可将目标作为动态库

message

project(<PROJECT-NAME>
        [VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]
        [DESCRIPTION <project-description-string>]
        [HOMEPAGE_URL <url-string>]
        [LANGUAGES <language-name>...])
#项目名称、版本

add_subdirectory()#可指定输出目录的名字:
add_subdirectory(输入目录名,输出目录名)

configure_file(<input> <output>
               [COPYONLY] [ESCAPE_QUOTES] [@ONLY]
               [NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF] ])  
#将input文件复制到output文件中    
  
INCLUDE_DIRECTORIES( "dir1" "dir2" ... )
#头文件路径,相当于编译器参数 -Idir1 -Idir2

LINK_DIRECTORIES("dir1" "dir2")
#库文件路径。注意:
#由于历史原因,相对路径会原样传递给链接器。
#尽量使用FIND_LIBRARY而避免使用这个。

AUX_SOURCE_DIRECTORY( “sourcedir” variable)
#收集目录中的文件名并赋值给变量

ADD_CUSTOM_TARGET
#自定义目标

ADD_DEPENDENCIES( target1 t2 t3 )
#目标target1依赖于t2 t3

ADD_DEFINITIONS( "-Wall -ansi")
#本意是供设置 -D... /D... 等编译预处理需要的宏定义参数,对比 REMOVE_DEFINITIONS()

TARGET_LINK_LIBRARIES( target-name lib1 lib2 ...)
#设置单个目标需要链接的库

LINK_LIBRARIES( lib1 lib2 ...)
#设置所有目标需要链接的库

SET_TARGET_PROPERTIES( ... )
#设置目标的属性 OUTPUT_NAME, VERSION, ....

MESSAGE(...)

INSTALL( FILES “f1” “f2”DESTINATION . )
#DESTINATION 相对于 ${CMAKE_INSTALL_PREFIX}

LIST( APPEND|INSERT|LENGTH|GET| REMOVE_ITEM|REMOVE_AT|SORT ...)
#列表操作

STRING( TOUPPER|TOLOWER|LENGTH| SUBSTRING|REPLACE|REGEX ...)
#字符串操作

SEPARATE_ARGUMENTS( VAR )
#转换空格分隔的字符串到列表

FILE( WRITE|READ|APPEND|GLOB| GLOB_RECURSE|REMOVE|MAKE_DIRECTORY ...)
#文件操作

FIND_FILE
#注意 CMAKE_INCLUDE_PATH

FIND_PATH
#注意 CMAKE_INCLUDE_PATH

FIND_LIBRARY
#注意 CMAKE_LIBRARY_PATH

FIND_PROGRAM
 
FIND_PACKAGE
#注意 CMAKE_MODULE_PATH

EXEC_PROGRAM( bin [work_dir] ARGS <..> [OUTPUT_VARIABLE var] [RETURN_VALUE var] )
#执行外部程序

OPTION( OPTION_VAR “description” [initial value] )
#选择是否添加可选项
#多数情况会有大量的依赖第三方的库文件.添加一个可选库等
#一般在最高层的CMakeLists.txt

include_directories,link_directories,link_libraries和target_link_libraries区别:

1.INCLUDE_DIRECTORIES(添加头文件目录)
它相当于g++选项中的-I参数的作用,也相当于环境变量中增加路径到CPLUS_INCLUDE_PATH变量的作用(这里特指c++。c和Java中用法类似)。比如:

include_directories("/opt/MATLAB/R2012a/extern/include")
export CPLUS_INCLUDE_PATH=CPLUS_INCLUDE_PATH:$MATLAB/extern/include

2.LINK_DIRECTORIES(添加需要链接的库文件目录)
语法:link_directories(directory1 directory2 …)
它相当于g++命令的-L选项的作用,也相当于环境变量中增加LD_LIBRARY_PATH的路径的作用。比如:

LINK_DIRECTORIES("/opt/MATLAB/R2012a/bin/glnxa64")
export LD_LIBRARY_PATH=LD_LIBRARY_PATH:MATLAB/bin/glnxa64

3.LINK_LIBRARIES (添加需要链接的库文件路径,注意这里是全路径)
List of direct link dependencies.
比如:

LINK_LIBRARIES("/opt/MATLAB/R2012a/bin/glnxa64/libeng.so")
LINK_LIBRARIES("/opt/MATLAB/R2012a/bin/glnxa64/libeng.so" “/opt/MATLAB/R2012a/bin/glnxa64/libmx.so”)

4.TARGET_LINK_LIBRARIES (设置要链接的库文件的名称)
语法:TARGET_LINK_LIBRARIES(targetlibrary1 library2 …)
比如(以下写法(包括备注中的)都可以):

TARGET_LINK_LIBRARIES(myProject hello),连接libhello.so库
TARGET_LINK_LIBRARIES(myProject libhello.a)
TARGET_LINK_LIBRARIES(myProject libhello.so)

再如:

TARGET_LINK_LIBRARIES(myProject libeng.so)  #这些库名写法都可以。
TARGET_LINK_LIBRARIES(myProject eng)
TARGET_LINK_LIBRARIES(myProject -leng)

下面是具体的例子:

cmake_minimum_required(VERSION 2.8 FATAL_ERROR)

include_directories("/opt/MATLAB/R2012a/extern/include")

#directly link to the libraries.
LINK_LIBRARIES("/opt/MATLAB/R2012a/bin/glnxa64/libeng.so")
LINK_LIBRARIES("/opt/MATLAB/R2012a/bin/glnxa64/libmx.so")

#equals to below
#LINK_LIBRARIES("/opt/MATLAB/R2012a/bin/glnxa64/libeng.so" “/opt/MATLAB/R2012a/bin/glnxa64/libmx.so”)

工程路径

CMAKE_SOURCE_DIR
PROJECT_SOURCE_DIR
<projectname>_SOURCE_DIR

这三个变量指代的内容是一致的,是工程顶层目录

CMAKE_BINARY_DIR
PROJECT_BINARY_DIR
<projectname>_BINARY_DIR

这三个变量指代的内容是一致的,如果是in source编译,指得就是工程顶层目录,如果 是out-of-source编译,指的是工程编译发生的目录

CMAKE_CURRENT_SOURCE_DIR

指的是当前处理的CMakeLists.txt所在的路径。

CMAKE_CURRRENT_BINARY_DIR

如果是in-source编译,它跟CMAKE_CURRENT_SOURCE_DIR一致,如果是out-ofsource 编译,他指的是target编译目录。

CMAKE_CURRENT_LIST_FILE

输出调用这个变量的CMakeLists.txt的完整路径

各种参数

1.CMAKE_BUILD_TYPE
控制 Debug 和 Release 模式的构建
CMakeList.txt文件:

SET(CMAKE_BUILD_TYPE Debug)

命令行参数:

cmake DCMAKE_BUILD_TYPE=Release

2.编译器参数
CMAKE_C_FLAGS
CMAKE_CXX_FLAGS
也可以通过指令ADD_DEFINITIONS()添加

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

4.CMAKE_LIBRARY_PATH
配合 FIND_LIBRARY() 使用。否则没有任何作用

5.CMAKE_MODULE_PATH
cmake 为上百个软件包提供了查找器(finder):FindXXXX.cmake

当使用非cmake自带的finder时,需要指定finder的路径,这就是CMAKE_MODULE_PATH,配合 FIND_PACKAGE()使用

6.CMAKE_INSTALL_PREFIX
控制make install是文件会安装到什么地方。默认定义是/usr/local 或 %PROGRAMFILES%

7.BUILD_SHARED_LIBS
如果不进行设置,使用ADD_LIBRARY且没有指定库类型,默认编译生成的库是静态库。

8.UNIX 与 WIN32
UNIX,在所有的类UNIX平台为TRUE,包括OS X和cygwin
WIN32,在所有的win32平台为TRUE,包括cygwin

find_package

基本使用

FIND_PACKAGE( <name> [version] [EXACT] [QUIET] [NO_MODULE] [ [ REQUIRED | COMPONENTS ] [ componets... ] ] )

功能::帮助我们取找头文件和库文件。

find_package()命令首先会在模块路径中寻找Find.cmake,这是查找库的一个典型方式。具体查找路径依次为CMake:变量$ {CMAKE_MODULE_PATH}中的所有目录。如果没有,然后再查看它自己的模块目录/share/cmake-x.y/Modules/($CMAKE_ROOT的具体值可以通过CMake中message命令输出)。这称为模块模式。

例如:我们要使用bzip2库时:

include_directiories(/usr/include/curl)
target_link_libraries(myprogram path/curl.so)

当我们使用find_package查找bzip2时:

project(helloworld)
add_executable(helloworld hello.c)
find_package (BZip2 REQUIRED)	//库文件 选项
if (BZIP2_FOUND)
    include_directories(${BZIP_INCLUDE_DIRS})		//库文件自己定义的变量
    target_link_libraries (helloworld ${BZIP2_LIBRARIES})
endif (BZIP2_FOUND)

为了能支持各种常见的库和包,CMake自带了很多模块。可以通过命令 cmake –help-module-list (输入cmake –help,然后双击Tab会有命令提示)得到你的CMake支持的模块的列表: 直接查看模块路径。比如Ubuntu linux上,模块的路径是 ls /usr/share/cmake/Modules/
以bzip2库为例。CMake中有个 FindBZip2.cmake 模块。只要使用 find_package(BZip2) 调用这个模块,cmake会自动给一些变量赋值,然后就可以在CMake脚本中使用它们了。变量的列表可以查看cmake模块文件,或者使用命令:

root@xy:~/cmake_practice/cmake_build/build_demo10# cmake --help-module FindBZip2
FindBZip2
---------

Try to find BZip2

Once done this will define
::
BZIP2_FOUND - system has BZip2
BZIP2_INCLUDE_DIR - the BZip2 include directory
BZIP2_LIBRARIES - Link these to use BZip2
BZIP2_NEED_PREFIX - this is set if the functions are prefixed with BZ2_
BZIP2_VERSION_STRING - the version of BZip2 found (since CMake 2.8.8)

如何编写自己的cmake module

如上所说,find是根据库提供的.cmake等文件来查找,那么就需要制作此.cmake文件

以上内容参考自:
https://blog.csdn.net/alan711/article/details/86171103
https://blog.csdn.net/yanchuang1/article/details/69683236
https://blog.csdn.net/alan711/article/details/86171103
https://blog.csdn.net/dbzhang800/article/details/6329068
继续学习可看文章:
https://blog.csdn.net/dbzhang800/article/details/6329314
https://blog.csdn.net/dbzhang800/article/details/6340102
https://blog.csdn.net/dbzhang800/article/details/6341029
https://blog.csdn.net/dbzhang800/article/details/6341803

你可能感兴趣的:(工具)