简体   繁体   English

如何在makefile中编写编译规则时删除源文件的路径?

[英]How I strip path of source file while writing a compilation rule in makefile?

In short: I want to compile sources from different directories, and put object files into current directory. 简而言之:我想从不同的目录编译源代码,并将目标文件放入当前目录。

For example, I have files: 例如,我有文件:

test.c
../../lib1/boot.c
../../lib2/startup.c
../common/utils.c

(also few files .s (assembly) and .cpp, but I hope this is not important). (也有少量文件.s(程序集)和.cpp,但我希望这不重要)。

All of their object-files I want to be in the current directory: 我想要的所有目标文件都在当前目录中:

test.o
boot.o
startup.o
utils.o

And I can't figure out how to write such rule in my makefile. 我无法弄清楚如何在我的makefile中编写这样的规则。

For example, 例如,

%o.: %.c

does not work now because make can't find a rule to build boot.o from ../../lib1/boot.c , it can only find rule to build ../../lib1/boot.o from ../../lib1/boot.c . 现在不工作,因为make不能发现一个规律来构建boot.o../../lib1/boot.c ,它只能找到规则建立../../lib1/boot.o../../lib1/boot.c

I tried to use this: 我试着用这个:

%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)

and it works. 它的工作原理。 But obviously this is not generic enough, and in addition, some user came to me today and said that his application has also some ../../some_other_lib/common_things.c , hence my makefile failed. 但显然这不够通用,此外,有些用户今天来找我并说他的应用程序也有一些../../some_other_lib/common_things.c ,因此我的makefile失败了。 I looked through our project, and found many such cases with a lot of different directories involved. 我查看了我们的项目,发现很多这样的案例涉及很多不同的目录。 With my approach, I'll have to write a separate rule for each such directory, with identical compilation line. 根据我的方法,我将不得不为每个这样的目录编写一个单独的规则,具有相同的编译行。 This does not seem good to me. 这对我来说似乎不太好。

So my question is: how to make some generic compilation rule that puts (and checks) object files in current directory, while operating with sources in different directories? 所以我的问题是:如何制作一些通用编译规则,将目标文件放入(并检查)当前目录,同时使用不同目录中的源操作?

Thank you. 谢谢。

The directories can be extracted from the CSRC variable with $(dir ...) and this list can then be used in the vpath directive. 可以使用$(dir ...)CSRC变量中提取$(dir ...) ,然后可以在vpath指令中使用此列表。

vpath %.c $(sort $(dir $(CSRC)))
vpath %.s $(sort $(dir $(SSRC)))
vpath %.cpp $(sort $(dir $(CPPSRC)))

(I've thrown in the sort function to remove duplicates, but that's not absolutely necessary.) (我已经抛出了sort函数来删除重复项,但这不是绝对必要的。)

Now the rules can be kept simple and make will search the source files in the list of directories. 现在规则可以保持简单, 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
    ...

Try to use makefile function notdir as this: 尝试使用makefile函数notdir如下所示:

%.o:    %.c
    gcc -c $< -o $(notdir $@)

$@ must be equal to the full path ex: ../../lib2/startup.o ad notdir will trunk it to: startup.o . $@必须等于完整路径ex: ../../lib2/startup.o ad notdir将其中notdir到: startup.o

With this rule you will be able to compile all your source in the current directory. 使用此规则,您将能够在当前目录中编译所有源。

Actually, your example is like that: 实际上,你的例子是这样的:

.
└── common
    ├── lib1
    │   └── boot.c
    ├── lib2
    │   └── startup.c
    ├── test
    │   ├── Makefile
    │   └── test.c
    └── utils.c

I think i will be better like that: 我想我会更好:

.
├── 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

For that you need all your Makefiles to call the subdirs Makefiles. 为此,您需要所有Makefile调用子目录Makefile。 and the src / obj dirs is a separation between your source and objects. 并且src / obj目录是源和对象之间的分隔。

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 $@

OK, took me some time, but finally I found the solution (using some threads on this site by the way): 好吧,花了我一些时间,但最后我找到了解决方案(顺便使用本网站上的一些线程):

# 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) contains list of source files with their paths. $(CSRC)包含源文件列表及其路径。

Just need to take into account that if earlier I had something like this: 只需要考虑到如果我之前有这样的事情:

.c.o:
    $(CC) $(CFLAGS) $(CDEFINES) $^ -o $@

all: <List of my targets>

...now I have to put all sentence above the rules which I described in my_c_rule procedure. ...现在我必须将all句子置于我在my_c_rule程序中描述的规则my_c_rule If I don't do this, make stops after compiling first source file. 如果我不这样做, make编译第一个源文件后停止。 This is because old "wildcard" rules like .co or %.o: %.c do not replace all as a default target (even being written earlier), but non-wildcard rules like boot.o: ../../lib1/boot.c (result of the above macros) do replace the default target in case they are written earlier. 这是因为旧的“通配符”规则,如.co%.o: %.c不会将all替换为默认目标(即使是之前编写的),但是非通配符规则,如boot.o: ../../lib1/boot.c (上述宏的结果)确实替换了以前写入的默认目标。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM