章工运维 章工运维
首页
  • linux
  • windows
  • 中间件
  • 监控
  • 网络
  • 存储
  • 安全
  • 防火墙
  • 数据库
  • 系统
  • docker
  • 运维工具
  • other
  • elk
  • K8S
  • ansible
  • Jenkins
  • GitLabCI_CD
  • 随笔
  • 面试
  • 工具
  • 收藏夹
  • Shell
  • python
  • golang
友链
  • 索引

    • 分类
    • 标签
    • 归档
    • 首页 (opens new window)
    • 关于我 (opens new window)
    • 图床 (opens new window)
    • 评论 (opens new window)
    • 导航栏 (opens new window)
周刊
GitHub (opens new window)

章工运维

业精于勤,荒于嬉
首页
  • linux
  • windows
  • 中间件
  • 监控
  • 网络
  • 存储
  • 安全
  • 防火墙
  • 数据库
  • 系统
  • docker
  • 运维工具
  • other
  • elk
  • K8S
  • ansible
  • Jenkins
  • GitLabCI_CD
  • 随笔
  • 面试
  • 工具
  • 收藏夹
  • Shell
  • python
  • golang
友链
  • 索引

    • 分类
    • 标签
    • 归档
    • 首页 (opens new window)
    • 关于我 (opens new window)
    • 图床 (opens new window)
    • 评论 (opens new window)
    • 导航栏 (opens new window)
周刊
GitHub (opens new window)
  • linux

  • windows

  • 中间件

  • 网络

  • 安全

  • 存储

  • 防火墙

  • 数据库

  • 系统

  • docker

  • other

    • debian中科大替换教程
    • Alpine安装php各种扩展
    • 使用http-server启动本地服务
    • windows文件同步备份
    • axure将项目同步到svn和axhub
    • Makefile入门
      • Rsyslog开源日志服务器
      • 在windows64位系统安装mysql
      • 博客vue报错版本依赖问题解决
      • VMware搭建群晖
      • 一个开源的照片管理程序——photoprism
      • 搭建属于自己的云笔记——leanote
      • 浏览器跨域问题
      • 从0到1搭建支付和发卡系统
      • 运维常见故障及排查方法
      • 高德MCP智能体搞定旅游计划
      • 不花一分钱从0到1建站教程
    • 监控

    • 运维
    • other
    章工运维
    2024-02-02
    目录

    Makefile入门

    # 一、Makefile简介

    官网:https://www.gnu.org/software/make/manual

    # 1、Makefile是什么

    Makefile是一种用于自动化构建程序的工具,它提供了一系列规则来指定源代码文件之间的依赖关系,以及如何生成目标文件。通过使用Makefile,程序员可以有效地管理和组织软件项目的编译过程,从而提高开发效率。

    Makefile文件是一个文本文件,其中包含一系列规则和指令,用于编译源代码并生成可执行文件或库。每个规则由一个目标文件、一个或多个依赖文件和一组命令组成,这些命令描述了如何从依赖文件生成目标文件。

    Makefile的主要作用是简化或组织编译代码的过程,它可以帮助程序员自动化编译、链接和打包程序。通过将整个项目分解为多个模块,并定义每个模块之间的依赖关系,当某个模块发生变化时,只需要重新编译该模块及其依赖的其他模块即可。这有助于减少手动操作和错误,并提高代码质量。

    此外,Makefile还支持变量定义和隐晦规则等特性,这些特性可以帮助程序员更加灵活地编写Makefile,并使构建过程更加易于维护和扩展。

    # 2、make 和 Makefile的关系

    Make是一个命令工具,用于解释和执行Makefile中的指令,完成项目的自动化构建。Makefile是一个文件,其中定义了一系列的规则来指定哪些文件需要先编译、哪些文件需要后编译、哪些文件需要重新编译等。

    当我们在命令行中输入make命令时,Make会查找当前目录下是否存在名为Makefile或makefile的文件。如果找到,Make会按照Makefile文件中的规则和指令,自动执行相应的命令来编译和链接源代码文件,生成可执行文件或库。

    # 二、Makefile 三要素

    Makefile的三个要素是目标、依赖和命令。它们在Makefile中的格式如下:

    目标(Target):目标是指需要生成的文件或目标体,可以是Object File(一般称为中间文件)、可执行文件或标签。目标定义了生成的目标体,并指明生成目标体需要哪些依赖文件。
    依赖(Dependency):依赖是指生成目标体所需的文件或另一个目标。它可以是一个或多个文件,也可以没有。依赖项描述了目标文件与源文件之间的依赖关系,告诉Make如何从源文件生成目标文件。
    命令(Command):命令是Make需要执行的命令行指令,可以是任意的shell命令。这些命令描述了如何从依赖文件生成目标文件。在Makefile中,命令部分需要有一定的缩进,可以是一行或多行,它们会依次执行。
    以下是Makefile三要素的格式示例:

    目标: 依赖  
        命令
    
    1
    2

    其中,目标和依赖之间用冒号(:)分隔,命令部分需要缩进。

    示例:

    # vim Makefile
    targeta:targetb targetc
            echo "targeta"
    
    targetb:
            echo "targetb"
    
    targetc:
            echo "targetc"
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    执行make命令

    # make
    echo "targetb"
    targetb
    echo "targetc"
    targetc
    echo "targeta"
    targeta
    
    
    1
    2
    3
    4
    5
    6
    7
    8

    指定执行命令

    
    # make targetb
    echo "targetb"
    targetb
    # touch targetb
    # make targetb			# 当前目录下targetb是最新文件不需要改变
    make: `targetb' is up to date.
    
    
    1
    2
    3
    4
    5
    6
    7
    8

    修改Makefile文件

    # vim Makefile
    .PHONY:targetb
    targeta:targetb targetc
            echo "targeta"
    
    targetb:
            echo "targetb"
    
    targetc:
            echo "targetc"
    # make targetb
    echo "targetb"
    targetb        
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

    .PHONY:targetb的意思是声明``targetb是一个伪目标,即使存在名为targetb的文件。这意味着,每次当你运行make targetb时,make不会尝试查找一个叫做targetb的文件并尝试运行它的命令,而是会执行与targetb` 关联的命令。

    在这个例子中,如果你运行 make targetb,它会输出 "targetb"。如果你运行 make targeta,它会首先运行 targetb 和 targetc 的命令,然后执行与 targeta 关联的命令,输出 "targeta"。

    # 三、引入Makefile管理项目

    生成两个文件

    # vim mp3.c
    #include<stdio.h>
    
    void play()
    {
            printf("paly music!\r\n");
    }
    
    void stop()
    {
            printf("stop music!\r\n");
    }
    # vim main.c
    #include<stdio.h>
    
    int main()
    {
            play();
            stop();
            return 0;
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22

    编写Makefile

    # vim Makefile
    mq3:main.c mp3.c
            gcc main.c mp3.c -o mp3
    
    .PHONE:clean
    
    clean:
            rm mp3
    # make
    # ls
    main.c  Makefile  mp3  mp3.c
    # ./mp3
    paly music!
    stop music!
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15

    改造Makefile,目的是将mp3.c和main.c解耦,当修改mp3.c或者main.c时,不需要重新编译另一个文件

    # vim Makefile
    mq3:main.o mp3.o
            gcc main.o mp3.o -o mp3
    
    main.o:
            gcc -c main.c -o main.o
    
    mp3.o:
            gcc -c mp3.c -o mp3.o
    
    .PHONE:clean
    
    clean:
            rm mp3
    # make clean
    rm mp3
    # make
    # ./mp3
    paly music!
    stop music!
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21

    # 四、Makefile的变量和模式匹配

    # 1、系统变量

    # vim Makefile
    .PHONY:all
    
    all:
            echo "${CC}"
            echo "${AS}"
            echo "${MAKE}"
            echo "${PATH}"
    # make
    echo "cc"
    cc
    echo "as"
    as
    echo "make"
    make
    echo "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin"
    /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18

    # 2、自定义变量

    1、延迟赋值

    在Makefile中,变量的默认赋值方式是“延迟”的。这意味着变量只有在被引用时才会被计算,并且只计算一次。如果一个变量在多个地方被引用,那么只有第一次引用时会被计算,后续的引用会使用第一次计算的结果。

    # vim Makefile
    A=123
    B=$(A)
    A=456
    
    .PHONY:all
    
    all:
            echo "${B}"
    # make
    echo "456"
    456
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

    2、立即赋值

    为了改变默认的延迟赋值行为,我们可以使用:=操作符进行“立即”赋值。这意味着变量会在声明时立即被计算,并且在之后的所有引用中都会使用这个计算结果。即使变量的值在后续发生了变化,之前的引用也不会受到影响。

    # vim Makefile
    A=123
    B:=$(A)
    A=456
    
    .PHONY:all
    
    all:
            echo "${B}"
    # make
    echo "123"
    123        
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

    3、空赋值

    使用=操作符可以将变量设置为空字符串。这在需要临时清除变量的内容时很有用。

    # vim Makefile
    A?=123
    #B:=$(A)
    A?=456
    
    .PHONY:all
    
    all:
            echo "${A}"
    # make
    echo "123"
    123        
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

    4、追加赋值

    如果想要将一个值追加到变量的末尾,可以使用+=操作符。这不会覆盖变量的现有内容,而是将新值添加到变量的末尾。

    # vim Makefile
    A?=123
    #B:=$(A)
    A+=456
    
    .PHONY:all
    
    all:
            echo "${A}"
    # make
    echo "123 456"
    123 456
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

    # 3、自动化变量

    1、$<

    代表第一个依赖项。在规则的命令部分,$<将被替换为第一个依赖项的文件名。

    # vim Makefile
    all:targeta targetb
            echo "$<"
    
    targeta:
    
    targetb:
    # make
    echo "targeta"
    targeta
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    2、$^

    代表所有的依赖项。在规则的命令部分,$^将被替换为一个空格分隔的列表,包含了所有依赖项的文件名

    # vim Makefile
    all:targeta targetb
            echo "$^"
    
    targeta:
    
    targetb:
    # make
    echo "targeta targetb"
    targeta targetb
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    3、$@

    代表目标文件。在规则的命令部分,$@将被替换为目标文件的名字。

    # vim Makefile
    all:targeta targetb
            echo "$@"
    
    targeta:
    
    targetb:
    # make
    echo "all"
    all
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    # 4、变量使用

    # vim Makefile
    CC=gcc
    TARGET=mp3
    OBJS=main.o mp3.o
    
    $(TARGET):$(OBJS)
            $(CC) $^ -o $@
    
    main.o:main.c
            $(CC) -c main.c -o main.o
    
    mp3.o:mp3.c
            $(CC) -c mp3.c -o mp3.o
    
    .PHONY:clean
    
    clean:
            rm mp3
    # make
    gcc main.o mp3.o -o mp3
    # ./mp3
    paly music!
    stop music!
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24

    # 5、模式匹配

    %:匹配任意多个非空字符

    # vim Makefile
    %:
            echo "$@"
    # make test			# make后跟任意字符
    echo "test"
    test
    
    
    1
    2
    3
    4
    5
    6
    7

    优化Makefile

    # vim Makefile
    CC=gcc
    TARGET=mp3
    OBJS=main.o mp3.o
    
    $(TARGET):$(OBJS)
            $(CC) $^ -o $@
    # 因为.o文件默认使用.c文件来进行编译,所以可以注释以下两行
    #%.o:%.c
    #        ${CC} -c $< -o $@
    
    .PHONY:clean
    
    clean:
            rm mp3
    # make
    gcc main.o mp3.o -o mp3
    # ./mp3
    paly music!
    stop music!
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21

    # 五、Makefile的条件分支

    # vim Makefile
    ARCH ?= x86
    
    ifeq ($(ARCH),x86)
            CC=gcc
    else
            CC=arm-linux-gnueabihf-gcc
    endif
    
    TARGET=mp3
    OBJS=main.o mp3.o
    
    $(TARGET):$(OBJS)
            $(CC) $^ -o $@
    
    .PHONY:clean
    
    clean:
            rm mp3 *.o
    # make
    gcc    -c -o mp3.o mp3.c
    gcc main.o mp3.o -o mp3
    # make ARCH=arm
    arm-linux-gnueabihf-gcc    -c -o mp3.o mp3.c
    arm-linux-gnueabihf-gcc main.o mp3.o -o mp3
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26

    # 六、Makefile管理Docker

    # 1、创建一个Dockerfile

    FROM nginx
    RUN echo '<h1>Hello World!</h1>' > /usr/share/nginx/html/index.html
    
    
    1
    2
    3

    # 2、创建Makefile文件

    # 定义 Docker 镜像名称和标签  
    REGISTRY := your-private-registry  
    USERNAME := your-username  
    PASSWORD := your-password  
    TAG := latest  
    IMAGE := my-web  
    # 这是一个条件赋值。如果变量 CONTAINER_NAME 还没有被赋值,那么它会被赋值为 my-container
    CONTAINER_NAME ?= my-container
    
    # 构建镜像 
    build: docker-build  
        docker build -t $(IMAGE):$(TAG) .  
        
    # 上传镜像到私有仓库  
    upload: docker-push  
        docker login -u $(USERNAME) -p $(PASSWORD) $(REGISTRY)  
        docker push $(IMAGE):$(TAG)  
      
    # 运行镜像
    run: docker-run  
        docker run -p 80:80 $(CONTAINER_NAME) $(IMAGE):$(TAG)
        
    # 停止并删除容器
    clean: docker-stop docker-rm  
        docker stop $(CONTAINER_NAME)
        docker rm $(CONTAINER_NAME)  
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27

    # 3、执行命令

    # make build
    # make upload
    # make run
    # make clean
    
    
    1
    2
    3
    4
    5

    原文链接 (opens new window)

    微信 支付宝
    上次更新: 2024/02/20, 11:05:50

    ← axure将项目同步到svn和axhub Rsyslog开源日志服务器→

    最近更新
    01
    shell脚本模块集合
    05-13
    02
    生活小技巧(认知版)
    04-29
    03
    生活小技巧(防骗版)
    04-29
    更多文章>
    Theme by Vdoing | Copyright © 2019-2025 | 点击查看十年之约 | 鄂ICP备2024072800号
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式