makefilegnu-make

Define make rule to modify make variable


I'm trying to define a make rule that modifies a make variable, as a way to conditionally compile the code. Something like:

[...]
LD_PREL:=

all: main

main: $(OBJ)
    $(COMP) $(DEBUG) $(FLAGS) $^ -shared -o libname.so $(LIBS)

main_ld: ld_prel_def $(OBJ)
    $(COMP) $(DEBUG) $(FLAGS) $^ -shared -o libname_ld.so $(LIBS)

ld_prel_def:
    $(eval LD_PREL:=-DWITH_LD_PRELOAD)
    echo $(LD_PREL)

$(OBJDIR)/%.o: src/%.c $(DEPS)
    $(COMP) $(DEBUG) $(FLAGS) $(DDEFS) $(TDEFS) $(LD_PREL) $(WARN) -c -fPIC -o $@ $<

From the echo line, it seems that it is working as expected:

echo -DWITH_LD_PRELOAD
-DWITH_LD_PRELOAD

except that the linker than throws error:

/usr/local/bin/ld: cannot find ld_prel_def: No such file or directory
collect2: error: ld returned 1 exit status
make: *** [Makefile:27: main_ld] Error 1

What am I doing wrong?


Solution

  • Oh, I see the problem. This rule:

    main_ld: ld_prel_def $(OBJ)
             $(COMP) $(DEBUG) $(FLAGS) $^ -shared -o libname_ld.so $(LIBS)
    

    uses $^ which resolves to all the prerequisites. One of the prerequisites is your target ld_prel_def which obviously is not a valid object file, so your linker fails.

    You could use:

    main_ld: ld_prel_def $(OBJ)
             $(COMP) $(DEBUG) $(FLAGS) $(filter %.o,$^) -shared -o libname_ld.so $(LIBS)
    

    In general, as with almost any use of $(eval ...) inside recipes, this is a pretty brittle way to write a makefile IMO. What if some of the objects are compiled one way, say without the option, and then you run make main_ld and compile the rest of the objects that aren't up to date the other way? Now you have a mix of some objects built one way and some built the other way.