Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 745
shark1987 Avatar asked Dec 31 '25 17:12

shark1987


1 Answers

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).

like image 129
shark1987 Avatar answered Jan 03 '26 13:01

shark1987



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!