Makefile速上手

前言

上一个文档是对《跟我一起写Makefile》的转述。但随着Makfile学习的深入,愈来愈发现Makefile所蕴含的内容不少,对应的奇怪的技巧也不少,因此我认为我们不必一直纠结于一些技巧与特性,先写着再说。所以本次是分享对于一个小的学习项目我们的Makefile的一个通用写法。

就到此为止吧,再通篇写一些概念就不礼貌了。

文章参考了B站up主Cukor丘克的写法,视频教程参考点此进入视频

常使用的文件结构

我们一般可以像如下结构一样组织我们的文件:

  • bin放可执行文件
  • include放头文件
  • obj放中间文件
  • src放源文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
gnol@kubt20  ~/makefile_study  tree .
.
├── bin
│   └── helloworld
├── include
│   ├── now_time.h
│   └── print.h
├── Makefile
├── obj
│   ├── main.o
│   ├── now_time.o
│   └── print.o
└── src
├── main.c
├── now_time.c
└── print.c

Makfile写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
SRC = ./src
OBJ = ./obj
INC = ./include
BIN = ./bin
SRCS = $(wildcard $(SRC)/*.c)
OBJS = $(patsubst %.c,$(OBJ)/%.o,$(notdir $(SRCS)))

target = $(BIN)/helloworld
cc = gcc
cflags = -g -I $(INC) -no-pie -fno-stack-protector -z execstack

$(target) : $(OBJS)
$(cc) $^ -o $@ $(cflags)
$(OBJ)/%.o : $(SRC)/%.c
$(cc) -c $< -o $@ $(cflags)

.PHONY: clean run

clean :
rm $(OBJ)/*.o $(target)

run :
$(target)

变量解释

  • 开头SRCOBJINCBIN定义了基本文件夹的路径
  • 用wildcard函数将所有的源文件找出来并赋值给SRCS
  • SRCS变量中所有的文件的后缀改为.o再赋值给OBJS,patsubst是一个字符串替换函数
  • target用来定义目标生成的路径
  • cc用来定义所使用的编译器gcc,g++,clang之类的
  • cflags用来添加编译选项,-I 指定头文件路径,-g 表示文件添加源码调试信息,-no-pie关闭PIE,-fno-stack-protector关闭栈的保护,即没有canary,-z execstack 关闭堆栈不可执行保护,程序将存在rwx段,可注入shellcode执行。还有等等很多很多的选项,不再赘述。

对于上述的Makefile,我们只需要掌握以下知识

  1. Makefile的基本结构
    1
    2
    3
    4
    target ... : prerequisites ...
    command
    ...
    ...
  2. 变量
  3. 自动化变量
    • $^ 表示基本结构中的依赖项
    • $< 表示将依赖项有顺序的展开
    • $@表示的是目标项
  4. 函数(直接在PDF中全局搜索或看视频)
    • patsubst 字符串替换函数
    • wildcard 通配符结果展开函数
  5. 伪目标

后记

先看了一遍《跟我一起写Makefile》后再看Cukor丘克的视频畅通无阻。因为make是一个方便工程编译的工具,所以Makefile的学习应该要结合自身实际情况,找对应的项目的Makefile学习。(当然大项目用CMake可能是一个更好的决定)

相关阅读:makefile笔记(一)_详记

(10.23)因此物理机为了腾C盘把VS卸载了,用mingw代替。想了想不如直接remote服务器写作业就好了,然后发现Linux下Makefile的默认缩进为八空格(似乎)。嗯,之后写的时候注意一下就好。解决方案网上还挺多。我之后解决了再补充吧。