Search code examples
makefileprerequisites

Variables in makefile prerequisites


Is it possible to use makefile variables in prerequisites? My example below is a little backward, but should demonstrate what I'm trying to achieve:

objects_subsystem1 := $(patsubst %.c,%.o,$(wildcard ../src/ss1/*.c))
objects_subsystem2 := $(patsubst %.c,%.o,$(wildcard ../src/ss2/*.c))

all : subsystem1.elf subsystem2.elf

%.elf : $(objects_%)
    $(LD) $< -o $@

EDIT: I'm using GNU Make 3.80 so unfortunately SECONDEXPANSION is not available!


Solution

  • Yes, if you're using GNUMake:

    .SECONDEXPANSION:
    %.elf : $$(objects_%)
        $(LD) $< -o $@
    

    EDIT:

    As @bobbogo points out, there is a solution that does not require .SECONDEXPANSION. First, we spell out the rules:

    objects_subsystem1 := $(patsubst %.c,%.o,$(wildcard ../src/ss1/*.c))
    objects_subsystem2 := $(patsubst %.c,%.o,$(wildcard ../src/ss2/*.c))
    objects_subsystem3 := $(patsubst %.c,%.o,$(wildcard ../src/ss3/*.c))
    
    all : subsystem1.elf subsystem2.elf subsystem3.elf
    
    subsystem1.elf : $(objects_subsystem1)
        $(LD) $< -o $@
    subsystem2.elf : $(objects_subsystem2)
        $(LD) $< -o $@
    subsystem3.elf : $(objects_subsystem3)
        $(LD) $< -o $@
    

    Then we rearrange things a little:

    objects_subsystem1 := $(patsubst %.c,%.o,$(wildcard ../src/ss1/*.c))
    all : subsystem1.elf
    subsystem1.elf : $(objects_subsystem1)
    objects_subsystem2 := $(patsubst %.c,%.o,$(wildcard ../src/ss2/*.c))
    all : subsystem2.elf
    subsystem2.elf : $(objects_subsystem2)
    objects_subsystem3 := $(patsubst %.c,%.o,$(wildcard ../src/ss3/*.c))
    all : subsystem3.elf
    subsystem3.elf : $(objects_subsystem3)
    
    %.elf :
        $(LD) $< -o $@
    

    Then we use the eval function:

    define RULE_TEMPLATE
    objects_subsystem$(1) := $(patsubst %.c,%.o,$(wildcard ../src/ss$(1)/*.c))
    all : subsystem$(1).elf
    subsystem$(1).elf : $$(objects_subsystem$(1))
    endef
    
    $(eval $(call RULE_TEMPLATE,1))
    $(eval $(call RULE_TEMPLATE,2))
    $(eval $(call RULE_TEMPLATE,3))
    
    %.elf :
        $(LD) $< -o $@
    

    Then finish up with a loop (if it's worth it):

    define RULE_TEMPLATE
    objects_subsystem$(1) := $(patsubst %.c,%.o,$(wildcard ../src/ss$(1)/*.c))
    all : subsystem$(1).elf
    subsystem$(1).elf : $$(objects_subsystem$(1))
    endef
    
    SUBSYSTEMS := 1 2 3 # this can be made automatic...
    
    $(foreach sys,$(SUBSYSTEMS),$(eval $(call RULE_TEMPLATE,$(sys))))
    
    %.elf :
        $(LD) $< -o $@