简而言之:我想从不同的目录编译源代码,并将目标文件放入当前目录。
例如,我有文件:
test.c
../../lib1/boot.c
../../lib2/startup.c
../common/utils.c
(也有少量文件.s(汇编)和.cpp,但我希望这不重要。)
我想要的所有目标文件都在当前目录中:
test.o
boot.o
startup.o
utils.o
我无法弄清楚如何在我的makefile中编写这样的规则。
例如,
%o.: %.c
现在无效,因为make
找不到从boot.o
构建../../lib1/boot.c
的规则,它只能从{{1}找到构建../../lib1/boot.o
的规则}。
我试着用这个:
../../lib1/boot.c
它有效。但显然这不够通用,此外,有些用户今天来找我并说他的应用程序也有一些%o.: %.c
(my compilation line, for example "gcc -c $^ -o $@")
%o.: ../../lib1/%.c
(my compilation line)
%o.: ../../lib2/%.c
(my compilation line)
%o.: ../common/%.c
(my compilation line)
,因此我的makefile失败了。我查看了我们的项目,发现很多这样的案例涉及很多不同的目录。根据我的方法,我将不得不为每个这样的目录编写一个单独的规则,具有相同的编译行。这对我来说似乎不太好。
所以我的问题是:如何制作一些通用编译规则,将目标文件放入(并检查)当前目录,同时使用不同目录中的源进行操作?
谢谢。
答案 0 :(得分:5)
可以使用CSRC
从$(dir ...)
变量中提取目录,然后可以在vpath
指令中使用此列表。
vpath %.c $(sort $(dir $(CSRC)))
vpath %.s $(sort $(dir $(SSRC)))
vpath %.cpp $(sort $(dir $(CPPSRC)))
(我已经在sort
函数中删除了重复项,但这并非绝对必要。)
现在规则可以保持简单,make
将搜索目录列表中的源文件。
$(COBJ) := $(notdir $(CSRC))
$(SOBJ) := $(notdir $(SSRC))
$(CPPOBJ) := $(notdir $(CPPSRC))
.PHONY: all
all: $(EXECUTABLE)
$(EXECUTABLE): $(COBJ) $(SOBJ) $(CPPOBJ)
....
$(COBJ): %.o: %.c
...
$(SOBJ): %.o: %.s
...
$(CPPOBJ): %.o: %.cpp
...
答案 1 :(得分:4)
尝试使用makefile函数notdir
:
%.o: %.c
gcc -c $< -o $(notdir $@)
$@
必须等于ex的完整路径:../../lib2/startup.o
ad notdir
会将其中止为:startup.o
。
使用此规则,您将能够编译当前目录中的所有源。
实际上,你的例子是这样的:
.
└── common
├── lib1
│ └── boot.c
├── lib2
│ └── startup.c
├── test
│ ├── Makefile
│ └── test.c
└── utils.c
我想我会更好:
.
├── common
│ ├── lib1
│ │ ├── Makefile
│ │ ├── obj
│ │ └── src
│ │ └── boot.c
│ ├── lib2
│ │ ├── Makefile
│ │ ├── obj
│ │ └── src
│ │ └── startup.c
│ ├── Makefile
│ ├── obj
│ ├── src
│ │ └── utils.c
│ └── test
│ ├── Makefile
│ ├── obj
│ └── src
│ └── test.c
└── Makefile
为此你需要所有的Makefile来调用子目录Makefile。
src
/ obj
dirs是源和对象之间的分隔。
SRC := utils.c
OBJ := $(SRC:%.c=%.o)
NAME := project
SRC_D := src
OBJ_D := obj
SUBDIRS := lib1/ \
lib2/ \
test/
all: $(NAME) $(SUBDIRS)
@for dir in $(SUBDIRS); \
do \
$(MAKE) -C $$dir; \
done
$(NAME): $(OBJ:%.o=$(OBJ_D)/%.o)
$(OBJ_D)/%.o : $(SRC_D)/%.c
gcc -c $< -o $@
答案 2 :(得分:2)
好的,花了我一些时间,但最后我找到了解决方案(顺便使用本网站上的一些帖子):
# Defining compilation rules in a way that object files will be produced in current directory, and not in the directory of source files:
all: <List of my targets>
define my_c_rule
$(subst .c,.o,$(notdir $(1))): $(1)
$(CC) $(CFLAGS) $(CDEFINES) $$^ -o $$@
endef
$(foreach f, $(CSRC), $(eval $(call my_c_rule, $(f))))
$(CSRC)
包含源文件列表及其路径。
只需要考虑到如果我之前有这样的事情:
.c.o:
$(CC) $(CFLAGS) $(CDEFINES) $^ -o $@
all: <List of my targets>
...现在我必须将all
句子置于我在my_c_rule
程序中描述的规则之上。如果我不这样做,make
在编译第一个源文件后停止。这是因为像.c.o
或%.o: %.c
这样的旧“通配符”规则不会将all
替换为默认目标(即使是之前编写的),但是非通配符规则,例如boot.o: ../../lib1/boot.c
(上述宏的结果)确实替换了以前写入的默认目标。