返回顶部
首页 > 资讯 > 操作系统 >GNU make系列之介绍Makefile(0)
  • 445
分享到

GNU make系列之介绍Makefile(0)

gnulinux服务器 2023-08-30 11:08:53 445人浏览 安东尼
摘要

一.欢迎来到我的酒馆       在本章节介绍Makefile。 目录 一.欢迎来到我的酒馆二.GNU make 预览三.一个简单的Makefile四.make程序如何处理Makefile文件五.在Makefile中使用变量

一.欢迎来到我的酒馆

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

make

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

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

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

target ... : prerequisite ...recipe 1recipe 2recipe 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目录,文件像下面这样:
在这里插入图片描述

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

all: testtest: 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.cclean:        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: testtest: 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.ctest.o: test.c        cc -W -Wall -c -o test.o test.cclean:        rm -rf *.o test 

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

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

objects=cJSON.o test.o

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

$(object)

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

objects=cJSON.o test.oall: testtest: $(objects)        cc -W -Wall -o test $(objects) -lm         cJSON.o: cJSON.c cJSON.h        cc -W -Wall -c -o cJSON.o cJSON.ctest.o: test.c        cc -W -Wall -c -o test.o test.cclean:        rm -rf *.o test 

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.oall: testtest: $(objects)        cc -W -Wall -o test $(objects) -lm cJSON.o: cJSON.htest.o: clean:        rm -rf $(objects) test 

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

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

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

clean:rm -rf $(objects) test

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

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

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

来源地址:https://blog.csdn.net/StayAlive1887/article/details/132471884

--结束END--

本文标题: GNU make系列之介绍Makefile(0)

本文链接: https://lsjlt.com/news/382608.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • GNU make系列之介绍Makefile(0)
    一.欢迎来到我的酒馆       在本章节介绍Makefile。 目录 一.欢迎来到我的酒馆二.GNU make 预览三.一个简单的Makefile四.make程序如何处理Makefile文件五.在Makefile中使用变量 ...
    99+
    2023-08-30
    gnu linux 服务器
  • GNU make系列之写Makefile文件(1)
    一.欢迎来到我的酒馆       在本章节介绍如何写Makefile文件。 目录 一.欢迎来到我的酒馆二.Makefile包含了什么三.引入其它的Makefile文件 二.Makefile包含了什么       2.1 Ma...
    99+
    2023-08-30
    gnu 服务器
  • C语言make和Makefile介绍及使用
    1:make和Makefile的介绍: 概念 在软件的工程中的源文件是不计其数的,其按照类型,功能,模块分别放在若干个目录中,哪些文件需要编译,那些文件需要后编译,那些文件需要重新编...
    99+
    2024-04-02
  • Android控件系列之Toast使用介绍
    Toast英文含义是吐司,在Android中,它就像烘烤机里做好的吐司弹出来,并持续一小段时间后慢慢消失Toast也是一个容器,可以包含各种View,并承载着它们显示。 使用...
    99+
    2022-06-06
    toast Android
  • Android控件系列之CheckBox使用介绍
    学习目的: 1、掌握在Android中如何建立CheckBox 2、掌握CheckBox的常用属性 3、掌握CheckBox选中状态变换的事件(监听器) CheckBox简介:...
    99+
    2022-06-06
    checkbox Android
  • Android控件系列之TextView使用介绍
    学习目的: 1、了解在Android中如何使用TextView控件 2、掌握TextView控件重要属性 作用:TextView类似一般UI中的Label,TextBlock等...
    99+
    2022-06-06
    Android
  • iOS砸壳系列之三:Frida介绍和使用
    当涉及从App Store下载应用程序时,它们都是已安装的iOS应用(IPA)存储在设备上。这些应用程序通常带有保护的代码和资源,以限制用户对其进行修改或者逆向工程。 然而,有时候,为了进行调试、制作...
    99+
    2023-10-09
    ios cocoa macos iOS逆向 objective-c
  • Android控件系列之XML静态资源使用介绍
    学习目的: 1、了解在Android中如何设置和调用XML资源 2、掌握如何利用XML和JAVA代码进行协同开发界面 3、理解R文件的作用 开发Android时,总能看到一个...
    99+
    2022-06-06
    XML Android
  • Android控件系列之Button以及Android监听器使用介绍
    学习目的: 1、掌握在Android中如何建立Button 2、掌握Button的常用属性 3、掌握Button按钮的点击事件(监听器) Button是各种UI中最常用的控件之...
    99+
    2022-06-06
    button Android
  • 【Java系列】Mybatis-Plus 使用方式介绍
    1 Mybatis-Plus简介 Mybatis-Plus 提供了多种方式来执行 SQL,包括使用注解、XML 映射文件和 Lambda 表达式等。其中,使用 Lambda 表达式是 Mybatis-Plus 推荐的方式,因为它更加直...
    99+
    2023-08-31
    mybatis java 开发语言 原力计划
  • Flask入门系列Cookie与session的介绍
    目录一、Cookie的使用1、什么是Cookie2、在Flask中使用Cookie二、session的使用1、什么是session2、Flask中的session对象3、在Flask...
    99+
    2024-04-02
  • Android之联系人PinnedHeaderListView使用介绍
    Android联系人中的ListView是做得比较独特的,但是源码写得比较复制,当我们想使用他的时候再从源码中提取,实属不易啊,而且容易出错,这几天,我把他提取出来了,写成一个...
    99+
    2022-06-06
    联系 Android
  • Linux系统编程之进程介绍
    我们平时写的 C 语言代码,通过编译器编译,最终它会成为一个可执行程序,当这个可执行程序运行起来后(没有结束之前),它就成为了一个进程。一、进程概述...
    99+
    2023-06-05
  • 数据库之关系模型介绍
    关系模型是一种用于描述和管理数据的概念模型,它通过定义实体、属性和实体之间的关系来组织数据。关系模型是数据库领域最为常用和广泛应用的...
    99+
    2023-09-21
    数据库
  • 【Kubernetes系列】第2篇 基础概念介绍
    1 Pod - 实例Pod是一组紧密关联的容器集合,支持多个容器在一个Pod里共享网络和文件系统,可以通过进程间通信和文件共享这种简单高效的方式完成服务,是Kubernetes调度的基本单位。Pod的设计理念是 每个Pod都有一个唯一的IP...
    99+
    2023-06-04
  • 华为云服务器系列产品介绍
    云服务器:包括 Hyper-V 和 Hyper-Cloud ,用于虚拟化、容器化和 Web 应用程序的开发。 云硬盘:包括 Raider-Server 和 Raider-H ,用于数据存储和备份。 云网络:包括 Kubernetes 和 ...
    99+
    2023-10-27
    华为 产品介绍 服务器
  • mysql 8.0.11 innodb cluster 高可用集群手册系列之一 ------集群介绍
    MySQL 8.0.12 innodb cluster 高可用集群部署运维管理手册 一 innodb cluster 原理介绍 作者 方连超 Innodb cluster 原理介绍 Innodb ...
    99+
    2024-04-02
  • 【Java系列】Java虚拟机—类加载器介绍
    什么是Java虚拟机  Java虚拟机(Java Virtual Machine,JVM)是一个能够执行 Java 字节码的虚拟计算机。它是 Java 技术的核心部分,是 Java 应用程序运行的基础。 Java 程序在编译后会...
    99+
    2023-09-01
    java 开发语言 原力计划
  • 【Android车载系列】第1章 车载系统整体介绍
    1 车载操作系统         汽车操作系统是从传统汽车电子不断演变而来的,传统汽车电子产品可分为两类: 一类是汽车电子控制装置,通过直接向执行机构(如电子阀门、继电器开关、执行马达)发送指令,以控制车辆关键部件(如发动机、变...
    99+
    2023-08-31
    Android 车载开发 Automotive 车载系统
  • Java8深入学习系列(一)lambda表达式介绍
    前言最近在学习java8,所以接下来会给大家介绍一系列的Java8学习内容,那么让我们先从lambda表达式开始。众所周知从java8出现以来lambda是最重要的特性之一,它可以让我们用简洁流畅的代码完成一个功能。 很长一段时间java被...
    99+
    2023-05-31
    java8 lambda表达式 ava
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作