精华内容
下载资源
问答
  • 嵌入式系统中Makefile的作用不言而喻,下面我写一下嵌套Makefile的编写。在一些大的工程中,我们会把我们不同模块或是不同功能的源文件放在不同的目录中,在每个目录中都书写一个该目录的Makefile,这有利于让我们的...
  • linux–多目录下的MakeFile文件(嵌套Makefile)编写

    linux–多目录下的MakeFile文件(嵌套Makefile)编写

    转自:https://blog.csdn.net/qq_38880380/article/details/98879969

    展开全文
  • 逐步学习嵌套Makefile

    2020-03-23 20:06:40
    文章目录c文件的编译原理什么是Makefile为什么使用MakefileMakefile与shell c文件的编译原理 单个源文件 说到Makefile,不得不谈一谈C源文件的编译过程了,整个过程使用下图足以说明一切。 n个源文件 什么是...

    c文件的编译原理

    • 原理流程

    说到Makefile,不得不谈一谈C源文件的编译过程啦,整个过程使用下图足以说明一切。
    在这里插入图片描述

    • 功能

    在这里插入图片描述

    • 上述编译流程针对每个源文件而言,在一个项目的编译工作中,一般使用linux GNU make管理和构建自己的工程,如果不使用make,可想而知,编译上百个源文件得编译到何年马月,所以Makefile对于一个linux开发人员是何等的重要。

    什么是Makefile

    1、make如何工作的

    make工具依赖Makefile或着makefile文件,执行make命令时,make会去当前工作目录下寻找Makefile或makefile文件,然后根据目标和依赖项按顺序执行任务。首次make将执行所有任务,如果后面某个依赖项被更新,make只执行被更新过的依赖项,减少不必要的系统开销,节省编译时间。

    2、为什么要使用Makefile

    Makefile的最大作用就是自动化编译,只要写好了Makefile文件,终端键入make命令就可以执行Makefile文件里面的指令。在实际项目中,一个工程包含几十个,甚至几百个源文件,如果手动gcc编译一个个源文件,即使你有使不完的力气,和你协作共事的小伙伴也没有那个耐心等你gcc编译完所有的源文件。所以,Makefile不仅可以提高个人的专业技能,更重要的是大大提高了工作的效率。

    一次编写Makefile,终生受用,源文件被修改后,只需一键make就搞定。

    3、Makefile与shell

    Makefile类似于shell脚本,都可以执行操作系统的命令。Makefile和shell是两种不同的脚本,Makefile专门用于编译的专用工具,shell相当于一个命令行终端,是一个通用工具。当然用shell脚本也可以实现自动化编译,但相对Makefile来说,无论从执行效率、编程难易上来说都显得复杂很多。所以在工程编译工作中,开发人员都比较喜欢使用Makefile,有时结合shell脚本做一些简单的工作,比如程序稳定性测试、黑白盒测试、压力测试等。

    Makefile中的shell命令必须以[tab]键开头。

    Makefile的核心思想

    target...: 	dependency...
    command
    ...
    ...
    

    Makefile的核心思想如上面的代码所示,其实很简单,主要由目标项、依赖项和shell命令组成。

    • 目标项(target)
      目标项执行这条shell命令要生成的目标文件,比如gcc hello.c -o hello,hello就是一个目标项。这个目标项不一定是最终的可执行文件hello,也可使是中间目标文件hello.o,还可以是一个标签,如伪目标。

    • 依赖项(dependency)
      依赖项就是生成这个目标项所必要的文件。

    • shell命令(command)
      shell对于我们来说再熟悉不过了,我们在linux终端使用的一切命令都是shell命令。

    逐步了解Makefile

    初始版示例

    • 工作目录下的文件
      在这里插入图片描述
      对client.h文件的说明:在这个目录下,我将所有头文件都包含在client.h中,单独一个文件管理着所有文件,当增加头文件时,只需在这个文件中添加,不必去c源文件中添加。
      在这里插入图片描述

    • Makefile文件

      1 
      2 client_main:client_main.o domain_parse.o get_temp.o log.o
      3     gcc -o client_main client_main.o domain_parse.o get_temp.o log.o
      4 
      5 client_main.o:client_main.c client.h
      6     gcc -c client_main.c 
      7 
      8 domain_parse.o:domain_parse.c client.h
      9     gcc -c domain_parse.c
     10 
     11 get_temp.o:get_temp.c client.h
     12     gcc -c get_temp.c
     13 
     14 log.o:log.c client.h
     15     gcc -c log.c
     16 
     17 clean:
     18     rm -rf client_main.o domain_parse.o get_temp.o log.o 
    
    解析:
    	2、5、8、11、14、17一共有6个目标,其中第17行clean不是总目标的依赖项,make不会自动执行,只有输入
    	make clean才执行它。
    	第一步:输入make命令后,make机制开始在当前目录下寻找Makefile文件,并找到总目标,如client_main。
    	第二步:然后按总目标的依赖项的先后顺序找到依赖项,如client_main.o。
    	第三步:如果该依赖项也是一个目标项,程序就跳到相应依赖项作为目标项的地方,如第5行client_main.o:。
    	第四步:如果新依赖项满足新目标项,程序开始执行shell命令,如gcc -c client_main.c 。
    	第五步:重复第二步~第五步,直到所有任务执行完成。
    
    • make结果
      在这里插入图片描述
      此时可以看到目录中多了 *.o文件和client_main,make并没有自动执行clean,因为clean并不是总目标里面的依赖项。

      所以手动make clean
      在这里插入图片描述此时make删除所有.o文件。

    改进版

    一级示例

      1 
      2 OBJS=client_main.o domain_parse.o get_temp.o log.o
      3 
      4 client_main:$(OBJS)
      5     gcc -o client_main $(OBJS)
      6 
      7 client_main.o:client.h
      8 
      9 domain_parse.o:client.h
     10 
     11 get_temp.o:client.h
     12 
     13 log.o:client.h
     14 
     15 .PHONY:clean
     16 clean:
     17     -rm client_main $(OBJS) 
    

    从上面的Makefile文件中可以看出,代码比初始版本简洁许多,在此版本中增加了以下内容:

    • 变量
      类似于c语言中的宏定义,它代表文本字串。第2行定义OBJS变量并赋值为所有的*.o文件,在后面的语句中所有使用.o文件的地方用$(OBJS)代替,这样做的好处是,增加或删除某个.o文件时,只需修改变量OBJS的值。

    • 自动推导功能
      make会根据.o文件自动推到出.c文件,并根据总目标中的shell命令执行次级目标任务,比如在此版本中将所有次级目标的依赖文件.c文件删除。

    • 伪目标
      伪目标不是文件,可有可无依赖文件,是一个标签,第15行.PHONY是伪目标关键词,clean使用伪目标的原因是,如果当前工作目下有一个文件名为clean,执行make就会出错,所以使用伪目标用于出区分。

    • -rm
      如果文件出错,不管,继续往后执行。

    二级示例

      1 OBJS:=$(patsubst %.c,%.o,$(wildcard *.c))
      2 CC:=gcc 
      3 CFLAGS:=-g
      4 TARGETS:=client_main
      5 RM:=-rm
      6 #终极目标
      7 $(TARGETS):$(OBJS)
      8     $(CC) -o $@ $^ $(CFLGS) $(LDFLAGES)
      9 
     10 #清除命令
     11 .PHONY:clean cleanall
     12 clean:
     13     $(RM) $(OBJS)
     14 cleanall:
     15     $(RM) $(OBJS) $(TARGETS)
    

    解析:

    • 第1行 调用函数将当前工作目录下的所有c文件替换为中间目标文件.o文件。简单对函数说明一下:

    1、patsubst
    调用:$(patsubst pattern,replacement,text)
    参数:查找text中的单词(单词以“空格”、“Tab”或“回车”“换行”分隔)是否符合模式pattern,如果匹
    配的话,则以replacement替换。这里,pattern可以包括通配符“%”,表示任意长度的字串。如果
    replacement中也包含“%”,那么,replacement中的这个“%”将是pattern中的那个“%”所代表的字
    串。(可以用“\”来转义,以“%”来表示真实含义的“%”字符)
    返回 :函数返回被替换过后的字符串。
    2、wildcard 获取当前目录下的所有c文件

    • 第2行~第5行:对环境变量重新定义,使之不适用默认值
    • 第7行:总目标和依赖
    • 第8行:执行shell命令。这里去掉了一级版本中的语句,通过使用make的隐含规则,自动推导c文件所需要的头文件和编译总目标需要的中间目标文件。
    • 第11行~第15行:使用伪目标做删除文件处理,在这里主要删除中间目标文件和最终的可执行文件。

    高级版

    前面的示例是在同一个目录下编写Makefile,但在linux内核源码中,有多个子目录,每个子目录下存在着一个管理文件的Makefile,决定哪些文件需要编译,哪些文件不需要编译。在顶层根目录下有一个总控Makefile,这个Makefile的作用就是管理着其他子目录下的Makefile。

    • 先在根目录下创建目录树和定义好测试文件。比如:
      在这里插入图片描述
    • 简单介绍一下目录中的文件,print1.c、print2.c、print3.c三个文件内程序是一样的,函数名和头文件不同而已:
    #include "../../include/print1.h"
    
    
    void print1(void)
    {
    	printf("here is print1\n");
    }
    
    • print1、print2、print3目录下是Makefile是一样的,用于管理自己目录下c文件的编译:
    #遍历目录下的c文件
    SRC:=$(wildcard *.c)                   	
    #更改文件名后缀
    OBJS:=$(patsubst %.c,%.o,$(SRC))       
    
    ../../$(OBJS_DIR)/$(OBJS):$(SRC)
    	$(CC) -c $^ -o $@
    
    • src目录下的Makefile用于管理自己的子目录,决定make应该进去哪个子目录里面,在这一层中子目录是print1、print2、print3:
    #定义子目录
    SUBDIRS := print1 print2 print3
    
    
    all:compile_src
    
    #set命令-e,若指令传回值不等于0,则立即退出shell
    #for循环依次进入子目录
    compile_src:
    	set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done
    
    
    • 顶层中的Makefile,也可以叫它总控Makefile,它控制着子目录中make的走向,功能和src中的Makefile是一样的:
    #定义gcc
    CC := gcc
    
    #定义子目录
    SUBDIRS := main src obj
    
    #定义bin目录
    BIN_DIR := bin
    
    #定义最终得可执行文件
    BIN := my_app
    
    #定义.o文件目录
    OBJS_DIR := obj
    
    #定义清除命令
    RM := rm
    
    #传参下一层Makefile
    export CC OBJS_DIR BIN_DIR BIN
    
    #总目标
    all:check_bin compile_src
    
    #创建bin目录
    check_bin:
    	mkdir -p $(BIN_DIR)
    
    #编译子目录中的源码
    compile_src:
    	set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done
    
    #清除文件
    .PHONY:clean cleanall
    clean:
    	$(RM) -rf $(OBJS_DIR)/*.o
    
    cleanall:
    	$(RM) -rf $(OBJS_DIR)/*.o $(BIN_DIR)/$(BIN)
    
    
    • 说一下export
      export的作用是总控Makefile向下一层Makefile中传递参数。

    调用格式

    export <variable …>

    在本示例中总控Makefile

    export CC OBJS_DIR BIN_DIR BIN

    下层的Makefile加$直接使用,不必向c语言中一样定义参变量。

    • 测试
      在顶层目录下输入make,回车
      在这里插入图片描述
      运行一下最终的可执行文件
      在这里插入图片描述

    总结一下

    通过学习了Makefile,我想说一下自己的感受,Makefile说简单也简单,说难也难,说简单是因为它的编程思想简单,一个目标项,一个依赖项,再加上shell命令,它没有c/c++、java中的算法,也没有很多的函数。说难是因为平时自己写程序都是几个文件而已,少则一个c文件,多则十几个,写个Makefile很简单,但是有的工程,目录加子目录几十个,文件上百个,可能每个目录下都有Makefile,一层嵌套一层,就像在c程序中大量使用go to语句一样,很难受。可能我还是小白的原因,我相信只要矜持学习,一切都会变得简单起来的。

    展开全文
  • 多级makefile嵌套执行时上层makefile中定义变量并不能影响下层makefile的执行(除非设置环境变量) 如分别在目录/home/zsli/test及/home/zsli/test/sub_test中创建文件Makefile_t及Makefile,内容如下: CUR_DIR = ...

    多级makefile嵌套执行时上层makefile中定义变量并不能影响下层makefile的执行(除非设置环境变量)

    如分别在目录/home/zsli/test及/home/zsli/test/sub_test中创建文件Makefile_t及Makefile,内容如下:

    CUR_DIR = $(shell pwd)
    .PHONY: all;
    all:
        @echo $(ZSLI_TEST)
        @$(MAKE) -C $(CUR_DIR)/sub_test/
    
    ZSLI_TEST:= "test"
    


    .PHONY: all;
    all:
        @echo $(ZSLI_TEST)                                                                                                                                       

    执行

    make -f Makefile_t
    得到

    test
    make[1]: Entering directory `/home/mumu/test/sub_test'
    
    make[1]: Leaving directory `/home/mumu/test/sub_test'

    若需嵌套子makefile可使用上传makefile中定义变量,可将该变量定义为环境变量(export)



    展开全文
  • 简单的实例,多层嵌套Makefile(一)

    万次阅读 多人点赞 2017-02-17 11:37:33
    参考了网上的博客,自己整理了一份并且...源文件都是一个printf 没什么好讲的,主要是makefile。 首先是顶层Makefile的内容; 第1行:设置编译器 第2行:设置所有会生成的目标文件,为了最后一步连接成可执行文件。

    参考了网上的博客,自己整理了一份并且可以编译通过,也能够正常执行,所以就做了记录。


    防止过段时间就又忘记了。


    首先先上个还没执行make前的源码树:



    源文件都是一个printf 没什么好讲的,主要是makefile。


    首先是顶层Makefile的内容;


    第1行:设置编译器

    第2行:设置所有会生成的目标文件,为了最后一步连接成可执行文件。
    第3行:设置顶层Makefile坐在的目录

    第4行:设置目标文件存放的目录,待会第二行的那些目标文件,都会保存在这个目录下面

    第5行:设置可执行文件存放的目录

    第6行:设置可执行文件的名字

    第7行:保存所有子目录下的Makefile的路径。只要子目录有makefile存在就在这个地方添加上这个makefile相对顶层Makefile的路径。

    第11行:讲1~6行的变量设置成全局变量,在子目录的makefile里面可以直接使用这些变量。

    第13行:神奇的all标号。

    有网友比较官方的解释:一种简写,可以让多个目标操作顺次执行

    有网友比较接地气的解释(根据本篇makefile做了修改):

    直接 make 或 make all 的话会执行CHECKDIR 和 $(SUB_DIR) 的编译命令
    后面不加参数的话,会把第一个目标作为默认的
    make CHECKDIR 的话只执行第16行内容
    make $(SUB_DIR)的话只编译17~21行内容

     现在我们只是直接make,所以会先执行CHECKDIR然后再执行$(SUB_DIR)部分:


    CHECKDIR:创建一大堆目录,目录存在就不创建了。


    关键点在$(SUB_DIR):遍历make所有目录下面的makefile。

    首先查找依赖部分“ECHO”,就是一些打印信息,echo前面的‘@’符号不加也是可以的。

    接着就是执行:make -C  $(SUB_DIR) (-C是大写的C,小写的c编译出目标文件

    -C 参数的含义: -C DIRECTORY, --directory=DIRECTORY  Change to DIRECTORY before doing anything.

    翻译过来就是:在离开这个目录前做点什么。

    真特么的奇葩。 直接讲执行该目录下的makefile不就好了。

    所以加上-C 选项意思就是:在$(SUB_DIR) 目录下面执行make

    make -C  $(SUB_DIR) 展开就是:make -C main/  src/ src/eat/ obj/ :按顺序对各个目录下面的makefile,make一下。


    第23行:执行make clean 就会执行clean部分。


    src目录下面的makefile:


    稍微解释下:

    OBJ_DIR : 在顶层makefile中定义了,变量值为保存目标文件的目录。

         CC       :编译器,在顶层makefile中定义。

    生成的目标文件的路径/目标文件xxx.o:生成目标文件的依赖文件(xxx.c)

    (编译器) -c (依赖文件xxx.c) -o (生成的目标文件路径/目标文件xxx.o)


    src/eat/目录下面的makefile:

    不解释了。


    obj目录下面的makefile:

    链接成可执行文件文件名为$(BIN),最终可执行文件保存在$(BIN_DIR)目录下.


    在顶层makefile那里执行make,看执行后的源码树:


    展开全文
  • 先看一下目录结构 总控Makefile如下: 1: CFLAGS=-Wall 2: CC=gcc 3: 4: 5: SUBDIRS=server client 6: 7: export CFLAGS CC 8: 9: 10: 11: all:$(SUBDIRS) 12: 13: ...
  • makefile嵌套

    2018-11-10 22:43:13
    参考链接: https://www.cnblogs.com/hzijone/p/9940935.html, 通过makefile调用另外的makefilemakefile嵌套
  • Makefile嵌套学习

    2016-09-29 19:41:15
    今天学了嵌套makefile,在这里简单讲解一下。 新建一个文件夹Multi_Makefile_test(mkdir Multi_Makefile_test),里面新建两个文件夹(mkdir 1f 2f)和新建两个文件(touch main.c Makefile)。文件夹1f里新建两个...
  • Makefile嵌套

    2020-03-05 20:32:57
    大型项目中,每个模块都有自己的一个makefile。 例如一个 子模块目录subdir , 总的makefile 可以写为:  subsystem:  cd subdir && $(MAKE) 等价于 :  subsystem:  $(MAKE) -C subdir 总的...
  • makefile嵌套编译

    2019-03-09 18:19:05
    根目录makefile all: gbdt ffm-train ffm-predict gbdt: #编译 solvers/gbdt 目录下的makefile make -C solvers/gbdt ln -sf solvers/gbdt/gbdt ffm-train: #编译 solvers/libffm-...
  • https://blog.csdn.net/sinat_29830917/article/details/55506309
  • Makefile 嵌套执行

    2019-07-10 14:54:33
    在一些大的工程中,我们会把我们不同模块或是不同功能的源文件放在不同的目录中,我们可以在每个目录中都书写一个该目录的Makefile,这有利于让我们的Makefile变得更加地简洁,而不至于把所有的东西全部写在一个...
  • Makefile 嵌套和宏定义的应用详解

    千次阅读 2018-02-23 15:08:56
    在linux中使用Makefile实现自动化编译的时候,除了常用的功能外,还有一些不太常用却非常实用的技巧或是功能,比如Makefile嵌套Makefile中定义宏,Makefile中export变量等。在这里做一个学习记录以供参考学习。...
  • Linux中的Makefile是重要的编译文件,通常待编译文件在同一目录下可以简单的直接... 那么这时就需要进行Makefile嵌套使用了。所以我们第一步就是在子目录和父目录各建一个Makefile文件。我们以以下目录为例。 ...
  • Makefile嵌套调用

    千次阅读 2017-12-03 18:12:33
    Makefile嵌套调用ContentMakefile的嵌套调用 Content 问题介绍 解决方法一 问题再发现 解决方法二 参考问题介绍 现有子文件夹A和B,A、B中均有已经可以正常编译的代码以及Makefile,现要在文件夹中利用Makefile...
  • 最近遇到需要将vs2010的c++项目移植到linux下面的问题,由于项目中分了很多个子目录,如何写Makefile是一个很头疼的问题,不过还好,经过一番折腾,还是实现了初步的要求,下面给出一个嵌套目录的Makefile示例: ...
  • Makefile 嵌套补充

    2013-03-28 15:24:41
    #makefile for virtualinterface #2013 02 23 by clara CC = gcc CXX = g++ DEFINES = -DMONGO_HAVE_STDINT CFLAGS += -Wall $(DEFINES) INCLUDE = -I./src \ -I./CConfigFile \ -I./CLogFile L
  • makefile 多层嵌套实例

    千次阅读 2017-12-02 18:20:20
    编译时需要使用makefile的多层嵌套的方式。 makefile没有系统的学过,基本处在拿来用的级别,网上找了些资料最终化了几个小时才配好。   首先源码树如下: 最深的有三层,最顶层、base目录层以及base目录下的子...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 8,899
精华内容 3,559
关键字:

嵌套makefile