我正在尝试创建一个Makefile,它.c可以编译所有文件而无需在Makefile中每行添加文件名行.我认为这与makefile非常相似- 一次编译所有c文件.这就是我想要做的事情:
1 - 验证是否所有.c文件都来自/src其各自的.o文件/obj.如果该.o文件不存在,请从该.c文件构建它;
2 - main.exe从所有编译.o并打开它/bin.
我的Makefile:
BIN = ./bin
OBJ = ./obj
INCLUDE = ./include
SRC = ./src
all:
gcc -c "$(SRC)/Distances.c" -o "$(OBJ)/Distances.o"
gcc -c "$(SRC)/HandleArrays.c" -o "$(OBJ)/HandleArrays.o"
gcc -c "$(SRC)/HandleFiles.c" -o "$(OBJ)/HandleFiles.o"
gcc -c "$(SRC)/Classifier.c" -o "$(OBJ)/Classifier.o"
gcc -c main.c -o "$(OBJ)/main.o"
gcc -o $(BIN)/main.exe $(OBJ)/*.o -lm
run:
$(BIN)/main.exe
clean:
del /F /Q "$(OBJ)" ".o"
del /F /Q "$(BIN)" ".exe"
Run Code Online (Sandbox Code Playgroud)
我想我需要使用类似的东西$(SRC)/*.c,但我无法做到.
现在,关于make clean,我不知道如何让它跨平台工作.我正在使用,del因为我在Windows上.
注意:此答案假定您使用的是GNU make.如果不是这种情况,可能会有一些事情要适应.我不会回答你关于跨平台可移植性的最后一个问题.首先是因为这是一个复杂的问题,其次是因为我没有Windows框而且无法使用此操作系统进行任何测试.但是如果您知道一种可移植的方法来检测操作系统,请查看最后一个注释.同时,以下内容应该在Windows下运行.
在您的情况下使用GNU make的最简单和标准的方法可能是:
MKDIR := md
RMDIR := rd /S /Q
CC := gcc
BIN := ./bin
OBJ := ./obj
INCLUDE := ./include
SRC := ./src
SRCS := $(wildcard $(SRC)/*.c)
OBJS := $(patsubst $(SRC)/%.c,$(OBJ)/%.o,$(SRCS))
EXE := $(BIN)/main.exe
CFLAGS := -I$(INCLUDE)
LDLIBS := -lm
.PHONY: all run clean
all: $(EXE)
$(EXE): $(OBJS) | $(BIN)
$(CC) $(LDFLAGS) $^ -o $@ $(LDLIBS)
$(OBJ)/%.o: $(SRC)/%.c | $(OBJ)
$(CC) $(CFLAGS) -c $< -o $@
$(BIN) $(OBJ):
$(MKDIR) $@
run: $(EXE)
$<
clean:
$(RMDIR) $(OBJ) $(BIN)
Run Code Online (Sandbox Code Playgroud)
说明:
wildcard补充功能用于发现的C源文件的列表.patsubst补充功能用于C源文件名转换为目标文件名..PHONY专项的目标告诉make它的所有先决条件是假的:它们不是真正的文件,必须通过化妆来考虑,即使有此名称的文件已经由事故存在.$(OBJ)/%.o: $(SRC)/%.c | $(OBJ)是一种模式规则,一种适用于所有类似对象构建规则的通用规则.这个告诉make如何./obj/xxx.o通过编译相应的./src/xxx.cC源文件来生成每个目标文件.... | $(OBJ)模式规则的一部分告诉make这$(OBJ)是一个仅订单的先决条件.如果它不存在,Make将构建它.否则,它不会考虑其最后修改时间来决定是否必须重建目标.目录几乎总是列为仅限订单的先决条件,因为它们的上次修改时间不相关.这里,它用于告诉make $(OBJ)必须在构建任何目标文件之前构建目录.同为$(BIN)在$(EXE): $(OBJS) | $(BIN)规则.$@,$<并且$^是3个自动变量.在规则的配方中,它们分别作为目标,第一个常规先决条件和规则的所有常规(非订单)先决条件进行扩展.CC,CFLAGS并且LDLIBS是标准的make隐式变量,分别用于定义C编译器,C编译器选项和-lxxx链接器选项.:=可变分配是优选在该特定情况下在=分配出于性能原因.有关详细说明,请参阅GNU make文档.注意:因为你有一个include目录我想你也有自定义头文件.应将它们列为相关目标文件的先决条件,以便make知道如果它依赖于更改的头文件,则必须重建目标文件.您可以通过在模式规则之后添加没有配方的规则来执行此操作:
$(OBJ)/Distances.o: $(INCLUDE)/foo.h $(INCLUDE)/bar.h
Run Code Online (Sandbox Code Playgroud)
如果项目的所有C源文件都包含头文件,只需添加:
$(OBJS): $(INCLUDE)/common.h
Run Code Online (Sandbox Code Playgroud)
如果头文件有一种模式(例如,如果每个$(SRC)/xxx.c包含$(INCLUDE)/xxx.h),您还可以添加模式规则来声明这种依赖:
$(OBJ)/%.o: $(INCLUDE)/%.h
Run Code Online (Sandbox Code Playgroud)
注意:如果您知道一种方法将make变量(例如OS)设置为当前操作系统的名称,您可以修改先前使用GNU make conditional使其可移植的内容.例如,您可以将以下两行替换为:
OS := $(shell <the-command-that-returns-the-current-OS-name>)
ifeq ($(OS),Windows)
MKDIR := md
RMDIR := rd /S /Q
else ifeq ($(OS),GNU/Linux)
MKDIR := mkdir -p
RMDIR := rm -rf
else ifeq ($(OS),pokemon)
MKDIR := bulbasaur
RMDIR := charmander
endif
Run Code Online (Sandbox Code Playgroud)
小智 -1
% 通配符模式规则可以提供帮助 %.o:%c