Cmake学习

文章详细介绍了CMake的基本用法,包括设置变量、搜索文件、自定义库文件(静态和动态)、链接库(静态和动态)、以及如何在CMakeLists.txt中组织和管理项目的构建过程。
摘要由CSDN通过智能技术生成

cmake大致

image.png

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_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_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是有可执行权限的

制作动态库

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

链接静态库

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

#使用静态链接库
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那个文件夹里面

链接动态库

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中定义的方法。

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

使用动态链接库

#使用动态链接库
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_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_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_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")

image.png

#使用动态链接库
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")

image.png

字符串操作

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

#移除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长度

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

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

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

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

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

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

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

等等。。。

cmake中自定义宏

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

image.png

cmake_minimum_required(VERSION 3.5)
project(Test)
file(GLOB SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
add_definitions(-DDEBUG)
add_executable(app ${SRC})
 

image.png

嵌套的cmake

文件夹目录
image.png
根目录下的cmakelist

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 子节点中的变量无法在父节点中用,父节点的变量可以在子节点用

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

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的主程序

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

#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_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_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了
image.png

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值