Cmake入门

1.cmake介绍

cmake是一种高级编译配置工具,当多个人用不同的语言或者编译器开发一个项目,最终要输出一个可执行文件或者共享库(dllso等等)时,Cmake就可以帮你做到,所有操作都是通过编译CMakeLists.txt来完成的。

2. Cmake使用

2.1 CMake构建一个HelloWord-内部构建

1、新建main.cpp

#include <iostream>

int main(){
    std::cout<<"hello world!"<<std::endl;
}

2、新建CMakeLists.txt,内部构建两个变量HELLO_SOURCE_DIR和HELLO_BINARY_DIR都是工程路径

PROJECT(HELLO)
SET(SRC_LIST main.cpp)
MESSAGE(STATUS "This is BINARY dir" ${HELLO_BINARY_DIR})
MESSAGE(STATUS "This is SOURCE dir" ${HELLO_SOURCE_DIR})
ADD_EXECUTABLE(hello ${SRC_LIST})

3、新建完毕目录结构如下


root@8d3:/work/cmake01# tree
.
├── CMakeLists.txt
└── main.cpp

0 directories, 2 files

4、执行cmake .,生成makefile文和CMakeFiles、CMakeCache.txt、 cmake_install.cmake 等文件,我们只需要关注Makefile文件。

root@8d3:/work/cmake01# cmake .
-- The C compiler identification is GNU 9.3.0
-- The CXX compiler identification is GNU 9.3.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- This is BINARY dir/work/cmake01
-- This is SOURCE dir/work/cmake01
-- Configuring done
-- Generating done
-- Build files have been written to: /work/cmake01
root@8d3:/work/cmake01# ls -l
total 40
-rw-r--r-- 1 root root 13738 Aug 24 16:48 CMakeCache.txt
drwxr-xr-x 5 root root  4096 Aug 24 16:48 CMakeFiles
-rw-r--r-- 1 root root   186 Aug 24 09:08 CMakeLists.txt
-rw-r--r-- 1 root root  5068 Aug 24 16:48 Makefile
-rw-r--r-- 1 root root  1610 Aug 24 16:48 cmake_install.cmake
-rw-r--r-- 1 root root    74 Aug 24 09:03 main.cpp

5、使用make命令编译,生成了hello的可执行程序,运行./hello,打印hello world!

root@8d3:/work/cmake01# make
[ 50%] Building CXX object CMakeFiles/hello.dir/main.cpp.o
[100%] Linking CXX executable hello
[100%] Built target hello
root@8d3:/work/cmake01# ls
CMakeCache.txt  CMakeFiles  CMakeLists.txt  Makefile  cmake_install.cmake  hello  main.cpp
root@8d3:/work/cmake01# ./hello
hello world!

2.2  CMake一个HelloWord-外部构建

内部构建生产的临时文件特别多,不方便清理,外部构建,就会把生成的临时文件放在build目录下,不会对源文件有任何影响

1、目录结构如下,其中build为新建目录,main.cpp与CMakeLists.txt文件内容与1相同

root@8d3:/work/cmake02# tree
.
├── CMakeLists.txt
├── build
└── main.cpp

1 directory, 2 files

2、进入build,运行cmake ..   ,..表示上一级目录,你也可以写CMakeLists.txt所在的绝对路径,生产的文件都在build目录下了

root@8d3:/work/cmake02/build# cmake ..

root@8d3:/work/cmake02/build# ls
CMakeCache.txt  CMakeFiles  Makefile  cmake_install.cmake

3、外部构建变量HELLO_SOURCE_DIR是工程路径,HELLO_BINARY_DIR是编译路径,即build的路径

4、在build目录下,使用make命令编译,生成了hello的可执行程序,运行./hello,打印hello world

root@8d3:/work/cmake02/build# make
[ 50%] Building CXX object CMakeFiles/hello.dir/main.cpp.o
[100%] Linking CXX executable hello
[100%] Built target hello
root@8d3:/work/cmake02/build# ls
CMakeCache.txt  CMakeFiles  Makefile  cmake_install.cmake  hello
root@8d3:/work/cmake02/build# ./hello
hello world!

2.3 安装HelloWord

1、目录结构如下

root@8d3:/work/cmake03# tree
.
├── CMakeLists.txt
├── COPYRIGHT
├── README
├── build
├── doc
│   └── hello.txt
├── runhello.sh
└── src
    ├── CMakeLists.txt
    └── main.cpp

2、主路径CMakeLists.txt内容

PROJECT(HELLO)
//将构建后的目标文件放入构建目录的 bin 子目录
ADD_SUBDIRECTORY(src bin)
/*
* 将COPYRIGHT/README 安装到${CMAKE_INSTALL_PREFIX}/share/doc/cmake/路径
* CMAKE_INSTALL_PREFIX  默认是在 /usr/local/
* 可在cmake时指定 cmake -D CMAKE_INSTALL_PREFIX=/usr
*/
INSTALL(FILES COPYRIGHT README DESTINATION share/doc/cmake/)
//安装脚本runhello.sh PROGRAMS:非目标文件的可执行程序安装
//实际安装到的是 /usr/local/bin
INSTALL(PROGRAMS runhello.sh DESTINATION bin)
//将doc目录下的文件安装到${CMAKE_INSTALL_PREFIX}/share/doc/cmake/路径
INSTALL(DIRECTORY doc/ DESTINATION share/doc/cmake)

3、src/CMakeLists.txt内容

ADD_EXECUTABLE(hello main.cpp)

4、src/main.cpp内容

#include <iostream>

int main(){
        std::cout<<"hello world!"<<std::endl;
}

5、进入build,运行cmake .. 

root@8d3:/work/cmake03/build# cmake ..

root@8d3:/work/cmake03/build# ls
CMakeCache.txt  CMakeFiles  Makefile  bin  cmake_install.cmake
root@8d3:/work/cmake03/build# cd bin/
root@8d3:/work/cmake03/build/bin# ls
CMakeFiles  Makefile  cmake_install.cmake

6、在build目录下,使用make命令编译,在build/bin目录下生成了hello的可执行程序,运行./hello,打印hello world

root@8d3:/work/cmake03/build# make
[ 50%] Building CXX object bin/CMakeFiles/hello.dir/main.o
[100%] Linking CXX executable hello
[100%] Built target hello
root@8d3:/work/cmake03/build# ls
CMakeCache.txt  CMakeFiles  Makefile  bin  cmake_install.cmake
root@8d3:/work/cmake03/build# cd bin/
root@8d3:/work/cmake03/build/bin# ls
CMakeFiles  Makefile  cmake_install.cmake  hello
root@8d3:/work/cmake03/build/bin# ./hello
hello world!

7、在build目录下,执行make install,将配置的文档和脚本安装至相应路径

root@8d3:/work/cmake03/build# make install
Consolidate compiler generated dependencies of target hello
[100%] Built target hello
Install the project...
-- Install configuration: ""
-- Installing: /usr/local/share/doc/cmake/COPYRIGHT
-- Installing: /usr/local/share/doc/cmake/README
-- Installing: /usr/local/bin/runhello.sh
-- Up-to-date: /usr/local/share/doc/cmake
-- Installing: /usr/local/share/doc/cmake/hello.txt

2.4 静态库和动态库的构建

2.4.1 静态库和动态库的区别

1、静态库的扩展名一般为“.a”或“.lib”;动态库的扩展名一般为“.so”或“.dll”。

2、静态库在编译时会直接整合到目标程序中,编译成功的可执行文件可独立运行

3、动态库在编译时不会放到连接的目标程序中,即可执行文件无法单独运行

2.4.2 构建安装动态库

1、目录结构如下

root@8d3:/work/cmake06# tree
.
├── CMakeLists.txt
├── build
└── lib
    ├── CMakeLists.txt
    ├── hello.cpp
    └── hello.h

2 directories, 4 files

2、各个文件内容如下

1.主目录 CMakeLists.txt
PROJECT(HELLO)
ADD_SUBDIRECTORY(lib bin)

2.lib/CMakeLists.txt
SET(LIBHELLO_SRC hello.cpp)
/**
* hello:就是正常的库名,生成的名字前面会加上lib,最终产生的文件是libhello.so
* SHARED,动态库 STATIC,静态库
* ${LIBHELLO_SRC} :源文件
/
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
INSTALL(FILES hello.h DESTINATION include/hello)
INSTALL(TARGETS hello LIBRARY DESTINATION lib)

3.lib/hello.h
#ifndef HELLO_H
#define Hello_H
void HelloFunc();
#endif

4.lib/hello.cpp
#include "hello.h"
#include <iostream>
void HelloFunc(){
     std :: cout << "hello world" << std :: endl;
}

3、在build目录下依次执行cmake .. 、make 、make install命令,动态库成功生成并安装至对应路径/usr/local/lib/libhello.so(/usr/local是make install默认的安装路径,/bin是CMakeLists.txt文件中指定的DESTINATION路径)

root@8d3:/work/cmake06/build# cmake ..
root@8d3d08540d36:/work/chenlu/cmake06/build# make
[ 50%] Building CXX object bin/CMakeFiles/hello.dir/hello.o
[100%] Linking CXX shared library libhello.so
[100%] Built target hello
root@8d3:/work/cmake06/build# make install
Consolidate compiler generated dependencies of target hello
[100%] Built target hello
Install the project...
-- Install configuration: ""
-- Installing: /usr/local/include/hello/hello.h //hello.h安装到了此路径
-- Installing: /usr/local/lib/libhello.so       //libhello.so安装到了此路径
root@8d3:/work/cmake06/build# ls
CMakeCache.txt  CMakeFiles  Makefile  bin  cmake_install.cmake  install_manifest.txt
root@8d3:/work/cmake06/build# cd bin/
root@8d3:/work/cmake06/build/bin# ls
CMakeFiles  Makefile  cmake_install.cmake  libhello.so //bin目录下生成了libhello.so

2.4.3 构建和安装动态库和静态库

使用不同的名字


// 如果用这种方式,只会构建一个动态库,不会构建出静态库,虽然静态库的后缀是.a
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
ADD_LIBRARY(hello STATIC ${LIBHELLO_SRC})

// 修改静态库的名字,这样是可以的,但是我们往往希望他们的名字是相同的,只是后缀不同而已
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
ADD_LIBRARY(hello_static STATIC ${LIBHELLO_SRC})

使用相同的名字

1.目录结构与构建动态库相同,lib目录下CMakeLists.txt内容如下,其他文件内容一致

SET(LIBHELLO_SRC hello.cpp)

ADD_LIBRARY(hello_static STATIC ${LIBHELLO_SRC})
SET_TARGET_PROPERTIES(hello_static PROPERTIES  OUTPUT_NAME "hello")
SET_TARGET_PROPERTIES(hello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)

ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
SET_TARGET_PROPERTIES(hello PROPERTIES  OUTPUT_NAME "hello")
SET_TARGET_PROPERTIES(hello PROPERTIES CLEAN_DIRECT_OUTPUT 1)

INSTALL(FILES hello.h DESTINATION include/hello)
INSTALL(TARGETS hello hello_static LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)

2. 在build目录下依次执行cmake .. 、make 、make install命令,动态库和静态库成功生成

root@8d3:/work/cmake07/build# cmake ..
root@8d3:/work/cmake07/build# make
[ 25%] Building CXX object bin/CMakeFiles/hello_static.dir/hello.o
[ 50%] Linking CXX static library libhello.a
[ 50%] Built target hello_static
[ 75%] Building CXX object bin/CMakeFiles/hello.dir/hello.o
[100%] Linking CXX shared library libhello.so
[100%] Built target hello
root@8d3:/work/cmake07/build# make install
Consolidate compiler generated dependencies of target hello_static
[ 50%] Built target hello_static
Consolidate compiler generated dependencies of target hello
[100%] Built target hello
Install the project...
-- Install configuration: ""
-- Installing: /usr/local/include/hello/hello.h  //头文件安装地址
-- Installing: /usr/local/lib/libhello.so        //动态库安装地址   
-- Installing: /usr/local/lib/libhello.a         //静态库安装地址

2.4.4  使用外部共享库和头文件

1.目录结构如下:

root@8d3:/work/cmake08# tree
.
├── CMakeLists.txt
├── build
└── src
    ├── CMakeLists.txt
    └── main.cpp

2、各个文件内容如下

1.主目录 CMakeLists.txt
PROJECT(HELLO)
ADD_SUBDIRECTORY(src bin)

2.src/CMakeLists.txt
//将hello.h的文件地址包含至工程中头文件的搜索路径
INCLUDE_DIRECTORIES(/usr/local/include/hello)
ADD_EXECUTABLE(hello main.cpp)
//链接动态库
TARGET_LINK_LIBRARIES(hello libhello.so)

3.src/main.cpp
#include <hello.h>
int main(){
    HelloFunc();
}

3、在build目录下,执行cmake..和make命令编译,在build/bin目录下生成了hello的可执行程序

root@8d3:/work/cmake08/build# cmake ..
root@8d3:/work/cmake08/build# make
[ 50%] Building CXX object bin/CMakeFiles/hello.dir/main.o
[100%] Linking CXX executable hello
[100%] Built target hello
root@8d3:/work/cmake08/build# cd bin/
root@8d3:/work/cmake08/build/bin# ls
CMakeFiles  Makefile  cmake_install.cmake  hello

 4、运行./hello,产生如下报错,因为生成的libhello.so文件在/usr/local/lib目录下,应该将其移至/usr/lib目录下(若电脑为64位,则移至/usr/lib64)

root@8d3:/work/cmake08/build/bin# ./hello
./hello: error while loading shared libraries: libhello.so: cannot open shared object file: No such file or directory
root@8d3:/work/cmake08/build/bin#

5、动态文件移至/usr/lib目录下,再执行./hello,程序成功运行

root@8d3:/work/cmake08/build/bin# mv /usr/local/lib/libhello.so /usr/lib
root@8d3:/work/cmake08/build/bin# ./hello
hello world

3. CMake语法介绍

3.1 关键字介绍

3.1.1 PROJECT

可以用来指定工程的名字和支持的语言,默认支持所有语言

PROJECT (HELLO)   指定了工程的名字,并且支持所有语言—建议

PROJECT (HELLO CXX)      指定了工程的名字,并且支持语言是C++

PROJECT (HELLO C CXX)      指定了工程的名字,并且支持语言是C和C++

该指定隐式定义了两个CMAKE的变量

 <projectname>_BINARY_DIR,例1中是 HELLO_BINARY_DIR

<projectname>_SOURCE_DIR,例1中是 HELLO_SOURCE_DIR

MESSAGE关键字就可以直接使用者两个变量

问题:如果改了工程名,这两个变量名也会改变

解决:又定义两个预定义变量:PROJECT_BINARY_DIR和PROJECT_SOURCE_DIR,这两个变量和HELLO_BINARY_DIR,HELLO_SOURCE_DIR是一致的。所以改了工程名也没有关系

3.1.2 SET

用来显示指定变量的

SET(SRC_LIST main.cpp)    SRC_LIST变量就包含了main.cpp

也可以 SET(SRC_LIST main.cpp t1.cpp t2.cpp)

更改二进制的保存路径

SET 指令重新定义 EXECUTABLE_OUTPUT_PATH 和 LIBRARY_OUTPUT_PATH 变量来指定最终的目标二进制的位置

SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)

3.1.3 MESSAGE

向终端输出用户自定义的信息

主要包含三种信息:

- SEND_ERROR,产生错误,生成过程被跳过

- STATUS,输出前缀为—的信息

- FATAL_ERROR,立即终止所有 cmake 过程

3.1.4 ADD_EXECUTABLE

生成可执行文件

ADD_EXECUTABLE(hello ${SRC_LIST})     生成的可执行文件名是hello,源文件读取变量SRC_LIST中的内容

也可以直接写 ADD_EXECUTABLE(hello main.cpp)

例1可以简化的写成

PROJECT(HELLO)

ADD_EXECUTABLE(hello main.cpp)

注意:工程名的 HELLO 和生成的可执行文件 hello 是没有任何关系的

3.1.5 ADD_SUBDIRECTORY 

ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])

这个指令用于向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制存放的位置,EXCLUDE_FROM_ALL函数是将写的目录从编译中排除,如程序中的example

ADD_SUBDIRECTORY(src bin),指将 src 子目录加入工程并指定编译输出(包含编译中间结果)路径为bin 目录,如果不进行 bin 目录的指定,那么编译结果(包括中间结果)都将存放在build/src 目录

3.1.6 INSTALL

1.安装文件
INSTALL(FILES COPYRIGHT README DESTINATION share/doc/cmake/)

2.非目标文件的可执行程序安装(如脚本)
INSTALL(PROGRAMS runhello.sh DESTINATION bin) 

3.安装目录下所包含的所有文件
INSTALL(DIRECTORY doc/ DESTINATION share/doc/cmake)

4.安装过程
make install

DESTINATION,写绝对路径,也可以写相对路径,相对路径实际路径是:${CMAKE_INSTALL_PREFIX}/<DESTINATION 定义的路径>

CMAKE_INSTALL_PREFIX  默认是在 /usr/local/

cmake -DCMAKE_INSTALL_PREFIX=/usr    在cmake的时候指定CMAKE_INSTALL_PREFIX变量的路径

3.1.7 ADD_LIBRARY

ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})

hello:就是正常的库名,生成的名字前面会加上lib,最终产生的文件是libhello.so

SHARED,动态库    STATIC,静态库

${LIBHELLO_SRC} :源文件

3.1.8 SET_TARGET_PROPERTIES

这条指令可以用来设置输出的名称,对于动态库,还可以用来指定动态库版本和 API 版本

//对hello_static的重名为hello
SET_TARGET_PROPERTIES(hello_static PROPERTIES  OUTPUT_NAME "hello")
//cmake 在构建一个新的target 时,会尝试清理掉其他使用这个名字的库,因为,在构建 libhello.so 时, 就会清理掉 libhello.a
SET_TARGET_PROPERTIES(hello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)

3.1.9 TARGET_LINK_LIBRARIES

链接静态库

TARGET_LINK_LIBRARIES(main libhello.a)  main二进制执行文件名 

链接动态库

TARGET_LINK_LIBRARIES(main libhello.so)  main二进制执行文件名 

3.1.10 SET_TARGET_PROPERTIES

SET_TARGET_PROPERTIES(hello PROPERTIES VERSION 1.2 SOVERSION 1)

VERSION 指代动态库版本,SOVERSION 指代 API 版本,生成文件如下:

root@8d3:/work/cmake09/build/bin# ls -l
total 36
drwxr-xr-x 3 root root  4096 Aug 25 10:37 CMakeFiles
-rw-r--r-- 1 root root  7459 Aug 25 10:37 Makefile
-rw-r--r-- 1 root root  3203 Aug 25 10:37 cmake_install.cmake
lrwxrwxrwx 1 root root    13 Aug 25 10:37 libhello.so -> libhello.so.1
lrwxrwxrwx 1 root root    15 Aug 25 10:37 libhello.so.1 -> libhello.so.1.2
-rwxr-xr-x 1 root root 16856 Aug 25 10:37 libhello.so.1.2

3.2 语法的基本原则

1、变量使用${}方式取值,但是在 IF 控制语句中是直接使用变量名

2、指令(参数 1 参数 2...) 参数使用括弧括起,参数之间使用空格或分号分开。 以上面的 ADD_EXECUTABLE 指令为例,如果存在另外一个 func.cpp 源文件,可以写成以下两种:

ADD_EXECUTABLE(hello main.cpp func.cpp)

ADD_EXECUTABLE(hello main.cpp;func.cpp)

3、指令是大小写无关的,参数和变量是大小写相关的。推荐全部使用大写指令

3.3 语法的注意事项

1、SET(SRC_LIST main.cpp) 可以写成 SET(SRC_LIST “main.cpp”),如果源文件名中含有空格,就必须要加双引号

2、ADD_EXECUTABLE(hello main) 后缀可以不写,他会自动去找.c和.cpp,最好不要这样写,可能会有这两个文件main.cpp和main

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值