GNU make系列之介绍Makefile(0)

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

一.欢迎来到我的酒馆

      在本章节介绍Makefile。

二.GNU make 预览

      2.1 GNU make工具会自动决定哪些程序需要被重新编译,并且执行相应的命令来重新编译程序。在本系列博客中,我们会介绍GNU make。GNU make是由Richard Stallman和Roland McGrath开发的,在3.76版本后由Paul D. Smith开发。
      在本系列博客中,所有的例子都用c语言,c语言是使用最广泛的编程语言之一。但是,你可以使用make来构建任何编程语言的程序,只要是编译器可以运行在shell命令行上。make不仅限于构建应用程序,你还可以用make来描述某些文件必须自动更新的任何任务,无论何时有文件变动了,就需要自动更新某些文件。

2.2 准备和运行make
      在使用make工具之前,你必须写一个名为makefile的文件,这个makefile文件描述了文件之间的关系,并提供用于更新每个文件的命令。在一个应用程序中,通常,可执行文件从object文件(.o文件)上更新,而这些object文件又是通过编译源文件生成的。
      一旦有一个合适的makefile文件,每当你更改了一些源文件,你可以使用一条如下的简单命令:

make

来执行必要的重新编译。应用程序使用makefile数据为基础并且确定需要更新哪些文件。对于其中的每一个文件,它都会发布一个记录在以makefile数据为基础的配方。你可以提供命令行参数去控制哪些文件需要被更新。

2.3 一个简单的Makefile介绍
      你需要写一个文件名为makefile的文件来告诉make程序要执行哪些操作。大部分情况下,makefile文件表明如何编译和链接一个应用程序。当有明确的要求时(如,删除一个文件来执行清理操作)makefile文件还可以告诉make程序如何执行复杂的命令。
      当重新编译可执行文件的时候,每个更新过的c源文件必须重新编译。如果一个头文件已经更新了,为了安全起见,每一个包含了这个头文件的c源文件也必须重新编译。每次编译源文件都会生成一个对应的object文件(.o文件)。最后,如果任何的源文件已经被重新编译了,则所有的object文件,无论是新生成的还是以前编译中保存的,都必须一起链接来生成一个新的可执行文件。

2.4 一个执行单元长啥样
      一个简单的makefile文件包含了一个执行单元(rule),如下:

target ... : prerequisite ...
	recipe 1
	recipe 2
	recipe 3
	...
  • target(目标), 通常是一个文件的名字,target也可以是一个可执行文件或object文件。target也可以是要执行操作的名称,例如:clean。
  • prereauisite (先决条件), 是用作输入的文件,用于创建target。一个target通常依赖多个文件。
  • recipe(配方),是执行的操作。recipe可以有多个命令,要么在同一行上,要么在自己所在的行上。这里要记住的是:在写每个recipe之前都要敲一个tab键。如果你偏爱某个字符而不是tab字符加在recipe之前,你可以设置一个变量来替代字符。

      通常,配方是一条命令且需要用到先决条件,如果任何的先决条件发生更改,将会生成一个target。但是一个有配方和target的执行单元(rule),可以不写先决条件。例如:一个执行删除操作的target可以不写先决条件,如clean。
      一个执行单元,说明了如何且何时执行重新编译,在先决条件上执行一个配方来创建和更新一个target。一个执行单元同样可以说明如何执行一个操作。
      一个makefile文件可以包含除执行单元外的其他文本。但是一个简单的makefile仅仅只需要包含执行单元。相比较于展示的例子,执行单元可能看起来更复杂一些,但是所有的执行单元或多或少都适应这种模式。

三.一个简单的Makefile

      下面是一个简单的makefile例子,cJSON是c语言编写的JSON解码器,代码非常简洁,只有750行代码。点击这里下载cJSON
使用命令解压:

tar -zxvf cJSON.tar

解压之后,进入cJSON目录,文件像下面这样:
GNU make系列之介绍Makefile(0),gnu,linux,服务器

在项目cJSON目录下我已经写好了一个Makefile文件,这个例子描述了一个可执行文件test依赖于1个cJSON.o object文件,这个object文件又依赖于一个c源文件。

all: test

test: cJSON.o test.c 
        cc -W -Wall -o test test.c cJSON.o -lm 

cJSON.o: cJSON.c cJSON.h
        cc -W -Wall -c -o cJSON.o cJSON.c

clean:
        rm -rf *.o test 

要使用这个Makefile生成一个可执行文件,输入命令:

make

删除目录下的可执行文件和object文件,输入命令:

make clean

      在本例中,target是all,它依赖test,而test又依赖于cJSON.o,test.c,cJSON.h文件。配方是两个gcc编译指令。clean没有先决条件,它不依赖于任何文件,因此,它默认情况下是不执行的,除非指定命令(如:make clean)才会执行。
      当target是一个文件时,如果任何的prerequisite发生了更改,target需要被重新编译或重新链接。此外,任何prerequisite应首先更新自己自动生成的内容。在上面的例子中,cJSON.o依赖于cJSON.c源文件和cJSON.h头文件。
      一个配方会紧跟着一个target和prerequisite,这些配方表示了如何更新target文件。在makefile文件里,每行配方前必须敲一个tab键,以此来区分不同的配方。这里要记住的是:makefile并不知道配方是如何工作的,这取决于你提供各种配方来更新target文件。当一个target需要被更新的时候,所有提供的配方都会被执行。
      这里clean是一个target,但不是一个文件,它是一个操作的名称。在这个执行单元中,因为默认不会执行这个操作,clean不是任何其他执行单元的先决条件。因此,不要用它做任何事情,除非你告诉它要执行哪些操作。这里要记住的是:clean这个执行单元不仅不是一个先决条件,而且它没有任何的先决条件,因此这个执行单元的目的是运行特定的配方。target不是一个文件,但是是一个操作称之为phony target。如果一个object文件被重新编译了,他会比可执行程序test更新,所以test需要重新链接。
      因此,如果我们修改了cJSON.c文件,之后运行命令make,make会编译cJSON.c文件为cJSON.o文件,并且重新链接可执行程序test。

四.make程序如何处理Makefile文件

      默认的,make程序从上到下执行,它会找到第一个target。第一个target称为默认目标。
在上一小节的简单Makefile例子中,默认目标为test,因此,test这个执行单元会首先执行。当你下命令:

make

      make程序会在当前的目录下读取makefile文件,并且开始处理第一个执行单元。在这个例子中,第一个执行单元是all: test,而test又依赖于cJSON.o和test.c文件,在处理执行单元all: test之前,需要首先处理test的依赖文件。每个依赖文件都有自己的处理单元,通过编译源程序,这些处理单元会更新每个.o文件。如果先决条件是头文件和源文件,在这种情况下必须执行重新编译。
      其他的执行单元会被执行,因为它们的target是一个先决条件。如果一个执行单元不依赖任何的文件或先决条件,那么这个执行单元不会执行,除非你告诉make工具如何执行,如:make clean。
      在重新编译一个object文件之前,make程序会考虑更新它的先决条件,源文件和头文件。这个makefile文件没有指定具体的要执行的任务,.c和.h文件不是任何执行单元的target,因此对于这些文件,make程序不会执行任何操作,但是make程序会自动更新可执行程序。
      在重新编译任何需要它的object文件之后,make程序会决定是否重新链接可执行程序test。如果可执行程序test不存在,或者任何的object文件比这个test文件更新。如果一个object文件被重新编译了,那么它会比test可执行文件更新,因此会重新链接test。
      因此,如果我们修改了cJSON.c文件,然后执行make指令,make会把这个cJSON.c文件编译为cJSON.o文件,并且重新链接test可执行文件。如果修改了cJSON.h,make工具会把cJSON.c文件编译成cJSON.o文件,并且重新链接test。

五.在Makefile中使用变量

      5.1 上面的Makefile也可以写成下面这样:

all: test

test: cJSON.o test.o
        cc -W -Wall -o test test.o cJSON.o -lm 

cJSON.o: cJSON.c cJSON.h
        cc -W -Wall -c -o cJSON.o cJSON.c

test.o: test.c
        cc -W -Wall -c -o test.o test.c

clean:
        rm -rf *.o test 

      在上面的例子中,我们需要重复写两次cJSON.o、test.o,随着项目越来越大,这种重复非常容易出错,这时候我们可以使用变量来降低这种风险。变量允许一个文本字符串定义一次,以后可以在不同位置使用这个文本字符串(变量名)。

      对每个makefile创建一个名为objects的变量,这是一种标准练习。我们可以在makefile中定义一个变量objects:

objects=cJSON.o test.o

之后,在每个地方我们想要罗列出所有的object文件时,我们可以通过写:

$(object)

来替换变量的值。
下面是使用变量的makefile版本:

objects=cJSON.o test.o

all: test

test: $(objects)
        cc -W -Wall -o test $(objects) -lm 
        
cJSON.o: cJSON.c cJSON.h
        cc -W -Wall -c -o cJSON.o cJSON.c

test.o: test.c
        cc -W -Wall -c -o test.o test.c

clean:
        rm -rf *.o test 

5.2 让make程序推断出配方
      对于编译单个的.c源文件,可以不写配方。因为make工具可以自己推断出配方。从.c文件更新对应的.o文件可以使用cc -c命令,这是一个隐式的规则。
例如,使用配方:

cc -W -Wall -c -o cJSON.o cJSON.c

会将cJSON.c文件编译为cJSON.o文件。这里,我们可以省略配方,不写。当以这种方式自动调用.c文件时,它会自动添加到先决条件列表中。下面是一个完整的makefile,省略配方、省略.c文件、使用变量:

objects=cJSON.o test.o

all: test

test: $(objects)
        cc -W -Wall -o test $(objects) -lm 
cJSON.o: cJSON.h

test.o: 

clean:
        rm -rf $(objects) test 

这就是我们在实际操作中编写makefile的方式。因为隐式规则非常方便,也很重要,你会频繁的看到它被使用。

5.3 另一种类型的makefile
当makefile的object文件仅由隐式规则创建时,可以使用替代样式的makefile。在上面这个makefile中,你可以按先决条件而不是目标对条目进行分组。这是否是一种更好的尝试,这看起来更加紧凑,但是一些人并不喜欢它,因为它们发现将每个目标的所有信息放在一个地方更清晰。

5.4 清除目录
你不仅仅只想写编译一个程序的执行单元,当编译一个程序的时候。makefile一般会告诉你如何去做一些其他事情。例如,如何删除所有的object文件和可执行文件,下面是我们编写一个make执行单元来清除目录:

clean:
	rm -rf $(objects) test

在实际开发中,我们可能会写一个复杂的执行单元来处理意想不到的情况。我们可以这样写:

.PHONY: clean
clean:
	rm -rf $(objects) test

这可以防止make程序被名为clean的实际文件混淆。.PHONY: clean 表示clean不是一个文件而是一个命令。像上面的执行单元不应该放置在makefile文件的首行,因为我们并不希望它默认被执行。因此,在上面的makefile例子中,我们想要一个生成test的执行单元,test是默认目标。
因为clean不是test的先决条件,所以当我们输入命令:make的时候,clean这个执行单元不会被执行。如果要允许clean这个执行单元的话,需要输入:make clean。文章来源地址https://www.toymoban.com/news/detail-683260.html

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

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

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

相关文章

  • 交叉编译工具 aarch64-linux-gnu-gcc 的介绍与安装

    AArch64 是随 ARMv8 ISA 一起引入的 64 位架构,用于执行 A64 指令的计算机。而且在 AArch64 状态下执行的代码只能使用 A64 指令集。,而不能执行 A32 或 T32 指令。但是,与 AArch32 中不同,在64位状态下,指令可以访问 64 位和 32 位寄存器。 aarch64-linux-gnu-gcc 是一个交叉编译工具链,可

    2024年04月14日
    浏览(49)
  • 【Linux系列P6】自动化构建工具-make/Makefile详解

     前言 大家好吖,欢迎来到 YY 滴 Linux系列 ,热烈欢迎! 本章主要内容面向接触过Linux的老铁,主要内容含 欢迎订阅 YY 滴Linux专栏!更多干货持续更新!以下是传送门!  订阅专栏阅读:YY的《Linux》系列 ❀❀❀❀❀ 【Linux系列-P1】 Linux环境的搭建 【Linux系列-P2】Linux的基本知

    2024年02月16日
    浏览(38)
  • 【闪击Linux系列P6】自动化构建工具-make/Makefile详解

     前言 大家好吖,欢迎来到 YY 滴 Linux系列 ,热烈欢迎! 本章主要内容面向接触过Linux的老铁,主要内容含 欢迎订阅 YY 滴Linux专栏!更多干货持续更新!以下是传送门!  订阅专栏阅读:YY的《Linux》系列 ❀❀❀❀❀ 【Linux系列-P1】 Linux环境的搭建 【Linux系列-P2】Linux的基本知

    2024年02月13日
    浏览(39)
  • [SDR] GNU Radio 系列教程(十四) —— GNU Radio 低阶到高阶用法的分水岭 ZMQ 的使用详解

    目录 1、前言 2、ZMQ 块的类型 3、ZMQ 块的使用 4、DEMO 4.1 同一台电脑上的两个流程图 4.2 不同电脑上的两个流程图 4.3 作为 REQ/REP 服务器的 Python 程序 4.4 作为 PUSH/PULL 服务器的 Python 程序 4.5 处理流程图数据的 Python 程序 参考链接 学会使用 GNU Radio 中的 ZMQ,是从低阶使用者向高阶

    2023年04月26日
    浏览(36)
  • 【ARM 嵌入式 编译系列 10.3 -- GNU elfutils 工具小结】

    请阅读 【ARM GCC 编译专栏导读】 上篇文章:【ARM 嵌入式 编译系列 10.2 – 符号表与可执行程序分离详细讲解】 下篇文章:【ARM 嵌入式 编译系列 11 – GCC attribute ((packed))详细介绍】 GNU elfutils是一个开源的工具集,用于处理 ELF (Executable and Linkable Format)格式的可执行文件、

    2024年02月13日
    浏览(52)
  • Linux Bash Shell 脚本入门(2)——GNU

    ​ 目录 Linux Bash Shell 脚本入门(2)——GNU GNU与Linux GNU GNU的组成 Shell GNOME桌面环境 X Window 软件 GNOME 可点击内容,大部分来自维基百科,可以点击了解详情。 GNU操作系统起源于GNU计划,由理查德·斯托曼在麻省理工学院人工智能实验室发起,希望发展出一套完整的开放源代码

    2024年02月19日
    浏览(36)
  • [QT编程系列-33]:科学计算 - 开源数值计算库GNU Scientific Library(简称GSL)

    目录 第1章 简介 1.1 概述 1.2 主要功能 1.3 C++接口 1.4 在QT中使用GSL的步骤 第2章 GSL C++函数库 2.1 功能概述 2.2 代码示例 GNU Scientific Library(简称GSL)是一个开源数值计算库,旨在提供各种数学和科学计算的功能。它用于解决 数学、物理、工程和计算科学中的复杂问题,并提供了

    2024年02月11日
    浏览(42)
  • 探秘GNU/Linux Shell:命令行的魔法世界

    GNU/Linux的Shell是一种特殊的交互式工具,为用户提供了强大的控制和管理Linux系统的方式。在这个博客中,我们将深入了解Shell的基本概念、功能以及不同类型的Shell。 Shell的核心是命令行提示符,它是用户与Linux系统进行交互的媒介。通过命令行提示符,用户可以输入文本命令

    2024年02月19日
    浏览(40)
  • 【Linux】使用Bash和GNU Parallel并行解压缩文件

    在本教程中,我们将学习如何使用Bash脚本和GNU Parallel实现高效并行解压缩多个文件。这种方法在处理大量文件时可以显著加快提取过程。 先决条件 确保系统上已安装以下内容: Bash GNU Parallel 你可以使用以下命令在不同Linux系统上安装它们: 在Ubuntu上安装 在CentOS上安装 想象

    2024年02月04日
    浏览(41)
  • Linux和其他类Unix系统的GNU coreutils 知多少

    GNU coreutils是GNU项目的一部分,它是一组基本的命令行工具集,用于操作和管理Linux和其他类Unix系统中的文件和数据流。这些工具被广泛用于终端和脚本中,提供了许多常用的功能和实用程序。Linux和其他类Unix系统的GNU coreutils 知多少?了解它有助你熟悉常用的linux命令。 官网

    2024年02月11日
    浏览(42)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包