makefile 基础

makefile项目总结

命令行的方式编译文件需要怎么做

  1. 一个命令构建最终目标文件
    gcc $(所有源文件) -o $(目标文件)
    
  2. 拆分多个步骤编译
    gcc -S 生成汇编
    gcc -c 生成编译文件
    gcc 生成链接文件
    
  3. 其他命令
    -I 引入头
    -L 导入库
    

编写一个最简单的makefile

  1. 目标的目录结构
    pro1
    ├── main.cpp
    └── makefile
    
  2. 命令行上怎么编译这个文件
    # 编译前需要考虑是否清理掉之前的输出
    rm -f pro1.out
    # 编译main.cpp 并生成
    g++ -o pro1.out main.cpp
    
  3. 怎么把这些写到makefile文件呢
    #定义一个最终输出目标
    pro1.out:
    	g++ -o pro1.out main.cpp
        
    #定义目标的清理规则
    clean:
    	rm -f pro1.out
    
  4. 执行编译命令
    ggg@ggg-X550JX ~/test_demo/test_demo/pro1 $ make pro1.out
    g++ -o pro1.out main.cpp
    ggg@ggg-X550JX ~/test_demo/test_demo/pro1 $ ls
    main.cpp  makefile  pro1.out
    ggg@ggg-X550JX ~/test_demo/test_demo/pro1 $ make clean
    rm -f pro1.out
    ggg@ggg-X550JX ~/test_demo/test_demo/pro1 $ ls
    main.cpp  makefile
    

    make [目标名]
    使用该命令则可调用makefile内的编译方法

  5. 当然makefile文件名称并不规定只有这一种写法
    ggg@ggg-X550JX ~/test_demo/test_demo/pro1 $ mv makefile pro1.mk
    ggg@ggg-X550JX ~/test_demo/test_demo/pro1 $ make -f pro1.mk
    g++ -o pro1.out main.cpp
    ggg@ggg-X550JX ~/test_demo/test_demo/pro1 $ tree
    .
    ├── main.cpp
    ├── pro1.mk
    └── pro1.out
    
    0 directories, 3 files
    

    make -f [makefile文件名] [目标名]
    同样可以使用这样的一种方式编译

  6. 如果make时不指明编译目标,会默认执行makefile内第一个编译目标
  7. 至此解决了一个基本问题,就是不用每次编译都输入编译命令

变量

  1. 设置变量

    设置变量时候不需要引号,这里make进行直接字符替换

    INC=../util
    

    使用变量

    g++ -o pro1.out main.cpp -I$(INC)
    
  2. 变量允许嵌套

    比如现在使用一个公共头文件名称是util_pro1.h

    PRO=pro1
    pro1_INC=../util/util_pro1.h
    g++ -o pro1.out main.cpp -I$($(PRO)_INC)
    
  3. 变量追加

    比如现在多了一个log.cpp需要和 main.cpp一块便于

    file = main.cpp
    file += log.cpp
    g++ -o pro1.out main.cpp -I$($(PRO)_INC)
    
  4. 内置的几个变量
    $@ 输入
    $< 所有依赖
    $^ 当前依赖
    
  5. include 导入参数文件
    在make时可以使用外部文件进行参数的导入,这个文件里边既可以是变量,也可以是目标方法,但如果是目标方法。
    但需要注意和主makefile的命名冲突.
    include 在文件头则作用于makefilre整个文件
    如果在末尾,则只能作用在文件的执行区域,既不能用在依赖上。

使用场景:本次有10个工程共用一个makefile,因此差异化的参数就不能体现在一个makefile里,
因此设计一个附加工程用来专门生成RES.dep文件,
在编译不同项目时RES.dep内参数一致,但内容不同,
因此主makefile只需倒入这些变量即可不做任何修改,提升通用性,

  1. 至此将变量提取出来,分离了编译过程和编译参数

常用函数

  1. 获取源文件
    1.1 方法1
    source_path=$(shell find $(src_path) -maxdepth 3 -type d)
    source_file = ($foreach dir,$(source_path),$(wildcard *.c))
    
    1.2 方法2
    $(wildcard *.c */*.c)
    
  2. 去除路径信息,只保留源文件
    $(notdir $(souerce_file))
    
  3. 文件过滤
    3.1 取参数2与参数3的交集
    $(filrter a.c b.c,a.c) #结果a.c
    
    3.2 取参数2对参数3差集
    $(filrter-out a.c b.c,a.c) #结果a.c
    
  4. 字符串的替换
    4.1 方法1
    files4=$(patsubst %.c,%.o,$(src))
    
    4.2 方法2
    file=$(sourcefile:%.s=%.o)
    
    4.3 部分替换
    file=$(sourcefile:$(src_path)/%.s=%.o)
    

流程控制

  1. 两种依赖方法
    1.1 链式依赖
    a:b
    b:c
    
    1.2 顺序依赖
    a: b c
    
  2. if 分支
    ifeq (Y,$(diffmode))
        操作1
    else ifeq(N,$(diffmode))     
        操作2
    endif
    
  3. 判断是否被定义
    ifdef speaxial_path
        booter =hhh
    endif
    

自动推导.o编译

  1. 使用默认的编译指令
    #设置编译器版本
    CC=gcc 
    #设置输出目标
    OBJS=1.o 2.o 3.o
    
    all:$(OBJS)
        mv *.o ../build
    #这里注意只要写目标就行    
    1.o:
    2.o:
    3.o:
    clean:
        rm  ../build/*.o
    
  2. 自定义编译指令
    src=$(wildcard *.c dir/*.c)
    files4=$(src:%.c=%.o)
    #把依赖从all上像下依赖
    all:$(files4)
        echo "sucess"
    #all 将会依赖到这里,如果输入*.c中带有路径,则*.o也带路径
    %.o:%.c
        $(CC) -c $^ -o $@
    #允许特例化
    1.o:1.c
        $(CC) -c 1.c -o 1.o -lpthread
    

其他

  1. 指明伪目标
    .PHONY:clean
    clean:
        rm -rf *.o
    
  2. 在编译选项中进行替换 只能使用patsubst,而在变量定义中既可以用patsubst也可以用xx:%.c=%.d
  3. 隐藏命令和忽略错误
    #比如echo 如果不隐藏则会打印两次
    @命令 隐藏
    #针对一些可以预见的错误
    -命令 忽略错误
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值