Makefile for parallel library build problem

I have been trying to write a Makefile to build the modules for a library in parallel. What I have works for a single threaded make, and for parallel builds of the full library, but parallel makes (make -j2) fail to update changed modules in the library (though the source IS compiled to an object file). Any suggestions as to what I am doing wrong in the following example?

Code:
# Small Makefile to demonstrate a difference between normal and                
# parallel makes. Needs 2 .c files, create them using                          
#       echo "int a() { return 'a'; }" >a.c                                    
#       echo "int b() { return 'b'; }" >b.c                                    
# Build the library using "make", then observe that                            
# touch a.c; make       # Correctly updates the library                        
# touch a.c; make -j2   # Fails to update the library                          

LIB=    libtest.a
OBJ=    a.o b.o

$(LIB): $(LIB)($(OBJ))
        ar cru $(LIB) $(.OODATE)
        ranlib $(LIB)
        rm $(.OODATE)
 
I don't know all the answers - being a bit rusty with make but perhaps some of this will help. The "traditional" BSD way to write the Makefile you look like you want is:

Code:
LIB=    test
SRCS=   a.c b.c

.include <bsd.lib.mk>

and that seems to work fine with and without -j 2 (as well as easily supporting shared libs, profiling, a clean target etc). You can also get your Makefile to work by making $(LIB) depend on $(OBJ) directly (and removing the rm) rather than using $(LIB)($(OBJ)).

The question of why your Makefile doesn't work is a bit harder. You look to be trying to use make's special support for libraries - in which case you need to indicate a .a file is a library by using:

Code:
.LIBS: .a

If you do that the dependencies in your Makefile work, even with -j, but make cores. That is no doubt a bug but I haven't tried to track it down. Why you get the behaviour you see without using .LIBS i.e. differences between -j and non -j I'm not sure. I initially thought it must be a race condition but it occurs even when using -j 1. What I did find was it hinges on the fact you are missing a rule to tell make how to go from a .o file to a .a file containing the .o file. This would be a .o.a suffix rule (see chapter 4.2 of the PMake tutorial). As make has no way of updating the .a even when the .o had to be updated it doesn't bother and just pretends to anything that depended on that step that it was up to date all along. If you put in a .o.a suffix rule everything works as expected. An example rule could do nothing at all …it just needs to exist. e.g.

Code:
.o.a:
	echo hello world

That doesn't explain the whole -j/non-j thing however, but hopefully it's enough to get you going and perhaps someone else will come along and elucidate us both.

HTH,

Andrew
 
Back
Top