2

I am doing a build system based on recursive(toxic but not matter) make. The main problem I have is that make recreates the libraries I instruct it to do even if there were no changes to an of the *o files.

Here is the section in on of my makefiles that handles the static library creation.

all: $(DEPS) $(OBJS) $(LIB_TARGET)

### Archive into a library file (.a)
%.a: $(OBJS)
    @echo $(MSG_L)
    @echo 'Adding $< to library $@'
    $(AR) $(ARFLAGS) $(LIB_DIR)/$@ $^
    @echo $(MSG_L)

Under certain directories in their respective makefiles, the $(LIB_TARGET) is defined with the library name and each subdir uses the prefixes makefile to know how to create it's share. Now my biggest problem is that first run it is normal to create everything but on the second run, or every subsequent run without any changes to anything in the code, the libraries are recreated(but not *d or *o files, they are not recreated, they are not deleted, their timestamp is not changed, which is normal).

make -C modules all
make[3]: Entering directory `F:/automata/tmp/remake/src/modules'
make -C interface all
make[4]: Entering directory `F:/automata/tmp/remake/src/modules/interface'
make -C cli all
make[5]: Entering directory `F:/automata/tmp/remake/src/modules/interface/cli'
------- make Lib -------
Adding cli.o to library libInterface.a
avr-ar rcs F:/automata/tmp/remake//tmp/app/brick/lib/atmega328p/libInterface.a c
li.o
------- make Lib -------

NOTE: this is from the second/third run, here it can be seen that *d and *o are not recreated

I created the rule to use files, the only problem that I can see is that I put the libraries in a special directory and not in the same as the one it gets the sources from. Any idea on how to have to solve this and not have the system also recreate the libraries?

Thank you.

weaz
  • 35
  • 8

1 Answers1

3

Anytime you see a recipe which creates a target file which is not exactly $@, you know it's wrong and you're going to have this problem.

Here, you tell make you're going to create a target that matches the pattern %.a. make matches that pattern to libInterface.a and sets $@ to libInterface.a and invokes your recipe.

But your recipe doesn't build $@, it builds $(LIBDIR)/$@ which is a totally different file. So the next time you run make, it will look for libInterface.a as the prerequisite to all, see that it doesn't exist, and re-run the rule you provided... which again will not create the target you told make it would, $@, but instead create some other file make doesn't know anything about.

You need to use:

LIB_TARGET = $(LIB_DIR)/libInterface.a

....

### Archive into a library file (.a)
$(LIB_DIR)/%.a: $(OBJS)
        @echo $(MSG_L)
        @echo 'Adding $< to library $@'
        $(AR) $(ARFLAGS) $@ $^
        @echo $(MSG_L)
MadScientist
  • 92,819
  • 9
  • 109
  • 136
  • Thank you for you answer and lesson. Much logic has been added to my understanding of make. – weaz Apr 23 '14 at 14:15
  • Also, while it may work, it's a bit ... unusual ... in my experience to see a pattern matching rule (`$(LIB_DIR)/%.a`) that doesn't have the corresponding pattern referenced somewhere on the right-hand side of the `:`... That rule could just be `$(LIB_TARGET): $(OBJS)`, which I think would be clearer... – twalberg Apr 23 '14 at 16:17
  • Apparently there is one issue I lack to understand. It works ok except for a library that needs to add more the one *.o file from a subdirectory. The first obj file is added ok but the second is sometimes missed. It is very strange since it sometimes adds it and sometimes doesn't. – weaz Apr 24 '14 at 08:21
  • @weaz Are you sure that's what it's doing? I notice in the recipe above, the `@echo` line references the `$<` automatic variable while the `$(AR)` line uses `$^`. So perhaps, it's reporting one thing and doing another... – twalberg Apr 24 '14 at 11:41
  • @twalberg The main problem with those `*.o` files is that they appear to be older then the library itself to make and so they are no added and ignored. Depending on the small difference in speed and the fact that I use Windows perhaps this is what causes make to sometimes behave normally and sometimes not. `Prerequisite 'uart.o' is older than target 'F:/automata/tmp/remake//tmp/app/brick/lib/atmega328p/libHw.a'.` – weaz Apr 24 '14 at 16:31
  • We don't know what `ARFLAGS` is here. But, make will check ALL the prerequisites (object files), and it will run the recipe if ANY one or more of them is newer. Then on the command line you pass ALL the objects (`$^`), not just the newer objects. So as long as the flags to the `AR` program ask to replace all objects, you should be fine. – MadScientist Jul 08 '20 at 19:35