【CMake】简单学习

快速上手

1. 安装Cake

sudo apt-get install cmake

2. 编写HelloWorld

main.cpp

#inlcude<iostream>

int main()
{
	std::cout << "Hello, World!" << std::endl;
	return 0;
}

3. 编写Cmake文件CMakeLists.txt

注意,Cmake文件的名字只能是CMakeLists.txt

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})

4. 使用cmake命令编译当前目录

cmake .

在这里插入图片描述

5. 使用make命令进A行编译

make

在这里插入图片描述

查看当前目录
在这里插入图片描述

6. 执行hello文件

./hello

执行结果
在这里插入图片描述

语法介绍

以上述例子中的CMakeLists.txt为例

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})

PROJECT关键字

可以用来指定工程的名字和支持的语言,默认支持所有语言
PROJECT(HELLO) 指定了工程的名字,并且支持所有语言
PROJECT(HELLO CXX) 指定了工程的名字,并且支持语言是C++
PROJECT(HELLO C CXX) 指定了工程的名字,并且支持所有语言是C和C++

该指定隐式定义了两个CMake的变量
<projectname>_BINARY_DIR 本例中是HELLO_BINARY_DIR
<projectname>_SOURCE_DIR 本例中是HELLO_SOURCE_DIR
MESSAGE关键字可以直接使用这两个变量,都指向当前的工作目录
问题:如果改变了工程名,则这两个变量名也会改变
解决:又定义两个预定义变量:PROJECT_BINARY_DIR,PROJECT_SOURCE_DIR,而这两个变量和HELLO_BINARY_DIR,HELLO_SOURCE_DIR是一致的。

SET关键字

用来显式地指定变量
SET(SRC_LIST main.cpp) SRC_LIST变量就包含了main.cpp
也可以SET(SRC_LIST main.cpp t1.cpp t2.cpp)
多个cpp之间用空格分隔

MESSAGE关键字

向终端输出用户自定义信息
主要包含三种:

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

  • STATUS, 输出前缀为--的信息
    在这里插入图片描述

  • FATAL_ERORR, 立刻终止所有CMake的过程

ADD_EXECUTABLE关键字

生成可执行文件
ADD_EXECUTABLE(hello ${SRC_LIST})
其中hello为生成的可执行文件的文件名,源文件读取变量SRC_LIST中的内容
也可以直接写成ADD_EXECUTABLE(hello main.cpp)

快速上手中的CMakeLists.txt例子可以简化为

PROJECT(HELLO)
ADD_EXECUTABLE(hello main.cpp)

注意这里的工程名HELLO和最后生成的可执行文件文件名hello没有关系

语法基本原则

  • 变量使用${}方式取值,但是在IF控制语句中是直接使用变量名
  • 指令(参数1, 参数2…),参数使用括弧括起,参数之间使用空格或分号隔开,以上述的ADD_EXECUTABLE指令为例,如果存在另外一个func.cpp源文件,写法为
    • ADD_EXECUTABLE(hello main.cpp func.cpp)
    • ADD_EXECUTABLE(hello main.cpp;func.cpp)
  • 指令是大小写无关的,参数是大小写相关的,但是推荐指令全部大写

语法注意事项

  • SET(SRC_LIST main.cpp)可以写成SET(SRC_LIST “main.cpp”),如果源文件名中有空格,则必须要加双引号
  • ADD_EXECUTABLE(hello main)后缀可以不加,但是推荐添加

内部构建和外部构建

  • 内部构建:上述例子就是内部构建,产生较多的临时文件,不方便清理
  • 外部构建:把生成的临时文件放在build目录下,不会对源文件有任何影响,推荐使用外部构建

使用外部构建

清除之前的所有临时文件
rm -rf CMakeCache.txt CMakeFiles cmake_install.cmake Makefile

创建build目录用来存放这些临时文件
mkdir build
cd build

使用cmake进行编译
cmake .. 编译的是build目录的上一级目录

使用make进行编译
make

在这里插入图片描述

让HelloWorld看起来更像一个工程

  • 添加一个子目录src,用来存放工程源代码
  • 添加一个子目录doc,用来存放工程文档
  • 在工程目录中添加文本文件COPYRIGHT(版权),READEME(阅读信息)
  • 在工程目录中添加一个runhello.sh脚本,用来调用hello二进制文件
  • 将构建后的目标文件放入构建目录的bin子目录
  • 将doc目录的内容以及COPYRIGHT/READEME安装到/usr/share/doc/cmake/

将目标文件放入构建目录的bin子目录

每个目录下都要有一个CMakeLists.txt

  • 创建src目录,并将main.cpp移动到src

    mkdir src
    mv main.cpp src
    
  • 重写项目根目录下的CMakeLists.txt

    echo "" > CMakeLists.txt
    
    PROJECT(HELLO)
    ADD_SUBDIRECTORY(src bin) //关联到src,生成的中间二进制或目标二进制文件都存放到bin目录
    
  • 重写src目录下的CMakeLists.txt

    ADD_EXECUTABLE(hello main.cpp)
    
  • 跳转到build目录下进行cmake编译和make编译

    cmake ..
    make
    
  • 可以发现build目录下多出了bin目录,bin目录结构
    在这里插入图片描述

ADD_SUBDIRECTORY指令

ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])

  • 这个指令用于向当前工程项目添加存放源文件的子目录,并且可以指定中间二进制和目标二进制的存放位置
  • EXCLUDE_FROM_ALL函数是将写的目录从编译中排除,如程序中的example
  • ADD_SUBDIRECTORY(bin src)
    将src子目录加入工程项目并指定编译输出(包含编译中间结果)路径为bin目录
    如果不进行bin目录的指定,则编译结果(包含编译中间结果)都将存放到build/src目录中

更改二进制的保存路径

SET指令重新定义EXECUTABLE_OUTPUT_PATH和LIBRARY_OUTPUT_PATH变量来指定最终的目标二进制的位置
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)

哪里要改变目标存放路径,就在哪里加入上述的定义,所以应该在src/CMakeLists.txt中写

如何安装HelloWorld

使用CMAKE一个新的指令:INSTALL
INSTALL的安装可以包括:二进制、动态库、静态库以及文件、目录、脚本等
使用CMAKE一个新的变量:CMAKE_INSTALL_PREFIX

首先添加相应需要添加的文件

touch COPYRIGHT
mkdir doc
cd doc
touch hello.txt
cd ..
touch README
touch runhello.sh

安装COPYRIGHT和README

INSTALL(FILES COPYRIGHT README DESTINATION share/doc/cmake/)
FILES:文件
DESTINATION:
1、写绝对路径
2、写相对路径,相对路径的实际路径是:${CMAKE_INSTALL_PREFIX}/<DESTINATION定义的路径>
CMAKE_INSTALL_PREFIX默认是在/usr/local/
cmake -DCMAKE_INSTALL_PREFIX=/usr ,在cmake的时候指定CMAKE_INSTALL_PREFIX变量的值

安装脚本runhello.sh

PROGRAMS:非目标文件的可执行程序安装(比如脚本)
INSTALL(PROGRAMS runhello.sh DESTINATION bin)
说明:实际安装到的是/usr/local/bin

安装doc中的hello.txt

  • 通过在doc目录中建立CMakeLists.txt,通过install下的file
  • 直接在工程目录通过 INSTALL (DIRECTORY doc/ DESTINATION share/doc/cmake)
    DIRECTORY 后面连接的是所在SOURCE目录的相对路径
    注意:abc和abc/有很大区别
    目录名不以/结尾:这个目录将被安装为目标路径下的/
    目录名以/结尾:将这个目录中的内容安装到目标路径
cd build
cmake ..
make
make install   //如果出现Maybe need administrative privileges. 使用sudo make install

在这里插入图片描述

静态库和动态库的构建

1、建立一个静态库和动态库,提供HelloFunc函数供其他程序编程使用,HelloFunc向终端输出Hello World字符串
2、安装头文件与共享库

静态库和动态库的区别:

  • 静态库的扩展名一般为".a"或".lib";动态库的扩展名一般为".so"或".dll"
  • 静态库在编译时会直接整合到目标程序中,编译成功的可执行文件可独立运行
  • 动态库在编译时不会被放到连接的目标程序中,可执行程序无法单独运行
mkdir cmake02
cd cmake02
mkdir build
touch CMakeLists.txt
mkdir lib
cd lib
touch CMakeLists.txt
touch hello.cpp
touch hello.h
hello.h
#ifndef HELLO_H
#define HELLO_H

void HelloFunc();

#endif


hello.cpp
#include"hello.h"
#include<iostream>

void HelloFunc() {
	std::cout << "Hello World!" << std::endl;
}

cmake02/CMakeLists.txt
PROJECT(HELLO)
ADD_SUBDIRECTORY(lib bin)

cmake02/lib/CMakeLists.txt
SET(LIBHELLO_SRC hello.cpp)
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})

进行编译

cd build
cmake ..
make

在这里插入图片描述

ADD_LIBRARY

ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})

  • hello:就是正常的库名,生成的名字前面会加上lib,最终产生的文件是libhello.so
  • SHARED:动态库;STATIC:静态库
  • ${LIBHELLO_SRC}:源文件

同时构建静态库和动态库

// 使用如下方式,只会构建出一个动态库,不会构建出静态库
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})

SET_TARGET_PROPERTIES

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

修改版本号
SET_TARGET_PROPERTIES(hello PROPERTIES VERSION 1.2 SOVERSION 1)
VERSION指动态库版本,SOVERSION指API版本

同时构建静态和动态库

SET(LIBHELLO_SRC hello.cpp)

ADD_LIBRARY(hello_static STATIC ${LIBHELLO_SRC})

//对于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)

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

在build目录下执行

rm -rf *
cmake ..
make

在这里插入图片描述

安装共享库和头文件

在lib/CMakeLists.txt下添加

//将hello.放到相对路径的include/hello下,实际默认是/usr/local/include/hello
INSTALL(FILES hello.h DESTINATION include/hello)

// 其中hello动态库由LIBRARY指定到lib下,而hello_static由ARCHIVE指定到lib下
// 二进制,静态库和动态库安装都用TARGETS
// ARCHIVE特指静态库,LIBRARY特指动态库,RUNTIME特指可执行二进制目标文件
// lib是相对路径,实际默认是/usr/local/lib
INSTALL(TARGETS hello hello_static LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)

安装时,指定一下路径,放到系统下

cmake -D CMAKE_INSTALL_PREFIX=/usr ..
make
make install

.在这里插入图片描述
在这里插入图片描述

使用外部共享库和头文件

mkdir cmake03
mkdir build
touch CMakeLists.txt
mkdir src
cd src
touch CMakeLists.txt
touch main.cpp
cd ..
cmake03/CMakeLists.txt
PROJECT(HELLO)
ADD_SUBDIRECTORY(src bin)


cmake03/src/CMakeLists.txt
ADD_EXECUTABLE(hello main.cpp)
INCLUDE_DIRECTORIES(/usr/include/hello)


main.cpp
#include<hello.h>
int main()
{
	HelloFunc();
	return 0;
}

如果出现问题,将cmake03/src/CMakeLists.txt修改如此

INCLUDE_DIRECTORIES(/usr/include/hello)

LINK_DIRECTORIES(/usr/include/hello)

ADD_EXECUTABLE(hello main.cpp)

TARGET_LINK_LIBRARIES(hello libhello.so)

LINK_DIRECTORIES

用来指定非标准库的共享库的路径

TARGET_LINK_LIBRABRIES

用于将两个可执行文件进行链接,这里是hello和libhello.so

在这里插入图片描述

至此,就完成了使用外部共享库和头文件

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值