信息发布→ 登录 注册 退出

C++学习进阶之Makefile基础用法详解

发布时间:2026-01-11

点击量:
目录
  • 1. Makefile基本语法与执行
  • 2. Makefile简化过程
  • 3. Makefile生成并使用库
    • 3.1 动态库的建立与使用
    • 3.2 动态加载库的建立与使用
  • 总结

    1. Makefile基本语法与执行

    为什么要使用 Makefile?

    Makefile 文件描述了整个工程的编译、链接的规则。

    为工程编写 Makefile 的好处是能够使用一行命令来完成“自动化编译”。只需提供一个(通常对于一个工程来说会是多个)正确的 Makefile,接下来每次的编译都只需要在终端输入“make”命令,整个工程便会完全自动编译,极大提高了效率。尤其是在编译一个仅有一小部分文件被改动过的大项目的情况下。

    绝大多数的 IDE 开发环境都会为用户自动编写 Makefile。

    Make 是怎么工作的?

    Make 工作的原则就是:

    一个目标文件当且仅当在其依赖文件(dependencies)的更改时间戳比该目标文件的创建时间戳新时,这个目标文件才需要被重新编译。

    Make 工具会遍历所有的依赖文件,并且把它们对应的目标文件进行更新。编译的命令和这些目标文件及它们对应的依赖文件的关系则全部储存在 Makefile 中。

    Makefile 中也指定了应该如何创建,创建出怎么样的目标文件和可执行文件等信息。

    除此之外,你甚至还可以在 Makefile 中储存一些你想调用的系统终端的命令,像一个 Shell 脚本一样使用它。

    作用:

    Makefile 文件告诉 Make 怎样编译和连接成一个程序

    可用命令 dnf install make 安装make功能

    格式:

    按如下格式编写 Makefile

    目标(target): 依赖(prerequiries)...
      命令(command)

    注意:每个命令行前面必须是一个Tab字符,即命令行第一个字符是Tab

    实验:

    vim Makefile 编辑文件:

    simpletest:simple.o simpletest.o
            g++ simple.o simpletest.o -o simpletest
    simple.o:simple.cpp
            g++ -c simple.cpp -o simple.o
    simpletest.o:simpletest.cpp
            g++ -c simpletest.cpp -o simpletest.o
    

    结果为:

    [root@foundation1 shishi]# make
    g++ -c simple.cpp -o simple.o
    g++ -c simpletest.cpp -o simpletest.o
    g++ simple.o simpletest.o -o simpletest

    命令上下是有顺序的,上一行对下一行具有依赖关系

    如果文件夹中已经有.o文件,make后会提示已经生成,需要删除.o文件后再make

    clean的作用: 被指定时会删除对应.o文件,避免上述情况

    simpletest:simple.o simpletest.o
            g++ simple.o simpletest.o -o simpletest
    simple.o:simple.cpp
            g++ -c simple.cpp -o simple.o
    simpletest.o:simpletest.cpp
            g++ -c simpletest.cpp -o simpletest.o
    clean:
            rm simpletest simple.o simpletest.o
    

    结果为:

    [root@foundation1 shishi]# make clean
    rm simpletest simple.o simpletest.o
    [root@foundation1 shishi]# make
    g++ -c simple.cpp -o simple.o
    g++ -c simpletest.cpp -o simpletest.o
    g++ simple.o simpletest.o -o simpletest

    2. Makefile简化过程

    使用变量: 如果调用某个文件用的次数较多,可以使用变量代替,变量可以直接替换

    变量定义: 变量 = 字符串
    变量使用: $(变量名)

    makefile 文件可改为:

    TARGET = simpletest
    OBJS = simple.o simpletest.o
    
    $(TARGET):$(OBJS)
            g++ $(OBJS) -o $(TARGET)
    simple.o:simple.cpp
            g++ -c simple.cpp -o simple.o
    simpletest.o:simpletest.cpp
            g++ -c simpletest.cpp -o simpletest.o
    clean:
            rm $(TARGET) $(OBJS)
    

    命令自动推导: 我们可以发现,由于 .cpp 文件都是生成对应的 .o 文件,所以 makefile 文件是可以自动识别的

    makefile 文件可改为:

    TARGET = simpletest
    OBJS = simple.o simpletest.o
    
    $(TARGET):$(OBJS)
            g++ $(OBJS) -o $(TARGET)
    simple.o:simple.cpp
    simpletest.o:simpletest.cpp
    clean:
            rm $(TARGET) $(OBJS)
    

    预定义变量: 系统中自己也定义了一些变量

    变量 程序 默认值
    CC C语言编译程序 cc
    CXX C++编译程序 g++
    AR C++打包程序 ar
    CPP 带有标准输出的C语言预处理程序 $(CC) -E
    RM 删除命令 rm

    makefile 文件可改为:

    TARGET = simpletest
    OBJS = simple.o simpletest.o
    
    $(TARGET):$(OBJS)
            $(CXX) $(OBJS) -o $(TARGET)
    simple.o:simple.cpp
    simpletest.o:simpletest.cpp
    clean:
            $(RM) $(TARGET) $(OBJS)
    

    假想目标: 如果文件夹中有clean文件,那么make clean就不能使用,需要使用假想目标,可以在执行命令时不查看文件夹里面的文件,直接生效

    makefile 文件可改为:

    TARGET = simpletest
    OBJS = simple.o simpletest.o
    
    .PHONY: clean
    
    $(TARGET):$(OBJS)
            $(CXX) $(OBJS) -o $(TARGET)
    simple.o:simple.cpp
    simpletest.o:simpletest.cpp
    clean:
            $(RM) $(TARGET) $(OBJS)
    

    建议不生成目标文件的命令都设为假想目标

    3. Makefile生成并使用库

    3.1 动态库的建立与使用

    vim Makefile 编辑文件:

    TARGET = simpletest
    OBJS = simple.o
    LIB = libsimple.so
    CXXFLAGS = -c -fPIC
    
    .PHONY: clean
    
    $(TARGET):$(LIB) simpletest.o
            $(CXX) simpletest.o -o $(TARGET) -L. -lsimple
    $(LIB):$(OBJS)
            $(CXX) -shared $(OBJS) -o $(LIB)
    simple.o:simple.cpp
            $(CXX) $(CXXFLAGS) simple.cpp -o $(OBJS)
    simpletest.o:simpletest.cpp
            $(CXX) $(CXXFLAGS) simpletest.cpp -o simpletest.o
    clean:
            $(RM) $(TARGET) $(OBJS) $(LIB)
    

    结果为:

    [root@foundation1 shishi]# make clean
    rm -f simpletest simple.o libsimple.so
    [root@foundation1 shishi]# make
    g++ -c -fPIC simple.cpp -o simple.o
    g++ -shared simple.o -o libsimple.so
    g++ -c -fPIC simpletest.cpp -o simpletest.o
    g++ simpletest.o -o simpletest -L. -lsimple

    预定义变量:

    还是需要在前面定义

    变量 程序参数
    CFLAGS 用于C编译器的额外标志
    CXXFLAGS 用于C++编译器的额外标志
    ARFLAGS 用于C/C++打包器的额外标志
    LDFLAGS 链接库路径-L
    LDLIBS 链接库-l

    makefile 文件可改为:

    TARGET = simpletest
    OBJS = simple.o
    LIB = libsimple.so
    CXXFLAGS = -c -fPIC
    LDFLAGS = -L.
    LDLIBS = -lsimple
    
    .PHONY: clean
    
    $(TARGET):$(LIB) simpletest.o
            $(CXX) simpletest.o -o $(TARGET) $(LDFLAGS) $(LDLIBS)
    $(LIB):$(OBJS)
            $(CXX) -shared $(OBJS) -o $(LIB)
    simple.o:simple.cpp
            $(CXX) $(CXXFLAGS) simple.cpp -o $(OBJS)
    simpletest.o:simpletest.cpp
            $(CXX) $(CXXFLAGS) simpletest.cpp -o simpletest.o
    clean:
            $(RM) $(TARGET) $(OBJS) $(LIB)
    

    自动变量:

    自动变量是在规则每次执行时都基于目标和依赖产生新值的变量

    自动变量 含义
    $< 表示第一个匹配的依赖
    $@ 表示目标
    $^ 所有依赖
    $? 所有依赖中更新的文件
    $+ 所有依赖文件不去重
    $(@D) 目标文件路径
    $(@F) 目标文件名称

    makefile 文件可改为:

    TARGET = simpletest
    OBJS = simple.o
    LIB = libsimple.so
    CXXFLAGS = -c -fPIC
    LDFLAGS = -L.
    LDLIBS = -lsimple
    
    .PHONY: clean
    
    $(TARGET):simpletest.o $(LIB)
            $(CXX) $< -o $@ $(LDFLAGS) $(LDLIBS)
    $(LIB):$(OBJS)
            $(CXX) -shared $^ -o $@
    simple.o:simple.cpp
            $(CXX) $(CXXFLAGS) $< -o $@
    simpletest.o:simpletest.cpp
            $(CXX) $(CXXFLAGS) $< -o $@
    clean:
            $(RM) $(TARGET) $(OBJS) $(LIB)
    

    自动匹配:

    通配符主要用于匹配文件名,makefile中使用%作为通配符。从匹配目标格式的目标名中依据通配符抽取部分字符串,再按照抽取字符串分配到每一个依赖格式中产生依赖名。例如,使用%.o:%.cpp

    可以让重复的语句合为一句

    makefile 文件可改为:

    TARGET = simpletest
    OBJS = simple.o
    LIB = libsimple.so
    CXXFLAGS = -c -fPIC
    LDFLAGS = -L.
    LDLIBS = -lsimple
    TESTOBJ = simpletest.o
    
    .PHONY: clean
    
    $(TARGET):$(TESTOBJ) $(LIB)
            $(CXX) $< -o $@ $(LDFLAGS) $(LDLIBS)
    
    $(LIB):$(OBJS)
            $(CXX) -shared $^ -o $@
    
    $(TESTOBJ) $(OBJS):%.o:%.cpp
            $(CXX) $(CXXFLAGS) $< -o $@
    
    clean:
            $(RM) $(TARGET) $(OBJS) $(LIB) $(TESTOBJ)
    

    3.2 动态加载库的建立与使用

    TARGET = simpletest2
    OBJS = simple.o
    LIB = libsimple.so
    CXXFLAGS = -c -fPIC
    LDLIBS = -ldl
    TESTOBJ = simpletest2.o
    
    .PHONY: clean
    
    # 生成可执行文件
    $(TARGET):$(TESTOBJ) $(LIB)
            $(CXX) $< -o $@ $(LDFLAGS) $(LDLIBS)
    
    # 生成库
    $(LIB):$(OBJS)
            $(CXX) -shared $^ -o $@
    
    # 生成目标文件
    $(TESTOBJ) $(OBJS):%.o:%.cpp
            $(CXX) $(CXXFLAGS) $< -o $@
    
    clean:
            $(RM) $(TARGET) $(OBJS) $(LIB) $(TESTOBJ)
    

    结果为:

    [root@foundation1 C++7.4]# make clean
    rm -f simpletest2 simple.o libsimple.so simpletest2.o
    [root@foundation1 C++7.4]# make
    g++ -c -fPIC simpletest2.cpp -o simpletest2.o
    g++ -c -fPIC simple.cpp -o simple.o
    g++ -shared simple.o -o libsimple.so
    g++ simpletest2.o -o simpletest2  -ldl
    [root@foundation1 C++7.4]# ./simpletest2
    Simple()
    Test()
    ~Simple()

    总结

    在线客服
    服务热线

    服务热线

    4008888355

    微信咨询
    二维码
    返回顶部
    ×二维码

    截屏,微信识别二维码

    打开微信

    微信号已复制,请打开微信添加咨询详情!