Makefile可以编译所有.c文件而无需指定它们

Ati*_*ioA 0 c makefile

我正在尝试创建一个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上.

Ren*_*let 6

注意:此答案假定您使用的是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)

说明:

  1. wildcard补充功能用于发现的C源文件的列表.
  2. patsubst补充功能用于C源文件名转换为目标文件名.
  3. .PHONY专项的目标告诉make它的所有先决条件是假的:它们不是真正的文件,必须通过化妆来考虑,即使有此名称的文件已经由事故存在.
  4. $(OBJ)/%.o: $(SRC)/%.c | $(OBJ)是一种模式规则,一种适用于所有类似对象构建规则的通用规则.这个告诉make如何./obj/xxx.o通过编译相应的./src/xxx.cC源文件来生成每个目标文件.
  5. ... | $(OBJ)模式规则的一部分告诉make这$(OBJ)是一个仅订单的先决条件.如果它不存在,Make将构建它.否则,它不会考虑其最后修改时间来决定是否必须重建目标.目录几乎总是列为仅限订单的先决条件,因为它们的上次修改时间不相关.这里,它用于告诉make $(OBJ)必须在构建任何目标文件之前构建目录.同为$(BIN)$(EXE): $(OBJS) | $(BIN)规则.
  6. $@,$<并且$^是3个自动变量.在规则的配方中,它们分别作为目标,第一个常规先决条件和规则的所有常规(非订单)先决条件进行扩展.
  7. CC,CFLAGS并且LDLIBS是标准的make隐式变量,分别用于定义C编译器,C编译器选项和-lxxx链接器选项.
  8. 所述:=可变分配是优选在该特定情况下=分配出于性能原因.有关详细说明,请参阅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

  • 我明白你的意思,但是没有 makefile 规则经验的人可能会对你的答案感到困惑。也许添加一个示例或获取他的 makefile 并为他转换它? (5认同)