functions.c:
#include <stdio.h>
#include "functions.h"
void
hello ()
{
printf ("Hello, world!\n");
}
functions.h:
void hello ();
main.c:
#include "functions.h"
int
main ()
{
hello ();
return 0;
}

Makefile:
CC ?= gcc #指定编译器为 gcc,如果外部未定义 CC,则使用 gcc。
CFLAGS ?= -std=c11 -Wall -Wextra -Wpedantic -Werror -g #-std=c11:使用 C11 标准;-Wall -Wextra -Wpedantic -Werror:开启严格警告并将警告视为错误;-g:生成调试信息。
LDFLAGS ?= -Wl,--as-needed -Wl,--no-undefined #--as-needed:仅链接用到的库;--no-undefined:链接时禁止未定义符号。
OUTPUT_DIR ?= . #输出目录为当前目录。
SRCS = main.c functions.c #源文件;
OBJS = $(SRCS:.c=.o) #将源文件后缀 .c 替换为 .o,生成目标文件列表。
TARGET = $(OUTPUT_DIR)/exercise-01 #最终可执行文件名为 exercise-01,位于当前目录。$(OUTPUT_DIR) 变量的值是 .,表示当前目录;
all: $(TARGET) #默认目标,执行 make 时构建可执行文件。
$(OUTPUT_DIR): #如果输出目录不存在,则创建
mkdir -p $(OUTPUT_DIR)
$(TARGET): $(OBJS)
#构建目标 exercise-01;
$(TARGET): $(OBJS) | $(OUTPUT_DIR) #依赖目标文件 main.o functions.o 和输出目录;构建目标 exercise-01 之前,确保目录 $(OUTPUT_DIR) 存在;但如果目录本身变化,不要触发重建。
$(CC) $(LDFLAGS) -o $@ $(OBJS) #使用 $(CC) 和 $(LDFLAGS) 链接。
%.o: %.c # #通用规则:将 .c 文件编译为 .o 文件。
# 在这里指定 C 文件的编译命令
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -f $(TARGET) $(OBJS)
