Makefile简介及如何指定头文件和库文件

Makefile简介

  • 初学C/C++时,我们编译源文件时,通常直接敲命令去进行编译。但在实际项目中,源文件非常多,直接敲命令编译就不现实了,这时候就需要用到Makefile,Makefile是一个文本文件,我们只需要提前在Makefile中写好源文件的编译规则,然后直接执行make命令,就可以自动编译。
  • 现在使用cmake的比较多,cmake相比于makefile,语法更加简洁,学习门槛更低,实现相同的编译功能,Makefile可能需要几十行脚本来完成,cmake只需要几行脚本就可以搞定。但鉴于可能有些老项目或者部分公司依旧使用makefile,所以我们还是得对此熟悉。

Makefile语法

  • Makefile有三大要素:目标、依赖、规则命令
    • 目标:我们要生成的最终文件
    • 依赖:生成目标文件要依赖的文件
    • 规则命令:要生成目标文件所执行的命令
  • 语法
    •   目标:依赖
        	规则命令
      
    • 注:规则命令前面必须要有Tab键

简单使用

  • 目前有以下源文件
  •   ├── main.cpp
      ├── Makefile
      ├── myadd.cpp
      ├── myadd.h
      ├── myminus.cpp
      └── myminus.h
    

版本一

  •   # 生成最终可执行文件的文件名和需要的依赖文件
      res:main.o myadd.o myminus.o
      	# 生成最终可执行文件需要执行的命令
      	g++ main.o myadd.o myminus.o -o res
      # 生成中间文件main.o需要的源文件
      main.o:main.cpp
      	# 生成中间文件main.o需要执行的命令
      	g++ -c main.cpp
      myadd.o:myadd.cpp
      	g++ -c myadd.cpp
      myminus.o:myminus.cpp
      	g++ -c myminus.cpp
    
      # 执行清理操作
      clean:
      	rm *.o
    
  • 直接执行make命令就可以生成最终可执行文件res
  •   root@ubuntu:/home/lng/makefiledir# make
      g++ -c main.cpp
      g++ -c myadd.cpp
      g++ -c myminus.cpp
      g++ main.o myadd.o myminus.o -o res
      root@ubuntu:/home/lng/makefiledir# ls
      main.cpp  main.o  Makefile  myadd.cpp  myadd.h  myadd.o  myminus.cpp  myminus.h  myminus.o  res
      root@ubuntu:/home/lng/makefiledir# 
    
  • 一般*.o文件是不需要的,可以执行make clean命令来清除*.o文件
  •   root@ubuntu:/home/lng/makefiledir# make clean
      rm *.o
      root@ubuntu:/home/lng/makefiledir# ls
      main.cpp  Makefile  myadd.cpp  myadd.h  myminus.cpp  myminus.h  res
      root@ubuntu:/home/lng/makefiledir# 
    
  • 备注
    • 可能有人会有疑问,为什么一定要生成中间文件*.o, 我们平常使用命令编译时,都是直接用源文件生成可执行文件。
    • 当然可以不用生成*.o文件,使用以下命令,直接用源文件生成可执行文件
    •   res:main.cpp myadd.cpp myminus.cpp
        	g++ main.cpp myadd.cpp myminus.cpp -o res
      
    • 但这样就会存在一个问题,一旦我们修改任何一个源文件,所有的文件都重新编译。在一些大型项目中,编译是非常耗时的,每修改一个源文件,都去重新编译,这将大大降低工作效率。因此我们通常都是先生成中间文件*.o, 当我们修改其中一个源文件时,只需要编译修改的文件,其他文件都不需要重新编译。

版本二

  • 在makefile中允许我们使用变量,可以对Makefile内容进行简化
  •   # 对变量赋值
      Target=res
      Objs=main.o myadd.o myminus.o
      Src=main.cpp myadd.cpp myminus.cpp
      # 取出变量中的值
      $(Target):$(Objs)
      	g++ $(Objs) -o $(Target)
      $(Objs):$(Src)
      	g++ -c $(Src)
    
      clean:
      	rm *.o
    
  • 这个版本的Makefile与版本一的效果完全一样,但代码量更少,也更简洁。

版本三

  • 目前还存在一个问题,就是我们一旦要添加新的源文件,必须修改Makefile,有没有一种写法,在添加源文件时不需要修改Makefile?当然也有。
  • 首先需要介绍两个函数和四个变量
  • 函数
    • wildcard:进行文件匹配
    • patsubst:内容替换
  • 变量
    • $@ : 目标
    • $^ : 全部依赖
    • $< : 第一个依赖
    • $? : 第一个变化的
  •   Target=res
      # 获取当前目录下所有源文件
      Src:=$(wildcard *.cpp)
      # 将所有*.cpp文件替换为*.o文件。Objs变量中就保存了所有*.o文件名
      Objs:=$(patsubst %.cpp,%.o, $(Src))
    
      $(Target):$(Objs)
      	g++ $(Objs) -o $(Target)
      *.o:*.cpp
      	# 相当于 g++ -c *.cpp -o *.o
      	g++ -c $< -o $@
    
      clean:
      	rm *.o
    
  • 通过变量和函数我们就可以自动获取文件名,不用再去手动进行赋值。

指定头文件和库文件

  • 目录结构如下
  •   ├── include
      │   ├── myadd.h
      │   ├── myminus.h
      │   └── mymult.h
      ├── lib
      │   └── libmymult.so
      ├── Makefile
      └── src
      	├── main.cpp
      	├── myadd.cpp
      	└── myminus.cpp
    
  • Makefile
  •   # 指定编译器
      CC=g++
      #指定编译选项
      CFLAGS=-Wall -g
      Target=res
      Src:=$(wildcard ./src/*.cpp)
      Objs:=$(patsubst %.cpp,%.o, $(Src))
      #指定头文件位置
      INCLUDES = -I ./include
      #指定库文件
      LIBS=-L ./lib -lmymult
    
      $(Target):$(Objs)
      	echo $(Objs)
      	@mkdir -p output
      	$(CC) $(Objs) $(LIBS) -o output/$(Target)
    
      %.o:%.cpp
      	$(CC) $(INCLUDES) $(CFLAGS) -c $< -o $@
    
      clean:
      	rm $(Objs)
    

猜你喜欢

转载自blog.csdn.net/new9232/article/details/129107708
今日推荐