zoukankan      html  css  js  c++  java
  • Makefile的初学教程

    进入大二以后天天写代码,不如就重新使用自己的blog吧。感觉看自己之前写的东西重新学习还挺不错的。

    Makefile可以帮助你编译。原来搞OI的时候都是一个cpp文件直接编译运行就行了。不过现在假设你要写一个很简单的小计算器,每一个cpp文件执行一种算术方法,你如果一个一个编译的话,大概是要写成这样的:

    g++ -c -Wall main.cpp -o main.o
    g++ -c -Wall add.cpp -o add.o
    g++ -c -Wall sub.cpp -o sub.o
    g++ -c -Wall mul.cpp -o mul.o
    g++ -c -Wall div.cpp -o div.o
    
    g++ -o main main.o add.o sub.o mul.o div.o
    

    这样写起来很麻烦,所以Makefile应运而生。

    1.基本规则

    Makefile的核心规则(核心语法?)大概是这样的:
    targets : prerequisites
    commands

    其中targets是目标文件(目前大多数你写的程序都只有一个执行文件,可以先理解为执行文件),prerequisites是用于生成target的文件或目标。
    表示输入一个Tab缩进(这个非常重要!!),commands 是你要执行的命令(shell命令)。

    写一个比较简单的,只有3个cpp的makefile示例:

    main : main.cpp printhello.cpp factorial.cpp
      g++ -o main main.cpp printhello.cpp factorial.cpp
    

    在终端输入make就可以运行makefile了。之后./main来执行程序。

    2.使用变量

    Makefile中使用变量其实很像C++中的宏(#define),大致写法是:

    CC = g++
    TARGET = main
    OBJ = main.o printhello.o factorial.o
    
    $(TARGET) : $(OBJ)
      $(CC) -o $(TARGET) $(OBJ)
    

    其中,CC,TARGET,OBJ等赋值符号左边的叫做变量(variables),其实只看代码的话,和上一个是完全一样的,我们把宏替换一下就是一样的代码了。
    这个主要是用于减少代码量,写起来更加简洁。

    3.文件依赖(我也不知道是不是该叫这个名字)

    有的时候只有一个或几个cpp被改动,我们是不需要重新编译所有文件的。设想如果有上百个cpp,只改动其中一个就要全部重新编译显然非常浪费时间,因此我们可以将我们的代码改写一下:

    CC = g++
    TARGET = main
    OBJ = main.o printhello.o factorial.o
    
    main.o: main.cpp
      $(CC) -c main.cpp
    
    
    printhello.o: printhello.cpp
      $(CC) -c printhello.cpp
    
    
    factorial.o: factorial.cpp
      $(CC) -c factorial.cpp
    
    

    假如我们只改变了main.cpp,那么重新执行make的时候他就只会重新编译main.cpp,而不会把所有cpp都重新编译一次了。
    不过现在的问题是代码量增加了很多,如果有上百个cpp我们显然是吃不消的,这时候就需要使用文件依赖。大致意思是,每一个.o文件都是.cpp文件编译而成的。所以我们将代码采取如下写法:

    CC = g++
    TARGET = main
    OBJ = main.o printhello.o factorial.o
    CFLAGS = -c -Wall
    
    $(TARGET) : $(OBJ)
      $(CC) -o $@ $(OBJ)
    
    %.o : %.cpp
      $(CC) $(CFLAGS) $< -o $@
    
    #本段中$@表示所有目标文件,$^表示所有prerequisites文件,$<表示第一个prerequsites文件。
    #因为每一个.o依赖于一个.cpp,所以这里写$<或者$^都是可以的。
    #注意这里前后两个$@表示的文件是不同的,第一个表示的是TARGET(main),即可执行文件,而第二个表示的这个.o文件对应的.cpp文件。
    
    

    注意其中一行%.o : %.cpp,这一段是一个规则,大致意思就是我们的文件依赖,所有的.o都是依赖于.cpp文件的。

    4.使用函数

    Makefile中的函数非常多,这里只简单介绍两种,wildcard和patsubst。
    我们的代码已经很简洁了,但是看OBJ一行,如果我们有上百个.cpp,也就会有上百个.o,那手动输入进去还是很麻烦的。
    解决方法就是使用wildcard(通配符)函数,这个函数可以自动搜索路径中的一类文件(我们这里先假定为cpp文件),用法如下:

    SRC = $(wildcard ./*.cpp)
    

    现在SRC就找到了路径中所有的.cpp文件,之后我们使用字符串函数patsubst,它可以批量处理字符串,我们的目标是把所有.cpp改成.o,用法如下:

    SRC = $(wildcard ./*.cpp)
    OBJ = $(patsubst %.cpp, %.o, $(SRC))
    target:
      @echo $(SRC)
      @echo $(OBJ)
    

    target后面是输出语句,可以让你验证一下找的是不是正确的文件。

    那么现在我们就可以非常简洁的写好makefile了。直接上最终版的代码吧。src是存储所有cpp文件的文件夹,inc是存储所有hpp(h)文件的文件夹,makefile文件应该和这两个文件夹处在一个子目录下。

    #第一行这里写 = src也行
    SRC_DIR = ./src
    SOURCE = $(wildcard $(SRC_DIR)/*.cpp)
    OBJ = $(patsubst %.cpp, %.o, $(SOURCE))
    TARGET = main
    INCLUDE = -I./inc 
    #这里是在inc里找所有引用的hpp文件
    
    CC = g++
    CFLAGS = -c -Wall
    
    $(TARGET) : $(OBJ)
      $(CC) -o $@  $(OBJ)
    %.o : %.cpp
      $(CC) $(CFLAGS) $< -o $@ $(INCLUDE)
    
    .PHONY : clean
    clean:
      rm -f $(SRC_DIR)/*.o $(TARGET)
    

    最后.PHONY : clean这里是clean函数,用于清理多余的.o文件。使用方法是在终端输入make clean即可。

    本文章只包含一些非常初级的makefile用法,如果想学更多,可以看这里或者这里

    当你意识到,每个上一秒都成为永恒。
  • 相关阅读:
    .html(),.text()和.val()的差异
    jQuery选取表单元素
    jquery中动画特效方法
    js正则函数match、exec、test、search、replace、split使用介绍集合
    关于LDA的几何表示——MATLAB实现
    关于PCA的几何表示——MATLAB实现
    简单的线性分类——MATLAB,python3实现
    关于KNN的python3实现
    拔靴法--Bootstrap--R语言实现
    Poisson Distribution——泊松分布
  • 原文地址:https://www.cnblogs.com/captain1/p/15328320.html
Copyright © 2011-2022 走看看