将Makefile从平面目录结构演化为子目录结构

将Makefile从平面目录结构演化为子目录结构,makefile,Makefile,请参阅下面的更新 已完成的研究:我发现学习如何将makefile从一种情况发展到另一种情况很困难。这里有大量的问题和答案,但很少有真正显示出随着项目的变化,生成文件是如何演变的。它们似乎都使用了各种不同的Makefiles技术和习惯用法,所以当您第一次学习Makefiles时,在一个问题和另一个问题之间进行翻译可能会很棘手,就像我一样 问题:我的问题是,我有一个项目开始时是一个平面目录结构,但现在正在迁移到一个带有子目录的结构。我不能做的是让我的Makefile随行 首先,我将展示我所创建的工

请参阅下面的更新


已完成的研究:我发现学习如何将makefile从一种情况发展到另一种情况很困难。这里有大量的问题和答案,但很少有真正显示出随着项目的变化,生成文件是如何演变的。它们似乎都使用了各种不同的Makefiles技术和习惯用法,所以当您第一次学习Makefiles时,在一个问题和另一个问题之间进行翻译可能会很棘手,就像我一样

问题:我的问题是,我有一个项目开始时是一个平面目录结构,但现在正在迁移到一个带有子目录的结构。我不能做的是让我的Makefile随行

首先,我将展示我所创建的工作,然后我将展示我希望它如何发展,以及它如何不工作

平面目录结构,工作Makefile

我有一个项目目录,其中包含我的所有C文件和一个头文件以及我的Makefile:

project
  Makefile
  c8_asm.c
  c8_dasm.c
  c8_terp.c
  chip8.h
这是我的Makefile(工作正常):

我的所有.o文件和可执行文件都是在项目目录中创建的

发展项目

但我想做的是将我的源文件(all.c和.h)放在src目录中。我想构建一个obj目录,并将可执行文件放入bin目录中。所以我的项目是这样的:

project
  src
    c8_asm.c
    c8_dasm.c
    c8_terp.c
    chip8.h
  Makefile
子目录结构,Makefile不工作

为了适应上述情况,我相应地更改了Makefile:

CC = gcc

CFLAGS += -c -Wall -std=c99
CFLAGS += -D_POSIX_C_SOURCE=200809L

LDLIBS += -lm

SRC_DIR = src
OBJ_DIR = obj
BIN_DIR = bin

SOURCES := $(wildcard $(SRC_DIR)/*.c)
OBJECTS := $(SOURCES:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)

MKDIR_P ?= mkdir -p

# Targets

all: $(BIN_DIR)/c8_dasm $(BIN_DIR)/c8_asm $(BIN_DIR)/c8_terp

$(BIN_DIR)/c8_dasm: $(OBJ_DIR)/c8_dasm.o
    $(CC) $(LDLIBS) $(OBJ_DIR)/c8_dasm.o -o $@

$(BIN_DIR)/c8_asm: $(OBJ_DIR)/c8_asm.o
    $(CC) $(LDLIBS) $(OBJ_DIR)/c8_asm.o -o $@

$(BIN_DIR)/c8_terp: $(OBJ_DIR)/c8_terp.o
    $(MKDIR_P) $(dir $@)
    $(CC) $(LDLIBS) $(OBJ_DIR)/c8_terp.o -o $@

$(OBJECTS): $(OBJ_DIR)/%.o : $(SRC_DIR)/%.c
    $(MKDIR_P) $(dir $@)
    $(CC) $< -o $(OBJ_DIR)/$@

# Using implicit rules for updating an '.o' file from a correspondingly
# named '.c' file.

$(OBJ_DIR)/c8_dasm.o: $(SRC_DIR)/chip8.h
$(OBJ_DIR)/c8_asm.o: $(SRC_DIR)/chip8.h
$(OBJ_DIR)/c8_terp.o: $(SRC_DIR)/chip8.h

.PHONY: clean
clean:
    rm -r $(BUILD_DIR)
    rm $(OBJECTS)
我想在这里停下来,寻求一些帮助,因为我担心我把这个Makefile做得比它需要的复杂,我正在努力避免养成坏习惯

我希望听到关于我在这里没有正确概念化的观点

第一次更新

我设法一点一点地接受它,并使它基本正常工作。以下是我的结论:

CC = gcc

CFLAGS += -c -Wall -std=c99
CFLAGS += -D_POSIX_C_SOURCE=200809L

LDLIBS += -lm

# Directories.

SRC_DIR = src
BIN_DIR = bin

$(shell mkdir -p $(BIN_DIR))

# Patterns for files.

SOURCES := $(wildcard $(SRC_DIR)/*.c)
OBJECTS := $(SOURCES:$(SRC_DIR)/%.c=$(SRC_DIR)/%.o)

EXECUTABLES := c8_dasm c8_asm c8_terp

# Targets

all: $(EXECUTABLES)

c8_dasm: $(SRC_DIR)/c8_dasm.o
    $(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$@
    @echo "C8 Disassembler Built"

c8_asm: $(SRC_DIR)/c8_asm.o
    $(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$@
    @echo "C8 Assembler Built"

c8_terp: $(SRC_DIR)/c8_terp.o
    $(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$@
    @echo "C8 Interpreter Built"

# Using implicit rules for updating an '.o' file from a correspondingly
# named '.c' file.

c8_dasm.o: $(SRC_DIR)/chip8.h
c8_asm.o: $(SRC_DIR)/chip8.h
c8_terp.o: $(SRC_DIR)/chip8.h

.PHONY: clean
clean:
    rm $(OBJECTS)
    rm -r $(BIN_DIR)
当然,正如我在Make中发现的那样,这会导致其他模糊的问题。例如,这样做:

make
make clean
很好。这意味着生成所有文件并清理文件,包括
bin
目录

但是,如果我这样做:

make c8_dasm
make clean
这很好。但是clean无法删除
bin
目录(尽管它确实删除了对象文件)。无论我试图构建哪个可执行文件,这种情况都会发生

再多的搜索也不能帮我找到原因

第二次更新

我发现这个问题也解决了。它只需要在clean目标中对rm语句使用“-f”

第三次更新

为了使对象文件目录部件正常工作,我尝试(从以下位置:)按如下方式构造Makefile:

CC = gcc

CFLAGS += -c -Wall -std=c99
CFLAGS += -D_POSIX_C_SOURCE=200809L

LDLIBS += -lm

SRC_DIR = src
OBJ_DIR = obj
BIN_DIR = bin

$(shell mkdir -p $(BIN_DIR))
$(shell mkdir -p $(OBJ_DIR))

SOURCES := $(wildcard $(SRC_DIR)/*.c)
OBJECTS := $(SOURCES:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)

EXECUTABLES := c8_dasm c8_asm c8_terp

all: $(EXECUTABLES)

c8_dasm: $(SRC_DIR)/c8_dasm.o
    $(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$@
    @echo "C8 Disassembler Built"

c8_asm: $(SRC_DIR)/c8_asm.o
    $(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$@
    @echo "C8 Assembler Built"

c8_terp: $(SRC_DIR)/c8_terp.o
    $(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$@
    @echo "C8 Interpreter Built"

$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
    $(CC) $(CFLAGS) -c $< -o $(BIN_DIR)/$@

.PHONY: clean
clean:
    rm -rf $(BIN_DIR)
    rm -f $(OBJECTS)
CC=gcc
CFLAGS+=-c-墙体-std=c99
CFLAGS+=-D_POSIX_C_SOURCE=200809L
LDLIBS+=-lm
SRC_DIR=SRC
OBJ_DIR=OBJ
BIN_DIR=BIN
$(shell mkdir-p$(BIN_DIR))
$(shell mkdir-p$(OBJ_DIR))
来源:=$(通配符$(SRC_DIR)/*.c)
对象:=$(源:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
可执行文件:=c8_dasm c8_asm c8_terp
全部:$(可执行文件)
c8_dasm:$(SRC_DIR)/c8_dasm.o
$(CC)$^$(LDLIBS)-o$(BIN_DIR)/$@
@echo“C8反汇编程序已构建”
c8_asm:$(SRC_DIR)/c8_asm.o
$(CC)$^$(LDLIBS)-o$(BIN_DIR)/$@
@echo“C8汇编程序构建”
c8_terp:$(SRC_DIR)/c8_terp.o
$(CC)$^$(LDLIBS)-o$(BIN_DIR)/$@
@echo“构建C8解释器”
$(OBJ_DIR)/%.o:$(SRC_DIR)/%.c
$(CC)$(CFLAGS)-c$<-o$(BIN_DIR)/$@
.假冒:干净
清洁:
rm-rf$(本部目录)
rm-f$(对象)
我能够使用
chip8.h
将原来的三行压缩成一个目标,但我无法知道这是否正确。它至少可以编译。我还更改了
对象
行,以反映我创建的新
对象目录


但是,这并没有将对象文件放在正确的位置。它仍然将它们放在
src
目录中,而不是
obj
目录中。

这就是为什么不做任何复杂的makefile操作是有意义的。只需在命令中输入实际的目录名。永远不要依赖通配符

人们使用C和C++,并使用MaFrimes花费太多时间试图使这些文件工作,而不是实际完成任务。这就是为什么你会看到这么多的问题,为什么答案会有这么多的差异

在您的特定情况下,您的目标并不总是包含目录,这是问题的一部分。生成的规则在您的文件中没有实际的目标,因为您正在为所有内容预先添加目录。你必须根据每个目标产生的内容来思考:意义,输出。因此,如果c8_dasm获得输出,这就是您的目标。目录与此无关。因此,您需要删除所有不需要的目录替换


但在这样做之前,问问自己:如果你的第一个解决方案是有效的,为什么要改变它?在使用Make时,最好甚至不做目录。只要把所有东西都放在你刚开始的目录里就行了。您甚至可以看到,这使您的Makefile更加干净。

Stackoverflow抱怨评论太多,所以我将给出另一个“答案”。在我们来回回复我的原始评论之后,您的最后一条评论是正确的。这就是我想让你看到的

明白你不能用Make来做你想做的事情

因此,答案确实是这样的:您不能创建多个可执行文件,并且在使用目录结构时,只能对每个文件应用一些对象文件。Make无法处理这一点

现在,您正试图以一种非预期的方式使用Make,这就是为什么您会遇到这么多问题的原因。如果你继续玩下去,你会遇到一个系列赛o
make c8_dasm
make clean
CC = gcc

CFLAGS += -c -Wall -std=c99
CFLAGS += -D_POSIX_C_SOURCE=200809L

LDLIBS += -lm

SRC_DIR = src
OBJ_DIR = obj
BIN_DIR = bin

$(shell mkdir -p $(BIN_DIR))
$(shell mkdir -p $(OBJ_DIR))

SOURCES := $(wildcard $(SRC_DIR)/*.c)
OBJECTS := $(SOURCES:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)

EXECUTABLES := c8_dasm c8_asm c8_terp

all: $(EXECUTABLES)

c8_dasm: $(SRC_DIR)/c8_dasm.o
    $(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$@
    @echo "C8 Disassembler Built"

c8_asm: $(SRC_DIR)/c8_asm.o
    $(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$@
    @echo "C8 Assembler Built"

c8_terp: $(SRC_DIR)/c8_terp.o
    $(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$@
    @echo "C8 Interpreter Built"

$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
    $(CC) $(CFLAGS) -c $< -o $(BIN_DIR)/$@

.PHONY: clean
clean:
    rm -rf $(BIN_DIR)
    rm -f $(OBJECTS)
CC = gcc

CFLAGS += -c -Wall -std=c99
CFLAGS += -D_POSIX_C_SOURCE=200809L

LDLIBS += -lm

SRC_DIR = src
OBJ_DIR = obj
BIN_DIR = bin

$(shell mkdir -p $(BIN_DIR))
$(shell mkdir -p $(OBJ_DIR))

SOURCES := $(wildcard $(SRC_DIR)/*.c)
OBJECTS := $(SOURCES:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)

EXECUTABLES := c8_dasm c8_asm c8_terp

all: $(EXECUTABLES)

c8_dasm: $(OBJ_DIR)/c8_dasm.o
    $(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$@
    @echo "C8 Disassembler Built"

c8_asm: $(OBJ_DIR)/c8_asm.o
    $(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$@
    @echo "C8 Assembler Built"

c8_terp: $(OBJ_DIR)/c8_terp.o
   $(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$@
   @echo "C8 Interpreter Built"

$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c $(SRC_DIR)/chip8.h
    $(CC) $(CFLAGS) -c $< -o $@

.PHONY: clean
clean:
    rm -rf $(BIN_DIR)
    rm -rf $(OBJ_DIR)