c-有没有一种方法可以使用Make将我的所有对象文件都放在同一个目录中



所以,我决定把学习make作为我进入大型项目的第一步,我不得不说,如果你只是做简单的任务并沉迷其中,这并不难。然而,我通常为我的目录使用一个方案:

.
├── build
├── include
│   └── func.h
├── lib
│   └── func.c
├── Makefile
└── src
└── main.c

我通常将所有的对象文件分布在构建目录中。然而,我只能将源文件映射到构建文件夹(如./build/src/main.o,我更喜欢./build/main.o(。我试着阅读文档,但没有成功!这就是我到目前为止想到的:

# C Compiler
CC                  = gcc
#------------- Directories
SOURCE_DIR          = src lib
OBJECTS_DIR         = build
INCLUDE_DIR         = . ./include
#----------------------------
VPATH               = $(SOURCE_DIR)
#------------- Files
SOURCE              = $(foreach dir,    $(SOURCE_DIR),  $(wildcard  $(dir)/*.c))
# Fake Objects (Just so I can map them to c files)
FOBJECTS            = $(addprefix $(OBJECTS_DIR)/, $(SOURCE:.c=.o))
OBJECTS             = $(addprefix $(OBJECTS_DIR)/, $(notdir $(FOBJECTS)))
DEPS                = $(foreach dir,    $(INCLUDE_DIR), $(wildcard  $(dir)/*.h))
#----------------------------
#------------- Flags
OPT                 = -O0
IFLAGS              = $(foreach dir,    $(INCLUDE_DIR), -I$(dir))
LFLAGS              = -lm
CFLAGS              = -Wall
FLAGS               = $(OPT) $(IFLAGS) $(LFLAGS) $(CFLAGS)
#----------------------------
BINARY              = bin
all                 : $(BINARY)
$(BINARY)           : $(OBJECTS)
$(CC) -o $@ $(OBJECTS)
$(OBJECTS)          : $(FOBJECTS)
mv -t $(OBJECTS_DIR) $(FOBJECTS) 
rm -rf -- $(OBJECTS_DIR)/*/
$(OBJECTS_DIR)/%.o  : %.c $(DEPS)
$(CC) $(FLAGS) -c -o $@ $<
exec                : $(BINARY)
@./$(BINARY)
clean               :
rm -rf $(OBJECTS) $(BINARY)

我一直收到这个错误:

gcc                      -O0  -I.  -I./include -lm -Wall -c -o build/src/main.o src/main.c
Assembler messages:
Fatal error: can't create build/src/main.o: No such file or directory
make: *** [Makefile:39: build/src/main.o] Error 1

我知道原因是我创建了假对象,但创建完美的规则是很难的

正如我所说,您可能确实不想将所有.o放在同一目录中,因为将不相关项目的.o文件合并不是最好的组织方式。如果.o文件相关,则可能会将.c文件放在同一个子目录中。


但是,如果您确实希望在单个build目录中所有.o,一种方法是创建build/*子目录:

# C Compiler
CC                  = gcc
#------------- Directories
SOURCE_DIR          = src lib
OBJECTS_DIR         = build
INCLUDE_DIR         = . ./include
OBJ_MK              = $(addprefix $(OBJECTS_DIR)/, $(SOURCE_DIR))
#----------------------------
VPATH               = $(SOURCE_DIR)
#------------- Files
SOURCE              = $(foreach dir,    $(SOURCE_DIR),  $(wildcard  $(dir)/*.c))
# Fake Objects (Just so I can map them to c files)
FOBJECTS            = $(addprefix $(OBJECTS_DIR)/, $(SOURCE:.c=.o))
OBJECTS             = $(addprefix $(OBJECTS_DIR)/, $(notdir $(FOBJECTS)))
DEPS                = $(foreach dir,    $(INCLUDE_DIR), $(wildcard  $(dir)/*.h))
#----------------------------
#------------- Flags
OPT                 = -O0
IFLAGS              = $(foreach dir,    $(INCLUDE_DIR), -I$(dir))
LFLAGS              = -lm
CFLAGS              = -Wall
FLAGS               = $(OPT) $(IFLAGS) $(LFLAGS) $(CFLAGS)
#----------------------------
BINARY              = bin
all                 : $(OBJ_MK) $(BINARY)
$(BINARY)           : $(OBJECTS)
$(CC) -o $@ $(OBJECTS)
$(OBJECTS)          : $(FOBJECTS)
mv -t $(OBJECTS_DIR) $(FOBJECTS)
rm -rf -- $(OBJECTS_DIR)/*/
$(OBJECTS_DIR)/%.o  : %.c $(DEPS)
$(CC) $(FLAGS) -c -o $@ $<
exec                : $(BINARY)
@./$(BINARY)
clean               :
rm -rf $(OBJECTS) $(BINARY)
rm -rf $(OBJ_MK)
$(OBJ_MK):
mkdir $@

make输出为:

mkdir build/src
mkdir build/lib
gcc -O0  -I.  -I./include -lm -Wall -c -o build/src/main.o src/main.c
gcc -O0  -I.  -I./include -lm -Wall -c -o build/lib/func.o lib/func.c
mv -t build build/src/main.o build/lib/func.o
rm -rf -- build/*/
gcc -o bin build/main.o build/func.o

然而,上述内容实际上使构建更加复杂,因为它的";天然的";倾向于创建分区。要覆盖它,需要额外的mvrm命令。

要使用子目录方法,构建实际上更简单,我们可以做到:

# C Compiler
CC                  = gcc
#------------- Directories
SOURCE_DIR          = src lib
OBJECTS_DIR         = build
INCLUDE_DIR         = . ./include
OBJ_MK              = $(addprefix $(OBJECTS_DIR)/, $(SOURCE_DIR))
#----------------------------
VPATH               = $(SOURCE_DIR)
#------------- Files
SOURCE              = $(foreach dir,    $(SOURCE_DIR),  $(wildcard  $(dir)/*.c))
# Fake Objects (Just so I can map them to c files)
OBJECTS             = $(addprefix $(OBJECTS_DIR)/, $(SOURCE:.c=.o))
DEPS                = $(foreach dir,    $(INCLUDE_DIR), $(wildcard  $(dir)/*.h))
#----------------------------
#------------- Flags
OPT                 = -O0
IFLAGS              = $(foreach dir,    $(INCLUDE_DIR), -I$(dir))
LFLAGS              = -lm
CFLAGS              = -Wall
FLAGS               = $(OPT) $(IFLAGS) $(LFLAGS) $(CFLAGS)
#----------------------------
BINARY              = bin
all                 : $(OBJ_MK) $(BINARY)
$(BINARY)           : $(OBJECTS)
$(CC) -o $@ $(OBJECTS)
$(OBJECTS_DIR)/%.o  : %.c $(DEPS)
$(CC) $(FLAGS) -c -o $@ $<
exec                : $(BINARY)
@./$(BINARY)
clean               :
rm -rf $(OBJECTS) $(BINARY)
rm -rf $(OBJ_MK)
$(OBJ_MK):
mkdir $@

make输出为:

mkdir build/src
mkdir build/lib
gcc -O0  -I.  -I./include -lm -Wall -c -o build/src/main.o src/main.c
gcc -O0  -I.  -I./include -lm -Wall -c -o build/lib/func.o lib/func.c
gcc -o bin build/src/main.o build/lib/func.o

如果你真的想把所有对象都放在一个目录中,你几乎是对的,但你添加了一些我不理解的非常奇怪的规则;这个是干什么的:

$(OBJECTS) : $(FOBJECTS)
mv -t $(OBJECTS_DIR) $(FOBJECTS) 
rm -rf -- $(OBJECTS_DIR)/*/

这就是造成你问题的原因。你是说每个单独的对象文件都依赖于所有的";中间体";对象文件,因此make尝试构建这些";中间体";对象文件。它知道的唯一方法是使用您提供的模式规则,但这并不能构建这些文件。

完全删除该规则,它可能会起作用。你只想:

VPATH = $(SOURCE_DIR)
OBJECTS = $(addprefix $(OBJECTS_DIR)/, $(notdir $(SOURCE:.c=.o)))
all : $(BINARY)
$(BINARY) : $(OBJECTS)
$(CC) -o $@ $(OBJECTS)
$(OBJECTS_DIR)/%.o  : %.c $(DEPS)
$(CC) $(FLAGS) -c -o $@ $<

等等。编译器将把对象文件直接构建到它们的最终目的地。你不需要FOBJECTS或使用它的规则

最新更新