make与cmake入门

2023-05-16

文章目录

  • 1. 手动链接与编译
  • 2. make编译工具
    • 2.1 介绍makefile
    • 2.2 makefile三要素
    • 2.3 make工作原理
    • 2.4 实战
      • 案例1
      • 案例2
      • 案例3
      • 案例4
    • 2.5 常见的自动化变量解析
  • 3. 使用cmake进行编译
    • 3.1 介绍cmake
    • 3.2 介绍CMakeLists.txt
    • 3.3 CMake安装
    • 3.4 实战案例
    • ==3.5 语法介绍==
      • 3.5.1 PROJECT关键字
      • 3.5.2 SET关键字
      • 3.5.3 MESSAGE关键字
      • 3.5.4 ADD_EXECUTABLE关键字
      • 3.5.5 cmake_minimum_required关键字
      • 3.5.6 include_directories关键字
      • 3.5.7 link_directories关键字
      • 3.5.8 add_library关键字
      • 3.5.9 add_compile_options关键字
      • 3.5.10 target_link_libraries关键字
      • 3.5.11 add_subdirectory关键字
      • 3.5.12 aux_source_directory关键字
    • ==3.5 Cmake 常用变量==
    • 3.6 语法的基本原则
      • 3.6.1语法注意事项
    • 3.7 内部构建和外部构建
      • ==3.7.1 外部构建方式举例==
    • 3.8 让编译可执行文件看起来更像一个工程
      • 3.8.1将目标文件放入构建目录的 bin 子目录
      • 3.8.2关于ADD_SUBDIRECTORY 指令
      • 3.8.3更改二进制的保存路径
    • 3.9 CMake项目的编译概述
  • 4. 使用cmake进行安装
    • 4.1 如何安装
      • 4.1.0 首先是需要创建目录树结构
      • 4.1.1 安装文件COPYRIGHT和README
      • 4.1.2 安装脚本runhello.sh
      • 4.1.3 安装 doc 中的 hello.txt
      • 4.1.3 安装过程
  • 5. 使用cmake进行静态库和动态库的构建
    • 5.0 构建实例
    • 5.1 ADD_LIBRARY关键字
    • 5.2 同时构建静态和动态库
    • 5.3 SET_TARGET_PROPERTIES关键字
    • 5.4 动态库的版本号
    • 5.5 安装共享库和头文件
    • 5.6 使用外部共享库和头文件
    • 5.7 解决:make后头文件找不到的问题
    • 5.8 解决:找到引用的函数问题
    • 5.9 找不到动态库
    • 5.10 特殊的环境变量 CMAKE_INCLUDE_PATH 和 CMAKE_LIBRARY_PATH
  • 6. 关于GNU, GCC,gcc,g++,Mingw,MSVC关系
    • GNU
    • GCC
    • gcc
    • g++
    • MingW
    • MSVC
  • 7. windows系统下:vscode中使用cmake和gdb:
    • 改写配置文件launch.json和tasks.json
  • 8. linux系统下:vscode中使用cmake和gdb:
  • 9. 参考博文:

1. 手动链接与编译

采用逐个编译

g++ cpp文件 -c	#会生成.o文件

生成可执行文件需要链接所有.o文件

g++ *.o -o main	#生成可执行文件

以上操作中过于繁琐

所有的g++编译的文件可以写成脚本,按照makefile格式进行编写

2. make编译工具

2.1 介绍makefile

  • make 工具通过一个称为 makefile 的文件来完成并自动维护编译工作,执行make指令,make工具会在当前目录下找名字叫“Makefile”或“makefile”的文档,类似于执行脚本。

  • makefile 需要按照某种语法进行编写,其中说明了如何编译各个源文件并连接生成可执行文件,并定义了源文件之间的依赖关系

  • 当修改了其中某个源文件时,如果其他源文件依赖于该文件,则也要重新编译所有依赖该文件的源文件。

  • 简单来说,make工具通过编写makefile来批量编译,取代了手动编写编译文档的工作量。但是当工程非常大的时候,手写makefile也是非常麻烦的,如果换了个平台makefile又要重新修改。

2.2 makefile三要素

在这里插入图片描述

基于三要素,接下来介绍makefile的基本格式

[目标] : [依赖] 	
	[命令](命令前面是tab制表符,不是空格)
  • 目标:规则的目标,可以是 Object File(一般称它为中间文件),也可以是可执行文件,还可以是一个标签;

  • 依赖:是我们的依赖文件,要生成 targets 需要的文件或者是另一个目标。可以是多个,也可以是没有;

  • 命令:make 需要执行的命令(任意的 shell 命令)。可以有多条命令,每一条命令占一行。

输入make命令会在当前路径下找到Makefile,或者也可以指定make -f Makefile

2.3 make工作原理

在这里插入图片描述

2.4 实战

案例1

hello: main.cpp printhello.cpp factorial.cpp
	g++ -o hello main.cpp printhello.cpp factorial.cpp

案例2

CXX = g++
TARGET = hello 
OBJ = main.o printhello.o factorial.o

$(TARGET): $(OBJ)
	$(CXX) -o $(TARGET) $(OBJ)

main.o: main.cpp
	$(CXX) -c main.cpp

printhello.o: printhello.cpp
	$(CXX) -c printhello.cpp

factorial.o: factorial.cpp
	$(CXX) -c factorial.cpp

案例3

CXX = g++
TARGET = hello 
OBJ = main.o printhello.o factorial.o

CXXFLAGS = -c -Wall #解除所有警告

$(TARGET): $(OBJ)
	$(CXX) -o $@ $^ #$@表示目标,$^表示依赖(所有)

%.o: %.cpp
	$(CXX) $(CXXFLAGS) $< -o $@ #$<表示依赖的第一个

.PHONY: clean
clean:
	rm -f *.o $(TARGET) # -f表示强制删除

.PHONY,makefile的特殊变量。以clean为例,第一种情况,我们不需要生成"clean"这个文件,另一种情况“clean”目标与文件"clean"重名时,目标不会执行。所以我们需要一个"伪目标"去执行makefile中的“clean”下面的命令。

案例4

CXX = g++
TARGET = hello 
SRC = $(wildcard *.cpp) #源文件为所有的cpp文件
OBJ = $(patsubst %.cpp, %.o, $(SRC))

CXXFLAGS = -c -Wall

$(TARGET): $(OBJ)
	$(CXX) -o $@ $^

%.o: %.cpp
	$(CXX) $(CXXFLAGS) $< -o $@

.PHONY: clean
clean:
	rm -f *.o $(TARGET)

2.5 常见的自动化变量解析

变量解析
$0当前脚本的文件名。
$n(n≥1)传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是 $1,第二个参数是 $2>。
$#传递给脚本或函数的参数个数。
$*传递给脚本或函数的所有参数。
$@表示目标文件。
$?上个命令的退出状态,或函数的返回值。
$$当前 Shell 进程 ID。对于 Shell 脚本,就是这些脚本所在的进程 ID。
$^表示所有的依赖文件
$<表示第一个依赖文件

wildcard,用于防止通配符解析失败。使变量定义时,括号里的通配符仍然生效。

patsubst,用于防止替换文件解析失效。替换文件后缀。

3. 使用cmake进行编译

3.1 介绍cmake

  • Cmake工具可以更加简单的生成makefile文件,执行make指令即可完成编译。当然cmake还有其他功能,就是可以跨平台生成对应平台能用的makefile,你不用自己去修改了。
  • cmake的定义是什么 ?-----高级编译配置工具

3.2 介绍CMakeLists.txt

  • 可是cmake根据什么生成makefile呢?cmake要根据一个叫CMakeLists.txt文件(学名:组态档)去生成makefile。注意,文件名必须是CMakeLists.txt。

  • CMakeLists.txt需要手动编写,但是它也有它的规则。

3.3 CMake安装

1、绝大多数的linux系统已经安装了CMake

cmake --version#查看是否安装cmake

如果没有安装则执行如下代码:

sudo apt-get install cmake

2、Windows或某些没有安装过的linux系统,去点我跳转可以下载安装

3.4 实战案例

CMakeList.txt

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

创建build目录,便于清除cmake产生的除Makefile之外的多余文件

#创建build目录
mkdir build 
cd build

# build中编译
cmake .. 	#返回上一级目录中找到CMakeList.txt

# 构建 make或 cmake --build . 
cmake --build .  

执行生成的makefile

# 进入build文件中执行,要在makefile文件的路径下执行
make

输出结果
在这里插入图片描述

3.5 语法介绍

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

3.5.1 PROJECT关键字

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

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

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

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

该指定隐式定义了两个CMAKE的变量,projectname需要用变量去代替

  • <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是一致的。所以改了工程名也没有关系

3.5.2 SET关键字

用来显示的指定变量的

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

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

3.5.3 MESSAGE关键字

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

主要包含三种信息:

  • SEND_ERROR,产生错误,生成过程被跳过。
  • SATUS,输出前缀为—— ——的信息。
  • FATAL_ERROR,立即终止所有 cmake 过程.

3.5.4 ADD_EXECUTABLE关键字

  • add_excutable : 生成可执行文件

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

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

上述例子可以简化的写成

PROJECT(HELLO)
ADD_EXECUTABLE(hello main.cpp)

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

3.5.5 cmake_minimum_required关键字

  • cmake_minimum_required : 指定cmake最小版本要求
# 指定cmake最小版本要求为 2.8.3
cmake_minimum_required(VERSION 2.8.3)

3.5.6 include_directories关键字

  • include_directories : 向工程中添加多个头文件搜索路径,相当于指定 g++-I 参数
# 将 /usr/include 和 ./include 路径添加到头文件搜索路径中
include_directories(/usr/include ./include)

3.5.7 link_directories关键字

  • link_directories : 向工程中添加多个库文件搜索路径,相当于 g++-L 参数
# 将 /usr/lib 和 ./lib 路径添加到库文件搜索路径中
link_directories(/usr/lib ./lib)

3.5.8 add_library关键字

  • add_library : 生成库文件
# 通过变量SRC_LIST 生成hello.so 共享库,第二个参数填 SHARED 或 STATIC 或 MOUDLE
add_library(hello SHARED ${SRC_LIST })

3.5.9 add_compile_options关键字

  • add_compile_options : 添加编译参数
# 添加编译参数 -Wall -std=c++11 以及 -o2
add_compile_options(-Wall -std=c++11 -o2)

3.5.10 target_link_libraries关键字

  • target_link_libraries : 为目标可执行文件添加需要的共享库,相当于g++编译器的-l参数
# 将hello动态库文件链接到可执行文件main
target_link_libraries(main hello)

例如,生成了动态库和可执行文件,运行可执行文件的时候链接动态库
在这里插入图片描述

总结:一般有add_library就有target_link_libraries

3.5.11 add_subdirectory关键字

  • add_subdirectory : 向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制存放的位置
# 添加src子目录,src中需要有一个 CMakeLists.txt
add_subdirectory(src)

3.5.12 aux_source_directory关键字

  • aux_source_directory : 发现一个目录下所有的源代码文件并将列表存储在一个变量中,这个指令临时被用来自动构建源文件列表。
# 定义 SRC 变量,其值为当前目录下所有的源代码文件
aux_source_directory(. SRC)
# 编译SRC 变量下的源代码文件,生成 mian 可执行文件
add_excutable(main ${SRC)

3.5 Cmake 常用变量

  • CMAKE_FLAGS : gcc 编译选项
  • CMAKE_CXX_FLAGS : g++ 的编译选项
# 在 CMAKE_CXX_FLAGS 编译选项后追加 -std=c++11
set(CMAKE_CXX_FLAGS "{CMAKE_CXX_FLAGS} -std=c++11")
  • CMAKE_BUILD_TYPE : 编译类型(Debug,Release)
# 设定编译类型为 debug ,调试时需要选择 debug 
set(CMAKE_BUILD_TYPE Debug)
# 设定编译类型为release,发布时需要选择 release
set(CMAKE_BUILD_TYPE Release)
  • CMAKE_BINARY_DIRPROJECT_BINARY_DIR<projectname>_BINARY_DIR
  1. 这三个变量指代的内容是一致的
  2. 如果是 in binary build ,指的就是工程顶级目录
  3. 如果是 out-of-binary 编译,指的是工程编译发生的目录
  4. PROJECT_BINARY_DIR 跟其他指令稍有区别,但这里可以理解他们是一致的
  • CMAKE_SOURCE_DIRPROJECT_SOURCE_DIR<projectname>_SOURCE_DIR
  1. 这三个变量指代的内容是一致的,不论采用何种编译方式,都是工程经层目录
  2. 如果是 in source build ,跟 CMAKE_BINARY_DIR 变量一致
  3. PROJECT_SOURCE_DIR 跟其他指令稍有区别,但这里可以理解他们是一致的
  • CMAKE_C_COMPILE : 指定C编译器

  • CMAKE_CXX_COMPILE : 指定C++编译器

  • EXECUTABLE_OUT_PATH : 可执行文件输出的存放路径

  • LIBRARY_OUTOUT_PATH : 库文件输出的存放路径

3.6 语法的基本原则

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

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

    就要写成:ADD_EXECUTABLE(hello main.cpp func.cpp)或者ADD_EXECUTABLE(hello main.cpp;func.cpp)

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

3.6.1语法注意事项

  • SET(SRC_LIST main.cpp) 可以写成 SET(SRC_LIST “main.cpp”),如果源文件名中含有空格,就必须要加双引号
  • ADD_EXECUTABLE(hello main) 后缀可以不行,他会自动去找.c和.cpp,最好不要这样写,可能会有这两个文件main.cpp和main

3.7 内部构建和外部构建

  • 上述例子就是内部构建,内部构建会产生很多中间文件,这些文件并不是我们最终想要的,和工程源代码文件放在一起会显得杂乱无章。
  • 外部构建,就会把生成的临时文件放在build目录下,不会对源文件有任何影响强烈使用外部构建方式

内部构建示例

# 在项目源代码根目录下,使用  cmake 指令解析 CMakeLists.txt ,生成 Makefile 和其他文件
cmake .
# 执行 make 命令,生成 target
make

3.7.1 外部构建方式举例

1、建立一个build目录,可以在任何地方,建议在当前目录下

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

3、在build目录下,运行make来构建工程

注意外部构建的两个变量

  • 1、HELLO_SOURCE_DIR 还是工程路径 也就是 /root/cmake【SOURCE表示源文件】

  • 2、HELLO_BINARY_DIR 编译路径 也就是 /root/cmake/bulid【这里的BINARY也就是bin文件夹的简写,一般存放二进制可执行文件】

3.8 让编译可执行文件看起来更像一个工程

  • 为工程添加一个子目录 src,用来放置工程源代码
  • 添加一个子目录 doc,用来放置这个工程的文档 hello.txt
  • 在工程目录添加文本文件 COPYRIGHT, README
  • 在工程目录添加一个 runhello.sh 脚本,用来调用 hello 二进制
  • 将构建后的目标文件放入构建目录的 bin 子目录
  • 将 doc 目录 的内容以及 COPYRIGHT/README 安装到/usr/share/doc/cmake/

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

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

[root@localhost cmake]# tree
.
├── build
├── CMakeLists.txt
└── src
    ├── CMakeLists.txt
    └── main.cpp

外层CMakeLists.txt

PROJECT(HELLO)
ADD_SUBDIRECTORY(src bin) #关联内部的CMakeLists.txt

src下的CMakeLists.txt

ADD_EXECUTABLE(hello main.cpp)

3.8.2关于ADD_SUBDIRECTORY 指令

ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
  • 这个指令用于向当前工程添加存放源文件的子目录【source_dir变量】,并可以指定中间二进制和目标二进制存放的位置【binary_dir变量】

  • EXCLUDE_FROM_ALL函数是将写的目录从编译中排除,如程序中的example

  • ADD_SUBDIRECTORY(src bin)

    • 将 src 子目录加入工程并指定编译输出(包含编译中间结果)路径为bin 目录

    • 如果不进行 bin 目录的指定,那么编译结果(包括中间结果)都将存放在build/src 目录

3.8.3更改二进制的保存路径

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

SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)

思考:加载哪个CMakeLists.txt当中

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

3.9 CMake项目的编译概述

CMake项目的主要目录存在一个 CMakeLists.txt 文件

我们有两种当时设置编译规则

  • 包含源文件的子文件夹包含 CMakeLists.txt 文件,主目录的 CMakeLists.txt 通过 add_subdirectory 添加子目录即可
  • 包含源文件的子文件夹未包含 CMakeLists.txt 文件,子目录编译规则体现在主目录的 CMakeLists.txt 文件

4. 使用cmake进行安装

  • 一种是从代码编译后直接 make install 安装
  • 一种是打包时的指定 目录安装。
    • 简单的可以这样指定目录:make install DESTDIR=/tmp/test
    • 稍微复杂一点可以这样指定目录:./configure –prefix=/usr

4.1 如何安装

使用CMAKE一个新的指令:INSTALL

INSTALL的安装可以包括:二进制、动态库、静态库以及文件、目录、脚本等

使用CMAKE一个新的变量:CMAKE_INSTALL_PREFIX,指定安装目录,默认是在 /usr/local/

4.1.0 首先是需要创建目录树结构

// 目录树结构
[root@localhost cmake]# tree
.
├── build
├── CMakeLists.txt
├── COPYRIGHT
├── doc
│   └── hello.txt
├── README
├── runhello.sh
└── src
    ├── CMakeLists.txt
    └── main.cpp

4.1.1 安装文件COPYRIGHT和README

在外部CMakeLists.txt文件中添加如下指令

INSTALL(FILES COPYRIGHT README DESTINATION share/doc/cmake/)
  • FILES:安装文件

  • DESTINATION:

    • 1、可以写绝对路径

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

CMAKE_INSTALL_PREFIX 默认是在 /usr/local/,所以DESTINATION 的路径在/usr/local/share/doc/cmake/

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

4.1.2 安装脚本runhello.sh

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

说明:实际安装到的是 /usr/bin

4.1.3 安装 doc 中的 hello.txt

  • 一、是通过在 doc 目录建立CMakeLists.txt ,通过install下的file

  • 二、是直接在工程目录通过

INSTALL(DIRECTORY doc/ DESTINATION share/doc/cmake)
  • DIRECTORY 后面连接的是所在 Source 目录的相对路径

注意:abc 和 abc/有很大的区别

  • 目录名不以/结尾:这个目录将被安装为目标路径下的

  • 目录名以/结尾:将这个目录中的内容安装到目标路径

4.1.3 安装过程

cmake ..

make

make install

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

5. 使用cmake进行静态库和动态库的构建

任务:

1,建立一个静态库和动态库,提供 HelloFunc 函数供其他程序编程使用,HelloFunc 向终端输出 Hello World 字符串。

2,安装头文件与共享库。

静态库和动态库的区别

  • 静态库的扩展名一般为“.a”或“.lib”;动态库的扩展名一般为“.so”或“.dll”。
  • 静态库在编译时会直接整合到目标程序中,编译成功的可执行文件可独立运行
  • 动态库在编译时不会放到连接的目标程序中,即可执行文件无法单独运行。

5.0 构建实例

[root@localhost cmake2]# tree
.
├── build
├── CMakeLists.txt
└── lib
    ├── CMakeLists.txt
    ├── hello.cpp
    └── 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;
}

外部CMakeLists.txt的内容

PROJECT(HELLO)
ADD_SUBDIRECTORY(lib bin)

lib中CMakeLists.txt中的内容

SET(LIBHELLO_SRC hello.cpp)
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})

5.1 ADD_LIBRARY关键字

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

运行:

cmake ..

make

cd bin/

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

5.2 同时构建静态和动态库

// 如果用这种方式,只会构建一个动态库,不会构建出静态库,虽然静态库的后缀是.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})

5.3 SET_TARGET_PROPERTIES关键字

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

同时构建静态和动态库

lib中CMakeLists.txt中的内容

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)

输出结果:

在这里插入图片描述

5.4 动态库的版本号

一般动态库都有一个版本号的关联

libhello.so.1.2
libhello.so ->libhello.so.1
libhello.so.1->libhello.so.1.2

lib中CMakeLists.txt 插入如下

SET_TARGET_PROPERTIES(hello PROPERTIES VERSION 1.2 SOVERSION 1)
  • VERSION 指代动态库版本
  • SOVERSION 指代 API 版本。

5.5 安装共享库和头文件

本例中我们将 hello 的共享库安装到/lib目录,将 hello.h 安装到/include/hello 目录

lib中CMakeLists.txt中的内容

//文件放到该目录下
INSTALL(FILES hello.h DESTINATION include/hello)

//二进制,静态库,动态库安装都用TARGETS
//ARCHIVE 特指静态库,LIBRARY 特指动态库,RUNTIME 特指可执行目标二进制。
INSTALL(TARGETS hello hello_static LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)

注意:

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

在build路径下执行:

cmake -D CMAKE_INSTALL_PREFIX=/usr ..

然后依次执行

make

make install

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

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

准备工作,新建一个目录来使用外部共享库和头文件

[root@MiWiFi-R4CM-srv cmake3]# tree
.
├── build
├── CMakeLists.txt
└── src
    ├── CMakeLists.txt
    └── main.cpp

main.cpp

#include <hello.h>

int main(){
	HelloFunc();
}

外部CMakeLists.txt的内容

PROJECT(HELLO)
ADD_SUBDIRECTORY(lib bin)

src中CMakeLists.txt中的内容

ADD_EXECUTABLE(hello main.cpp)

依次执行:

cmake ..

make

5.7 解决:make后头文件找不到的问题

报错信息:fatal error:hello.h:No such file or directory

关键字:INCLUDE_DIRECTORIES 这条指令可以用来向工程添加多个特定的头文件搜索路径,路径之间用空格分割

在src中CMakeLists.txt中加入头文件搜索路径

在最上面添加

INCLUDE_DIRECTORIES(/usr/include/hello)

5.8 解决:找到引用的函数问题

报错信息:undefined reference to `HelloFunc()’

方法一:关键字:LINK_DIRECTORIES 添加非标准的共享库搜索路径

  • 指定第三方库所在路径,LINK_DIRECTORIES(/home/myproject/libs)

方法二:关键字:TARGET_LINK_LIBRARIES 添加需要链接的共享库

  • TARGET_LINK_LIBRARIES的时候,只需要给出动态链接库的名字就行了。

  • TARGET_LINK_LIBRARIES第一个参数和生成的可执行文件名相同

  • 在CMakeLists.txt中插入链接共享库,主要要插在executable的后面

如果需要链接静态库,使用如下命令

TARGET_LINK_LIBRARIES(main libhello.a)

5.9 找不到动态库

报错信息:./hello: error while loading sharedlibraries:libhello.so:can not open shared object such file or directory

由于当前系统是63位的,需要将libs下的动态库移动到lib64下

执行:

mv usr/libs/libhello.so usr/lib64/

5.10 特殊的环境变量 CMAKE_INCLUDE_PATH 和 CMAKE_LIBRARY_PATH

注意:这两个是环境变量而不是 cmake 变量,可以在linux的bash中进行设置

我们上面例子中使用了绝对路径INCLUDE_DIRECTORIES(/usr/include/hello)来指明include路径的位置

我们还可以使用另外一种方式,使用环境变量export CMAKE_INCLUDE_PATH=/usr/include/hello

补充:正常是生成release版本,如要生产debug版本的方法:
cmake … -DCMAKE_BUILD_TYPE=debug

生成debug版本可以用gdb进行调试

6. 关于GNU, GCC,gcc,g++,Mingw,MSVC关系

GNU

  • GNU是一个操作系统计划,由Richard Stallman在1983年发起,其目的是开发基于GPL协议的GNU操作系统内核hurd和GNU系统套件,其中就包括编译器部分。后来林纳斯开发出Linux内核,再后来GNU与Linux集成,诞生了完全自由的操作系统GNU\Linux或Linux。虽然GNU在开发操作系统上做出了杰出的贡献,但遗憾的是,GNU系统的内核hurd至今未能正式发布。

GCC

  • GCC是GNU Compiler Collection(就是GNU编译器套件),也可以简单认为是编译器,它可以编译很多种编程语言(括C、C++、Objective-C、Fortran、Java等等)。

gcc

  • gcc是GCC中的GUN C Compiler(C 编译器)。

g++

  • g++是GCC中的GUN C++ Compiler(C++编译器)

MingW

  • MinGW(Minimalist GNUfor Windows),是GNU的windows版本。

MSVC

  • MSVC是微软自己开发的C/C++编译器。

7. windows系统下:vscode中使用cmake和gdb:

  1. 安装cmake tools工具,会包含cmake插件
  2. 书写CMakeLists.txt
  3. 按下ctrl+shift+p,选择CMake:Configure,然后选择:在这里插入图片描述
  4. 此时显示选择了GCC编译器,终端也会进行切换,同时文件夹里面也会创建build文件夹【自动】在这里插入图片描述
  5. 在终端依次输入cd .\buildcmake ..mingw32-make.exe,终端会显示生成的可执行文件名,位置在build文件夹里面【注意:linux里面第三个指令是make,但是在windows下是mingw32-make.exe】
  6. 修改launch.json,替换program属性值为该可执行文件在这里插入图片描述

改写配置文件launch.json和tasks.json

  • 如果注释了launch.jso文件里面的preLaunchTask字段,此时修改main.cpp文件后,再去调试时是执行原来的可执行文件
  • 打开preLaunchTask字段,该字段的功能是根据taks.json文件自动编译新的可执行文件,如图,可以修改需要编译的文件,以及输出的可执行文件名
    在这里插入图片描述
  • 确保两处的名字是一致的
    在这里插入图片描述
  • 关联可执行文件

在这里插入图片描述

  • 此时再按下F5调试,会生成新的可执行文件进行调试

总结:tasks.json文件的目的就是做调试之前的编译工作,程序员无须反复编译

例如:在build文件路径下自动执行camke和make指令
在这里插入图片描述

8. linux系统下:vscode中使用cmake和gdb:

查看博文:在Linux系统下使用GDB调试C++程序【命令行调试与vscode编译器调试】

9. 参考博文:

make的基础用法
cmake用法
gcc、g++编译详解
B站视频链接
VSCode的C++环境搭建,多文件编译,Cmake,json调试配置

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

make与cmake入门 的相关文章

随机推荐

  • leaflet加载postgis发布的矢量切片数据

    之前写过使用mapbox加载矢量切片 xff1a https www cnblogs com 2008nmj p 15069842 html 那么leaflet怎么加载python 43 postgis发布的矢量切片服务呢 xff1f 矢量
  • opencv安装make时报错: 没有指明目标并且找不到makefile

    在利用安装包进行opencv安装时 xff0c 当按照指令安装好依赖 xff0c 进行下载opencv文件夹下 xff0c 建立build文件夹并进入其文件夹后 xff0c 利用CMAKE进行编译 xff0c 但是编译成功之后 xff0c
  • 在Ubuntu中安装Chrome浏览器

    Chrome 简介 Google Chrome是由Google开发的一款设计简单 高效的Web浏览工具 Google Chrome的特点是简洁 快速 GoogleChrome支持多标签浏览 xff0c 每个标签页面都在独立的 沙箱 内运行
  • STM32H747 / STM32H745 简单测试

    目录 1 简介 2 datasheet关键点介绍 2 1 PWR 3 资料说明 4 例程运行 4 1 选择CM7作为项目工程对象 xff0c 并编译下载程序 4 2 同理编译CM4项目对象 4 3 编译结果说明 参考链接 1 简介 STM3
  • NUCLEO STM32H743购买和使用说明

    摘要 STM32H743的NUCLEO板子有两种 xff0c 对应不同的PCB电路 xff0c 使用方式也有所不同 本文将对这两款评估板进行比较 xff0c 并给出参考资料和选择建议 两款板子的资料可以在ST官网上下 xff0c 分别是MB
  • 关于硬盘数据恢复的一些思考

    我平时会将数据保存在两台电脑和两个移动硬盘上 xff0c 但由于假期回家 xff0c IDE软件用起来容易崩 xff0c 于是决定重装下系统 xff0c 但发现USB启动盘找不到了 xff0c 便将移动硬盘隔分了小的个新逻辑卷 xff0c
  • Simulink中的Simscape

    Simscape是在Simulink环境下创建物理系统模型的工具和语言 8 它可以通过基于Matlab语法的Simscape语法来制作自己的物理仿真系统 如果使用Simscape中现有的基础库 xff08 Foundation Librar
  • Matlab电路仿真

    电路仿真的工具有很多 xff0c 比如专业点的Pspice 本科时学习时经常使用 但问题是 xff0c 即使电信专业以后真的从事硬件设计的也寥寥无几 而为了进行简单的仿真还要多装个软件 xff0c 我能接收 xff0c 我的老电脑也接收不了
  • RK1126 平台环境搭建以及入坑指南(不不 应该是入门指南)

    手上有个RK1126的板子 如下图 采用的是底板 43 核心板 xff0c 摄像头是OS04a10 简单做个记录 相比与海思的sdk 和example RK1126 的sdk 和example 功能更丰富一些 基本的rtsp 什么的 都已经
  • 关于JSP开发中jsp页面调用DAO返回的ResultSet为空值完美解决方案

    不多说 问题蛮简单 直接上代码 关于ResultSet为空值的原因经我查阅资料 应该是因为在JSP页面的时候conn已经被释放掉了 因此对应的resultset也过期了 所以不能用 解决方案就是重新开辟一块内存存储它 用链表 关键代码 Li
  • 关系模式的基本概念

    为了更好地存储数据 xff0c 需要将现实世界的事物及其关系进行层层抽象 xff0c 从而得到数据模型 使用关系数据模型的数据库系统是现在的主流数据库系统 数据模型是数据库的框架 xff0c 该框架描述了数据及其联系的组织方式 表达方式和存
  • 惯性器件分析—— ICM-42688-P

    2019年年底新推出的一款很赞的IMU 陀螺特性 加计特性 相关链接 官网DataSheet xff1a https invensense tdk com download pdf icm 42688 p datasheet 两家IMU对比
  • vim学习导航

    vim学习曲线陡峭 xff0c 其实和开始学习键盘打字和双拼打字的过程差不多 以前练习打字是因为小学电脑课没游戏玩 xff0c 只能玩金山打字的 警察抓小偷 xff1b 学习双拼主要动力是为了打字手手不酸 xff0c 能尽量跟上思维速度 而
  • word论文格式调整

    目录 注意事项 论文框架搭建 论文分块 页边距 页眉 页脚 样式 默认样式 正文 标题 参考文献 致谢 目录 图表 参考文献 公式 最后 注意事项 1 使用同一个word版本编辑 xff0c 避免格式不兼容 本文可能不适用于WPS 本文用o
  • 符号编码与乱码问题

    目标 xff1a 解释符号与编码 xff0c 分析乱码问题 xff0c 于是就能明明白白地处理大多数符号乱码问题了 符号与编码 以C 43 43 为例 xff0c 符号A的 十进制 编码为65 即 39 A 39 为65 其中 xff0c
  • PWM变模拟信号(积分电路 )

    就是简单的积分电路 频率不变 xff0c 积分后的电平相当于把高电平的电压和对应的时间的面积 xff0c 平均到一个周期里 基本上占空比是50 xff0c 转换的电压 xff0c 就是最高电压的50 xff0c 占空比30 xff0c 模拟
  • 如何生成汇编代码文件

    61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
  • Ardupilot SITL——arducopter 操作步骤

    打开cygwin输入 cd ardupilot ArduCopter Tools autotest sim vehicle py map console xff08 默认master下版本arducopter xff0c 默认模拟 四轴 x
  • 3-catkin包介绍与构建

    本教程简单介绍ROS1的catkin包 至于为什么选择deepin而不是ROS通用的ubuntu 也仅仅是为了支持国产系统 鉴于本人水平有限 xff0c 如哪位攻城狮网友发现本文存在的问题 xff0c 烦请留言指正 xff0c 谢谢 cat
  • make与cmake入门

    文章目录 1 手动链接与编译2 make编译工具2 1 介绍makefile2 2 makefile三要素2 3 make工作原理2 4 实战案例1案例2案例3案例4 2 5 常见的自动化变量解析 3 使用cmake进行编译3 1 介绍cm