Pattern rule with files in different directories? - makefile

I have the following pattern rule that I wrote after some struggle
%.o : $(addprefix $(SRCDIR),$(notdir $(#:.o=.f90)))
$(COMPILE) $(addprefix $(SRCDIR),$(notdir $(#:.o=.f90))) -o $#
SRCDIR is where the corresponding source code files are found. Object files and source code files are in separate directories and the object file names contain their path. So, for each object file, the source code file name is obtained by text substitution and prefixed with SRCDIR.
How can I do this more concisely?
Thank you.

Your question is slightly unclear, but perhaps this is what you're looking for:
$(OBJDIR)/%.o: $(SRCDIR)/%.f90
$(COMPILE) $< -o $#

Related

GNU make: create targets baed on specific directory contents (1:1 target-directory mapping)

I have a series of directories organized like this:
foo/
foo.file1 foo.file2
bar/
bar.file1 bar.file2
baz/
baz.file1 baz.file2
Right now I'm processing these files using a script that does all the checking for file existence etc but I thought that perhaps I could use a Makefile for it (since said script is very fragile), to avoid reprocessing files that did not change.
The problem is that each directory is independent, and I'd need to do, for example:
foo.file1.processed: foo.file1
run_random_program foo.file1 -o foo.file1.processed
for each of the 71 directories that are in total in that path. This looks like being extremely tedious and I wonder if there's something that would prevent me from writing all of this by hand.
Is such a thing possible?
EDIT: Some examples that show what I have in mind, had I a single Makefile for each directory:
file1.cds.callable: file1.callable
long_script_name -i $< -o $#
file1.rds: file1.cds.callable
another_long_script_name $< additional_file_in_folder $#
file1.csv: file1.rds
yet_another_script $< $#
Seems like pattern rules are exactly what you need:
# These are the original source files (based on the example)
CALLABLE := $(wildcard */*.callable)
# These are the final targets
TARGETS := $(CALLABLE:%.callable=%.csv)
all: $(TARGETS)
%.csv : %.rds
yet_another_script $< $#
%.rds: %.cds.callable
another_long_script_name $< additional_file_in_folder $#
%.cds.callable: %.callable
long_script_name -i $< -o $#

Makefile pattern matching not working as I expected

I'm trying to setup a simple Makefile for building a simple project that's not too hard to maintain.
I want to make use of pattern matching rules e.g. %.o : %.c ; g++ ... where I have all the object files I would want to compile deduced from wildcard matched source files.
The directory structure is
./src
./include
./build/bin
./build/objs
Right now my problem looks something like this.
INCL_DIR = ./include
SRC_DIR = ./src
BUILD_DIR = ./build
BIN_DIR = $(BUILD_DIR)/bin
OBJ_DIR = $(BUILD_DIR)/objs
SRCS = $(notdir $(wildcard $(SRC_DIR)/*.cc))
OBJS = $(addprefix $(OBJ_DIR)/, $(SRCS:%.cc=%.o))
$(BIN_DIR)/program : $(OBJS)
$(CXX) $(CXXFLAGS) -I $(INCL_DIR) $^ -o $#
$(OBJS):%.o : %.cc
$(CXX) $(CXXFLAGS) -I $(INCL_DIR) -c $< -o $#
In the line $(OBJS):%.o : %.cc an example expansion would be from target rule ./build/objs/a.o that depends on ./build/objs/a.cc but the source file is in ./src/a.cc.
So I figured I could strip away the dependency format to try and match ./src/a.cc but the utilies for text manipulations don't seem to work on the dependency side of a rule.
I tried something like
$(OBJS):%.o : $(SRC_DIR)/$(notdir %.cc)
or
$(OBJS):%.o : $(SRC_DIR)/$(*F).cc
where $(*F) would expand to a in the earlier example case but it doesn't expand to anything when listed as a dependency.
I'm not experienced with Makefiles and not sure why my attempts arent working and would very much like to hear a solution that might solve my issue.
Thanks.
The solution is already in #John's comment. I will try to explain it in bit more detail. I will use an example with hello.cc in folder src.
pattern rules hold the pattern in % symbol. If there is in the makefile a pattern rule: build/objs/%.o : src/%.cc and you request to build file build/objs/hello.o, % will carry value hello. But if your pattern rule would be $(OBJS):%.o : %.cc, the pattern % will be build/objs/hello and the dependency file build/objs/hello.cc is missing (because it is saved in src, not in build/objs).
So solution for you would be:
$(OBJS):$(OBJ_DIR)%.o : $(SRC_DIR)%.cc
$(CXX) $(CXXFLAGS) -I $(INCL_DIR) -c $< -o $#
If you want to make sure how patterns work, you can print pattern content by adding line #echo $* to recipe.

Passing target name in dependencies which can be formatted in a makefile

What I would like to do is to get the target name in the dependency and be able to format it.
For example if the target is Objs/foo.o I would like to make the dependency to Sources1/foo.c, I tried doing this
$(filter %.o,$(OBJS)): $(filter %/$(patsubst %.o,%,$(notdir $#)).cpp, $(SRCS))
but none of them works. Where OBJS is a list of object files ex. Objs/foo.o Objs/moo.o etc..
Any help would be greatly appreciated. And SRCS is a list of different directories were sources can be located. Example Sources1/ and Sources2/ where I need to search in both those directories to find where the source is.
Using the vpath directive could take care of your issue. Here's an example:
OBJS:=Objs/foo.o Objs/bar.o
all: $(OBJS)
# This tells make to search for %.c files in Sources1 and Sources2.
vpath %.c Sources1 Sources2
$(filter %.o,$(OBJS)): Objs/%.o : %.c
#echo $# $^
When I run it here with foo.c in Sources1 and bar.c in Sources2, I get the following output:
Objs/foo.o Sources1/foo.c
Objs/bar.o Sources2/bar.c

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

Object file directory per compiler option combinations

I was reading gnu make section 10.5.4 "How patterns match" and it does not sound like I can do what I want.
I want to setup a directory structure where my source code is in one directory, and there are sub-directories to hold object files.
One sub-directory for each build configuration.
So I might have these files
a.c
debug/a.o # compiled with -g
release/a.o # compiled with -O
So I would like to make rules like this
debug/%.o : %.c
gcc -c -g %.c -o $#
release/%.o : %.c
gcc -c -O %.c -o $#
But section 10.5.4 tells me a match on "debug/a.o" will make the stem be "debug/a" so gnu make
will look for the source file at "debug/a.c" which is not what I want.
Is there a way to get GNU make to help me ?
Your makefile will work as written.
From that section of the manual:
When the target pattern does not contain a slash (and it usually does
not), directory names in the file names are removed from the file name
before it is compared with the target prefix and suffix. After the
comparison of the file name to the target pattern, the directory
names, along with the slash that ends them, are added on to the
prerequisite file names generated from the pattern rule's prerequisite
patterns... [bold added]
Your target patterns do contain slashes.
Try it if you don't believe me.
EDIT:
Correction: in the commands you should use $< rather than %.c.
CC=gcc
DEBUGFLAGS=-g
RELEASEFLAGS=-O
debug/%.o : %.c
$(CC) $(DEBUGFLAGS) -c $< -o $#
release/%.o : %.c
$(CC) $(RELEASEFLAGS) -c $< -o $#

Resources