shark1987
shark1987

Reputation: 71

Generic target/rule to build all source files from a list, outputting objects to one directory

I am trying to make one generic target in my makefile that will builds sources from mixed directories and output the object files to on single directory.

We have a source structure that is mixed in various directories (like said above, below is just an example)

SRCS = ../a/b/source1.c \
       b/source2.c \
       ../c/source3.c

But I would like all of the object files to output to the directory ./objs (same directory level as 'b')

To do this I was trying the following

OBJS  = $(addprefix objs/, $(notdir $(SRCS:.c=.o)))

$(OBJS): %.o : $(filter %/$(basename $(notdir %)).c, $(SRCS))
    echo "dependencies: $^" # shows up empty
    $(CC) $(filter %/$(basename $(notdir $@)).c, $(SRCS)) -o $@ # This works and finds the proper source file
    $(CC) $^, $(SRCS)) -o $@ # I would like to use this, but as I said the dependencies show up blank

There is a weird problem with this however, and I don't understand where the problem is.

In the dependency it doesn't match anything, but in the recipe it does match properly.

Now the weird part (for me atleast). If I try and test out by hard coding one of the paths then it match for ALL files in that path

$(OBJS): %.o : $(filter ../a/b/$(basename $(notdir %)).c, $(SRCS)) # matches for all files in "../a/b" directory

But using SECONDEXPANSION and hardcoding the directory it works

.SECONDEXPANSION:
$(OBJS): %.o : $$(filter ../a/b/$$(basename $$(notdir %)).c, $(SRCS))

And also not using SECONDEXPANSION and hardcoding the source file name works

$(OBJS): %.o : $(filter %source1.c, $(SRCS)) # Hardcoding source1.c works for source1.c

But it seems like I can't combine to two do what I want for some reason. I have tried secondexpansion stuff (thoguht I'm not really sure why I would need it in this case) and could never get anything working that way either.

I am trying to avoid manually declaring targets for each file individually i.e. objs/source1.o : ../a/b/source1.c

Because our real world example has tons of files and it would be nice to have less to maintain. I feel like I am very close to getting it.

I am using Cygwin with GNU Make 4.0.

Upvotes: 3

Views: 885

Answers (1)

shark1987
shark1987

Reputation: 71

After googling a few more times I finally came across the fix here:

http://lists.gnu.org/archive/html/help-make/2010-09/msg00062.html

I still don't know exactly why I needed to use the SECONDEXPANSION ($$-ness) at all but in practice it doesn't work without it. But basically I needed to create a variable for the '%' sign. Doing the following works for me.

SRCS = ../a/b/source1.c \
       b/source2.c \
       ../c/source3.c

OBJS  = $(addprefix objs/, $(notdir $(SRCS:.c=.o)))

.SECONDEXPANSION:
PERCENT = %

$(OBJS): %.o : $$(filter $$(PERCENT)/$$(notdir %).c, $(SRCS))
    $(CC) $< -o $@

This now builds source1.c, source2.c, and source3.c and outputs the object files into the objs/ directory.

What I didn't mention in my question but I knew all along was that this will only work if you have unique file names for all source files. But we are okay with that limitation (obviously).

Upvotes: 3

Related Questions