Wug
Wug

Reputation: 13196

Bizarre behavior observed in make 3.81 when attempting to use a reassigned variable as a dependancy

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 $(OBJ_CURRENTMOD) 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.

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)

Upvotes: 1

Views: 142

Answers (2)

Jonathan Wakely
Jonathan Wakely

Reputation: 171383

As I said in one of my comments, I don't see how the $(LIBDIR)%.so pattern will match any pre-requisite of modulename but assuming metrics.so is meant to be lib/metrics.so then it will be used to build lib/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)

Upvotes: 1

interjay
interjay

Reputation: 110155

You are using the target-specific variable value OBJ_CURRENTMOD in the prerequisite list of the $(LIBDIR)%.so rule. This is not allowed: Target-specific variables may only be used in the recipe of a target.

Another issue is that you are defining the variable OBJ_MODULENAME and later accessing a different variable $(OBJMOD_MODULENAME), which hasn't been assigned to.

Upvotes: 1

Related Questions