Imagine this structure:
root/
|
+-- include/
+-- src/
+-- build/
+-- lib/
+-- tests/
|
+-- common
+-- test1
+-- test2
+-- test3
In tests/
, the folder common/
contains a couple of source files that generate data or read data from logged file etc, which are shared between all tests. Each test therefore has only one file; main.c
(currently). The Makefile
of each test looks like this:
.SUFFIXES:
.SUFFIXES: .c .o
TARGET := test
# OS dependent stuff omitted for brevity
CFLAGS += -I../../include -I../common
LDFLAGS += -L../../lib -lname
VPATH = ../common
.phony: all clean
all: $(TARGET)
clean:
-$(RM) *.o $(TARGET)
# Other targets removed for brevity
OBJECTS := main.o io.o read_str.o
$(TARGET): $(OBJECTS) ../../lib/libname.a
$(LD) -o $@ $(OBJECTS) $(LDFLAGS)
%.o: %.c
$(CC) -c $(CFLAGS) -o $@ $<
main.o: main.c io.h $(wildcard ../../include/*.h)
At first I had the common/
files copied in each test and everything was fine, but now that I put them in common/
and used VPATH
, I am facing an issue.
Let me explain a few lines:
main.o: main.c io.h $(wildcard ../../include/*.h)
^^^^
VPATH correctly finds this file in common/
$(TARGET): $(OBJECTS) ../../lib/libname.a
^^^^^^^^^^^^^^^^^^^
If the library is rebuilt, the tests need to re-link
$(LD) -o $@ $(OBJECTS) $(LDFLAGS)
^^^^^^^^^^
I can't use $^ because that also includes ../../lib/libname.a
As you may have already guessed, since the common/*.o
files are not in this folder, $(LD)
fails to find them. On the other hand, make
, given VPATH = ../common
has no problem finding them. If I could remove ../../lib/libname.a
, then with $^
, I could give the correct paths to the object files.
Removing the dependency to the lib file however, means that when I make
at the top-level, the tests will not get updated if only the lib itself is being updated.
So, my question is, how can I tell make
there is a dependency to another file (a lib file) but it is not used in the command below it, given that the other dependencies are found using VPATH
?
I thought about removing the dependencies, and in the Makefile
that builds libname.a
, add a command after the library is made that tells the Makefile
s of tests to remove their TARGET
s:
lib/Makefile:
.SUFFIXES:
TARGET = libname.a
VPATH = ../build
.PHONY: all clean
all: $(TARGET)
clean:
-$(RM) $(TARGET)
$(TARGET): list.o of.o my.o library.o files.o
$(AR) $(TARGET) $^
@$(MAKE) --no-print-directory -C ../tests remove_targets
This would force $(LD)
to make them again. This solution however tends to make the Makefile
relationships into a mess. The Makefile
that builds the lib is unrelated to whether there are tests or not, and I prefer to keep them decoupled.
I build and test a lot, that is why I try to get the dependencies complete, so that make
takes the minimum possible actions to correctly build everything. A solution that says, clean and rebuild every time is not an option.
I am also aware of this syntax, which could be used if I wanted to give the lib file directory to gcc
, instead of using -Lpath/to/lib -lname
. I am not sure however if that is a good idea (I mean, I always saw linking with -L
, and I'm not sure if there is a disadvantage when directly giving the library file)
By the way, if I am doing something horribly wrong, or if I am making it too difficult for myself, please tell me how this should be done correctly.