Search code examples
makefilegnu-maketarget

How do I use a file from only one of two directories when writing a generic make target?


I'm trying to do something akin to this:

obj/32/%.o: src/all/%.c src/$(ARCH)/%.c
        @mkdir -p obj/32 || true
        $(CC) $(CFLAGS) -m32 -c $< -o $@
        objcopy --strip-unneeded $@

I would expect this to check if src/all/<file>.c exists, and if it doesn't, use src/$(ARCH)/<file>.c instead.

However, it doesn't work. It tries to make a target called obj/32/%.o with the dependencies src/all/%.c and src/$(ARCH)/%.c.

How do I do something like this?


Solution

  • I would expect this to check if src/all/<file>.c exists, and if it doesn't, use src/$(ARCH)/<file>.c instead.

    In this case one option is to create a symlink to one of these files:

    src/<file>.c : # no dependencies
        test -f src/all/<file>.c && ln -fs src/all/<file>.c $@ || ln -fs src/$(ARCH)/<file>.c $@
    

    And then use that symlink instead:

    obj/32/%.o : src/<file>.c | obj/32
        $(CC) $(CFLAGS) -m32 -c -o $@ $<
        objcopy --strip-unneeded $@
    
    obj/32 :
        mkdir -p $@ || true
    

    In the above it uses order-only dependency on the directory, so that the directory is a regular make target.


    Alternatively, use vpath:

    vpath %.c src/all
    vpath %.c src/$(ARCH)
    
    obj/32/%.o: %.c
            @mkdir -p obj/32 || true
            $(CC) $(CFLAGS) -m32 -c $< -o $@
            objcopy --strip-unneeded $@
    

    There may be errors in the above, as I cannot test it, but you should get the idea.