使用cmake+gcc 以库的形式编译多目录下的文件

cmake 以库的形式编译连接多目录下文件

demo 的目录树

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

这些是我自己随便添加的几个目录,实际上都只是添加了个打印源代码

将几个模块文件夹编译成库

1. 将bsp模块编译成库

  • 首先在bsp目录下新建个CMakeLists.txt

    # cmake的最低版本要求,可能新版本支持的特性旧版本不支持
    cmake_minimum_required(VERSION 3.0.0)
    
    # 指定头文件路径即bsp下的inc
    include_directories("./inc")
    ## 如果bps/src中有10个.c文件,只需要添加5个到库中,则使用下面这种方法,挨个添加
    # set(BSP_SRC "./src/bsp.c")  # 这个需要指定到.c
    ## 如果bsp/src下所有的.c代码都要编译到库中,则推荐下面这个方式,只需要路径,不需要挨个添加
    aux_source_directory("./src" BSP_SRC)   # 这个只需指定到路径
    
    # LIBRARY_OUTPUT_PATH是一个控制编译的变量,具体参考官方说明:
    # https://cmake.org/cmake/help/v3.15/manual/cmake-variables.7.html
    # 生成一个库并放置到指定目录下,如果此文件夹不存在则新建一个
    set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)	# 如果不指定,则默认路径下
    add_library(bsp_lib ${BSP_SRC}) # 默认情况下是静态库 xxx.a
    
    # 动态库和静态库设置
    # add_library(bsp_lib_dll SHARED ${BSP_SRC}) # 动态库
    # add_library(bsp_lib_a STATIC ${BSP_SRC}) # 静态库
    # set_target_properties(bsp_lib_dll PROPERTIES OUTPUT_NAME "bsp")
    # set_target_properties(bsp_lib_a PROPERTIES OUTPUT_NAME "bsp")
    
    # 用到其他的代码文件时,即头文件引用了其他的头文件
    # link_directories("${PROJECT_SOURCE_DIR}/lib")
    # target_link_libraries(bsp_lib xxx xxx)
    

2. 其他几个模块也是一样的添加CMakeLists.txt实现库

3. 回到项目的根目录,添加顶层的CMakeLists.txt

# 版本最低要求
cmake_minimum_required(VERSION 3.0.0)
# 设置工程名 语言为c和汇编
project(multiple_directory_cmake 
    LANGUAGES C ASM
)
# 设置编译器gcc 和 c99标准; 
set(CMAKE_C_COMIPLER "gcc")
set(CMAKE_C_STANDARD 99)
# 如果是c++则可如下设置
# set(CMAKE_CXX_COMIPLER "g++")
# set(CMAKE_CXX_STANDARD 11)

#dubug 模式 如果需要调试的话,这个参数需要设置
set(CMAKE_C_FLAGS  "${CMAKE_C_FLAGS} -g")

#=============添加文件一般这里需要修改=============
# 头文件路径, Note: 新加文件夹,这里添加头文件路径
include_directories(
    "${PROJECT_SOURCE_DIR}/app/inc"
    "${PROJECT_SOURCE_DIR}/bsp/inc" 
    "${PROJECT_SOURCE_DIR}/drv/inc"
    "${PROJECT_SOURCE_DIR}/third_party/fatfs/inc"
    "${PROJECT_SOURCE_DIR}/third_party/freertos/inc"
)

#=============添加文件一般这里需要修改=============
# 添加子目录,cmake会去这些目录下找CMakeLists.txt执行
add_subdirectory("./bsp")         
add_subdirectory("./drv")
add_subdirectory("./third_party/fatfs")
add_subdirectory("./third_party/freertos")

# 应用逻辑源代码的路径 
aux_source_directory("./app/src" DIR_MAIN)  # 这个只需指定到目录
# set(DIR_MAIN "./app/src/main.c")  # 这个需要指定到.c

# 编译成可执行文件并放置在指定路径,如果不存在此目录,则会新建一个
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) # 如果不指定,则在默认路径下
add_executable(demo ${DIR_MAIN}) # 生成可执行文件,在windows下就是demo.exe

# 这个需要放在add_executable()之后,因为只有生成了demo执行文件后,
# 才能将库连接信息添加进demo可执行文件中去
# 链接其他库文件  Note: 新加库的话,这里也需要做添加
link_directories("${PROJECT_SOURCE_DIR}/lib")
#=============添加库一般这里需要修改=============
target_link_libraries(
    "demo" 
    "drv_lib" 
    "bsp_lib"
    "freertos_lib"
    "fatfs_lib"
)

4. 然后看看具体代码的实现

1. bsp/inc/bsp.h和bsp/src/bsp.c
//! bsp.h
extern void bsp_execute(void);
//! bsp.c
#include <stdio.h>
#include "bsp.h"

void bsp_execute(void)
{
    printf("execute bsp func...\r\n");
}
2. 替他几个模块也基本一样
3. app/src/main.c
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include "bsp.h"
#include "drv.h"
#include "fatfs.h"
#include "freertos.h"

int32_t main(int8_t argc, int8_t* argv[])
{
    bool err_flag = false;
    if (argc == 2)
    {
        if(strcmp(argv[1], "bsp") == 0)
            bsp_execute();
        else if (strcmp(argv[1], "drv") == 0)
            drv_execute();
        else if (strcmp(argv[1], "third_fatfs") == 0)
            fatfs_execute();
        else if (strcmp(argv[1], "third_freertos") == 0)
            freertos_execute();
        else if (strcmp(argv[1], "all") == 0)
        {
            bsp_execute();
            drv_execute();
            fatfs_execute();
            freertos_execute();
        }
        else
            err_flag = true;
    }
    else
    {
        err_flag = true;
    }

    if (err_flag != false)
    {
        printf("param error,example:\r\n");
        printf("xxx.exe bsp\r\n");
        printf("xxx.exe drv\r\n");
        printf("xxx.exe third_fatfs\r\n");
        printf("xxx.exe third_freertos\r\n");
        printf("xxx.exe all\r\n");
    }

    return 0;
}

5. 通过cmake+make来编译

1.cmake操作

mkdir build

cd build

cmake -G "MinGW Makefiles" ..

此时工程下多了两文件夹(bin, lib),但是还没有内容,因为还没编译

2. make 操作

make -j8

此时bin目录和lib目录下就有了文件
在这里插入图片描述

3. 执行测试

在这里插入图片描述
此时输出正常了,表明前面的库连接没问题,至此结束

尝试使用tasks.json来配置,以及launch.json来调试

1. 首先试一试调试模式

1.创建launch.json

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

2. 添加launch.json的调试配置模板

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

3. 针对我们的电脑和项目修改配置

在这里插入图片描述
如上修改后启动调试,发现一下子就运行结束了,没有暂停,然后就再次修改
在这里插入图片描述
修改后结果如上图,可以单步调试了,stopAtEntry表示是否在入口停止,如果未false,则会直接往下运行,我们希望单步调试从main开始,就需要改为true;

此时还存在一个问题,因为我们程序是需要根据输入参数来判断执行什么逻辑,则还需要加入参数
在这里插入图片描述
到这里我们的调试设置也已完成

注意:如果需要调试,则cmake中需要设置 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g") ;否则会被优化,调试时不正常

2. 然后试一下任务的创建运行

  • 如果每次通过命令行去编译,则每次都需要手动输入命令,不方便,可以通过任务来替代手动输入
1. 创建tasks.json

ctrl+shift+p 输入tasks 选择配置任务,选择模板生成tasks.json,然后选择MSBuild
在这里插入图片描述

后面进行修改我们需要的命令和参数

{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    "version": "2.0.0",
    "tasks": [
        // 创建build目录
        // 即 mkdir build 
        {
            "label": "mkdir build",
            "type": "shell",
            "command": "mkdir",
            "args": [
                "build"
            ],
            "group": "build",
            "options": {
                "cwd": "${workspaceFolder}"   // 执行mkdir命令的路径
            },
        },
        // 切换生成器,生成Makefile 
        // 即 cmake -G "MinGW Makefiles" ../
        {
            "label": "prebuild",
            "type": "shell",
            "command": "cmake",
            "args": [
                "-G",   // 切换cmake生成器为MinGW
                "MinGW Makefiles",
                "-DCMAKE_BUILD_TYPE=Debug", // 设置为Debug模式,便于调试
                "../"
            ],
            "group": "build",
            "options": {
                "cwd": "${workspaceFolder}/build"   // 执行cmake命令的路径
            },
        },
        // 执行编译
        // make -j8
        {
            "label": "build",
            "type": "shell",
            "command": "make",
            "args": [
                "-j8",   //多线程编译
            ],
            "group": "build",
            // 使用gcc编译器
            "problemMatcher": "$gcc",
            "options": {
                "cwd": "${workspaceFolder}/build"   // 执行make命令的路径
            },
			// 每次执行make 前会先调用clean执行rm,再调用prebuild执行cmake
            "dependsOrder": "sequence", // 按顺序执行依赖关系
            "dependsOn":[
                "clean",	// 先清除 build下的内容
                "prebuild",	// 在生成需要的makefile
            ],				// 然后才会执行make
     
        },
        // 清除编译生成的文件
        // rm -r *
        {
            "label": "clean",
            "type": "shell",
            "command": "rm",
            "args": [
                "-r",
                "*",
            ],
            "group": "build",
            "options": {
                "cwd": "${workspaceFolder}/build"   // 执行rm命令的路径
            },
        }
    ]
}

使用ctrl + p在框中输入task + 空格,然后选择需要执行的任务即可

比如我们再已有build目录的情况下,选择build任务,则输出如下
在这里插入图片描述
在这里插入图片描述

最后:如果还有什么疑问的可参考上篇文章win10+gcc+cmake+vscode 的最简demo

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值