CMake使用简介(for Linux)

CMake使用简介(for Linux)

(2015-03-30 11:03:45)
转载
标签:

cmake

分类: linux
作者:  
Sam (甄峰)  sam_code@hotmail.com

之前有朋友推荐使用CMake,但当时工程已经使用CodeBlocks管理,且交叉编译已经很顺利,所以没有深入研究。这次要详细研究OpenCV的交叉编译,而OpenCV2.0版本之后就采用CMake管理了(OpenCV2.0还采用autoconfig),想要搞清楚如何选择或添加模块,就必须对CMake以及CMakeLists.txt非常了解。

0. CMake介绍:
CMake是一个跨平台的构建系统生成工具。 它使用平台无关的CMake清单文件CMakeLists.txt,指定工程的构建过程;源码树的每个路径下都有这个文件。CMake产生一个适用于具体平台的构建系统,用户使用这个系统构建自己的工程。

一个工程或项目作管理时,咱们在Linux/unix或ELinux下采用Makefile,CodeBlocks,KDevelop,Eclipse,scons等管理,在Windows下则使用VS。他们可以明确哪些目录的那些文件需要被编译,以及编译成什么目标文件。
以Sam最熟悉的Makefile为例,它明确说明了需要编译什么(应用程序,动态库,静态库),由什么编译器产生,需要的头文件和库文件目录,依赖的库文件等等。但当项目足够庞大,这个维护工作就非常复杂。

于是就有人想到采用一个Makefile的生成工具,这其实就是Autotool和socos的角色。只需要告知依赖关系,他们就可以生成Makefile。可以说,他们就是Makefile的生成器,极大地简化了手工维护Makefile的工作。

CMake则更进一步,它不光能够为Linux平台生成Makefile,还做到了跨平台,在Linux/Unix平台,它可以生成Makefile,还可以为Codeblocks,Eclipse等工具生成工程文件。在Windows平台,可以生成vs工程文件,在iOS下,也可以生成xcode工程。
记得在之前的嵌入式Linux游戏项目中,Sam手动编写Makefile管理工程,游戏部门同事完全无法接受,于是采用CodeBlocks作工程管理和编译。有同事想在Eclipse下工作,也无法实现。其实如果采用CMake,则完全没有这个问题。






1. 基础学习:
以V4L2_Utils模块作为例子学习.
V4L2_Utils模块在Linux下包含2个.cpp文件,他们将用来编译成动态库,然后被另一个测试程序main.cpp调用。

1.1:把所有.cpp文件编译成一个可执行程序。
这个例子,将不再建立动态或静态库,而是把main.cpp和另外两个cpp文件一起直接编译成一个可执行程序。
CMakeLists.txt 内容如下:
cmake_minimum_required (VERSION 2.6)
project (V4L2_Utils)
add_executable(V4L2_Utils main.cpp v4l2_util.cpp tran_data.cpp)

讲解如下:
a.cmake_minimum_required    设置一个工程所需要的最低CMake版本,如果CMake的当前版本低于指定的版本,它会停止处理工程文件,并报告错误
cmake_minimum_required(VERSION major[.minor[.patch[.tweak]]] [FATAL_ERROR])

b. project (V4L2_Utils):表明工程名称。
project (PROJECTNAME [CXX] [C] [
可以指定工程支持的语言,如果忽略,表明支持所有语言。

c.  add_executable(V4L2_Utilsmain.cpp   v4l2_util.cpp  tran_data.cpp)
生成可执行文件:V4L2_Utils. 由main.cpp  v4l2_util.cpp  tran_data.cpp生成。
add_executable([WIN32][MACOSX_BUNDLE]
                                [EXCLUDE_FROM_ALL]
                                source1 source2 ... sourceN)
引入一个名为的可执行目标,该目标会由调用该命令时在源文件列表中指定的源文件来构建。对应于逻辑目标名字,并且在工程范围内必须是全局唯一的

构建Unix/Linux标准Makefile
在src目录下,创建build目录。进入build目录
#mkdir build
#cd build
# cmake .. -G"UnixMakefiles"
此时,声称标准Makefile。
#make clean;make


cmake语法如下:
cmake [options]
cmake [options]

cmake [选项]<源码路径>

cmake [选项] <现有构建路径>

因为source 目录在../   所以指定../为源码目录。 

-G:指定构建系统,当前只想创建Linux/Unix系统标准Makefile。所以指定为Unix Makefile.

具体支持何种构建系统:mancmake 

可以看到类似入下内容:

Generators


The following generators areavailable on this platform:

  Ninja                   = Generates build.ninja files(experimental).

  Unix Makefiles           = Generates standard UNIX makefiles.

  CodeBlocks - Ninja        = Generates CodeBlocks projectfiles.

  CodeBlocks - UnixMakefiles = Generates CodeBlocks project files.

  Eclipse CDT4 -Ninja       = Generates Eclipse CDT 4.0 project files.

  Eclipse CDT4 -Unix Makefiles

                         = Generates Eclipse CDT 4.0 project files.

  KDevelop3                =Generates KDevelop 3 project files.

  KDevelop3 - UnixMakefiles  = Generates KDevelop 3 projectfiles.



这个CMakeLists.txt内容中,构成可执行文件的文件个数很少,但如果源文件很多,则最好如Makefile中一样,指定一个源文件列表:

cmake_minimum_required (VERSION 2.6)
project (V4L2_Utils)
set (SRC_LIST main.cpp v4l2_util.cpp tran_data.cpp)
message (${SRC_LIST})
add_executable(V4L2_Utils ${SRC_LIST})

(注1)


1.2:编译一个静态库,并使用这个静态库和main.cpp,最终再生成一个可执行程序:

即先生成libv4l2_utils.a. 

main.cpp使用libv4l2_utils.a中的符号并最终生成V4L2_Utils.

CMakeLists.txt:


cmake_minimum_required (VERSION2.6)


project (V4L2_Utils)

set (LIB_SRC_LIST v4l2_util.cpp tran_data.cpp)

set (EXEC_SRC_LISTmain.cpp)


add_library(V4L2_Utils STATIC ${LIB_SRC_LIST})

add_executable(Test_V4L2${EXEC_SRC_LIST})

 

target_link_libraries(Test_V4L2V4L2_Utils)


说明:

 add_library( [STATIC | SHARED |MODULE]
             [EXCLUDE_FROM_ALL]
             source1 source2 ... sourceN)

创建一个名为 name 的库文件,STATIC,SHARED指定为静态或动态库。

库文件由源文件列表生成。

add_library(V4L2_Utils STATIC ${LIB_SRC_LIST})

生成一个静态库libV4l2_Utils.a 由v4l2_util.cpp tran_data.cpp生成


add_executable(Test_V4L2 ${EXEC_SRC_LIST})

可执行程序由哪些.o组成。


target_link_libraries(Test_V4L2 V4L2_Utils)

可执行程序Test_V4L2需要链接库V4L2_Utils

target_link_libraries( [item1 [item2 [...]]][[debug|optimized|general] ] ...)

将给定的库链接到目标target上。



1.3:编译一个动态库,并使用这个动态和main.cpp,最终再生成一个可执行程序:

cmake_minimum_required (VERSION2.6)


project (V4L2_Utils)

set (LIB_SRC_LIST v4l2_util.cpp)

set (EXEC_SRC_LISTmain.cpp)


add_library(V4L2_Utils SHARED ${LIB_SRC_LIST})

add_executable(Test_V4L2${EXEC_SRC_LIST})

target_link_libraries(Test_V4L2V4L2_Utils)

只变化了STATIC-->SHARED




1.4: 指定include 路径

main.cpp中,需要include "v4l2_util.h"

但这个头文件并不在src目录内,而是在include目录

include,src为同级别目录。则main.cpp会找不到头文件。

所以,实际的CMakeLists.txt文件写法为:

cmake_minimum_required (VERSION2.6)


project (V4L2_Utils)

set (LIB_SRC_LIST v4l2_util.cpp)

set (EXEC_SRC_LISTmain.cpp)

set(INCLUDE_DIRECTORIES ../include)


include_directories(${INCLUDE_DIRECTORIES})

add_library(V4L2_Utils SHARED ${LIB_SRC_LIST})

add_executable(Test_V4L2${EXEC_SRC_LIST})

target_link_libraries(Test_V4L2V4L2_Utils)


将头文件目录添加进去。



1.5:添加第三方库和库路径

如果libV4L2.so是以第三方库形式出现。不需要编译,它放在resource目录下。则需要制定搜索库路径


cmake_minimum_required(VERSION 2.6)


project(V4L2_Utils)

set (EXEC_SRC_LISTmain.cpp)

set (INCLUDE_DIRECTORIES../include)

set (LINK_DIR../../resource)


include_directories(${INCLUDE_DIRECTORIES})

link_directories(${LINK_DIR})


add_executable(Test_V4L2${EXEC_SRC_LIST})

target_link_libraries(Test_V4L2V4L2_Utils)


说明:

link_directories 指定连接器查找库的路径。

 

  link_directories(directory1 directory2...)


1.6:创建Release和Debug版本:

#set (CMAKE_BUILD_TYPE Release)

set (CMAKE_BUILD_TYPE Debug)

分别指定为Release或者Debug模式。区别在于:

Release:  -O3-DNDEBUG 

Debug:-g


也可以不加在txt内。在产生Makefile时才加入:

cmake -DCMAKE_BUILD_TYPE=Release



1.7:增加编译和链接选项

CMAKE_C_FLAGS

CMAKE_CXX_FLAGS

CMAKE_EXE_LINKER_FLAGS

分别相当于:CFLAGS, CXXFLAGS, LDFLAGS。

set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}-DEMBED")

这种写法的好处是,不会覆盖CMAKE_CXX_FLAGS本来的信息。只是把需要添加的内容添加进去。



1.8:多目录结构的cmake 使用:

V4L2_Utils实际的目录结构其实并不是所有源码都存放在src目录内。

它的目录结构是:

src: 存放生成库的源码。v4l2_util.cpp,tran_data.cpp

test:存放使用库的测试程序: main.cpp

include: 存放头文件: v4l2_util.h

resource: 存放第三方库

build:存放编译过程的文件

build/lib: 存放生成的libv4l2_utils.so

build/bin:存放main.cpp所产生的测试程序可执行文件。


此时,可以采用顶层目录和每个有源码的目录中均创建CMakeLists.txt的方式来处理(和Makefile处理方式类似)

顶层目录的CMakeLists.txt 内容如下:

cmake_minimum_required (VERSION2.6)


project (V4L2_Utils)

add_subdirectory(src lib)

add_subdirectory(test bin)

说明:

add_subdirectory(source_dir [binary_dir]
                  [EXCLUDE_FROM_ALL])

构建添加一个子路径。source_dir选项指定了CMakeLists.txt源文件和代码文件的位置。如果source_dir是一个相对路径,那么source_dir选项会被解释为相对于当前的目录,但是它也可以是一个绝对路径。binary_dir选项指定了输出文件的路径。如果binary_dir是相对路径,它将会被解释为相对于当前输出路径

请注意两个相对路径的不同。因为Sam是在Build目录内执行cmake..

source_dir算相对路径时,是从CMakeLists.txt算起。

所以src指的是当前CMakeLists.txt所在路径下的src. 而bin, lib 指的是当前输出路径下的bin,lib. 也就是build/binbuild/lib 



srcCMakeLists.txt :

set (LIB_SRC_LIST v4l2_util.cpp)

set (CMAKE_BUILD_TYPERelease)


include_directories(../include)

add_library(V4L2_Utils SHARED ${LIB_SRC_LIST})


testCMakeLists.txt :

set (EXEC_SRC_LISTmain.cpp)

set (INCLUDE_DIRECTORIES../include)

set (LINK_DIR../../resource)

set (LINK_DIR "${LINK_DIR}../../libs/")

set (CMAKE_BUILD_TYPERelease)


include_directories(${INCLUDE_DIRECTORIES})

link_directories(${LINK_DIR})

add_executable(Test_V4L2${EXEC_SRC_LIST})

target_link_libraries(Test_V4L2V4L2_Utils)


这个做法一直不满意,其实有更好的做法


总结:

有了以下这些选项,写过Makefile的人可以很容易的使用CMake了。

生成可执行程序:

add_executable(Test_V4L2${EXEC_SRC_LIST})

生成静态库

add_library(V4L2_Utils STATIC ${LIB_SRC_LIST})

生成动态库:

add_library(V4L2_Utils SHARED ${LIB_SRC_LIST})


指定头文件路径:  -I

include_directories(${INCLUDE_DIRECTORIES})


指定库文件路径: -L 

link_directories(${LINK_DIR})


指定链接库:-l

target_link_libraries(Test_V4L2V4L2_Utils)


CFLAGS,CXXFLAGS,LDFLAGS:

CMAKE_C_FLAGS,CMAKE_CXX_FLAGS,CMAKE_EXE_LINKER_FLAGS



注1:set和message

set用来指定变量

如:

set (SRC_LIST main.cpp)

则变量SRC_LIST内容为main.cpp

${SRC_LIST} 则为取变量内容(与Bash类似)


message:用来显示变量

message (${SRC_LIST})



注2:

如何显示编译细节:

方法1:

在CMakeLists.txt中,

set(CMAKE_VERBOSE_MAKEFILE ON)

方法2:

有时不希望修改CMakeLists.txt文件,则可以在创建Makefile时加入:

cmake -DCMAKE_VERBOSE_MAKEFILE=ON

方法3:

有时连Makefile都不希望修改:

make VERBOSE=1



注2:相对路径问题:

set (LIBRARY_DIRECTORIES../resource)
link_directories(${LIBRARY_DIRECTORIES})

这里会出警告:

This command specifies the relativepath

 ../resource


可以做如下处理:

set (LIBRARY_DIRECTORIES../resource)
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/${LIBRARY_DIRECTORIES})




注3:

https://cmake.org/



注4:

find_package()功能讲解:

例如:

find_package(Qt5Widgets)

可以被用来在系统中自动查找配置构建工程所需的程序库。在linux和unix类系统下这个命令尤其有用。CMake自带的模块文件里有大半是对各种常见开源库的find_package支持,支持库的种类非常多.

find_package( [version] [EXACT] [QUIET]
               [[REQUIRED|COMPONENTS] [components...]]
               [NO_POLICY_SCOPE])
查找并加载外来工程的设置。该命令会设置_FOUND变量,用来指示要找的包是否被找到了。如果这个包被找到了,与它相关的信息可以通过包自身记载的变量中得到。REQUIRED选项表示如果报没有找到的话,cmake的过程会终止,并输出警告信息
在REQUIRED选项之后,或者如果没有指定REQUIRED选项但是指定了COMPONENTS选项,在它们的后面可以列出一些与包相关的部件清单(components list)。


FIND_PACKAGE

每一个模块都会产生如下变量
_FOUND
_INCLUDE_DIR
_LIBRARY or _LIBRARIES
如果_FOUND为真,把_INCLUDE_DIR加入到INCLUDE_DIRECTORIES中,_LIBRARY加入到TARGET_LINK_LIBRARIES中。

就会有变量Qt5Widgets_FOUND,Qt5Widgets_INCLUDE_DIRS等相应的变量生效。


例如:

find_package(catkin REQUIREDCOMPONENTS

roscpp

rospy

std_msgs)

如果找到catkin package. 则catkin_FOUND被设置为true. catkin_INCLUDE_DIRS, catkin_LIBRARIES 被设置。

如果没找到,因为有REQUIRED. 所以会抱错。

CMake is a cross-platform open-source build system that is widely used for building software projects. It provides a simple and efficient way to define, configure, and generate build files for various platforms and build environments. To use CMake in Linux, you can follow these steps: 1. Install CMake: You can install CMake from the official website or using your package manager. For example, in Ubuntu, you can use the following command to install it: ``` sudo apt-get install cmake ``` 2. Create a CMakeLists.txt file: Create a text file named "CMakeLists.txt" in the root directory of your project. This file will contain the instructions for building your project. 3. Configure the project: Open a terminal and navigate to your project's root directory. Run the following command to configure your project using CMake: ``` cmake . ``` This command will generate the necessary build files based on the instructions provided in the CMakeLists.txt file. 4. Build the project: After configuring the project, you can build it using the following command: ``` make ``` This command will compile the source code and generate the executable or library files specified in the CMakeLists.txt file. 5. Run the project: Once the build process is complete, you can run your project by executing the generated executable file. These are the basic steps to use CMake in Linux. You can customize the CMakeLists.txt file according to your project's requirements, including specifying source files, libraries, compiler options, etc.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值