大话C语言:大型项目构建基础Makefile
lipiwang 2024-11-27 17:15 10 浏览 0 评论
1 Makefile概述
Makefile是一种用于自动化构建和管理程序的工具,以文本文件的形式存在。它主要记录了程序的编译规则、依赖关系和操作指令,使得在开发过程中能够轻松地进行代码的编译、链接和部署。
Makefile文件中的命令有一定规范,一旦该文件编写好以后在Linux命令行中执行一条make命令即可自动编译整个工程。不同厂家的make可能会稍有不同,并且语法上也有区别,不过基本思想都差不多,主要还是落在目标依赖上,最广泛使用的是GNUmake。
Makefile的主要作用包括:
- 自动化编译和链接:通过定义编译器、编译选项、源文件、目标文件等信息,Makefile可以自动完成代码的编译和链接过程,从而提高开发效率。
- 管理依赖关系:Makefile中可以指定各个源文件之间的依赖关系,确保在修改某个文件后,只需要重新编译该文件及其相关的依赖文件。
- 跳过不必要的编译:Makefile通过检查源文件和目标文件的时间戳,可以避免重新编译未发生变化的文件,从而加快构建速度。
2 make概述
make是一个命令行工具和构建自动化工具,主要用于管理和构建软件项目。它通过Makefile文件来定义构建任务和依赖关系,并根据这些规则自动执行任务以生成最终的目标文件。
Makefile中包含了目标、依赖关系和相应的构建命令。make工具会根据目标和依赖关系来确定构建顺序,并执行构建命令以生成新的目标文件。这使得make能够根据代码的依赖关系自动构建并更新目标文件,从而提高编译效率。
make具有依赖管理功能,可以确保任务的正确构建顺序。它支持任务并行执行,并可以在多种操作系统上运行。make是一个稳定且广泛使用的工具,已经存在多年,适用于多种编程语言和项目类型的构建任务。
3 为什么需要make和Makefile?
之所以需要make和Makefile,主要原因主要可以归结为以下几点:
- 自动化编译:在软件开发过程中,尤其是大型项目,源文件众多,编译过程复杂。手动编译不仅效率低下,而且容易出错。make和Makefile可以自动化地处理编译过程,根据源文件的依赖关系自动确定编译顺序,并执行相应的编译命令,大大提高了编译效率。
- 管理依赖关系:在软件项目中,源文件之间往往存在复杂的依赖关系。当一个源文件发生变化时,可能需要重新编译与其相关的其他源文件。make和Makefile可以方便地管理这些依赖关系,确保在需要时只重新编译必要的文件,避免了不必要的重复编译。
- 抽象构建逻辑:Makefile将构建逻辑抽象化,使得开发者能够专注于代码编写,而不必关心繁琐的构建过程。Makefile中定义了目标、依赖和命令,使得构建过程更加清晰、易于理解和维护。
- 跨平台兼容性:make工具在不同的操作系统上都可以使用,只需要根据不同的操作系统和编译器编写相应的Makefile即可。这使得软件项目可以在不同的平台上进行构建,提高了项目的可移植性。
- 可定制性:Makefile具有很高的可定制性,可以根据项目的具体需求进行灵活的配置。开发者可以定义自己的变量、规则和函数,以满足特定的构建需求。
- 提高开发效率:通过自动化编译和管理依赖关系,make和Makefile可以大大减少开发人员在构建过程中的重复劳动,让他们有更多的时间专注于代码的开发和调试,从而提高开发效率。
4 Makefile语法规则
4.1 模块代码
实现简单计算器功能,核心功能包括:
- 两位数的加法,功能文件add.h和add.c
- 两位数的加法,功能文件subtract.h和subtract.c
- 两位数的除法,功能文件divide.h和divide.c
- 两位数的乘法,功能文件multiply.h和multiply.c
- 计算器功能主入口,功能文件calculator.c
核心功能模块:两位数的加法
// add.h文件实现
#ifndef __ADD_H__
#define __ADD_H__
/*
* 功能:实现两个整数相加
* @param num1 : 被加数
* @param num2 : 加数
* @return 两数相加之和
* @note 不考虑溢出问题
*/
int add(int num1, int num2);
#endif
// add.c文件实现
#include "add.h"
int add(int num1, int num2)
{
return num1 + num2;
}
核心功能模块:两位数的减法
// subtract.h文件实现
#ifndef __SUBTRACT_H__
#define __SUBTRACT_H__
/*
* 功能:实现两个整数相减
* @param num1 : 被减数
* @param num2 : 减数
* @return 两数相减之差
* @note 不考虑溢出问题
*/
int subtract(int num1, int num2);
#endif
// subtract.c文件实现
#include "subtract.h"
int subtract(int num1, int num2)
{
return num1 - num2;
}
核心功能模块:两位数的除法
// divide.h文件实现
#ifndef __DIVIDE_H__
#define __DIVIDE_H__
/*
* 功能:实现两个整数相除
* @param num1 : 被除数
* @param num2 : 除数,不能为0
* @return 两数相除
* @note 除数不能为0
*/
double divide(int num1, int num2);
#endif
// divide.C文件实现
#include "divide.h"
double divide(int num1, int num2)
{
if (b != 0)
{
return (double)num1 / num2;
}
else
{
return 0.0;
}
}
核心功能模块:两位数的乘法
// multiply.h文件实现
#ifndef __MULTIPLY_H__
#define __MULTIPLY_H__
/*
* 功能:实现两个整数相乘
* @param num1 : 被乘数
* @param num2 : 乘数
* @return 两数相乘
* @note 不考虑溢出问题
*/
int multiply(int num1, int num2);
#endif
// multiply.c文件实现
#include "multiply.h"
int multiply(int num1, int num2)
{
return num1 * num2;
}
核心功能模块:计算器功能主入口法
// calculator.c文件实现
#include <stdio.h>
#include "add.h"
#include "subtract.h"
#include "divide.h"
#include "multiply.h"
int main()
{
int num1 = 20
int num2 = 5;
printf("两数相加之和: %d\n", add(num1, num2));
printf("两数相减之差: %d\n", subtract(num1, num2));
printf("两数相乘之积: %d\n", multiply(num1, num2));
printf("两数相除之商: %f\n", divide(num1, num2));
return 0;
}
4.2 Makefile基础语法规则
Makefile遵循基础规则如下:
target: dependencies
command
...
其中,
- target:表示要生成的目标文件或执行的动作,它通常是文件名或特殊的伪目标(如clean)。
- dependencies:表示生成目标所依赖的文件列表,多个文件之间使用空格分隔。
- command:表示生成目标时执行的命令,每个命令占一行,且前面必须有一个Tab字符作为缩进。
4.3 make命令格式
make命令格式如下:
make [选项] [目标]
其中,
- 选项:是 make 命令的可选参数,用于控制 make 的行为。
- 目标:是要构建的目标文件或标签名。如果没有指定目标,make 会使用 Makefile 中的第一个目标(通常是 all)
make 命令选项包括:
- -f FILE 或 --file=FILE:使用指定的 Makefile,而不是默认的 Makefile 或 makefile。
- -n 或 --just-print:显示将要执行的命令,但并不真正执行它们。
- -s 或 --silent 或 --quiet:不显示执行的命令。
- -k 或 --keep-going:在出现错误时继续执行其他命令。
- -j [N] 或 --jobs[=N]:同时运行命令的个数。如果没有指定 N,则 make 会尝试并行执行尽可能多的任务。
- --load-average[=LOAD]:当系统负载高于某个值时,不运行新的任务。
- -C DIR 或 --directory=DIR:在读取 Makefile 之前改变到指定的目录 DIR。
目标 通常是 Makefile 中定义的一个标签或文件名,它可能代表一个要构建的特定目标文件,或者是一组任务的集合。例如,Makefile 中可能定义了 all、clean、install 等目标。
一般的时候,直接使用make就可以。
4.4 多文件Makefile设计
以简单计算器为例,设计一个多文件编译的Makefile,具体内容如下:
calculator:calculator.o add.o subtract.o divide.o multiply.o
gcc calculator.o add.o subtract.o divide.o multiply.o ‐o calculator
calculator.o:calculator.c
gcc ‐c calculator.c ‐o calculator.o
add.o:add.c
gcc ‐c add.c ‐o add.o
subtract.o:subtract.c
gcc ‐c subtract.c ‐o subtract.o
divide.o:divide.c
gcc ‐c divide.c ‐o divide.o
multiply.o:multiply.c
gcc ‐c multiply.c ‐o multiply.o
clean:
rm *.o calculator ‐rf
注意,运行时使用make clean 就会执行clean后面的命令
5 Makefile变量
Makefile支持变量的使用,类似于C语言中的宏定义。变量可以用于存储文件名、编译选项等,使得Makefile更易于维护。
Makefile中的变量可以根据其来源和用途分为以下几类:
- 环境变量:执行Makefile时从外部传入Make命令的环境变量。例如,`PWD 表示当前目录的绝对路径。环境变量通常是全局的,并且可以在整个Makefile中引用。
- 内置变量或默认变量:Makefile中有一些内置的或默认的变量,这些变量在Makefile中有特定的含义和用途。例如,CC 用于指定编译器的类型,CFLAGS 用于指定编译器选项(如调试信息、优化等)。这些变量在Makefile中预定义,并且可以在需要时进行修改。
- 自动变量:自动变量是Makefile中根据当前的目标和依赖关系自动生成的变量。例如,$@ 表示目标文件的名称(包含扩展名),lt; 表示第一个依赖文件的名称。这些变量在规则中特别有用,因为它们可以根据上下文自动变化。
- 用户自定义变量:除了上述几类变量外,用户还可以在Makefile中定义自己的变量。这些变量可以根据需要命名和赋值,用于存储文件名、目录路径、编译器选项等常用的定义,并可以动态地用于自动构建步骤的指令中。
5.1 用户自定义变量
用户自定义变量规则:
# 定义变量:
变量名=变量值
# 变量引用或者使用
$(变量名)或${变量名}
注意:
- 变量是大小写敏感的
- 变量一般都在makefile的头部定义
- 变量几乎可在makefile的任何地方使用
5.2 内置变量
makefile中有许多预定义变量,这些变量具有特殊的含义,可在makefile中直接使用。
变量名 | 含义 |
$@ | 当前规则中的目标文件名 |
lt; | 当前规则中的第一个依赖文件名 |
$^ | 当前规则中的所有依赖文件名列表 |
AR | 归档维护程序的程序名,默认值为ar |
ARFLAGS | 归档维护程序的选项 |
AS | 汇编程序的名称,默认值为as |
ASFLAGS | 汇编程序的选项 |
CC | C编译器的名称,默认值为cc |
CFLAGS | C编译器的选项 |
CPP | C预编译器的名称,默认值为$(CC) -E |
CPPFLAGS | C预编译的选项 |
CXX | C++编译器的名称,默认值为g++ |
CXXFLAGS | C++编译器的选项 |
5.3 优化多文件Makefile
基于Makefile变量规则,进一步优化设计多文件Makefile,优化后的Makefile如下:
# 编译器选项
CC=gcc
CFLAGS=‐Wall ‐g
#目标文件选项
obj=calculator
obj1=add
obj2=subtract
obj3=divide
obj4=multiply
OBJ=calculator.o add.o subtract.o divide.o multiply.o
# 构建目标程序
$(obj):$(OBJ)
$(CC) $^ ‐o $@
# 编译目标文件
$(obj).o:$(obj).c
$(CC) $(CFLAGS) ‐c lt; ‐o $@
$(obj1).o:$(obj1).c
$(CC) $(CFLAGS) ‐c lt; ‐o $@
$(obj2).o:$(obj2).c
$(CC) $(CFLAGS) ‐c lt; ‐o $@
$(obj3).o:$(obj3).c
$(CC) $(CFLAGS) ‐c lt; ‐o $@
$(obj4).o:$(obj4).c
$(CC) $(CFLAGS) ‐c lt; ‐o $@
# 中间文件清理
clean:
rm $(OBJ) $(obj) ‐rf
Makefile支持使用通配符来匹配文件名,常用的通配符有:%:代表任意数量的任意字符,可以用于匹配文件名中的一部分。例如,%.o 表示所有以 .o 结尾的文件。
进一步优化Makefile文件:
# 编译器选项
CC=gcc
CFLAGS=‐Wall ‐g
#目标文件选项
obj=calculator
OBJ=calculator.o add.o subtract.o divide.o multiply.o
$(obj):$(OBJ)
$(CC) $^ ‐o $@
%.o:%.c
$(CC) $(CFLAGS) ‐c lt; ‐o $@
# 中间文件清理
clean:
rm $(OBJ) $(obj) ‐rf
---E N D---
喜欢的记得关注哦!
您的支持是我们前进的动力!
- 上一篇:深入浅出Makefile:从基础到高级应用
- 下一篇:Makefile编写
相关推荐
- 前端入门——css 网格轨道详细介绍
-
上篇前端入门——cssGrid网格基础知识整体大概介绍了cssgrid的基本概念及使用方法,本文将介绍创建网格容器时会发生什么?以及在网格容器上使用行、列属性如何定位元素。在本文中,将介绍:...
- Islands Architecture(孤岛架构)在携程新版首页的实践
-
一、项目背景2022,携程PC版首页终于迎来了首次改版,完成了用户体验与技术栈的全面升级。作为与用户连接的重要入口,旧版PC首页已经陪伴携程走过了22年,承担着重要使命的同时,也遇到了很多问题:维护/...
- HTML中script标签中的那些属性
-
HTML中的<script>标签详解在HTML中,<script>标签用于包含或引用JavaScript代码,是前端开发中不可或缺的一部分。通过合理使用<scrip...
- CSS 中各种居中你真的玩明白了么
-
页面布局中最常见的需求就是元素或者文字居中了,但是根据场景的不同,居中也有简单到复杂各种不同的实现方式,本篇就带大家一起了解下,各种场景下,该如何使用CSS实现居中前言页面布局中最常见的需求就是元...
- CSS样式更改——列表、表格和轮廓
-
上篇文章主要介绍了CSS样式更改篇中的字体设置Font&边框Border设置,这篇文章分享列表、表格和轮廓,一起来看看吧。1.列表List1).列表的类型<ulstyle='list-...
- 一文吃透 CSS Flex 布局
-
原文链接:一文吃透CSSFlex布局教学游戏这里有两个小游戏,可用来练习flex布局。塔防游戏送小青蛙回家Flexbox概述Flexbox布局也叫Flex布局,弹性盒子布局。它决定了...
- css实现多行文本的展开收起
-
背景在我们写需求时可能会遇到类似于这样的多行文本展开与收起的场景:那么,如何通过纯css实现这样的效果呢?实现的难点(1)位于多行文本右下角的展开收起按钮。(2)展开和收起两种状态的切换。(3)文本...
- css 垂直居中的几种实现方式
-
前言设计是带有主观色彩的,同样网页设计中的css一样让人摸不头脑。网上列举的实现方式一大把,或许在这里你都看到过,但既然来到这里我希望这篇能让你看有所收获,毕竟这也是前端面试的基础。实现方式备注:...
- WordPress固定链接设置
-
WordPress设置里的最后一项就是固定链接设置,固定链接设置是决定WordPress文章及静态页面URL的重要步骤,从站点的SEO角度来讲也是。固定链接设置决定网站URL,当页面数少的时候,可以一...
- 面试发愁!吃透 20 道 CSS 核心题,大厂 Offer 轻松拿
-
前端小伙伴们,是不是一想到面试里的CSS布局题就发愁?写代码时布局总是对不齐,面试官追问兼容性就卡壳,想跳槽却总被“多列等高”“响应式布局”这些问题难住——别担心!从今天起,咱们每天拆解一...
- 3种CSS清除浮动的方法
-
今天这篇文章给大家介绍3种CSS清除浮动的方法。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。首先,这里就不讲为什么我们要清楚浮动,反正不清除浮动事多多。下面我就讲3种常用清除浮动的...
- 2025 年 CSS 终于要支持强大的自定义函数了?
-
大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发!1.什么是CSS自定义属性CSS自...
- css3属性(transform)的一个css3动画小应用
-
闲言碎语不多讲,咱们说说css3的transform属性:先上效果:效果说明:当鼠标移到a标签的时候,从右上角滑出二维码。实现方法:HTML代码如下:需要说明的一点是,a链接的跳转需要用javasc...
- CSS基础知识(七)CSS背景
-
一、CSS背景属性1.背景颜色(background-color)属性值:transparent(透明的)或color(颜色)2.背景图片(background-image)属性值:none(没有)...
- CSS 水平居中方式二
-
<divid="parent"><!--定义子级元素--><divid="child">居中布局</div>...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- maven镜像 (69)
- undefined reference to (60)
- zip格式 (63)
- oracle over (62)
- date_format函数用法 (67)
- 在线代理服务器 (60)
- shell 字符串比较 (74)
- x509证书 (61)
- localhost (65)
- java.awt.headless (66)
- syn_sent (64)
- settings.xml (59)
- 弹出窗口 (56)
- applicationcontextaware (72)
- my.cnf (73)
- httpsession (62)
- pkcs7 (62)
- session cookie (63)
- java 生成uuid (58)
- could not initialize class (58)
- beanpropertyrowmapper (58)
- word空格下划线不显示 (73)
- jar文件 (60)
- jsp内置对象 (58)
- makefile编写规则 (58)