linux系统编程(2)--Makefile

这篇具有很好参考价值的文章主要介绍了linux系统编程(2)--Makefile。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.Makefile简介

一个工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。

Makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。

make主要解决两个问题:

1) 大量代码的关系维护

大项目中源代码比较多,手工维护、编译时间长而且编译命令复杂,难以记忆及维护。把代码维护命令及编译命令写在makefile文件中,然后再用make工具解析此文件自动执行相应命令,可实现代码的合理编译。

2) 减少重复编译时间

在改动其中一个文件的时候,能判断哪些文件被修改过,可以只对该文件进行重新编译,然后重新链接所有的目标文件,节省编译时间。

Makefile文件命名规则

makefile和Makefile都可以,推荐使用Makefile。

make工具的安装

sudo apt install make

2.Makefile文件规则

#规则样式
目标:依赖文件列表
<tab>命令列表					

#命令列表前是一个制表符!推荐将vim的制表符设置为4个空格(在/etc/vim/vimrc文件最后添加set ts=4)
	
#目标:通常是要产生的文件名称,目标可以是可执行文件或其它obj文件,也可是一个动作的名称。
#依赖文件:用来输入从而产生目标的文件。一个目标通常有几个依赖文件(也可以没有)。
#命令列表:make执行的动作,一个规则可以含几个命令(也可以没有)。

举例(vim Makefile):

all:test1  test2
	echo "hello all"

test1:
	echo "hello test1"

test2:
	echo "hello test2"

在命令行输入make查看效果。

3.make命令

make是一个命令工具,用来解释Makefile中的规则。

#语法:
make [ -f file ][ options ][ targets ]

说明:

  • -f file
    • make默认在工作目录中寻找名为GNUmakefile、makefile、Makefile的文件作为输入文件
    • -f 可以指定以上名字以外的文件作为makefile输入文件
  • options
    • -v:显示make工具的版本信息
    • -w:在处理makefile之前和之后显示工作路径
    • -C dir:读取makefile之前改变工作路径至dir目录
    • -n:只打印要执行的命令但不执行
    • -s:执行但不显示执行的命令
  • targets
    • 若使用make命令时没有指定目标,则make工具默认实现Makefile文件内的第一个目标,然后退出
    • 指定make工具要实现的目标,目标可以是一个或多个(多个目标间用空格隔开)。

4.Makefile示例

测试文件:test.c add.c sub.c mul.c div.c

add.h:

#ifndef __ADD_H__
#define __ADD_H__

int add(int x, int y);

#endif /*__ADD_H__*/

add.c:

#include "add.h"

int add(int x, int y)
{
    return x + y;
}

类似完成sub.c mul.c div.c。

test.c:

#include <stdio.h>
#include "add.h"
#include "sub.h"
#include "mul.h"
#include "div.h"

int main()
{
    int x = 15;
    int y = 5;

    printf("x + y = %d\n", add(x, y));
    printf("x - y = %d\n", sub(x, y));
    printf("x * y = %d\n", mul(x, y));
    printf("x / y = %d\n", div(x, y));

    return 0;
}

Makefile文件的基础写法

test:add.c sub.c mul.c div.c test.c
	gcc add.c sub.c mul.c div.c test.c -o test

这种写法在修改一个文件后,所有文件会被重写编译,效率低。

改进后的Makefile:

test:add.o sub.o mul.o div.o test.o
	gcc add.o sub.o mul.o div.o test.o -o test

add.o:add.c
	gcc -c add.c -o add.o
sub.o:sub.c
	gcc -c sub.c -o sub.o
mul.o:mul.c
	gcc -c mul.c -o mul.o
div.o:div.c
	gcc -c div.c -o div.o
test.o:test.c
	gcc -c test.c -o test.o

5.Makefile中的变量

5.1 自定义变量

#创建变量:
变量名=变量值

#使用变量:
$(变量名)
${变量名}

#注意:
#makefile变量名可以以数字开头
#makefile变量名大小写敏感
#变量一般在makefile的头部定义

使用变量名修改Makefile:

OBJS = add.o sub.o mul.o div.o test.o

test:$(OBJS)
	gcc $(OBJS) -o test

add.o:add.c
	gcc -c add.c -o add.o
sub.o:sub.c
	gcc -c sub.c -o sub.o
mul.o:mul.c
	gcc -c mul.c -o mul.o
div.o:div.c
	gcc -c div.c -o div.o
test.o:test.c
	gcc -c test.c -o test.o

clean:
	rm -rf $(OBJS) test				#Tips: 使用make clean可以快速清理生成的文件

5.2 自动变量

  • $@: 表示规则中的目标
  • $<: 表示规则中的第一个依赖条件
  • $^: 表示规则中的所有依赖文件,组成一个列表,以空格隔开,如果这个列表中有重复的项则消除重复项。

注意:自动变量只能在规则的命令中中使用

使用自动变量进一步优化我们的Makefile:

OBJS = add.o sub.o mul.o div.o test.o
TARGET=test

$(TARGET):$(OBJS)
	gcc $^ -o $@
    echo $@
    echo $<
    echo $^

add.o:add.c
	gcc -c $< -o $@
sub.o:sub.c
	gcc -c $< -o $@
mul.o:mul.c
	gcc -c $< -o $@
div.o:div.c
	gcc -c $< -o $@
test.o:test.c
	gcc -c $< -o $@

clean:
	rm -rf $(OBJS) $(TARGET) 

5.3 模式规则

使用模式匹配进一步优化我们的Makefile:

OBJS = add.o sub.o mul.o div.o test.o
TARGET=test

$(TARGET):$(OBJS)
	gcc $^ -o $@ 

#模式匹配 所有的.o都依赖对应的.c
#将所有的.c 生成对应的.o
%.o:%.c
	gcc  -c $< -o $@

clean:
	rm -rf $(OBJS) $(TARGET) 

5.4 变量赋值的其他方式

  1. "="是最普通的等号,使用 “=”进行赋值,变量的值是整个Makefile中最后被指定的值。

    VAR_A = A
    VAR_B = $(VAR_A) B
    VAR_A = AA
    
    

    经过上面的赋值后,最后VIR_B的值是AA B,而不是A B,在make时,会把整个Makefile展开,来决定变量的值。

  2. :=” 表示直接赋值,赋予当前位置的值。

    VAR_A := A
    VAR_B := $(VAR_A) B
    VAR_A := AA
    
    

    最后VAR_B的值是A B,即根据当前位置进行赋值。

  3. ?=” 表示如果该变量没有被赋值,赋值予等号后面的值。

  4. "+="和平时写代码的理解是一样的,表示将符号后面的值添加到前面的变量上。

5.5 预定义变量

除了使用用户自定义变量,makefile中也提供了一些变量(变量名大写)供用户直接使用,我们可以直接对其进行赋值。

CC = gcc #arm-linux-gcc

CPPFLAGS : C预处理的选项 如:-I

CFLAGS: C编译器的选项 -Wall -g -c

LDFLAGS : 链接器选项 -L -l

6.Makefile中的函数

makefile中的函数有很多,以下两个比较常用。

  • wildcard:查找指定目录下的指定类型的文件
  • patsubst:匹配替换

使用这两个函数优化我们的Makefile:

SRC=$(wildcard ./*.c)					#获取当前目录下所有的.c文件
OBJS=$(patsubst %.c, %.o, $(SRC))		#将SRC中所有的.c替换成.o
TARGET=test

$(TARGET):$(OBJS)
	gcc $^ -o $@ 

%.o:%.c
	gcc  -c $< -o $@

clean:
	rm -rf $(OBJS) $(TARGET) 

7.Makefile中的伪目标

在之前的Makefile最后添加了一条clean规则。

当使用make clean时,方便清除编译生成的中间.o文件和最终目标文件。

问题:

如果当前目录下有一个名为clean的文件,当使用make clean时就不能执行clean规则中对应的命令。

解决:

声明clean为伪目标。声明为伪目标后,makefile将不会判断该目标是否存在或是否需要更新。

SRC=$(wildcard ./*.c)
OBJS=$(patsubst %.c, %.o, $(SRC))
TARGET=test

$(TARGET):$(OBJS)
	gcc $^ -o $@ 

%.o:%.c
	gcc  -c $< -o $@

.PHONY:clean		#声明clean为伪目标 伪目标不去判断目标文件是否存在或者已经更新 
clean:
	rm -rf $(OBJS) $(TARGET) 

8.命令中的特殊符号

  • - 此条命令出错,make也会继续执行后续的命令。
  • @ 不显示命令本身,只显示结果。

注意:只能在命令前加!

示例:文章来源地址https://www.toymoban.com/news/detail-408289.html

SRC=$(wildcard ./*.c)
OBJS=$(patsubst %.c, %.o, $(SRC))
TARGET=test

$(TARGET):$(OBJS)
	gcc $^ -o $@ 

%.o:%.c
	@gcc  -c $< -o $@			#make后的输出结果将不显示这条命令本身(即gcc -c ......)

.PHONY:clean
clean:
	-rm -rf $(OBJS) $(TARGET) 

⭐Makefile工作原理

  1. 若想生成目标,检查规则中的依赖条件是否存在,如不存在,则寻找是否有规则用来生成该依赖文件。
  2. 检查规则中的目标是否需要更新,必须先检查它的所有依赖,依赖中有任一个被更新,则目标必须更新。

到了这里,关于linux系统编程(2)--Makefile的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【系统编程】线程池以及API接口简介

    (꒪ꇴ꒪ ),Hello我是 祐言QAQ 我的博客主页:C/C++语言,数据结构,Linux基础,ARM开发板,网络编程等领域UP🌍 快上🚘,一起学习,让我们成为一个强大的攻城狮! 送给自己和读者的一句鸡汤🤔: 集中起来的意志可以击穿顽石! 作者水平很有限,如果发现错误,请在评论区指

    2024年02月09日
    浏览(27)
  • CUDA简介, 配置和运行第一个CUDA程序(Windows和Linux)

    CUDA(Compute Unified Device Architecture)是由NVIDIA开发的一种通用并行计算架构。CUDA允许程序员利用NVIDIA GPU的并行计算能力,加速各种计算密集型应用程序。 CUDA技术基于GPU的并行计算原理。传统的CPU处理器拥有少量的核心,可以同时执行少量的线程。但是,现代GPU拥有数百甚至上

    2024年01月21日
    浏览(28)
  • STM32 裸机编程 04 - Makefile 构建自动化

    我们可以用  make  命令行工具替代手动敲入“编译”、“链接”、“烧写”这些命令,自动完成整个过程。 make  工具使用一个名为  Makefile  的配置文件,从中读取执行动作的指令。这种自动化方式非常棒,因为这样可以把构建固件的过程、使用了哪些编译标记等也文档化

    2024年02月07日
    浏览(31)
  • linux环境编程(1): 实现一个单元测试框架-2

    在之前的文章中, 介绍了如何实现一个类似gtest的单元测试框架, 完整的项目代码可以参考这里: https://github.com/kfggww/cutest . 近期对cutest的实现做了一些修改, 包括: Test Suite的声明宏, 修改为TEST_SUITE 增加Test Suite的声明宏TEST_SUITE_WITH. 可传递Suite的init和cleanup函数, 在Suite中每个Cas

    2024年02月12日
    浏览(26)
  • Linux系统简介(简单粗暴)

    Linux之父(Linus Torwalds),1991年10月,发布了0.02版(第一个公开版)内核,1994年03月,发布1.0版内核,UNIX诞生时间为1970年1月1日,这里为什么要说到UNIX呢,主要是Linux的创始人为了纪念UNIX的诞生,把Linux系统的世界时间 ,它的起始点设置为1970年的1月1日,以后写脚本用得上,

    2024年02月05日
    浏览(37)
  • Linux系统简介与开源精神

    🎥 屿小夏 : 个人主页 🔥个人专栏 : Linux系统理论 🌄 莫道桑榆晚,为霞尚满天! Linux系统是一个什么样的系统?它的发展与诞生是什么样的?为什么Linux是开源软件的代名词?跟着本篇一起走进Linux,领略Linux系统及其开源精神的魅力! 在简要介绍Linux的发展史前,还得从

    2024年02月05日
    浏览(36)
  • 【Linux】Pinctrl子系统简介

    我们工作开发中非常常用的就是GPIO,在Linux开发中,是有必要去熟悉并理解的。在Linux内核中也有提供相应的子系统pinctrl子系统, 本文从大的面上去了解它 。 参考学习:Linux笔记老师课程(Pinctrl子系统) https://live.csdn.net/v/219059?spm=1001.2014.3001.5501 https://xuesong.blog.csdn.net/arti

    2024年02月07日
    浏览(37)
  • Linux 操作系统简介(1.1)

    第1章 Linux Shell简介 第2章 Shell基础 第3章 Bash Shell基础命令 第4章 Bash Shell命令进阶 第5章 Linux Shell深度理解 第6章 Linux环境变量 第7章 Linux文件权限 第8章 Linux文件系统的管理 第9章 Linux软件安装 第10章 Linux文本编辑器(Vim) 对于Linux操作系统的起源,你必须知道有一个名叫Lin

    2024年02月02日
    浏览(59)
  • Linux——kali系统简介及命令

    kali是Linux的一种,内部包含众多的网络安全相关的软件。 用户分为两类: 1.管理员用户也是root,管理员用户具有全部权限,可以进行任意的操作。 2.普通用户,新建的用户都是普通用户,权限非常低。 Linux是一个单根系统,根的表示方式是 /  Linux里的文件是严格区分大小写

    2024年02月05日
    浏览(41)
  • Linux IIO 子系统简介

    IIO 子系统系统框架 而在IIO子系统内部,则主要包括如下四部分的内容: iio buffer用于处理需要进行连续采集的数据,当一个IIO device的各通道数据支持连续采集时,则调用iio buffer模块提供的接口,创建iio buffer用于存储连续存储的数据,同时该模块提供字符设备文件的注册,因

    2024年02月16日
    浏览(25)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包