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

时间:2018-11-03 22:23:39

标签: c makefile

我正在尝试创建一个Makefile,该文件导致所有var createTable = document.createElement("table"); //creates the Table document.body.appendChild(createTable); //inserts the table into the body of the html page var data = ["Car", "Top Speed", "Price", "Chevrolet", "120mph", "$10,000", "Pontiac", "140mph", "$20,000"]; for (var r=0; r < 3; r++) { var row = document.createElement("tr"); //creates a row for (var x = 0; x < data.length; x++) { var cell = document.createElement("td"); //creates a cell cell.appendChild(data[x]); //puts each data array item, in order, into each cell? } row.appendChild(cell); //puts cells into row createTable.appendChild(row); //puts rows into table } 文件被编译,而无需在Makefile中每行添加文件名。我认为这与makefiles - compile all c files at once非常相似。这是我想做的:

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

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

我的Makefile:

/bin

我想我需要使用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,我不知道如何使其跨平台工作。我正在Windows上使用make clean

2 个答案:

答案 0 :(得分:5)

注意:此答案假设您正在使用GNU make。如果不是这种情况,可能需要调整一些内容。我不会回答您关于跨平台可移植性的最后一个问题。首先是因为这是一个复杂的问题,其次是因为我没有Windows框并且无法使用此OS进行任何测试。但是,如果您知道一种检测操作系统的可移植方式,请查看最后的注释。同时,以下应在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)

说明:

  1. wildcard make function用于发现C源文件的列表。
  2. patsubst make function用于将C源文件名转换为目标文件名。
  3. .PHONY special target告诉make所有先决条件都是 phony :它们不是真实文件,即使偶然使用此名称的文件也必须由make考虑。
  4. li>
  5. $(OBJ)/%.o: $(SRC)/%.c | $(OBJ)pattern rule,这是一条通用规则,适用于所有类似的对象构建规则。这一步告诉make如何通过编译相应的./obj/xxx.o C源文件来产生每个./src/xxx.c对象文件。
  6. 模式规则的... | $(OBJ)部分告诉make $(OBJ)order-only prerequisite。如果尚不存在,Make将对其进行构建。否则,它将不考虑其最后修改时间来决定是否必须重建目标。目录几乎总是被列为仅订购的先决条件,因为它们的上次修改时间无关紧要。在这里,它用来告诉make必须先构建$(OBJ)目录,然后才能构建任何目标文件。与$(BIN)规则中的$(EXE): $(OBJS) | $(BIN)相同。
  7. $@$<$^make automatic variables中的3个。在规则的配方中,它们分别扩展为目标,规则的第一个常规前提条件和所有常规(非仅订购)前提条件。
  8. CCCFLAGSLDLIBS是标准的make implicit variables,分别用于定义C编译器,C编译器选项和-lxxx链接器选项。 / li>
  9. 出于性能原因,在这种情况下,与:=分配相比,{strong>在=变量中更优选。有关详细说明,请参见the GNU make documentation

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

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

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

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

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

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

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

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

答案 1 :(得分:0)

%通配符模式规则可以帮助您 %.o:%c