Makefile 快速入门指南

Makefile 快速入门指南

什么是Makefile?

Makefile 是一个自动化构建工具的配置文件,用于管理代码编译、测试和清理等任务。它通过定义规则(rules)来指定文件之间的依赖关系,当源文件改变时,只重新编译受影响的部分,大大提高了开发效率。

比如你写了个main.c,手动编译要敲gcc main.c -o app,但项目大了文件多了,手动敲命令太麻烦 ——Makefile 能帮你一键搞定所有编译步骤。

最简单的Makefile

hello:echo "Hello, World!"

运行 make 会输出 “Hello, World!”(注意:命令前必须是Tab,不是空格)

核心概念

1. 规则结构

每条规则包含三部分:

目标: 依赖文件命令
  • 目标:要生成的文件或任务名称
  • 依赖:生成目标所需的文件
  • 命令:生成目标的Shell命令(必须用Tab缩进)

2. 基础示例

# 编译C程序
app: main.o utils.ogcc main.o utils.o -o appmain.o: main.cgcc -c main.cutils.o: utils.cgcc -c utils.cclean:rm -f *.o app

3. 使用变量

定义和使用变量让Makefile更易维护,比如把编译器和编译选项等定义成变量:

CC = gcc
CFLAGS = -Wall -O2
TARGET = app
OBJS = main.o utils.o$(TARGET): $(OBJS)$(CC) $(CFLAGS) $^ -o $@%.o: %.c$(CC) $(CFLAGS) -c $< -o $@

常用变量类型(简单理解版):
(1)VAR = 值:后续修改其他变量会影响它(递归展开)
例:A = 123,B = $(A),之后A = 456,则B会变成 456。
(2)VAR := 值:定义时就固定,后续修改不影响(直接展开)
例:A = 123,B := $(A),之后A = 456,B还是 123。
(3)VAR ?= 默认值:如果没给 VAR 赋值,就用默认值(方便别人修改)

4. 常用自动化变量

这些特殊变量在命令中使用:

变量含义示例
$@当前目标文件名app
$<第一个依赖文件名main.c
$^所有依赖文件main.c utils.c
$?比目标新的依赖文件修改过的文件

5. 伪目标

声明不生成文件的目标(如clean):

.PHONY: clean runclean:rm -f *.o $(TARGET)run:./$(TARGET)

为什么要声明.PHONY?
防止目录下有个叫clean的文件 —— 如果有,make clean会误以为 “文件已存在,不用执行”,加了.PHONY就会强制执行命令。

常用场景模板

1. 基础C项目

CC = gcc
CFLAGS = -Wall -g
TARGET = myapp
SRCS = main.c utils.c
OBJS = $(SRCS:.c=.o)$(TARGET): $(OBJS)$(CC) $(CFLAGS) $^ -o $@%.o: %.c$(CC) $(CFLAGS) -c $< -o $@clean:rm -f $(OBJS) $(TARGET).PHONY: clean

2. 多目录项目

CC = gcc
CFLAGS = -Wall -Iinclude
TARGET = app
SRC_DIR = src
OBJ_DIR = objSRCS = $(wildcard $(SRC_DIR)/*.c)
OBJS = $(patsubst $(SRC_DIR)/%.c,$(OBJ_DIR)/%.o,$(SRCS))$(TARGET): $(OBJS)$(CC) $(CFLAGS) $^ -o $@$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(OBJ_DIR)$(CC) $(CFLAGS) -c $< -o $@$(OBJ_DIR):mkdir -p $@clean:rm -rf $(OBJ_DIR) $(TARGET).PHONY: clean

3. 带测试的任务

TARGET = app
TEST_TARGET = testbuild: $(TARGET)test: $(TEST_TARGET)./$(TEST_TARGET)$(TARGET): main.cgcc main.c -o $@$(TEST_TARGET): test.cgcc test.c -o $@clean:rm -f $(TARGET) $(TEST_TARGET).PHONY: build test clean

初学者技巧

  1. Tab是关键:命令前必须使用Tab缩进,空格会导致错误

    # 正确
    target:
    <Tab>command# 错误
    target:command  # 这里用了空格
    
  2. 使用变量:把编译器、选项等定义为变量

    CC = gcc
    CFLAGS = -Wall -O2
    
  3. 通配符规则:使用%简化相似规则

    %.o: %.c$(CC) $(CFLAGS) -c $< -o $@
    
  4. 伪目标声明:为不生成文件的目标添加.PHONY

    .PHONY: clean all install
    
  5. 调试Makefile

    • make -n:显示但不执行命令
    • make --debug:显示详细调试信息

常见错误解决

  1. “missing separator” 错误
    原因:命令前使用了空格而不是Tab
    解决:确保命令前是Tab字符

  2. “No rule to make target” 错误
    原因:依赖文件不存在
    解决:检查文件名拼写,或添加生成该文件的规则

  3. 命令不执行
    原因:存在同名文件且比依赖文件新
    解决:使用.PHONY声明伪目标或make -B强制重建

  4. 头文件修改不触发重编译
    解决:添加头文件依赖

    main.o: main.c utils.h
    

完整示例

# ===========================================
# 简单C项目Makefile示例(带详细注释)
# ===========================================# 1. 编译器配置
# --------------------------------
# 定义使用的C编译器(默认为gcc)
CC = gcc# 编译选项:
#   -Wall: 启用所有警告
#   -g: 添加调试信息
CFLAGS = -Wall -g# 最终生成的可执行文件名
TARGET = calculator# 2. 源文件配置
# --------------------------------
# 列出所有源文件(.c文件)
SRCS = main.c math.c# 将源文件列表转换为目标文件列表(.c替换为.o)
OBJS = $(SRCS:.c=.o)# 项目中的头文件列表(用于依赖关系)
HEADERS = math.h# 3. 构建规则
# --------------------------------
# 主目标:生成可执行文件
# 依赖所有目标文件(OBJS)
$(TARGET): $(OBJS)# 链接所有目标文件生成可执行文件# $^ 表示所有依赖文件(这里是所有.o文件)# $@ 表示目标文件名(这里是$(TARGET))$(CC) $(CFLAGS) $^ -o $@# 通用规则:从.c文件生成.o文件
# % 是通配符,匹配任意文件名
# 依赖对应的.c文件和所有头文件(HEADERS)
%.o: %.c $(HEADERS)# 编译单个源文件生成目标文件# $< 表示第一个依赖文件(这里是.c文件)# $@ 表示目标文件名(这里是.o文件)$(CC) $(CFLAGS) -c $< -o $@# 4. 实用目标
# --------------------------------
# 清理生成的文件
clean:# 删除所有目标文件和可执行文件rm -f $(OBJS) $(TARGET)# 运行程序(先构建再运行)
run: $(TARGET)# 运行生成的可执行文件./$(TARGET)# 5. 伪目标声明
# --------------------------------
# 声明不生成实际文件的目标
# 这确保即使有同名文件存在,这些目标也会执行
.PHONY: clean run# ===========================================
# 使用说明:
#   1. 保存为 "Makefile"(无扩展名)
#   2. 在终端执行:
#       make      # 编译程序
#       make run  # 运行程序
#       make clean # 清理生成的文件
# ===========================================

使用步骤:

  1. 保存为 Makefile(无扩展名)
  2. 终端运行:
    make     # 编译程序
    make run # 运行程序
    make clean # 清理文件
    

学习资源

  1. GNU Make手册
  2. Makefile教程(中文):https://seisman.github.io/how-to-write-makefile/
  3. 交互式学习:https://makefiletutorial.com/

初学者建议:从简单项目开始,先掌握基本规则和变量使用,再逐步学习高级特性。实践是最好的学习方式!

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

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

相关文章

Linux学习--C语言(指针4、结构体)

1.二维数组的传参int a[2][3] {1, 2, 3, 4, 5, 6};fun(a,2); int fun(int (*p)[3], int len);2.指针数组的传参char *pastr[5] {NULL};int fun(char **pstr,int len);例子&#xff1a;#include <stdio.h> #include <string.h>int InputArray(char (*p)[32], int …

【STM32】FreeRTOS 消息队列(五)

在 FreeRTOS 中&#xff0c;任务消息队列&#xff08;Message Queue&#xff09; 是一种非常关键的通信机制&#xff0c;用于在任务之间 传递数据、同步事件。 它是实现任务 解耦、异步通信 的核心工具之一&#xff0c;FreeRTOS 的消息队列是任务之间通信的桥梁。 简单点说&am…

【笔记】加速 uv 安装:系统环境变量配置国内镜像源

使用 Conda 工具链创建 UV 本地虚拟环境全记录——基于《Python 多版本与开发环境治理架构设计》-CSDN博客 命令行创建 UV 环境及本地化实战演示—— 基于《Python 多版本与开发环境治理架构设计》的最佳实践-CSDN博客 加速 uv 包安装&#xff1a;Windows 系统环境变量配置国内…

Three.js 渲染优化处理

基于项目经验和最佳实践&#xff0c;以下是渲染优化的具体处理方法&#xff1a; 1. 几何体与材质优化 使用 BufferGeometry // 推荐&#xff1a;使用 BufferGeometry 替代 Geometry const geometry new THREE.BufferGeometry();合并几何体 // 将多个几何体合并为一个以减少绘制…

Kafka——Kafka控制器

引言在Kafka集群中&#xff0c;有一个组件堪称"隐形的指挥官"——它默默协调着Broker的加入与退出&#xff0c;管理着主题的创建与删除&#xff0c;掌控着分区领导者的选举&#xff0c;它就是控制器&#xff08;Controller&#xff09;。想象一个拥有100台Broker的大…

编程与数学 03-002 计算机网络 11_域名系统(DNS)

编程与数学 03-002 计算机网络 11_域名系统&#xff08;DNS&#xff09;一、DNS的作用与功能&#xff08;一&#xff09;域名与IP地址的映射关系&#xff08;二&#xff09;DNS的层次结构二、DNS查询过程&#xff08;一&#xff09;递归查询与迭代查询&#xff08;二&#xff0…

影翎Antigravity将发布全球首款全景无人机,8月开启公测招募

7月28日&#xff0c;消费级无人机品牌「影翎Antigravity」及品牌标识官宣亮相&#xff0c;计划推出全新品类——全球首款「全景无人机」。这一消息引发行业震动&#xff0c;消费级航拍无人机市场或将迎来颠覆性飞行体验。影翎Antigravity官方介绍&#xff0c;引力不仅是束缚双脚…

SpringBoot集成Quzrtz实现定时任务

一 定时任务介绍 自律是很多人都想拥有的一种能力&#xff0c;或者说素质&#xff0c;但是理想往往很美好&#xff0c;现实却是无比残酷的。在现实生活中&#xff0c;我们很难做到自律&#xff0c;或者说做到持续自律。例如&#xff0c;我们经常会做各种学习计划、储蓄计划或减…

Java中的异常判断以及文件中的常用方法及功能

目录 异常 作用 异常的处理方式 JVM&#xff08;虚拟机&#xff09;默认的处理方式 自己处理&#xff08;捕获异常&#xff09; 抛出异常&#xff08;也就是交给调用者处理&#xff09; 自定义异常 file File中常见成员方法 判断和获取 创建和删除 获取并遍历 异常…

【C++算法】74.优先级队列_最后一块石头的重量

文章目录题目链接&#xff1a;题目描述&#xff1a;解法C 算法代码&#xff1a;题目链接&#xff1a; 1046. 最后一块石头的重量 题目描述&#xff1a; 解法 每次取出最重的两块石头进行碰撞&#xff0c;将剩余的石头重新放入堆中。 C 算法代码&#xff1a; class Solution …

中兴云电脑W101D2-晶晨S905L3A-2G+8G-安卓9-线刷固件包

中兴云电脑W101D2-晶晨S905L3A-2G8G-WIFI-蓝牙5.0-3个USB2.0-线刷包线刷方法&#xff1a;1、准备好一根双公头USB线刷刷机线&#xff0c;长度30-50CM长度最佳&#xff0c;同时准备一台电脑&#xff1b;2、电脑上安装好刷机工具Amlogic USB Burning Tool 软件 →打开软件 →文件…

Android OkHttp 底层原理和实战完全教程(责任链模式详解)

目录 1. OkHttp 入门:从一个请求开始 1.1 基本 GET 请求:三步走 1.2 同步 vs 异步:选择你的风格 1.3 为什么选 OkHttp? 2. 配置 OkHttpClient:打造你的专属网络引擎 2.1 超时设置:别让请求卡死 2.2 添加拦截器:窥探请求全过程 2.3 缓存:让请求更快更省流量 3. …

【RK3588部署yolo】算法篇

简历描述收集并制作军事伪装目标数据集&#xff0c;包含真实与伪装各种类型军事目标共计60余类。其中&#xff0c;包含最新战场充气伪装军事装备30余类&#xff0c;并为每一张图片制作了详细的标注。针对军事伪装目标的特点&#xff0c;在YOLOv8的Backbone与Neck部分分别加…

【Spring Boot 快速入门】一、入门

目录Spring Boot 简介Web 入门Spring Boot 快速入门HTTP 协议概述请求协议响应协议解析协议TomcatSpring Boot 简介 Spring Boot 是由 Pivotal 团队&#xff08;后被 VMware 收购&#xff09;开发的基于 Spring 框架的开源项目&#xff0c;于 2014 年首次发布。其核心目标是简…

如何调整服务器的内核参数?-哈尔滨云前沿

调整服务器内核参数是一项较为专业的操作&#xff0c;不同的操作系统调整方式略有不同&#xff0c;以下以常见的 Linux 系统为例&#xff0c;介绍一些调整服务器内核参数的一般步骤和常用参数&#xff1a;一般步骤 备份当前配置&#xff1a;在修改内核参数之前&#xff0c;先备…

C++基础:模拟实现queue和stack。底层:适配器

引言模拟实现queue和stack&#xff0c;理解适配器&#xff0c;实现起来非常简单。一、适配器 适配器是一种能让原本不兼容的接口协同工作的设计模式或者组件。它的主要作用是对一个类的接口进行转换&#xff0c;使其符合另一个类的期望接口&#xff0c;进而实现适配和复用。&am…

OI 杂题

OI 杂题字符串括号匹配例 1&#xff1a;与之前的类似&#xff0c;就是讲一点技巧&#xff0c;但是比较乱&#xff0c;凑合着看吧。 字符串 括号匹配 几何意义&#xff1a;考虑令 ( 为 111 变换&#xff0c;令 ) 为 −1-1−1 变换&#xff0c;然后对这个 1/−11/-11/−1 构成…

【论文阅读】Safety Alignment Should Be Made More Than Just a Few Tokens Deep

Safety Alignment Should Be Made More Than Just a Few Tokens Deep原文摘要问题提出现状与漏洞&#xff1a;当前LLMs的安全对齐机制容易被攻破&#xff0c;即使是简单的攻击&#xff08;如对抗性后缀攻击&#xff09;或良性的微调也可能导致模型越狱。核心论点&#xff1a; 作…

Generative AI in Game Development

如有侵权或其他问题&#xff0c;欢迎留言联系更正或删除。 出处&#xff1a;CHI 20241. 一段话总结本研究通过对来自 Reddit 和 Facebook 群组的 3,091 条独立游戏开发者的在线帖子和评论进行定性分析&#xff0c;探讨了他们对生成式 AI在游戏开发中多方面作用的认知与设想。研…

【C++算法】72.队列+宽搜_二叉树的最大宽度

文章目录题目链接&#xff1a;题目描述&#xff1a;解法C 算法代码&#xff1a;题目链接&#xff1a; 662. 二叉树最大宽度 题目描述&#xff1a; 解法 这里的宽度指的是一层的最右边的非空节点到一层的最左边的非空节点&#xff0c;一共的节点数。 解法一&#xff1a;硬来&am…