Jamal的博客

cmake使用

CMake是一个跨平台的程序构建工具,比如起自己编写Makefile方便很多。

本文件不介绍CMake的基本语法,下面是篇不错的入门教程:
http://www.ibm.com/developerworks/cn/linux/l-cn-cmake/

构建命令: mac下一般clang自带了cmake,可以使用:/Applications/CLion.app/Contents/bin/cmake/bin/cmake –build ~/Library/Caches/CLion2016.2/cmake/generated/include-8feac24f/8feac24f/Debug –target hello – -j 8

一,首先构建比较简单的工程,来对CMake有个简单的了解

1.构建一个工程的时候,需要做的几件事情(如果下面几件事你知道怎么做了,多大的工程就都不是问题了):

A.源代码在哪里?
B.头文件在哪里?
C.怎么生成静态或者动态库?
D.程序链接的静态库在哪里?
E.如果工程的代码存放在很多地方,那又该怎么找到它们呢?

2.下面从一个最简单的HelloWorld开始,然后一步一步构建一个比较复杂的工程:

A.工程文件如下(只有一个helloworld.cpp源文件):
ciw@ubuntu:~/my_projects/test$ tree .
└── helloworld.cpp

B.这时候,我们要写一个CMakeLists.txt(就3句代码):
PROJECT(hello) #定义整个CMake的工程名
FILE(GLOB SOURCE “./*.cpp”) #告诉CMake:工程的源文件在哪里?
ADD_EXECUTABLE(hello ${SOURCE}) #告诉CMake:我们要生成可执行文件(hello),并且源文件是由上面定义的
这样就可以在目录下生成一个hello可执行文件了。

3.下面,我们讲一个带头文件的,而且文件都是存放在不同地方:

A.代码分布如下(main.cpp是main函数,里面调用了hello.h声明的SayHello,定义在hello.cpp中):
ciw@ubuntu:~/my_projects/test$ tree .
├── CMakeLists.txt
├── hello
│ └── hello.cpp
├── include
│ └── hello.h
└── main
└── main.cpp
B.main的代码:

#include “hello.h“
int main()
{
SayHello();
return 0;
}
C.CMakeLists.txt:
1 PROJECT(hello_2)
2
3 FILE(GLOB SOURCE_1 “${CMAKE_SOURCE_DIR}/main/.cpp”) //下面2句告诉CMake,源文件在哪里?main.cpp
4 FILE(GLOB SOURCE_2 “${CMAKE_SOURCE_DIR}/hello/
.cpp”)//程序必须链接到hello.cpp里面的SayHello
5
6 INCLUDE_DIRECTORIES(“${CMAKE_SOURCE_DIR}/include/“)//告诉CMake头文件在哪里?
7
8 ADD_EXECUTABLE(hello_2 ${SOURCE_1} ${SOURCE_2})

4.最后来一个复杂的工程:

A.工程描述:
该工程由一个静态库和一个可执行文件组成,头文件和源文件都不在同一个目录,并且CMake也是独立在一个目录

B.代码分布:
ciw@ubuntu:~/my_projects/test$ tree .
test //工程根目录
├── cmake //CMake目录:代码和CMake编译目录分离
│ ├── bin
│ │ └── main //生成后的可执行文件
│ ├── CMakeLists.txt
│ ├── lib
│ │ └── libhello.a //生成后的静态库
│ └── src
│ ├── CMakeLists.txt
│ ├── hello
│ │ └── CMakeLists.txt
│ └── main
│ └── CMakeLists.txt
├── hello //hello静态库的源代码
│ └── hello.cpp
├── include //头文件
│ └── hello.h
└── main //可执行文件的源代码目录
└── main.cpp
可以看出,CMake里面的每一个子目录都有一个CMakeLists.txt
C.编译该工程的过程:
(a).首先,需要给CMake的一个总入口,这个CMake设置一些全局的变量(cmake/CMakeLists.txt):
PROJECT(hello_3)
SET(PROJECT_ROOT_PATH “${CMAKE_SOURCE_DIR}/../“) #工程的根目录,即test
SET(EXECUTABLE_OUTPUT_PATH “${CMAKE_SOURCE_DIR}/bin/“) #可执行生成后存放的目录(CMAKE_SOURCE_DIR是cmake目录)
SET(LIBRARY_OUTPUT_PATH “${CMAKE_SOURCE_DIR}/lib/“) #静态库生成后存放的目录

INCLUDE_DIRECTORIES(“${PROJECT_ROOT_PATH}/include/“) #告诉CMake头文件在哪里?

LINK_DIRECTORIES(“${CMAKE_SOURCE_DIR}/lib/“) #告诉CMake静态库在哪里?

ADD_SUBDIRECTORY(src) #多目录,把src目录加进来,src里面才是真正编译main和hello的
(b).src目录下的CMakeList.txt,这个CMake只是简单地把main目录和hello目录链接起来:
ADD_SUBDIRECTORY(main)
ADD_SUBDIRECTORY(hello)
(c).hello静态库:
FILE(GLOB SOURCE_1 “${PROJECT_ROOT_PATH}/hello/*.cpp”) #告诉CMake源文件在哪里?
ADD_LIBRARY(hello STATIC ${SOURCE_1}) #告诉CMake生成的是一个静态库

(d).main可执行文件:
FILE(GLOB SOURCE_1 “${PROJECT_ROOT_PATH}/main/*.cpp”) #告诉CMake源文件在哪里?

ADD_EXECUTABLE(main ${SOURCE_1}) #告诉CMake生成一个main可执行文件
TARGET_LINK_LIBRARIES(main hello) #告诉CMake静态库在哪里?

整个编译的过程就是这样了,最主要的是记住上面”构建一个工程的时候,需要做的几件事情:头文件,源文件,静态库这个元素“,那么再复杂的工程都是这样一步一步构建的