Makefile 自动生成依赖

虽然以前对Makefile有个基本概念,但是真正到自己去写一个哪怕是简单的Makefile时也会遇到不少的麻烦。
    现在我有如下文件 dList.h dList.c memory.c debug.c debug.h test.c aaron.h 其中包含关系如下:
    aaron.h-->dList.h debug.h
    dList.c-->aaron.h
    debug.c-->aaron.h
    test.c-->aaron.h
    memory.c-->aaron.h
    第一次写Makefile如下:
    OBJS := test.o debug.o memory.o dList.o
    MACRO = DEBUGALL
    CFLAGS+= -g  -D$(MACRO)
    CC = gcc
    main: $(OBJS)
           $(CC) $(OBJS)  -D$(MACRO) $(CFLAGS) -o main  
    clean:
        rm -f $(OBJS)
        rm -f main
    第一次看看似乎没什么问题啊。真正运行发现这个Makefile没有反应出.c文件对.h文件的依赖性,所以当.h文件发生变化时Makefile执行并不会发生变化。于是有了第二版:
    OBJS := test.o debug.o memory.o dList.o
    MACRO = DEBUGALL
    CFLAGS+= -g  -D$(MACRO)
    CC = gcc
    main: $(OBJS)
           $(CC) $(OBJS)  -D$(MACRO) $(CFLAGS) -o main  
    %o: aaron.h
    clean:
        rm -f $(OBJS)
        rm -f main
    这样当aaron.h发生变化时,所有.o都会被更新,从而main也会被更新。但是问题还是有,aaron是依赖于dList.h, debug.h的,如果这两个头文件发生变化在这个Makefile里仍然不能使main重新编译。继续改造:
    OBJS := test.o debug.o memory.o dList.o
    MACRO = DEBUGALL
    CFLAGS+= -g  -D$(MACRO)
    CC = gcc
    main: $(OBJS)
           $(CC) $(OBJS)  -D$(MACRO) $(CFLAGS) -o main  
    %o: aaron.h dList.h debug.h
    clean:
        rm -f $(OBJS)
        rm -f main
    这下看上去能满足我的要求。但是仔细一想就会发现如果我这个工程很大,靠手工去找到每个.c文件对应的所有头文件然后来完成这个Makefile似乎是不太可能而且也很难维护。于是想着Makefile应该有机制能自动生成依赖关系吧。
    于是找出宝典《GNU make中文手册》搜索了下果然有自动生成依赖相关内容。主要是利用gcc 的编译选项-M和-MM。不过让我看了半天也没有看明白其中的玄机。最后又重新翻看了改宝典众多章节总算理解了。先把代码贴出来:
                                                                                                                               
    MACRO = DEBUGALL
    CFLAGS+= -g -w -D$(MACRO)
    SOURCES = $(wildcard *.c)
    OBJS := $(patsubst %.c, %.o,$(SOURCES))
    
    CC = gcc
    main: $(OBJS)
           @echo "source files:" $(SOURCES)
           @echo "object files:" $(OBJS)
           $(CC) $(OBJS)  -D$(MACRO) $(CFLAGS) -o main  
    sinclude $(SOURCES:.c=.d)
    %d: %c
          @echo "create depend"
          $(CC) -MM $(CFLAGS) $< > $@.$$$$; \
          sed 's,\($*\)\.o[ :]*,\1.o $@ ,g' < $@.$$$$ > $@; \
          $(RM) $@.$$$$
          
  clean:
          rm -rf $(OBJS)
          rm -f main
    下面一行一行来分析下这个Makefile.
    前面两行很简单就是定义编译变量和编译选项。
    SOURCES = $(wildcard *.c) 这句话意思是定义一个变量SOURCES,它的值包含当前目录下所有.c文件。 在我的例子里我把这个值打印出来了就是dList.c memory.c test.c debug.c
    $(wildcard PATTEN) 是Makefile内建的一个函数:
    函数名称:获取匹配模式文件名函数—wildcard
    函数功能:列出当前目录下所有符合模式“PATTERN”格式的文件名。
    返回值:空格分割的、存在当前目录下的所有符合模式“PATTERN”的文件名。
    函数说明:“PATTERN”使用shell可识别的通配符,包括“?”(单字符)、“*”(多字符)等
    
    
    OBJS := $(patsubst %.c, %.o,$(SOURCES)) 这一行是定义了一个变量OBJS,它的值是将变量SOURCES里的内容以空格分开,将所有.c文件替换成.o. 在我的例子里打印出来就是dList.o memory.o test.o debug.o。
    $(patsubst PATTEN, REPLACEMENT, TEXT)也是内建函数
    函数名称:模式替换函数—patsubst。
    函数功能:搜索“TEXT”中以空格分开的单词,将否符合模式“TATTERN”替换为“REPLACEMENT”
    
    
    sinclude $(SOURCES:.c=.d) 这一行是非常关键的,它在当前Makefile里去include另外的Makefile. 这里“另外”的Makefile是将SOURCES变量里所有.c替换成.d。 在我的例子里就是dList.d memory.d test.d debug.d. 意思就是执行到这里
    的时候先去依次执行dList.d memory.d test.d debug.d. 这里的.d文件就是包含了每个.c文件自动生成的对头文件的依赖关系。这个依赖关系将由下面的%d:%c来完成。
    
    %d: %c
    此规则的含义是:所有的.d文件依赖于同名的.c文件。
第一行;使用c编译器自自动生成依赖文件($<)的头文件的依赖关系,并输出成为一个临时文件,“$$$$”表示当前进程号。如果$(CC)为GNU的c编译工具,产生的依赖关系的规则中,依赖头文件包括了所有的使用的系统头文件和用户定义的头文件。如果需要生成的依赖描述文件不包含系统头文件,可使用“-MM”代替“-M”。
第二行;使用sed处理第二行已产生的那个临时文件并生成此规则的目标文件。经过这一行后test.d里内容如下:test.o: test.c aaron.h dList.h debug.h 其他.d里以此类推。
第三行;删除临时文件。

    到这里基本的意义弄明白了,但是让我不解的是%d: %c这个依赖的规则怎么能被执行到的?按照我的理解Makefile在执行时首先检查终极目标main是否存在,如果不存在则建立(根据main的依赖规则),如果存在在需要查看
    main的依赖文件是否存在并且是最新的,这我的例子里就是要看test.o dList.o memory.o debug.o是否存在且最新。这样追下去是否没有%d: %c什么事啊, .d文件也应该不存在或者说是空的。尽管我们include了.d文件,但是没有依赖规则去执行它啊。后来仔细阅读了
    Makefile文件的重建才明白了。
    Makefile如果由其它文件重建(这里我的Makefile include了所有.d文件,.d也可以看成是一个Makefile),Makefile在读入所有其他makefile文件(.d)之后,首先将所读取的每个makefile(.d)作为一个目标,寻找更新它们的规则。同样
    如果此目标不存在则根据依赖规则重新创建。在例子里其实.d文件开始并不存在,所以当Makefile在include这些.d文件时首先看.d存在不,不存在就要去寻找.d的依赖文件和规则。这里就找到了%d: %c从而创建出真正的.d文件。其实这里的关键点就是对于
    include了理解,它是把include的文件首先当成一个目标,然后要去寻找其依赖文件和规则的,而不是我事先想象的简单的把其他文件的内容包含过来。
    到此,问题解决,基本达到预期。

时间: 2024-10-03 02:49:43

Makefile 自动生成依赖的相关文章

makefile自动生成依赖关系

手工编写依赖关系不仅工作量大而且极易出现遗漏,更新也很难及时,修改源或头文件后makefile可能忘记修改.为了解决这个问题,可以用gcc的-M选项自动生成目标文件和源文件的依赖关系.-M选项会把包含的系统头文件以及其所包含的其他系统头文件也找出来了,如果我们不需要输出系统头文件的依赖关系时,可以用-MM选项. 下面我们以一个简单的例子来说明如何自动生成依赖关系: exm/      main.c      s.c      s.h makefile文件内容如下: all:a src=$(wil

Makefile自动生成头文件依赖

前言 Makefile自动生成头文件依赖是很常用的功能,本文的目的是想尽量详细说明其中的原理和过程. Makefile模板 首先给出一个本人在小项目中常用的Makefile模板,支持自动生成头文件依赖. CC = gcc CFLAGS = -Wall -O INCLUDEFLAGS = LDFLAGS = OBJS = seq.o TARGETS = test_seq .PHONY:all all : $(TARGETS) test_seq:test_seq.o $(OBJS) $(CC) -o

make自动生成依赖文件的两种形式

最近编译源文件发现当修改头文件后,make并不会自动把包含此头文件的所有源文件重新编译,而每次都是需要把对应的中间文件清除才能重新编译,非常的麻烦.因此需要make自动对源文件所依赖的头文件进行管理,即make自动生成依赖文件.鉴于本人的刚开始写的博客,很多方面经验不足,比如如何介绍我所用到的知识等,现在只是对我在过程中遇到的问题进行记录,相关的知识可以查看gnu make中文文档,上网等等. 遇到的问题记录如下:1.make在生成依赖文件后并不正确:原因是生成的依赖文件中的目标文件(.d与.o

Makefile自动生成工具-----autotools的使用(详细)

相信每个学习Linux的人都知道Makefile,这是一个很有用的东西,但是编写它是比较复杂,今天介绍一个它的自动生成工具,autotools的使用.很多GNULinux的的软件都是用它生成Makefile的,包括我们非常熟悉的Linux内核源代码.     1.准备:   需要工具   autoscan   aclocal   autoheader    automake   autoconf   auto make    在终端敲入命令,哪个没有安装哪个,一般是第一个autoscan没有,其

如何自动生成Makefile

如何自动生成Makefile 如果只是一个很小的程序,没有几个文件,那么,我们手工书写Makefile还是可以忍受的,如果是一个超大型的工程,谁能忍受的了,光一个Makefile文件就足以是Writer头疼了,但也没有人说一定要手工书写makefile文件.linux中提供了自动生成Makefile的工具,而且通过,这些工具生成的makefile还很符合GNU的习惯的.而且功能也很齐全. 自动生成makefile需要些工具来支持:autoscan,aclocal,autoconf,automak

原来的SSH2程序加了maven多模块继承和依赖后不能自动生成数据库中的表了

问题描述 我的程序以前在编译的时候可以自动生成数据库中的表,现在我给程序加上了maven,实现了多模块的maven继承和依赖.各模块之间关系结构如下.现在的问题是程序在编译的时候不能自动生成数据库中的表了,TOMCAT启动也不报错,TOMCAT可以正常启动.我第一次接触MAVEN,也不知道到底是哪里有问题.我想如果是缺少包的话程序应该报错的.请各位高手帮忙看看到底如何解决这个问题,在线等待中,谢谢了. 解决方案 解决方案二:在线等了俩个小时了怎么还是没人回答呢?

为 Python 项目自动生成的依赖文件 Pigar

Pigar 详细介绍 Pigar 是为 Python 项目自动生成精确无误的依赖文件. 用 pip 安装: $ [sudo] pip install pigar pigar 能找区别不同 Python 版本之间的差异,非常精确,并找出依赖包在代码中的哪些位置引用了,这非常方便,可以发现某些无用却引用了的包: $ pigar # example/e1.py: 18 pkg_a == 3.3.3 # example/e2.py: 10 pkg_b == 1.1.1 如果你折腾别人的项目的时候遇到"I

makefile问题-为何没有编译。c文件会自动生成。o文件,这是啥原理,求解答

问题描述 为何没有编译.c文件会自动生成.o文件,这是啥原理,求解答 解决方案 生成了.o文件那就是编译了,要想生成可执行文件用-o选项. 解决方案二: make肯之后会会生成o文件 解决方案三: o就是目标文件,你make肯定除触发了编译器编译.才会生成o文件

基于JSP网页自动生成工具的设计与实现

js|设计|网页 摘 要:Web开发技术是Internet应用的一个重要方面,而JSP又是Web开发的最先进的技术,是当前Web开发人员的首选技术.但是由于JSP对Web开发人员要求较高,所以许多一般的Web开发人员还不能够使用这一项先进的技术.讨论基于模板和标签库的JSP网页自动生成工具的设计和实现,提出具体的设计思想和实现方法. 关键词:JSP:自动生成:Web开发:标签:标签库:模板 目录: 引言-------------------------..2 1          系统设计目标和