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).
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.
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
.
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. 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 Cleanup Rule clean: rm *.o prog3 This is an optional rule. It allows you to type 'make clean' at the command line to get rid of your object and executable files. Sometimes the compiler will link or compile files incorrectly and the only way to get a fresh start is to remove all the object and executable files.
The file name of the target of the rule. If the target is an archive member, then ' $@ ' is the name of the archive file. In a pattern rule that has multiple targets (see Introduction to Pattern Rules), ' $@ ' is the name of whichever target caused the rule's recipe to be run.
realpath() expands all symbolic links and resolves references to /./ , /../ and extra / characters in the input path and returns the canonicalized absolute pathname.
The directories can be extracted from the CSRC
variable with $(dir ...)
and this list can then be used in the vpath
directive.
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.)
Now the rules can be kept simple and make
will search the source files in the list of directories.
$(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:
%.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
.
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.
and the src
/obj
dirs is a separation between your source and objects.
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 $@
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With