首页 > 其他分享 >makefile中.PHNOY的用法

makefile中.PHNOY的用法

时间:2023-10-20 17:46:50浏览次数:42  
标签:sub make PHNOY makefile 用法 add program clean test

makefile中PHONY的重要性

   

     伪目标是这样一个目标:它不代表一个真正的文件名,在执行make时可以指定这个目标来执行所在规则定义的命令,有时也可以将一个伪目标称为标签。伪目标通过   PHONY来指明。

     PHONY定义伪目标的命令一定会被执行,下面尝试分析这种优点的妙处。

1、如果我们指定的目标不是创建目标文件,而是使用makefile执行一些特定的命令,例如:

clean:
        rm *.o temp

    我们希望,只要输入”make clean“后,”rm *.o temp“命令就会执行。但是,当当前目录中存在一个和指定目标重名的文件时,例如clean文件,结果就不是我们想要的了。输入”make clean“后,“rm *.o temp” 命令一定不会被执行。

    解决的办法是,将目标clean定义成伪目标就成了。无论当前目录下是否存在“clean”这个文件,输入“make clean”后,“rm *.o temp”命令都会被执行。

注意:这种做法的带来的好处还不止此,它同时提高了make的执行效率,因为将clean定义成伪目标后,make的执行程序不会试图寻找clean的隐含规则。

2、PHONY可以确保源文件(*.c *.h)修改后,对应的目标文件会被重建。倘若缺少了PHONY,可以看到情况会很糟。

    现在做一个实验,实验的目录是/work,在这个目录中,包含了四个目录test、add、sub、include 和一个顶层目录makefile文件。test、add、sub三个目录分别包含了三个源程序test.c、add.c、sub.c和三个子目录makefile,目录include的是头文件heads.h的目录,分别展开四个目录的内容如下。

test目录
复制代码 复制代码
test.c
#include <stdio.h> #include "../include/heads.h" int main() { int a=15,b=16; printf("a+b=%d\n",add(a,b)); return 0; }

makefile
test.o:test.c ../include/heads.h
gcc -c -o $@ $<
.PHONY: clean
clean:
  rm -f *.o
复制代码 复制代码

    add目录

复制代码 复制代码
add.c
#include "../include/heads.h"
int add(int a,int b)
{
        return (a+b);
}

makefile
add.o :add.c ../include/heads.h
    gcc -c -o $@ $< 

.PHONY: clean
clean:
rm -f *.o
复制代码 复制代码

    sub目录

复制代码 复制代码
sub.c
#include "../include/heads.h"
int sub(int a,int b)
{
        return a-b;
}

makefile
sub.o:sub.c ../include/heads.h
      gcc -c -o $@ $< 

.PHONY: clean
clean:
rm -f *.o
复制代码 复制代码

    inlcude目录

复制代码 复制代码
heads.h
#ifndef _HEAD_H_
#define _HEAD_H_

extern int add(int,int);
extern int sub(int,int);

#endif
复制代码 复制代码

   顶层makefile文件

复制代码 复制代码
OBJS = ./add/add.o ./sub/sub.o ./test/test.o
program:  $(OBJS)
        gcc ./test/test.o ./add/add.o ./sub/sub.o -o program
$(OBJS): make -C $(dir $@) .PHONY: clean clean: make -C ./add clean make -C ./sub clean make -C ./test clean rm -f program
复制代码 复制代码

 编译调试:当在/work目录中,执行make后,编译出了program应用程序。修改了任意一个源文件(test.c、sub.c、add.c、heads.h)例如test.c,重新在/work目录中执行make,发现一直提示“make: `program' is up to date.” ,而不能重建test.o,更不用说重建program。

    修改顶层makefile文件,添加红色的一行

复制代码 复制代码
OBJS = ./add/add.o ./sub/sub.o ./test/test.o
program:  $(OBJS)
        gcc ./test/test.o ./add/add.o ./sub/sub.o -o program

.PHONY : $(OBJS)
$(OBJS):
        make -C $(dir $@)

.PHONY: clean
clean:
        make -C ./add  clean
        make -C ./sub  clean
        make -C ./test clean
        rm -f program
复制代码 复制代码

    加上伪目标修改后,问题就会解决。修改了任意一个源文件,执行make对应的目标文件就会重建,最后重建program。即使不修改源文件,执行make也会进入源文件目录中执行子make,但不会更新目标文件,最后还要重建program。

原因分析:由于(*.c *.h)- - > (*.o)- - > (program),修改前的顶层目标(program)依赖于(*.o)。执行make时,检查 (program)的依赖(*.o)是否比(program)新,而不会检查(*.h *.c)是否比(program)新,(*.h *.c)不是(program)的依赖。显然,(*.o)没有program新,所以不用重建。

    注意修改后的makefile,把./add/add.o ./sub/sub.o ./test/test.o当做三个伪目标,所以不会再检查 (program)的依赖(*.o)是否比(program)新。而原来的makefile中把./add/add.o ./sub/sub.o ./test/test.o当做三个依赖文件。可以说加上“PHONY”后,make程序对./add/add.o ./sub/sub.o ./test/test.o的看法已经完全不一样了。

    修改后的makefile,强制执行./add/add.o ./sub/sub.o ./test/test.o这三个伪目标的命令,即进入相应的子目录执行make,从而调用相应的子目录makefile。由于子目录中的makefile目标是(*.o),目标的依赖是(*.c heads.h),会检查(*.c heads.h)是否比(*.o)新,从而有可能重建(*.o)。而在跳回到顶层makefile后,还要执行“ gcc ./test/test.o ./add/add.o ./sub/sub.o -o program”。

总结:PHONY伪目标可以解决源文件不是最终目标直接依赖(实际上可以认为是间接依赖)带来的不能自动检查更新规则。

  分类: linux操作系统

from:makefile中.PHNOY的用法 - 轻轻的吻 - 博客园 (cnblogs.com)

 

https://www.cnblogs.com/yuanqiangfei/p/8032391.html

 

标签:sub,make,PHNOY,makefile,用法,add,program,clean,test
From: https://www.cnblogs.com/im18620660608/p/17777617.html

相关文章

  • postgresql【JSONB用法】
    //userNametypecode是我拿到数据结构出来的可以写固定值来测试;code字段为上面设置的唯一约束。如果code值没有变就是修改,否则就是新增INSERTINTO表名(username,type,code)VALUES('${userName}','${type}','${code}')ONCONFLICT9.6语法支持(code)DOUPDATE......
  • RestTemplate 用法总结
    一、RestTemplate是什么?   如果某个服务想获取其他服务的数据的时候,一般会用到RestTemplate,这是一种HTTP请求调用的工具二、如何使用?   通常情况下,服务与服务之间数据的获取并不是一次性的,所以我们把这个RestTemplate注入容器中,这样我们每次使用直接调用即可。@Co......
  • WPF触发器(Triggers):介绍与用法实例
    引言WindowsPresentationFoundation(WPF)提供了一个丰富和灵活的图形渲染框架,触发器(Triggers)是其中一个重要的功能。触发器能够用来控制或改变UI元素的属性、样式、甚至行为。在这篇博客文章中,我们将详细介绍WPF中触发器的种类、用法,并通过一些实际例子进行讲解。1.触发器的种......
  • uniapp打电话实现方法用法介绍
    一、uniapp打电话介绍uniapp是一个跨平台的开发框架,能够快速构建出高效、可靠、易维护的移动应用程序。在移动端开发中,打电话是一项常见的功能,而uniapp也提供了多种实现方法,下面将详细介绍uniapp中打电话的实现方法。二、使用系统API实现打电话在uniapp中,可以使用系统API实现打电话......
  • Makefile深入
    题目要求建立项目目录myutilxxxx(xxxx为学号后四位),子目录有:srcincludelibbin等源代码放入src,头文件放入include,生成的静态库,共享库放入lib,生成的中间文件,可执行文件放入bin编辑makefile放入mymath目录写出编译代码的makefile,编译出来的目标文件为testmyuti......
  • 在Python中range()的用法:
    在Python中,range()是一个内置函数,用于生成一个整数序列,通常用于循环遍历。以下是range()函数的一些常见用法:1.默认情况当你调用range()函数时,它会生成一个从0开始到给定数字(不包括该数字)的整数序列。foriinrange(5):print(i)#输出:0,1,2,3,42.指定开始和结......
  • 列表的增删改查(range用法:)
    列表的添加.append()lst=[]#向列表末尾添加内容#append()追加lst.append("张绍刚")lst.append("赵本山")lst.append("张无忌")print(lst)#insert()在指定位置插入,原先该位置以后的所有元素都需要往后挪n个位置,因此插入的效率极低。lst.insert(0,"赵敏")#在......
  • addEventListener()元素事件监听的用法及事件汇总
     addEventListener() 方法用于给元素添加监听事件,同一个元素可以重复添加,并且不会覆盖之前相同事件,用removeEventListener()方法来移除事件。使用方法:1vararberNameFilter=document.getElementById("arber_name_filter");2arberNameFilter.addEventListener("focus",......
  • 想让你的代码简洁,试试这个SimpleDateFormat类高深用法
    本文分享自华为云社区《从入门到精通:SimpleDateFormat类高深用法,让你的代码更简洁!》,作者:bug菌。环境说明:Windows10+IntelliJIDEA2021.3.2+Jdk1.8@[toc]前言日期时间在开发中是非常常见的需求,尤其是在处理与时间相关的业务逻辑时,我们需要对日期时间进行格式化、比较......
  • golang常见用法
    结构体数组与接口数组转换如果想把[]struct转为[]interface,我们发现直接赋值会报错。理论上interface可以转换任何数据,为什么结构体数组不可以呢?这是因为interface的设计导致的,如果能理解interface的底层实现,就能很清楚知道如何转换了。如图所示,与C++的虚函数类似,interface保......