Search code examples
makefile

how to factorise makefile targets?


I have the following 'working' snippet:

c_file_path := toto.c
asm_file_path := toto.S

c_files = $(notdir $(c_file_path)) 
asm_files = $(notdir $(asm_file_path)) 

vpath %.c $(dir $(c_file_path)) 
vpath %.S $(dir $(asm_file_path))

OBJDIR=objs/
c_objs:=$(addprefix $(OBJDIR),$(patsubst %.c,%.o,$(c_files)))
asm_objs:=$(addprefix $(OBJDIR),$(patsubst %.S,%.S.o,$(asm_files)))


$(info c_files $(c_files))
$(info s_files $(asm_files))
$(info c_objs $(c_objs))
$(info asm_objs $(asm_objs))

%.c:
    @touch $@
%.S:
    @touch $@

objs/%.o:%.c
    @mkdir -p  $(OBJDIR)
    @gcc -c $^ -o $@

objs/%.S.o:%.S
    @mkdir -p  $(OBJDIR)
    @gcc -c $^ -o $@

clean:
    @rm -rf objs/*
    
all: $(c_objs) $(asm_objs)
    @ls $(c_objs) $(asm_objs)
    @echo "hello"

I tried to merge targets:

c_file_path := toto.c
asm_file_path := toto.S

c_files = $(notdir $(c_file_path)) 
asm_files = $(notdir $(asm_file_path)) 

vpath %.c $(dir $(c_file_path)) 
vpath %.S $(dir $(asm_file_path))

OBJDIR=objs/
c_objs:=$(addprefix $(OBJDIR),$(patsubst %.c,%.o,$(c_files)))
asm_objs:=$(addprefix $(OBJDIR),$(patsubst %.S,%.S.o,$(asm_files)))


$(info c_files $(c_files))
$(info s_files $(asm_files))
$(info c_objs $(c_objs))
$(info asm_objs $(asm_objs))


%.c %.S:
    @touch $@

objs/%.o objs/%.S.o:%.c %.S
    @mkdir -p  $(OBJDIR)
    @gcc -c $^ -o $@

clean:
    @rm -rf objs/*
    
all: $(c_objs) $(asm_objs)
    @ls $(c_objs) $(asm_objs)
    @echo "hello"

which gives:

gcc: error: toto.c no such file or directory

why weren't target merged?

how to merge targets?


Solution

  • I'm not sure what you're trying to do but this rule:

    objs/%.o objs/%.S.o:%.c %.S
    

    tells make that for two files foo.c and foo.S (for any string foo) they can be used to create the targets objs/foo.o and objs/foo.S.o by invoking the recipe (gcc) one time.

    I'm pretty sure that that's not what you want to say because it means you can't use this pattern unless both files foo.c and foo.S exist for a given string foo.

    If what you're asking is how to reduce these two pattern rules:

    objs/%.o:%.c
            @mkdir -p  $(OBJDIR)
            @gcc -c $^ -o $@
    
    objs/%.S.o:%.S
            @mkdir -p  $(OBJDIR)
            @gcc -c $^ -o $@
    

    into a single pattern rule so you don't have to write it twice the answer is very simple:

    You can't.

    You could put the recipe into a variable, like this:

    build = @mkdir -p  $(OBJDIR) && gcc -c $^ -o $@
    

    then you can simplify the pattern rules somewhat like this:

    objs/%.o : %.c ; $(build)
    objs/%.S.o : %.S ; $(build)
    

    but that's the best you can do, without resorting to overly-complicated things like foreach/eval/call loops etc.