0

Here is the relevant part of my Makefile.

...
LIBS = gc ft

vpath %.a $(LIBS:%=lib%)

all:
    $(MAKE) $(NAME)

$(NAME): $(LIBS:%=lib%.a) $(OBJS) | libs
    $(CC) $(CFLAGS) $(OBJS) -o $(NAME) $(LDFLAGS)

-include $(DEPENDENCIES)
$(OBJS_DIR)/%.o: %.c $(OBJS_DIR)/debug$(DEBUG) | $(OBJS_DIR)
    $(CC) $(CFLAGS)  $(INCLUDES_DIR:%=-I %) -c $< -o $@

$(OBJS_DIR):
    $(MKDIR) $@

libs: $(LIBS:%=lib%.a)
    $(foreach LIB, ${LIBS}, ${MAKE} -C lib${LIB} ;)

lib%.a:
    $(MAKE) -C $(@:%.a=%)
...

My problem is that, whenever I touch a file in one of my libs, make recompile that lib, but I have to run make a second time to make it relink the object files.
What am I doing wrong ?
Thanks in advance.

---EDIT---
So now my Makefile looks like this.

...
all: $(NAME)

$(NAME): $(OBJS) libft/libft.a libgc/libgc.a
    $(CC) $(CFLAGS) $(OBJS) -o $(NAME) $(LDFLAGS)

-include $(DEPENDENCIES)
$(OBJS_DIR)/%.o: %.c $(OBJS_DIR)/debug$(DEBUG) | $(OBJS_DIR)
    $(CC) $(CFLAGS)  $(INCLUDES_DIR:%=-I %) -c $< -o $@

$(OBJS_DIR):
    $(MKDIR) $@

libft/libft.a:
    $(MAKE) -C libft

libgc/libgc.a:
    $(MAKE) -C libgc
    ...

It does not relink anymore but if change some file in the sources of my libs, it does not recompile either.

1 Answers1

0

You cannot use vpath to find generated files. It can only be used to locate source files (that always exist). See http://make.mad-scientist.net/papers/how-not-to-use-vpath/ for details.

You need to use the real path of the libraries generated as prerequisites, so that when make checks their modification time it knows they've changed.

ETA

You are using a recursive make model for building. That means that this makefile doesn't know whether your libraries are out of date or not: here you don't list any prerequisites for them, so as far as make is concerned if they exist, they are up to date.

Instead, you've relegated the knowledge of whether the libraries are up to date into the subdirectory makefiles. That means that in order to know if they're up to date, you have to run that sub-make so it can check. That means you ALWAYS want to run the sub-make, which will only update the libraries if they're out of date. A simple way to do this is using a FORCE target:

libft/libft.a: FORCE
        $(MAKE) -C libft

libgc/libgc.a: FORCE
        $(MAKE) -C libgc

FORCE:;
MadScientist
  • 92,819
  • 9
  • 109
  • 136
  • Thank you very much, I was not aware of that. Unfortunately, this does not fix my problem. If I just put the names of my libraries in the prerequisites, the makefile relinks. `$(NAME): libft.a libgc.a $(OBJS) | libs` And if I put the full path, the compilation just fails. `$(NAME): libft/libft.a libgc/libgc.a $(OBJS) | libs` `make[2]: *** libft/libft: No such file or directory. Stop.` `make[1]: *** [Makefile:97: libft/libft.a] Error 2` `make: *** [Makefile:75: all] Error 2` – Romain T-BIGOT Sep 25 '21 at 19:23
  • Sure. I guess I wasn't clear that you have to use the full pathname AND fix up your makefile to use those full paths as the targets that run the sub-make commands. Clearly you can't just use the library names without the directories, since those don't exist and so make can't compare the timestamps. – MadScientist Sep 25 '21 at 19:28
  • Yes, I figured that out. As you said,make connot guess where are my libs if I don't specify it. But unfortunately, fixing somethings break others. I just edited my issue. – Romain T-BIGOT Sep 25 '21 at 21:01