I’m running into a bizarre problem with a C++ makefile. I rewrote it this afternoon because the old one I was using made me want to kill myself, and I’m running into a weird problem regarding variable reassignment and dynamic dependancies.
for the purposes of this question, assume the following values:
OBJMOD_MODULENAME = obj/lib/foo.o obj/lib/bar.o obj/lib/quux.o
LIBDIR = lib/
CXX = g++
CXXLIBLINK = -shared
LIB = -lm -lpt
I have a target of the following format:
modulename: OBJ_CURRENTMOD = $(OBJMOD_MODULENAME)
modulename: $(OBJMOD_MODULENAME) lib/metrics.so
and later on, another of the following format:
$(LIBDIR)%.so: $(OBJ_CURRENTMOD)
$(CXX) $(CXXLIBLINK) -o $@ $(OBJ_CURRENTMOD) $(LIB)
Lines in code blocks always appear in the order in which they are presented in the code blocks, however over the course of debugging I have changed the position of the blocks relative to each other.
The problem occurs after I change a source file and try to recompile with ‘make modulename’. Building the object files works as expected, but rebuilding the library does not happen if the file already exists, i.e. the dependencies specified by $(OBJ_CURRENTMOD) are ignored. Using $(OBJMOD_MODULENAME) in the library dependencies works as expected. I have verified in a number of ways that the value of $(OBJ_CURRENTMOD) is as expected (stick echo on the first line of the library target for example), but no matter what I try, the variable does not seem to update in time to trigger a recompile due to dependancy checking.
$(OBJ_CURRENTMOD)
As I was typing this, I found a workaround:
OBJMOD_MODULENAME = obj/lib/foo.o obj/lib/bar.o obj/lib/quux.o
LIBDIR = lib/
CXX = g++
CXXLIBLINK = -shared
LIB = -lm -lpt
modulename: OBJ_CURRENTMOD = $(OBJMOD_MODULENAME)
modulename: $(OBJMOD_MODULENAME) lib/metrics.so
$(LIBDIR)%.so: herp $(OBJ_CURRENTMOD)
$(CXX) $(CXXLIBLINK) -o $@ $(OBJ_CURRENTMOD) $(LIB)
herp: $(OBJ_CURRENTMOD)
This dummy target tacked in before the variable reference seems to force it to update and solves my problem. Is this a bug in make or something? make –version indicates GNU make 3.81. Can anyone else confirm this weird behavior? Am I just doing something horribly stupid? I’ve been staring at it for hours, I wouldn’t be that surprised.
edit: turns out that wasn’t really fixing it, it was just trapping it into running every time regardless of whether or not it needed it.
To verify the altered value:
$(LIBDIR)%.so: $(OBJ_CURRENTMOD)
echo $(OBJ_CURRENTMOD)
$(CXX) $(CXXLIBLINK) -o $@ $(OBJ_CURRENTMOD) $(LIB)
As I said in one of my comments, I don’t see how the
$(LIBDIR)%.sopattern will match any pre-requisite ofmodulenamebut assumingmetrics.sois meant to belib/metrics.sothen it will be used to buildlib/metrics.so.As interjay pointed out, “As with automatic variables, these values are only available within the context of a target’s recipe (and in other target-specific assignments).” They can’t be used in a target pattern or in a list of pre-requisites, which explains why the target doesn’t get rebuilt when one of the pre-requisites in
$(OBJ_MODULENAME)changes.To make
$(OBJ_CURRENTMOD)valid in the prerequisites list you’ll need to use secondary expansion.SECONDEXPANSION: $(LIBDIR)%.so: $$(OBJ_CURRENTMOD) $(CXX) $(CXXLIBLINK) -o $@ $(OBJ_CURRENTMOD) $(LIB)