从零开始:Makefile 与 CMake 的基础入门与实践


本文适合基础学者 零基础


makefile

  • 定义:Makefile 是一种传统的构建工具,用于定义如何编译和链接源代码。它通过一系列规则来描述如何生成目标文件(如可执行文件或库)。
    功能:
  • 定义编译规则(如如何从源文件生成目标文件)。
    指定依赖关系(如哪些文件需要重新编译)。
    执行编译、链接等任务。
  • 特点:
    灵活性高,可以直接控制构建过程。
    适用于小型项目或简单的构建需求。
    编写规则需要手动处理依赖关系和平台差异。
server:g++ server.cpp -o server && g++ client.cpp -o client

即编译server.cpp 和clien.cpp 分别命名为server 和client

CMake

  • 定义:CMake 是一个跨平台的构建工具生成器。它通过读取项目的配置文件(通常是 CMakeLists.txt),生成适合特定平台的构建系统(如 Makefile、Visual Studio 项目文件等)。
  • 功能:
    自动生成 Makefile 或其他构建系统文件。
    检测平台和编译器特性,自动调整构建规则。
    管理项目的依赖关系和库路径。
    支持复杂的项目结构和多平台构建。
  • 特点:
    高度抽象,简化了跨平台构建的复杂性。
    适用于大型项目或需要跨平台支持的项目。
    需要编写 CMakeLists.txt 文件来描述项目的结构和依赖关系。

总结两者关系

  • Makefile 是一种具体的构建工具,直接用于编译和链接代码。
  • CMake 是一个构建工具生成器,它通过生成 Makefile 或其他构建系统文件来简化构建过程。
  • 关系:CMake 是 Makefile 的“上层工具”,它生成 Makefile,而 Makefile 是实际执行构建任务的工具。

零基础写cmake

创建一个cmakelist.txt
运行命令为 cmake .
然后为 make

最基本的cmake


# 设置 CMake 最低版本
cmake_minimum_required(VERSION 3.10)# 定义项目名称
project(MyProject)# 指定源文件路径
set(SOURCE_FILESsrc/main.cppsrc/utils.cpp
)
add_executable(${PROJECT_NAME} ${SOURCE_FILES})
  • set
    set(VARIABLE_NAME VALUE1 VALUE2 ... VALUE_N)
    • VARIABLE_NAME:变量的名称。
    • VALUE1 … VALUE_N:变量的值,可以是字符串、路径、文件名等(文件路径为项目根目录的路径(相对路径))
  • add_executable
    add_executable(TARGET_NAME SOURCE_FILES)
    • TARGET_NAME:生成的可执行文件的名称。
    • SOURCE_FILES:用于生成可执行文件的源文件列表($是代表变量的意思)
      你也可以不使用变量
    • add_executable(my_program src/main.cpp src/utils.cpp)

疑问:他有两个文件 你怎么一个变量参数
set 命令可以将多个值赋给一个变量,形成一个列表。当你将这个变量传递给 add_executable 时,CMake 会将这个列表展开,作为多个参数传递给add_executable。这就是为什么一个变量可以代表多个文件的原因。

链接其他库


前言
静态库

  • 定义:静态库是编译后的代码,直接嵌入到可执行文件中。生成的可执行文件是独立的,不需要额外的库文件。
    优点:可执行文件是独立的,不需要额外的库文件。
    适合小型项目或需要独立分发的程序。
    缺点:可执行文件体积较大。
    库的更新需要重新编译整个程序。

动态库

  • 定义:动态库是编译后的代码,但在运行时加载。生成的可执行文件需要在运行时找到动态库文件。
  • 优点:
    可执行文件体积较小。
    多个程序可以共享同一个动态库。
    库的更新不需要重新编译整个程序。
  • 缺点:
    可执行文件依赖于动态库文件,需要确保运行时库文件存在。
    需要管理动态库的路径。

系统库(单个库)
cmake_minimum_required(VERSION 3.10)
project(MyProject)# 指定头文件路径
include_directories(include)# 指定源文件
set(SOURCE_FILESsrc/main.cpp
)# 生成可执行文件
add_executable(${PROJECT_NAME} ${SOURCE_FILES})# 查找系统库
find_library(SSL_LIBRARY ssl)# 链接到目标
target_link_libraries(${PROJECT_NAME} ${SSL_LIBRARY})
  • find_library
    find_library(VARIABLE_NAME library_name [PATHS path1 path2 ...])
  • VARIABLE_NAME:用于存储找到的库文件路径的变量名。
  • library_name:要查找的库文件名(不包括前缀 lib 和后缀 .so、.a 等)。
  • PATHS(可选):指定查找库文件的路径列表。如果省略,CMake 会在默认的系统库路径中查找。

在 Linux 系统中,CMake 会查找以下默认路径:
/usr/lib
/usr/local/lib
/lib
/usr/lib64(64位系统)
/usr/local/lib64(64位系统
Windows
C:\Windows\System32
C:\Windows\System
C:\Windows
C:\Program Files
C:\Program Files (x86)
你可以通过运行以下命令查看 CMake 的默认库查找路径:cmake --help-variable CMAKE_FIND_ROOT_PATH

  • include_directories ([AFTER|BEFORE] dir1 [dir2 ...])
    • AFTER 或 BEFORE(可选):指定目录的优先级。默认是 AFTER,表示目录会添加到包含路径的后面。如果指定 BEFORE,目录会添加到包含路径的前面。
    • dir1, dir2, …:要添加的头文件路径。
自己的库
cmake_minimum_required(VERSION 3.10)
project(MyProject)# 添加子目录(如果库在子目录中)
add_subdirectory(lib/mylib)# 指定头文件路径
include_directories(include)# 指定源文件
set(SOURCE_FILESsrc/main.cppsrc/utils.cpp
)# 生成可执行文件
add_executable(${PROJECT_NAME} ${SOURCE_FILES})# 链接到库
target_link_libraries(${PROJECT_NAME} mylib)

这个你添加目录 就行了add_subdirectory(lib/mylib)

第三方库(多库 可以算框架吧)
cmake_minimum_required(VERSION 3.10)
project(MyProjectWithDependencies)# 指定头文件路径
include_directories(include)# 指定源文件
set(SOURCE_FILESsrc/main.cpp
)# 生成可执行文件
add_executable(${PROJECT_NAME} ${SOURCE_FILES})# 查找第三方库(如 Boost)
find_package(Boost REQUIRED)
include_directories(${Boost_INCLUDE_DIRS})
target_link_libraries(${PROJECT_NAME} ${Boost_LIBRARIES})
  • find_package(PackageName [version] [REQUIRED])
    • PackageName:要查找的包名称。
    • version(可选):指定所需的包版本。
    • REQUIRED(可选):如果包未找到,CMake 会报错并停止构建。
      并设置

Boost_INCLUDE_DIRS:包含 Boost 的头文件路径。
Boost_LIBRARIES:包含 Boost 的库文件路径。

跨平台

cmake_minimum_required(VERSION 3.10)
project(MyCrossPlatformProject)# 指定源文件
set(SOURCE_FILESsrc/main.cpp
)# 生成可执行文件
add_executable(${PROJECT_NAME} ${SOURCE_FILES})# 根据平台设置不同的编译选项
if(WIN32)target_compile_definitions(${PROJECT_NAME} PRIVATE _WIN32)
elseif(APPLE)target_compile_definitions(${PROJECT_NAME} PRIVATE _MACOS)
elseif(UNIX)target_compile_definitions(${PROJECT_NAME} PRIVATE _LINUX)
endif()
  • target_compile_definitions(TARGET_NAME [INTERFACE|PUBLIC|PRIVATE] definition1 [definition2 ...]) -
    • TARGET_NAME:目标名称(通常是通过 add_executable 或 add_library 定义的)。
    • INTERFACE、PUBLIC、PRIVATE(可选):指定宏的作用域:
      • INTERFACE:宏对目标本身和依赖该目标的其他目标可见。
    • -PUBLIC:宏对目标本身和依赖该目标的其他目标可见。
      • PRIVATE:宏仅对目标本身可见。
  • definition1, definition2, …:要定义的宏。

优化和调试


Debug 构建
目的:用于开发和调试阶段。
特点:
包含调试信息(如符号表),便于使用调试器(如 GDB)进行调试。
不启用优化,确保代码的可读性和调试的准确性。
通常会定义调试相关的宏(如 _DEBUG)。
编译选项:
-g:生成调试信息。
用途:帮助开发者快速定位和修复问题。
2. Release 构建
目的:用于生产环境或最终发布。
特点:
启用优化,提高代码的执行效率。
不包含调试信息,减小可执行文件的体积。
通常会定义发布相关的宏(如 NDEBUG)。
编译选项:
-O3:启用最高级别的优化。
用途:确保程序在生产环境中性能最佳。


cmake_minimum_required(VERSION 3.10)
project(MyOptimizedProject)# 指定源文件
set(SOURCE_FILESsrc/main.cpp
)# 生成可执行文件
add_executable(${PROJECT_NAME} ${SOURCE_FILES})# 设置编译选项
if(CMAKE_BUILD_TYPE STREQUAL "Release") #CMAKE_BUILD_TYPE 内置变量 STREQUAL:是否相等target_compile_options(${PROJECT_NAME} PRIVATE -O3) #:GCC/Clang 编译器的优化选项,启用最高级别的优化
elseif(CMAKE_BUILD_TYPE STREQUAL "Debug")target_compile_options(${PROJECT_NAME} PRIVATE -g) # -g:GCC/Clang 编译器的选项,用于生成调试信息
endif()

生成安装脚本

cmake_minimum_required(VERSION 3.10)
project(MyInstallableProject)# 指定源文件
set(SOURCE_FILESsrc/main.cpp
)# 生成可执行文件
add_executable(${PROJECT_NAME} ${SOURCE_FILES})# 设置安装路径
install(TARGETS ${PROJECT_NAME}DESTINATION bin
)
install(TARGETS target1 [target2 ...]DESTINATION destination[RUNTIME DESTINATION runtime_destination][LIBRARY DESTINATION library_destination][ARCHIVE DESTINATION archive_destination][PERMISSIONS permissions...])

TARGETS:指定要安装的目标(如可执行文件或库)。
DESTINATION:指定安装目标的目录。
RUNTIME DESTINATION(可选):指定可执行文件的安装目录。
LIBRARY DESTINATION(可选):指定动态库的安装目录。
ARCHIVE DESTINATION(可选):指定静态库的安装目录。
PERMISSIONS(可选):指定安装文件的权限。

示例
假设你有一个项目,需要将生成的可执行文件安装到 /usr/local/bin 目录。

DESTINATION:指定安装目录,这里是 bin。如果安装路径是绝对路径(如 /usr/local/bin),则文件会被安装到该路径。如果路径是相对的,则文件会被安装到 CMake 的安装前缀(默认是 CMAKE_INSTALL_PREFIX,通常是 /usr/local)下的对应目录。

cmake .#生成makefile文件
make #执行makefile文件
sudo make install#安装

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/74153.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

android开启Sys V IPC,并使用共享内存编程

参考:安卓开启Sys V IPC,并使用共享内存编程 | 久奈浜的CS部 删除config中-# CONFIG_SYSVIPC is not set 在rk3576.config中增加CONFIG_SYSVIPCy CONFIG_SYSVIPCy CONFIG_SYSVIPC_SYSCTLy CONFIG_SYSVIPC_COMPATy CONFIG_IPC_NSy system/sepolicy/pre…

docker pull lss233/one-api:latest 在哪里运行,作用是什么

docker pull lss233/one-api:latest 在哪里运行,作用是什么 1. 在哪里运行? docker pull lss233/one-api:latest 是一个Docker命令,需在已安装Docker的环境中执行。 适用环境:本地开发机、服务器、云主机等。前提条件:需先安装Docker并配置好环境。2. 作用是什么? 该命令…

轮胎厂相关笔记

一、术语 图解:https://news.yiche.com/hao/wenzhang/38498703/ 1、胚胎 在轮胎制造行业中,“胎胚”(也称“生胎”或“未硫化轮胎”)是指轮胎在硫化(高温高压固化)之前的半成品形态。它是轮胎成型的中间…

开发者视角:应用程序中HTTP代理的集成指南

目录 一、为何需要HTTP代理? 二、集成方式分阶解析 三、关键配置管理策略 四、安全与性能平衡 五、调试与问题排查 六、最佳实践总结 结语 在开发需要与外部网络交互的应用程序时,HTTP代理是绕不开的实用工具。它既能解决网络限制问题&#xff0c…

从纸质到 AI 时代:我的笔记工具探索之旅

今天清晨,在得到上闲逛时,偶然间发现了一本名为《笔记的方法》的书,这本由Flomo的作者出版的图书,深入探讨了记笔记的艺术。 说起记笔记,这些年来,我尝试了各种各样的工具,今天就来梳理一下我的…

Ubuntu22云服务器添加2G Swap分区

Ubuntu22云服务器添加2G Swap分区 步骤 1:检查当前 Swap 和内存步骤 2:创建 2GB 的 Swap 文件步骤 3:设置权限并格式化步骤 4:启用 Swap 文件步骤 5:永久保留 Swap 配置可选优化:调整 Swappiness验证结果注…

网络空间安全(43)Linux实战篇

一、系统配置安全 BIOS安全设置 设置BIOS密码:防止未授权用户修改BIOS设置。修改引导次序:禁止从软盘启动系统,减少潜在的启动攻击风险。 文件系统权限管理 最小化SUID权限程序:SUID(Set User ID)程序以ro…

软件的常用设计模式。可参考一个一个学习

以下是软件设计中常见的 **23种经典设计模式**(基于《设计模式:可复用面向对象软件的基础》GoF 的经典分类),并结合 **Python 语言特性**的简要说明和典型应用场景。我将它们分为 **创建型、结构型、行为型** 三大类,供…

性能比拼: Go(Gin) vs Python(Flask)

本内容是对知名性能评测博主 Anton Putra Go (Golang) vs Python Performance Benchmark (Kubernetes - OpenTelemetry - Prometheus - S3/Postgres) 内容的翻译与整理, 有适当删减, 相关指标和结论以原作为准 在本视频中,我们将比较 Golang 和 Python 的性能。 但…

Android版本更新服务通知下载实现

在日常开发中,我们肯定会有检查版本更新的需求,那我版本更新的轮子网上也是有的,想自己实现一下代码如下: 下载管理类: public class DownLoadManager {private static final String MAIN "main"; //Tagp…

UE5学习笔记 FPS游戏制作33 换子弹 动画事件

新建动画蒙太奇 为Rifle和Launcher各自新建一个动画蒙太奇,拖入动画,注意动画的轨道要和动画蓝图里的一致 在蒙太奇添加动画事件 在通知一栏新增一个轨道,右键轨道,新增一个 换枪完成 通知,不同动画的同名通知需要…

uniapp中uploadFile的用法

基本语法 uni.uploadFile(OBJECT)OBJECT 是一个包含上传相关配置的对象,常见参数如下: 参数类型必填说明urlString是开发者服务器地址。filePathString是要上传文件资源的本地路径。nameString是文件对应的 key,开发者在服务端可以通过这个 …

Android设计模式之责任链模式

一、定义: 使多个对象都有机会处理请求,从而避免了请求的发送者和接收者之间的耦合关系将这些对象连城一条链,并沿着这条链传递该请求,只到有对象处理它为止。 二、模式结构: 抽象处理者(Handler&#xff…

Oracle数据库数据编程SQL<3.3 PL/SQL 游标>

游标(Cursor)是Oracle数据库中用于处理查询结果集的重要机制,它允许开发者逐行处理SQL语句返回的数据。 目录 一、游标基本概念 1. 游标定义 2. 游标分类 二、静态游标 (一)显式游标 【一】不带参数,普通的显示游标 1. 显式…

逗万DareWorks|创意重构书写美学,引领新潮无界的文创革命

当传统文具陷入同质化泥潭时,逗万DareWorks品牌犹如一颗璀璨的明星,以其独特的创意理念和卓越的产品品质,迅速赢得了广大消费者的青睐。 逗万DareWorks隶属于东莞司贸文教赠品有限公司,后者深耕制笔行业45年,占地4.6万…

写Prompt的技巧和基本原则

一.基本原则 1.一定要描述清晰你需要大模型做的事情,不要模棱两可 2.告诉大模型需要它做什么,不需要做什么 改写前: 请帮我推荐一些电影 改写后: 请帮我推荐2025年新出的10部评分比较高的喜剧电影,不要问我个人喜好等其他问题&#xff…

【React】基于 React+Tailwind 的 EmojiPicker 选择器组件

1.背景 React 写一个 EmojiPicker 组件,基于 emoji-mart 组件二次封装。支持添加自定义背景 、Emoji 图标选择!并在页面上展示! 2.技术栈 emoji-mart/data 、emoji-mart : emoji 图标库、元数据 tailwindcss: 原子化 CSS 样式库 antd : 组…

Qt中绘制不规则控件

在Qt中绘制不规则控件可通过设置遮罩(Mask)实现。以下是详细步骤: ‌继承目标控件‌:如QPushButton或QWidget。‌重写resizeEvent‌:当控件大小变化时,更新遮罩形状。‌创建遮罩区域‌:使用QRegion或QPain…

Parallel_Scheduling_of_DAGs_under_Memory_Constraints论文阅读

内存约束下的 DAG 并行调度 点击阅读原文语雀链接更清晰 摘要 科学工作流通常被建模为任务的有向无环图(DAG),这些任务代表计算模块及其依赖关系,依赖关系表现为任务生成的数据被其他任务使用。这种形式化方法允许使用运行时系统&…

探索MVC、MVP、MVVM和DDD架构在不同编程语言中的实现差异

MVC与MVP/MVVM/DDD架构对比,不同语言实现 MVC 分层架构设计概述 模型-视图-控制器(Model-View-Controller,简称 MVC)是一种经典软件架构设计,通过分层解耦,使得系统结构清晰和易于维护,具有良…