Cmake学习

cmake大致

cmake 复制代码
cmake_minimum_required(VERSION 3.0)

project(test)
#通过set自定义变量,通过${}取出
#set(SRC add.cpp main.cpp muti.cpp sub.cpp)
#cmake搜索文件 宏定义PROJECT_SOURCE_DIR
aux_source_directory(${PROJECT_SOURCE_DIR} SRC)
#file(GLOB/GLOB_RECURSE 变量名 要搜索的文件路径和文件类型)
#GLOB: 将指定目录下搜索到的满足条件的所有文件名生成一个列表,并将其存储到变量中。
#GLOB_RECURSE:递归搜索指定目录,将搜索到的满足条件的文件名生成一个列表,并将其存储到变量中。

#指定最后生成程序输出的路径
set(EXECUTABLE_OUTPUT_PATH ./bin)
#指定c++使用的标准
set(CAMKE_CXX_STANDARD 11)
#生成可执行程序exe
add_executable(app ${SRC})
cmake 复制代码
#指定头文件路径
cmake_minimum_required(VERSION 3.0)

project(test)
#通过set自定义变量,通过${}取出
#aux_source_directory(${PROJECT_SOURCE_DIR}/src SRC)
file(GLOB SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
#指定最后生成程序输出的路径
set(EXECUTABLE_OUTPUT_PATH ./bin)
#引入头文件
include_directories(${PROJECT_SOURCE_DIR}/include)
#指定c++使用的标准
set(CAMKE_CXX_STANDARD 11)
add_executable(app ${SRC})

通过Cmake制作库文件

制作静态库

cmake 复制代码
cmake_minimum_required(VERSION 3.0)
project(CALC)
include_directories(${PROJECT_SOURCE_DIR}/include)
file(GLOB SRC_LIST "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
add_library(calc STATIC ${SRC_LIST})
#add_library(库名称 STATIC 源文件1 [源文件2] ...) 

动态库dll是有可执行权限的

制作动态库

cmake 复制代码
include_directories(${PROJECT_SOURCE_DIR}/include) #包含头文件
set(LIBRARY_OUTPUT_PATH ../lib)
add_library(calc SHARED ${SRC})

链接静态库

如果要新建一个项目使用库文件,需要将原来的头文件和库文件一同拷贝过来

cmake 复制代码
#使用静态链接库
cmake_minimum_required(VERSION 3.0)

project(test)
#通过set自定义变量,通过${}取出
file(GLOB SRC ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
include_directories(${PROJECT_SOURCE_DIR}/include)
#链接静态库
link_libraries(calc)
#指定静态库的位置
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/lib)
add_executable(app ${SRC})

当我们在使用静态库的时候,在生成可执行文件exe的时候相应的静态库文件会打包到exe那个文件夹里面

链接动态库

cmake 复制代码
target_link_libraries(
    <target> 
    <PRIVATE|PUBLIC|INTERFACE> <item>... 
    [<PRIVATE|PUBLIC|INTERFACE> <item>...]...)

target:指定要加载动态库的文件的名字

动态库具有链接的能力,假如说动态库a链接b再链接c,但是传递是由前提条件的,必须是public

该文件可能是一个源文件

该文件可能是一个动态库文件

该文件可能是一个可执行文件

PRIVATE|PUBLIC|INTERFACE:动态库的访问权限,默认为PUBLIC

如果各个动态库之间没有依赖关系,无需做任何设置,三者没有没有区别,一般无需指定,使用默认的 PUBLIC 即可。

动态库的链接具有传递性,如果动态库 A 链接了动态库B、C,动态库D链接了动态库A,此时动态库D相当于也链接了动态库B、C,并可以使用动态库B、C中定义的方法。

cmake 复制代码
target_link_libraries(A B C)
target_link_libraries(D A)
  • PUBLIC:在public后面的库会被Link到前面的target中,并且里面的符号也会被导出,提供给第三方使用。
  • PRIVATE:在private后面的库仅被link到前面的target中,并且终结掉,第三方不能感知你调了啥库
  • INTERFACE:在interface后面引入的库不会被链接到前面的target中,只会导出符号。

使用动态链接库

cmake 复制代码
#使用动态链接库
cmake_minimum_required(VERSION 3.0)
project(test)


FILE(GLOB SRC ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)

include_directories(${PROJECT_SOURCE_DIR}/include)
# 指定动态库存放的位置
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/lib)
add_executable(app ${SRC})
# 使用动态链接库
target_link_libraries(app calc)

动态库的链接和静态库是完全不同的:

静态库会在生成可执行程序的链接阶段被打包到可执行程序中,所以可执行程序启动,静态库就被加载到内存中了。

动态库在生成可执行程序的链接阶段不会被打包到可执行程序中,当可执行程序被启动并且调用了动态库中的函数的时候,动态库才会被加载到内存

因此,在cmake中指定要链接的动态库的时候,应该将命令写到生成了可执行文件之后:

cmake 复制代码
cmake_minimum_required(VERSION 3.0)
project(TEST)
file(GLOB SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
# 添加并指定最终生成的可执行程序名
add_executable(app ${SRC_LIST})
# 指定可执行程序要链接的动态库名字
target_link_libraries(app pthread)

在target_link_libraries(app pthread)中:

app: 对应的是最终生成的可执行程序的名字

pthread:这是可执行程序要加载的动态库,这个库是系统提供的线程库,全名为libpthread.so,在指定的时候一般会掐头(lib)去尾(.so)。

假设在测试文件main.cpp中既使用了自己制作的动态库libcalc.so又使用了系统提供的线程库,此时CMakeLists.txt文件可以这样写:

cmake 复制代码
cmake_minimum_required(VERSION 3.0)
project(TEST)
file(GLOB SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
include_directories(${PROJECT_SOURCE_DIR}/include)
add_executable(app ${SRC_LIST})
target_link_libraries(app pthread calc)

cmake日志

cmake 复制代码
#使用动态链接库
cmake_minimum_required(VERSION 3.0)
project(test)


FILE(GLOB SRC ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)

include_directories(${PROJECT_SOURCE_DIR}/include)
# 日志
message("first logs")
# 指定动态库存放的位置
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/lib)
message(STATUS "second logs")
add_executable(app ${SRC})
# 使用动态链接库
target_link_libraries(app calc)
message(FATAL_ERROR "third fatal error")
message(STATUS "fourth logs")
cmake 复制代码
#使用动态链接库
cmake_minimum_required(VERSION 3.0)
project(test)


FILE(GLOB SRC ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)

include_directories(${PROJECT_SOURCE_DIR}/include)
# 日志
message("first logs")
# 指定动态库存放的位置
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/lib)
message(STATUS "second logs")
add_executable(app ${SRC})
# 使用动态链接库
target_link_libraries(app calc)
#打印变量值
message("var is :"${SRC})
message(FATAL_ERROR "third fatal error")
message(STATUS "fourth logs")

字符串操作

cmake 复制代码
cmake_minimum_required(VERSION 3.5)
project(test)
set(value1 "value1")
set(value2 "value2")
message(${value1})
#字符串拼接
set(value3 ${value1} "+" ${value2})
message("value3:" ${value3})

#使用list追加字符串
list(APPEND value3 " zhui jia zi fu chuan")
message(${value3})
cmake 复制代码
#移除src中main.cpp的名字
cmake_minimum_required(VERSION 3.5)
project(test)
#获取src目录下所有源文件的绝对路径
file(GLOB SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
message("======================")
message(${SRC})
list(REMOVE_ITEM SRC ${PROJECT_SOURCE_DIR}/src/main.cpp)
message("删除之后的字符串")
message(${SRC})

=====================

D:/C++workspace/c++程序/cmake_str/src/add.cppD:/C++workspace/c++程序/cmake_str/src/main.cppD:/C++workspace/c++程序/cmake_str/src/muti.cppD:/C++workspace/c++程序/cmake_str/src/sub.cpp

删除之后的字符串

D:/C++workspace/c++程序/cmake_str/src/add.cppD:/C++workspace/c++程序/cmake_str/src/muti.cppD:/C++workspace/c++程序/cmake_str/src/sub.cpp

list的其他命令:

获取list长度

cmake 复制代码
list(LENGTH <list> <output variable>)
  • LENGTH:子命令LENGTH用于读取列表长度
  • :当前操作的列表
  • :新创建的变量,用于存储列表的长度。

读取列表中指定索引的的元素,可以指定多个索引:

cmake 复制代码
list(GET <list> <element index> [<element index> ...] <output variable>)
  • :当前操作的列表
  • :列表元素的索引
    • 从0开始编号,索引0的元素为列表中的第一个元素;
    • 索引也可以是负数,-1表示列表的最后一个元素,-2表示列表倒数第二个元素,以此类推
    • 当索引(不管是正还是负)超过列表的长度,运行会报错
  • :新创建的变量,存储指定索引元素的返回结果,也是一个列表。

将列表中的元素用连接符(字符串)连接起来组成一个字符串

cmake 复制代码
list (JOIN <list> <glue> <output variable>)
  • :当前操作的列表
  • :指定的连接符(字符串)
  • :新创建的变量,存储返回的字符串

查找列表是否存在指定的元素,若果未找到,返回-1

cmake 复制代码
list(FIND <list> <value> <output variable>)
  • :当前操作的列表
  • :需要再列表中搜索的元素
  • :新创建的变量

等等。。。

cmake中自定义宏

cpp 复制代码
#include <stdio.h>
#define NUMBER  3

int main()
{
    int a = 10;
    //cmake中没有添加debug相关配置所以在debug模式下运行,并不会运行ifdef debug里面的打印内容
    #ifdef DEBUG
    printf("我是一个程序猿, 我不会爬树...\n");
    #endif
    for(int i=0; i<NUMBER; ++i)
        {
            printf("hello, GCC!!!\n");
        }
    return 0;
}
cpp 复制代码
cmake_minimum_required(VERSION 3.5)
project(Test)
file(GLOB SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
add_definitions(-DDEBUG)
add_executable(app ${SRC})
 

嵌套的cmake

文件夹目录

根目录下的cmakelist

cpp 复制代码
cmake_minimum_required(VERSION 3.5)
project(test)
#定义变量
#静态库生成路径
set(LIBPATH ${PROJECT_SOURCE_DIR}/lib)
#可执行程序存放地址
set(EXECPATH ${PROJECT_SOURCE_DIR}/bin)
#头文件路径
set(HEADPATH ${PROJECT_SOURCE_DIR}/include)
#库文件的名字
set(CALCLIB calc)
set(SORTLIB sort)
#可执行程序的名字
set(APPNAME1 app1)
set(APPNAME2 app2)


#给当前节点添加子目录
add_subdirectory(calc)
add_subdirectory(sort)
add_subdirectory(test1)
add_subdirectory(test2)

calc文件夹下的cmakelist 子节点中的变量无法在父节点中用,父节点的变量可以在子节点用

cpp 复制代码
cmake_minimum_required(VERSION 3.5)
project(calc)
#搜索当前路径下的所有cpp文件 搜索源文件
aux_source_directory(./ SRC)
# 搜索头文件 include文件夹下 父节点已经定义了include文件夹路径变量HEADPATH
include_directories(${HEADPATH})
#指定静态库生成的路径
set(LIBRARY_OUTPUT_PATH ${LIBPATH})
#把源文件变成静态库
add_library(${CALCLIB} STATIC ${SRC})

sort目录下的文件cmakelist

cpp 复制代码
cmake_minimum_required(VERSION 3.5)
project(sort)
#搜索当前路径下的所有cpp文件 搜索源文件
aux_source_directory(./ SRC)
# 搜索头文件 include文件夹下 父节点已经定义了include文件夹路径变量HEADPATH
include_directories(${HEADPATH})
#指定静态库生成的路径
set(LIBRARY_OUTPUT_PATH ${LIBPATH})
#把源文件变成静态库
add_library(${SORTLIB} STATIC ${SRC})

test1目录下的cmakelist执行calc的主程序

cpp 复制代码
cmake_minimum_required(VERSION 3.5)
project(test1)

aux_source_directory(./ SRC)

include_directories(${HEADPATH})
link_directories(${LIBPATH})
link_libraries(${CALCLIB})
#生成可执行文件的目录
set(EXECUTABLE_OTPUT_PATH ${EXECPATH})
add_executable(${APPNAME1} ${SRC})

在静态库中链接静态库

主要做的是在排序的静态库sort.lib中引用calc.lib需要做以下修改

冒泡排序cpp中调用calc静态库的链接 删掉test2

cpp 复制代码
#include<iostream>
#include "sort.h"
#include "calc.h"

using namespace std;


void bubble_sort(int mylist[],int listsize){
    
    int number1 = add(mylist[0],mylist[1]);
    cout<<"在选择排序中调用calc的加法操作"<<number1<<endl;
    for(int i=0;i<listsize;i++){

        for(int j=i;j<listsize;j++){

            if(mylist[i]<mylist[j])
            {
                int temp = mylist[i];
                mylist[i]=mylist[j];
                mylist[j]=temp;

            }
        }

    }

}

calc目录下的cmakelist保持不变

sort目录下的cmakelist

cmake 复制代码
cmake_minimum_required(VERSION 3.5)
project(sort)
#搜索当前路径下的所有cpp文件 搜索源文件
aux_source_directory(./ SRC)
# 搜索头文件 include文件夹下 父节点已经定义了include文件夹路径变量HEADPATH
include_directories(${HEADPATH})
#指定静态库生成的路径
set(LIBRARY_OUTPUT_PATH ${LIBPATH})
# 指定自定义静态库的存放路径
link_directories(${LIBPATH})
# 链接calc静态库
link_libraries(${CALCLIB})
#把源文件变成静态库
add_library(${SORTLIB} STATIC ${SRC})

test/main.cpp下的cmakelist

cmake 复制代码
cmake_minimum_required(VERSION 3.5)
project(test2)

aux_source_directory(./ SRC)

include_directories(${HEADPATH})
link_directories(${LIBPATH})
link_libraries(${SORTLIB})
#生成可执行文件的目录
set(EXECUTABLE_OTPUT_PATH ${EXECPATH})
add_executable(${APPNAME2} ${SRC})

sort.lib已经引用的calc.lib所以,test下就不需要再引用calc.lib了

相关推荐
我是谁??22 分钟前
C/C++使用AddressSanitizer检测内存错误
c语言·c++
Mephisto.java26 分钟前
【大数据学习 | kafka高级部分】kafka中的选举机制
大数据·学习·kafka
Yawesh_best40 分钟前
思源笔记轻松连接本地Ollama大语言模型,开启AI写作新体验!
笔记·语言模型·ai写作
南宫生1 小时前
贪心算法习题其三【力扣】【算法学习day.20】
java·数据结构·学习·算法·leetcode·贪心算法
发霉的闲鱼1 小时前
MFC 重写了listControl类(类名为A),并把双击事件的处理函数定义在A中,主窗口如何接收表格是否被双击
c++·mfc
小c君tt1 小时前
MFC中Excel的导入以及使用步骤
c++·excel·mfc
xiaoxiao涛1 小时前
协程6 --- HOOK
c++·协程
武子康2 小时前
大数据-212 数据挖掘 机器学习理论 - 无监督学习算法 KMeans 基本原理 簇内误差平方和
大数据·人工智能·学习·算法·机器学习·数据挖掘
CXDNW2 小时前
【网络面试篇】HTTP(2)(笔记)——http、https、http1.1、http2.0
网络·笔记·http·面试·https·http2.0
使者大牙2 小时前
【大语言模型学习笔记】第一篇:LLM大规模语言模型介绍
笔记·学习·语言模型