Makefile可以编译所有.c文件,而无需指定它们 [英] Makefile to compile all .c files without needing to specify them

查看:1054
本文介绍了Makefile可以编译所有.c文件,而无需指定它们的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个Makefile,该文件将编译所有.c文件,而无需在Makefile中每行添加文件名.我认为这与 makefiles一样-一次编译所有c文件.这是我想做的:

I'm trying to create a Makefile that causes all .c files to be compiled without the need to add filenames line per line inside the Makefile. I think this is fairly similar to makefiles - compile all c files at once. Here's what I want to do:

1-验证/src中的所有.c文件是否都具有它们各自的.o文件.如果.o文件不存在,请从.c文件进行构建;

1 - Verify if all .c files from /src have their respective .o files from /obj. If the .o file does not exist, build it from the .c file;

2-从所有.o编译main.exe并将其放在/bin上.

2 - Compile main.exe from all .o and put it on /bin.

我的Makefile:

My 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"

我想我需要使用$(SRC)/*.c之类的东西,但我做不到.

I guess I need to use something like $(SRC)/*.c, but I couldn't make it.

现在,关于make clean,我不知道如何使其跨平台工作.我正在Windows上使用del.

Now, about make clean, I don't know how to make it work cross-platform. I'm using del as I'm on Windows.

推荐答案

注意:此答案假设您使用的是

Note: this answer assumes that you are using GNU make. If it is not the case there are probably a few things to adapt. I will not answer your last question about cross-platform portability. First because it is a complex question, second because I do not have a Windows box and cannot do any tests with this OS. But if you know a portable way to detect the OS, look at the last note. Meanwhile, the following should work under Windows.

在您的情况下,使用GNU make的最直接,最标准的方法可能是:

The most straightforward and standard way to use GNU make in your case is probably something like:

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)

说明:

  1. wildcard make函数是用来发现C源文件的列表.
  2. patsubst make函数用于将C源文件名转换为目标文件名.
  3. .PHONY特殊目标告诉确保其所有先决条件都是 phony :它们不是真实文件,即使偶然使用此名称的文件也必须由make加以考虑.
  4. $(OBJ)/%.o: $(SRC)/%.c | $(OBJ)样式规则 ,这是一条通用规则,适用于所有类似的对象构建规则.这一步告诉make如何通过编译相应的./src/xxx.c C源文件来生成每个./obj/xxx.o对象文件.
  5. 模式规则的... | $(OBJ)部分告诉make $(OBJ)仅订购先决条件.如果尚不存在,则Make将对其进行构建.否则,它将不考虑其最后修改时间来决定是否必须重建目标.目录几乎总是被列为仅订购的先决条件,因为它们的上次修改时间无关紧要.在这里,它用来告诉make必须先构建$(OBJ)目录,然后才能构建任何目标文件.与$(EXE): $(OBJS) | $(BIN)规则中的$(BIN)相同.
  6. $@$<$^ GNU make文档. li>
  1. The wildcard make function is used to discover the list of C source files.
  2. The patsubst make function is used to transform C source file names into object file names.
  3. The .PHONY special target tells make that all its prerequisites are phony: they are not real files and must be considered by make even if a file with this name already exists by accident.
  4. $(OBJ)/%.o: $(SRC)/%.c | $(OBJ) is a pattern rule, a generic rule that works for all your similar object-building rules. This one tells make how to produce each ./obj/xxx.o object file by compiling the corresponding ./src/xxx.c C source file.
  5. The ... | $(OBJ) part of the pattern rule tells make that $(OBJ) is an order-only prerequisite. Make will build it if it does not exist already. Else it will not consider its last modification time to decide if the target must be rebuilt or not. Directories are almost always listed as order-only prerequisite because their last modification time is not relevant. Here, it is used to tell make that the $(OBJ) directory must be built before any object file can be built. Same for $(BIN) in the $(EXE): $(OBJS) | $(BIN) rule.
  6. $@, $< and $^ are 3 of the make automatic variables. In the recipes of a rule they expand respectively as the target, the first regular prerequisite and all regular (non order-only) prerequisites of the rule.
  7. CC, CFLAGS and LDLIBS are standard make implicit variables used respectively to define the C compiler, the C compiler options and the -lxxx linker options.
  8. The := variable assignment is preferable in this specific case over the = assignment for performance reasons. See the GNU make documentation for a detailed explanation.

注意:由于您有一个include目录,所以我想您也有自定义头文件.应将它们列为相关目标文件的先决条件,以使他们知道,如果头文件依赖于更改,则必须重建目标文件.您可以通过在模式规则之后的任意位置添加不带配方的规则来做到这一点:

Note: as you have an include directory I guess that you also have custom header files. They should be listed as prerequisites of the relevant object files such that make knows that an object file must be rebuilt if the header files it depends on change. You can do this by adding rules without a recipe anywhere after the pattern rule:

$(OBJ)/Distances.o: $(INCLUDE)/foo.h $(INCLUDE)/bar.h

如果项目的所有C源文件都包含头文件,只需添加:

If a header file is included by all C source files of your project, simply add:

$(OBJS): $(INCLUDE)/common.h

如果头文件有一种模式(例如,每个$(SRC)/xxx.c包括$(INCLUDE)/xxx.h),您还可以添加一个模式规则来声明这种依赖关系:

And if there is a kind of pattern for the header files (for instance if each $(SRC)/xxx.c includes $(INCLUDE)/xxx.h) you can also add a pattern rule to declare this kind of dependency:

$(OBJ)/%.o: $(INCLUDE)/%.h

注意:如果您知道将make变量(例如OS)设置为当前OS名称的方法,则可以使用GNU make条件语句修改使其可移植的条件.例如,您可以将以下两行替换为:

Note: if you know a way to set a make variable (e.g. OS) to the name of the current OS you can probably modify what precedes to make it portable using GNU make conditionals. For instance, you could replace the two first lines by:

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

这篇关于Makefile可以编译所有.c文件,而无需指定它们的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆