【Cmake】—Cmake使用的介绍与使用

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

前言

一、Cmake的介绍

Cmake是什么?
CMake 是一个跨平台的开源构建系统工具,它使用 CMakeLists.txt 文件描述构建流程。可以让我们通过编写简单的配置文件去生成本地的Makefile,这个配置文件是独立于运行平台和编译器的,这样就不用亲自去编写Makefile文件了。它简化了构建过程,使得跨平台开发变得更加方便。

Makeflie的介绍:
Makefile 是一个用于自动化构建过程的文件,它与 make 工具一起使用。Makefile 文件包含了一系列规则和指令,用于指定如何编译和链接程序中的源文件,从而生成最终的可执行文件或库。Makefile 的主要目的是简化编译过程,使得项目的构建变得自动化和高效。

Cmake的主要功能(主要作用)
1.生成构建系统文件:CMake 通过读取 CMakeLists.txt 文件,生成适合当前平台的构建系统文件(如 Makefile 或项目文件)。
2.跨平台支持:CMake 支持多种操作系统和编译器,包括 Unix-like 系统、Windows 系统以及各种编译器(GCC、Clang、MSVC 等)。
3.配置和生成:CMake 能够处理复杂的配置需求,比如设置编译选项、定义宏、指定编译目标等

C++项目的Cmake构建流程
1.创建 CMakeLists.txt 文件:
a. 在项目的根目录下创建一个 CMakeLists.txt 文件,定义项目的基本信息(如项目名称、版本等)。
b. 通过 include_directories 和 link_directories 指定包含文件和库的路径。
c. 通过 add_executable 或 add_library 等命令指定编译目标(可执行文件或库)。

2.定义子目录和模块:
a. 对于大型项目,通常会将项目分成多个模块或子目录。可以在主 CMakeLists.txt 文件中使用 add_subdirectory 命令来包含子目录中的 CMakeLists.txt 文件。
b. 每个子目录可以有自己的 CMakeLists.txt 文件,负责该目录下文件的编译和链接。

3.运行cmake,配置项目:
a.运行指令: CMake .. 配置项目。这会生成适合当前平台的构建文件(如 Makefile)。
b.可以在配置过程中指定编译选项、调试信息、安装路径等参数。

4.构建项目:
a.运行指令:make, 使用生成的构建系统文件makefile进行编译

简单的示例:假设你的目录如下:

project/
├── CMakeLists.txt
├── src/
│   ├── main.cpp
│   └── foo.cpp
└── include/
    └── foo.h

project/CMakeLists.txt文件的内容示例如下:

cmake_minimum_required(VERSION 3.10)
project(MyProject VERSION 1.0)

# 设置 C++ 标准
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)

# 包含头文件目录
include_directories(include)

# 添加可执行文件
add_executable(MyExecutable src/main.cpp src/foo.cpp)

# 链接库(如果有的话)
# target_link_libraries(MyExecutable SomeLibrary)

构建的指令:

# 创建构建目录,存放中间编译文件的地方
mkdir build
cd build
# 运行 CMake 生成构建系统文件
cmake ..
# 使用生成的构建系统文件进行编译
make

二、环境搭建与简单的使用

1.编译多个源文件

(1)在同一个目录下的有多个源文件(.cpp)
简单的示例:假设你的目录如下:

project/
├── CMakeLists.txt
├── main.cpp
├── foo.cpp
└── foo.h

CMakeLists.txt文件的内容:

cmake_minimum_required(VERSION 3.10)
project(MyProject VERSION 1.0)

# 包含头文件目录
# include_directories(include)

# 添加可执行文件
add_executable(MyExecutable main.cpp foo.cpp)

注意:头文件 foo.h 位于与源文件相同的目录下,因此编译器会自动找到它,不需要单独指定包含目录。
如果在同一目录下有多个源文件,那么只要在add_executable里把所有源文件都添加进去就可以了。但是如果有一百个源文件,再这样做就太麻烦了,无法体现cmake的优越性。
因此,cmake中提供aux_source_directory指令来解决这个问题:

aux_source_directory(dir var)

指令参数介绍:
a. 第一个参数dir是指定源文件目录
b. 第二个参数var是用于存放源文件列表的变量
例如,文件结构如下:

project/
├── CMakeLists.txt
├── main.cpp
├── a.cpp
├── a.h
├── foo.cpp
└── foo.h

CMakeLists.txt的内容为:

cmake_minimum_required(VERSION 3.10)
project(MyProject VERSION 1.0)
# 指定源文件的路径
aux_source_directory(. SRC_LIST)
# 添加可执行文件
add_executable(main ${SRC_LIST})

解释:
a. ” . “:当前目录
b. 使用aux_source_directory把当前目录下的源文件存列表存放到变量SRC_LIST里
c. 然后在add_executable里调用SRC_LIST(调用变量时的写法)。

但是,aux_source_directory()也存在弊端,它会把指定目录下的所有源文件都加进来,可能会加入一些我们不需要的文件,此时我们可以使用set命令去新建变量来存放需要的源文件,可以使用以下的写法:

cmake_minimum_required(VERSION 3.10)
project(MyProject VERSION 1.0)
# 指定源文件的路径
set( SRC_LIST
	 ./main.cpp
	 ./a.cpp
	 ./foo.cpp)
# 添加可执行文件
add_executable(main ${SRC_LIST})

(2) 在不同的目录下有多个源文件
一般来说,当程序文件比较多时,我们会进行分类管理,把代码根据功能放在不同的目录下,这样方便查找。
示例,文件存放的结构如下:

project/
├── CMakeLists.txt
├── main.cpp
├── func_a/
│   ├── a.cpp
│   └── a.h
└── func_b/
    ├── b.cpp
    └── b.h

示例的CMakeLists.txt内容:

cmake_minimum_required(VERSION 3.10)
project(MyProject VERSION 1.0)

# 包含头文件目录
include_directories(func_a func_b)

# 指定源文件的路径
aux_source_directory(func_a  SRC_LIST)
aux_source_directory(func_b  SRC_LIST1)
# 添加可执行文件
add_executable(main ${SRC_LIST} ${SRC_LIST1})

出现一个新的指令:include_directories
该命令是用来向工程添加多个指定头文件的搜索路径,路径之间用空格分隔,如:

# include_directories(func_a func_b)

2.项目级的组织结构

对于真实的项目规范里面,一般会把源文件放到src目录下,把头文件放入到include文件下,生成的对象文件放入到build目录下,最终输出的可执行程序文件会放到bin目录下,这样整个结构更加清晰。
如文件结构:

project/
├── bin
├── build
├── CMakeLists.txt
├── src/
│   ├── main.cpp
│   └── foo.cpp
└── include/
    └── foo.h

示例的CMakeLists.txt源码:

cmake_minimum_required(VERSION 3.10)
project(MyProject VERSION 1.0)
# 包含头文件目录
include_directories(include)
# 指定源文件的目录
aux_source_directory (src SRC_LIST)
# 添加可执行文件
add_executable(MyExecutable  ${SRC_LIST})

对于的大型的项目,所有的功能文件如果都写在一个CMakeLists.txt进行管理,是不利于调试与维护,因此,将不同的功能模块拆分成独立的子目录和独立的构建配置。这样可以使得构建过程更加清晰和模块化,同时便于维护和扩展。
例如,文件结构如下:
project/
├── bin
├── build
├── CMakeLists.txt
├── src/
│ ├── CMakeLists.txt
│ ├── main.cpp
│ └── foo.cpp
└── include/
└── foo.h

CMakeLists.txt的内容为:

cmake_minimum_required(VERSION 3.10)
project(MyProject VERSION 1.0)

# 加编译子目录
add_subdirectory (src)

出现一个新的指令:add_subdirectory
这个语句的作用是增加编译子目录。其基本语法格式是:

add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])

一共有三个参数,后两个是可选参数
a.source_dir 源代码目录:指定一个包含CMakeLists.txt和代码文件所在的目录,该目录可以是绝对路径,也可以是相对路径,对于后者相对路径的起点是CMAKE_CURRENT_SOURCE_DIR。此外,如果子目录再次包含的CMakeLists.txt,则将继续处理里层的CMakeLists.txt,而不是继续处理当前源代码

b.binary_dir 二进制代码目录:这个目录是可选的,如果指定,cmake命令执行后的输出文件将会存放在此处,若没有指定,默认情况等于source_dir没有进行相对路径计算前的路径,也就是CMAKE_BINARY_DIR。

c.EXCLUDE_FROM_ALL标记

src/ CMakeLists.txt的内容为:

aux_source_directory (. SRC_LIST)

include_directories (../include)

add_executable (main ${SRC_LIST})

set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

上面的例子也可以只使用一个CMakeLists.txt,把最外层的CMakeLists.txt内容改成如下

cmake_minimum_required(VERSION 3.10)
project(MyProject VERSION 1.0)

set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

aux_source_directory (src SRC_LIST)

include_directories (include)

add_executable (main ${SRC_LIST})

同时,还要把src目录下的CMakeLists.txt删除。然后正常编译运行就可以。

示例2:

project/
├── bin
├── build
├── CMakeLists.txt
├── src/
│   ├── func_a/
│   │   ├── CMakeLists.txt
│   │   ├── src/
│   │   │   └── a.cpp
│   │   ├── include/
│   │   │   └── a.h
│   └── func_b/
│       ├── CMakeLists.txt
│       ├── src/
│       │   └── b.cpp
│       └── include/
│           └── b.h

三、动态库和静态库的编译控制

1. 生成库文件

文件的存放结构:

project/
├── build
├── CMakeLists.txt
├── lib
├── func_a/
│   ├── a.cpp
│   └──a.h

其中,会在build目录下运行cmake,并把生成的库文件存放到lib目录下。

CMakeLists.txt的源码为:

cmake_minimum_required(VERSION 3.10)
project(MyProject VERSION 1.0)
# 指定源文件的目录
set (SRC_LIST ${PROJECT_SOURCE_DIR}/func/a.cpp)

add_library (func_a_shared SHARED ${SRC_LIST})
add_library (func_a_static STATIC ${SRC_LIST})

set_target_properties (func_a_shared PROPERTIES OUTPUT_NAME "func_a")
set_target_properties (func_a_static PROPERTIES OUTPUT_NAME "func_a")

set (LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)

出现新的指令和预定义的变量:
a. add_library: 生成动态库或静态库(第1个参数指定库的名字;第2个参数决定是动态还是静态,如果没有就默认静态;第3个参数指定生成库的源文件)
b. set_target_properties:设置最终生成的库的名称,还有其它功能,如设置库的版本号等
c. LIBRARY_OUTPUT_PATH: 库文件的默认输出路径,这里设置为工程目录下的lib目录

说明:
前面使用set_target_properties重新定义了库的输出名称,如果不使用set_target_properties也可以,那么库的名称就是add_library里定义的名称,只是连续2次使用add_library指定库名称时(第一个参数),这个名称不能相同,而set_target_properties可以把名称设置为相同,只是最终生成的库文件后缀不同(一个是.so,一个是.a),这样相对来说会好看点。

运行查看

cd build/
cmake ..
make
cd ../lib/
ls

可以看到在lib目录下生成了libfunc_a.a和libfunc_a.so这两个文件,这就是生成的静态库和动态库文件

2. 链接库文件

重新建一个工程目录,然后把上节生成的库拷贝过来,然后在在工程目录下新建src目录和bin目录,在src目录下添加一个main.c,main.c中调用库中的函数
文件的存放结构如下所示:

project/
├── bin
├── build
├── CMakeLists.txt
├── src/
│   └── main.cpp
├── func_a/
│   ├── include/
│   │   └── a.h
│   └── lib/
│       ├── libfunc_a.a
│       └── libfunc_a.so

CMakeLists.txt的内容

cmake_minimum_required(VERSION 3.10)
project(MyProject VERSION 1.0)
# 指定可执行文件生成的目录
set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

set (SRC_LIST ${PROJECT_SOURCE_DIR}/src/main.cpp)

# find a.h
include_directories (${PROJECT_SOURCE_DIR}/func_a/include)

find_library(TESTFUNC_LIB func_a HINTS ${PROJECT_SOURCE_DIR}/func_a/lib)

add_executable (main ${SRC_LIST})

target_link_libraries (main ${TESTFUNC_LIB})

出现两个新的命令
a. find_library: 在指定目录下查找指定库,并把库的绝对路径存放到变量里,其中,第一个参数是变量名称,第二个参数是库名称(find_library 将会自动添加 lib 前缀和库的后缀.a 或 .so),第三个参数是HINTS,第4个参数是路径,其它用法可以参考cmake文档

b.target_link_libraries: 把目标文件与库文件进行链接

运行查看:

cd build/
cmake ..
make
cd ../bin/
./main

注意
ps:在lib目录下有testFunc的静态库和动态库,find_library(TESTFUNC_LIB testFunc
…默认是查找动态库,如果想直接指定使用动态库还是静态库,可以写成:
链接动态库:

find_library(TESTFUNC_LIB libfunc_a.so HINTS ${PROJECT_SOURCE_DIR}/func_a/lib)

链接静态库:

find_library(TESTFUNC_LIB libfunc_a.a HINTS ${PROJECT_SOURCE_DIR}/func_a/lib)

四、条件编译

五、相关的问题

既然最后都是要生成Makeflie文件,为什么不直接编写?而是通过编写Cmake的CMakeLists.txt来生成?各自有什么有优缺点?
可以简单提一下cmake是什么:

1.对于简单的项目或小型项目,直接编写 Makefile 是很直接和高效的,因为你可以完全控制编译和链接过程。
2.对于中大型的项目来讲,手动编写和维护 Makefile 可能变得非常复杂。需要管理多个目标、依赖关系、条件判断等。
3.对于跨平台来讲,在不同的平台(如 Windows、Linux、macOS)上,编写和维护 Makefile 需要处理平台特定的差异。而Cmake设计用于跨平台构建,通过 CMakeLists.txt 文件,你可以定义项目构建的逻辑,CMake 会根据目标平台生成适当的构建系统文件(如 Makefile、Visual Studio 工程等)。这大大简化了在不同平台上的构建过程。

使用 CMake 生成 Makefile 的优缺点:没什么太大的缺点,唯一的可能就是需要花时间学习如何编写CmakeLists.txt如何编写吧,哈哈哈哈!!!!

<think>好的,我现在需要帮助用户解决如何将JCG Q30 Pro路由器刷入OpenWRT固件的问题。首先,我要回顾用户提供的引用内容,尤其是引用[2]和[3],因为它们直接提到了刷机过程和相关固件。 用户的需求是详细的步骤,所以需要确保每一步都清晰。根据引用[2],JCG Q30 Pro的刷机过程不需要拆机,直接通过原系统升级过渡固件,然后刷入pb-boot或uboot,最后安装最终固件。引用[3]提到了一些具体的固件文件名和开发环境,可能需要确认用户是否需要特定的版本。 接下来,我需要将步骤分解成准备、刷过渡固件、刷入引导程序、安装OpenWRT这几个部分。同时要注意不同批次的内存容量(256MB和512MB),确保用户检查自己的设备版本,避免刷错固件。 另外,需要提醒用户备份原厂固件,以防万一。在步骤中要强调通过SSH连接路由器,可能需要使用PuTTY或者终端。在刷写引导程序时,必须准确输入命令,避免变砖。最后,要确认固件兼容性,可能需要参考引用[3]中的固件名称,比如openwrt-mediatek-mt7981-xxx.bin。 可能还需要警告用户操作风险,比如断电可能导致设备损坏,以及刷机后可能失去官方保修。此外,生成相关问题时要围绕刷机步骤、故障排除和固件选择展开,帮助用户进一步了解相关主题。</think>以下是为JCG Q30 Pro路由器刷入OpenWRT固件的详细教程,结合设备特性和公开刷机方案整理: ### 一、刷机准备 1. 确认设备版本:查看路由器底部标签,新批次为512MB内存(建议优先选择237176253编译的固件),旧批次为256MB内存[^2] 2. 下载必要文件: - 过渡固件:`openwrt-mediatek-filogic-jcg_q30-pro-initramfs-recovery.itb` - 正式固件:选择MT7981平台适配的OpenWRT固件,例如`openwrt-mediatek-mt7981-jcg_q30-pro-squashfs-sysupgrade.bin`[^3] - SSH工具:PuTTY或Termius 3. 连接准备:用网线连接路由器LAN口电脑,关闭防火墙/杀毒软件 ### 二、刷机步骤 1. **刷入过渡固件** - 登录原厂后台:`192.168.10.1`,使用标签密码 - 进入「系统升级」界面,上传过渡固件 - 等待自动重启(约3分钟),新IP变更为`192.168.1.1` 2. **刷入引导程序** ```bash ssh root@192.168.1.1 # 默认无密码 mtd write /tmp/xxx/uboot.bin FIP # 替换为实际引导程序路径 ``` 注意:不同开发者提供的引导程序名称可能为`uboot.bin`或`pb-boot.bin`[^3] 3. **刷入正式固件** - 按住RESET键通电,进入引导程序恢复模式(LED快闪) - 访问`192.168.1.1`上传sysupgrade格式固件 - 等待自动完成(约5分钟) ### 三、兼容性说明 1. 无线驱动:支持MT7976DN+MT7916AN双频芯片组 2. 硬件加速:默认启用HNAT硬件转发,WAN-LAN吞吐量可达940Mbps+ 3. 存储方案:SPI NAND闪存适配良好,支持overlay扩容 4. USB功能:需自行编译添加相关驱动模块
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

啥也不会的研究僧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值