weaz
weaz

Reputation: 35

makefile prerequisite appears older then target even if it was built afterwards

I am trying to add more then one file created in different directories to a static library but apparently it does not work as expected.

My makefile structure is something like this:

./src/drv/platform/AVR/
     - hal
     - hw
     --- spi
     --- uart
  1. In hal I define a library name in $(LIB_TARGET) named libHal and all the *.o files should be archived in that library.
  2. In hw I define another library name in $(LIB_TARGET) named libHw and all *.o files in hw/spi and hw/uart should go in that library: first the library libHw is created with the object files in hw/spi and they are never missed, then the objects in hw/uart are created and should be added to libHw.
  3. In each subdirectory a generic makefile with suffix rules is ran that creates the object files and then should add each *.o to the library. At the end of the run I should have in another library directory(as in another location) 2 libs, libHal and libHw, libHal contains everything in hal, libHw everything in hw.

In this case the directory hw does not have any source files and looks like this:

SUBDIRS:= spi uart
LIB_TARGET = libHw.a

.PHONY: $(SUBDIRS) clean all

default: all

$(SUBDIRS)::
    $(MAKE) -C $@ $(MAKECMDGOALS)

all clean : $(SUBDIRS)

Each of the uart and spi subdirs hold something like this:

include $(TGT_BASE)/make/generic.mk

SRCS  := uart.c

include $(TGT_BASE)/make/rules.mk

The file generic.mk only holds generic platform definitions.

The code for the generic makefile rules.mk with all the suffix rules.

.PHONY : all clean

OBJS = $(SRCS:.c=.o)
DEPS = $(OBJS:.o=.d)
LIB_TARGETT = $(LIB_DIR)/$(LIB_TARGET)

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

    ### rule for c files
%.o: %.c
    @echo $(MSG_C)
    $(CC) -c $(CFLAGS) $(MODULES_INC) $(TGT_LOCAL_INCLUDES) $< -o $@
    @echo $(MSG_C)

    ### make dependencies
%.d: %.c
    @echo $(MSG_D)
    $(CC) -E -MM $(CFLAGS) $(MODULES_INC) $(TGT_LOCAL_INCLUDES) $(CURDIR)/$< > $@
    @echo $(MSG_D)

all: $(DEPS) $(OBJS) $(LIB_TARGETT)

clean: 
    $(RM) -rf *.o *.d .depend

The makefile that exists in most

Now the problem is that sometimes some of the *.o files in hw/uart are not added to the library defined in hw. Running make in debug reveals that make itself considers the prerequisites for the library to be older then the last access to the library so they are missed.

Found an implicit rule for 'F:/automata/tmp/remake//tmp/app/brick/lib/atmega328p/libHw.a'.
 Pruning file 'uart.o'.
Finished prerequisites of target file 'F:/automata/tmp/remake//tmp/app/brick/lib/atmega328p/libHw.a'.
Prerequisite 'uart.o' is older than target    'F:/automata/tmp/remake//tmp/app/brick/lib/atmega328p/libHw.a'.

To explain better how this goes when it works here is an example

make[7]: Entering directory 'F:/automata/tmp/remake/src/drv/platform/AVR/hw/uart
'
-------- make c --------
avr-gcc -c -Wall -Werror  -Os -mmcu=atmega328p  -IF:/automata/tmp/remake//tmp/ap
p/brick -IF:/automata/tmp/remake/src/common/h -IF:/automata/tmp/remake/src/drv/p
latform/AVR/hw/spi -IF:/automata/tmp/remake/src/drv/platform/AVR/hw/uart -IF:/au
tomata/tmp/remake/src/modules/interface/cli  -IF:/automata/tmp/remake/src/drv/pl
atform/AVR/hw/uart uart.c -o uart.o
-------- make c --------
------- make Lib -------
Adding uart.o to library F:/automata/tmp/remake//tmp/app/brick/lib/atmega328p/li
bHw.a
avr-ar rcs F:/automata/tmp/remake//tmp/app/brick/lib/atmega328p/libHw.a uart.o
------- make Lib -------
make[7]: Leaving directory 'F:/automata/tmp/remake/src/drv/platform/AVR/hw/uart'

And here is an example if it when it is not working

make[7]: Entering directory 'F:/automata/tmp/remake/src/drv/platform/AVR/hw/uart
'
-------- make c --------
avr-gcc -c -Wall -Werror  -Os -mmcu=atmega328p  -IF:/automata/tmp/remake//tmp/ap
p/brick -IF:/automata/tmp/remake/src/common/h -IF:/automata/tmp/remake/src/drv/p
latform/AVR/hw/spi -IF:/automata/tmp/remake/src/drv/platform/AVR/hw/uart -IF:/au
tomata/tmp/remake/src/modules/interface/cli  -IF:/automata/tmp/remake/src/drv/pl
atform/AVR/hw/uart uart.c -o uart.o
-------- make c --------
make[7]: Leaving directory 'F:/automata/tmp/remake/src/drv/platform/AVR/hw/uart'

I am using make 3.82.90 and Windows 7.

So any idea how I can force make to not miss those objects? Or to see their real time of creation and properly add them to the library? Remember, sometimes they are added, but sometimes they are not.

Thank you.

Upvotes: 0

Views: 1450

Answers (1)

MadScientist
MadScientist

Reputation: 100876

When you say it always works when you run it with make all --debug=a it always works: which part of that matters? If you run make all does it always work? Or if you run make --debug=a does it always work? Or do you have to use both to make it always work?

Since you're not showing all the makefile, we can't say much. For example, how are you setting the value of OBJS? Where and how do you define the rules that build object files (or are you using make's built-in rules for that)? That information is critical. It looks like what's happening is that make is asking you to build one file but your rules build a different file, so make sees that the file it expects was not actually updated and doesn't do anything.

Also, it's very confusing that in your overview you talk about things like dir1, dir2, dir2.1, etc. but then in the error output you provide completely different paths. We can't determine how the "real" pathnames in your example match up with the pseudo-paths in your overview.

Please either use real paths everywhere, or edit your example output to use the pseudo-paths, so we can see which paths are doing what.

Upvotes: 1

Related Questions