24 / 07 / 08

「一生一芯」Learn C the hard way - Ex 2

练习 2:用 Make 来代替 Python

创建 Makefile 并写入以下内容。

CFLAGS=-Wall -g clean: rm -f ex1

$ make clean 不能移除生成的文件

废话孩子……你写的是 helloworld 不是 ex1

make 报错 *** missing separator. Stop.

复制粘贴一时爽,空格 TAB 火葬场……让我去看看怎么把 nano 改成四空格(万能的 man 啊)。

附加题 1

创建目标all:ex1,可以以单个命令make构建ex1

CFLAGS=-Wall -g all:helloworld clean: rm -f helloworld

附加题 2

阅读man make来了解关于如何执行它的更多信息。

make 是一个读取Makefile 文件控制编译和构建程序的程序。

  1. **目标 (Target)**:要生成的文件或执行的动作。

  2. **依赖 (Dependency)**:目标所依赖的文件。

  3. **规则 (Rule)**:定义如何根据依赖生成目标。

  4. **命令 (Command)**:实现规则的具体命令。

基本结构:

target: dependencies
    command

执行 make 时,工具会根据规则检查目标和依赖的时间戳,决定是否需要重新构建目标。

附加题 3

阅读man cc来了解关于-Wall-g行为的更多信息。

  • -Wall:启用所有常见的警告,帮助发现潜在的问题和错误。它是 “Warning all”的缩写,非常有用,尤其是在开发阶段。

  • -g:生成调试信息,使生成的可执行文件包含调试符号。

附加题 4

在互联网上搜索Makefile文件,看看你是否能改进你的文件。

CFLAGS = -Wall -g #定义编译器标志。-Wall 启用所有常见的警告,-g 生成调试信息。 LDFLAGS = #定义链接器标志。此处为空,但可以用来指定库路径和库文件。 TARGET = helloworld #定义要生成的目标可执行文件名称。 SRCS = helloworld.c #定义源文件。 OBJS = $(SRCS:.c=.o) #将源文件扩展名从 .c 转换为 .o 以得到目标文件。 all: $(TARGET) #默认目标,生成目标可执行文件。 $(TARGET): $(OBJS) #定义如何链接目标文件生成可执行文件。 $(CC) $(LDFLAGS) -o $(TARGET) $(OBJS) %.o: %.c #定义通用规则,编译 .c 文件生成 .o 文件。 $(CC) $(CFLAGS) -c $< -o $@ clean: #定义清理规则,删除目标文件和可执行文件。 $(RM) $(OBJS) $(TARGET) .PHONY: all clean #声明伪目标,避免与文件名冲突。
  1. 变量使用:将源文件和目标文件定义为变量,便于管理和修改。

  2. 通用规则:使用通配符规则编译 .c 文件到 .o 文件。

  3. 依赖文件:明确定义目标和依赖关系。

  4. $(RM) 变量:使用 $(RM) 变量,更加通用和可移植。

  5. .PHONY 目标:声明伪目标,避免与文件名冲突。

附加题 5

在另一个C语言项目中找到Makefile文件,并且尝试理解它做了什么。

verilator 的 Makefile 为例(我为什么要折磨自己……):

变量部分

  • 项目版本和路径

    • VERSION, VLVERNUM:定义了 Verilator 的版本信息。

    • TOPDIR:定义了项目的顶级目录。

  • 构建工具

    • CXX, CC:定义了 C++ 和 C 编译器。

    • CXXFLAGS, CFLAGS:定义了编译器选项。

  • 依赖库和路径

    • LDFLAGS, LDLIBS:定义了链接器选项和库。

目标部分

  • 默认目标

    • all:默认目标,构建所有需要的文件。
  • 构建目标

    • bin/verilator, bin/verilator_bin_dbg 等:定义了具体可执行文件的构建规则。
  • 安装目标

    • install:用于安装 Verilator 到指定目录。
  • 清理目标

    • clean:用于清理构建过程中生成的中间文件。

    • distclean:用于清理所有生成的文件,恢复到最初状态。