Makefile always executes even though it shouldn't - makefile

makefile noob here, my makefile always executes every recipe even though the files are up to date. Here is my code:
vpath *.pdf ../../../Figures/Arrowshape/ChemicalNoise
.PHONY : all clean
all : Fig_VP-CN-Revols_MeanfromDist_Dac0.0_F0.0-4.0_0to2.pdf\
Fig_VP-CN-Revols_MeanfromDist_Dac0.0_F0.0-4.0_2to4.pdf\
Fig_VP-CN-Revols_MeanfromDistImshow_Dac0.0_F0.0-4.0.pdf
Fig_%.pdf : %.py
$(warning Building $# )
python $<
Fig_%_2to4.pdf : %.py
$(warning Building $# )
python $<
Fig_%_0to2.pdf : %.py
$(warning Building $# )
python $<
clean:
rm all
I checked that the pdf files are put in the correct folder and the names match. What is wrong with my syntax?
Also, I know that my clean does not work, how would I make it work though?

When you say "put in the correct folder", which folder is that?
It's clearly not the local directory, because if it were your makefile would work.
The first thing wrong is you have the wrong syntax for vpath. See the manual; vpath takes a makefile pattern (that is a string with zero or one % character); it doesn't support shell globbing like *.h. This should be written:
vpath %.pdf ../../../Figures/Arrowshape/ChemicalNoise
However, even with that fix your makefile won't work as you hope, because vpath is not intended to find targets. It's intended to find source files (that is, files that are not created by make).
If you want to understand this deeply you can read http://make.mad-scientist.net/papers/how-not-to-use-vpath/
To get your makefile to work as you want you'll have to add in paths, like this:
OUTDIR = ../../../Figures/Arrowshape/ChemicalNoise
all : $(OUTDIR)/Fig_VP-CN-Revols_MeanfromDist_Dac0.0_F0.0-4.0_0to2.pdf\
$(OUTDIR)/Fig_VP-CN-Revols_MeanfromDist_Dac0.0_F0.0-4.0_2to4.pdf\
$(OUTDIR)/Fig_VP-CN-Revols_MeanfromDistImshow_Dac0.0_F0.0-4.0.pdf
$(OUTDIR)/Fig_%.pdf : %.py
$(warning Building $# )
python $<
$(OUTDIR)/Fig_%_2to4.pdf : %.py
$(warning Building $# )
python $<
$(OUTDIR)/Fig_%_0to2.pdf : %.py
$(warning Building $# )
python $<

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 $#

Make: Target name in Rule

I have created a Makefile to generate pdf and html for a md file mentioned while invoking make like make a.md should generate a.pdf and a.html, and should not convert other md files present in the directory.
My make file
But I am, getting error Nothing to be done for a.md
Could you please suggest changes?
Because a.md is already in place, make indeed does have nothing further to do. You can either just use for instance a as the specified target (which can depend on pdf and html files as prerequisites). Or pass the desired source through a variable and determine your desired target from that.
One (the latter) option would be this:
EXPORTED= $(SOURCE:%.md=%.html) $(SOURCE:%.md=%.pdf)
%.html : %.md
pandoc -o $# $<
%.pdf : %.md
pandoc -o $# $<
all: $(EXPORTED)
Which you can call with make SOURCE=a.md.
The other option (former):
%.html : %.md
pandoc -o $# $<
%.pdf : %.md
pandoc -o $# $<
.PHONY: $(MAKECMDGOALS)
$(MAKECMDGOALS): $(MAKECMDGOALS:%=%.html) $(MAKECMDGOALS:%=%.pdf)
Allows you to call make a.
But to reiterate. You cannot use (existing) source as a target, because make would (as it did) conclude it's done making that target.
Except (but I personally do not really like this as it is IMO confusing), if you insisted, you could do a variation on the previous take... but work with *.md targets... which you all declare as .PHONY. I.e. not real files and always to be considered/remade:
%.html : %.md
echo pandoc -o $# $<
%.pdf : %.md
echo pandoc -o $# $<
.PHONY: $(MAKECMDGOALS)
$(MAKECMDGOALS): $(MAKECMDGOALS:%.md=%.html) $(MAKECMDGOALS:%.md=%.pdf)
Now you could indeed call make a.md. I'd still prefer one of the two above.

Make use Pattern Rule for multiple prerequisites and multiple targets

I have a problem with make and I cannot figure out how to solve it. I would like to transform each file in a sub-directory using a shell script. This is what I wrote:
OBJ=$(wildcard src/*.in)
OUT=$(patsubst %.in, %.out, $(notdir $(OBJ)))
%.out : src/%.in
./myscript.sh $< > $#
$(OUT) : $(OBJ)
The makefile works but it runs the script only for the first .in file and then it stops. Sorry for the dumb question but I cannot fix this!
Because you are not telling the Makefile to build all $(OUT) files, you are just saying how it should be built.
Try instead this
OBJ=$(wildcard src/*.in)
OUT=$(patsubst %.in, %.out, $(notdir $(OBJ)))
all: $(OUT)
%.out : src/%.in
./myscript.sh $< > $#
.PHONY: all

Using % steam inside variables of your Makefiles prerequisites

I often find myself wanting to refer to the stem not in the recipe but int the prerequisites themselves.
For example here I was playing around with some python code that scans the .cpp and .hpp files of the executable source code, in a recursive fashion, to detect what objects it depends from. The script itself works pretty well but I can't figure out how to connect it with the makefile since the input varies.
$(TESTS): bin/tests/%_a : bin/obj/%.o $(foreach var, $(shell python3 ./autoInc.py ./src/lib/%.cpp), bin/obj/$(var).o)
#echo "#---------------------------"
#echo "# Linking $# "
$(CC) -o $# $^
(Here the makefile executes ./autoInc.py ./src/lib/%.cpp without substitution)
This is the form:
.SECONDEXPANSION:
$(TESTS): %_a : $$(foreach var, $$(shell whatever $$*.cpp), $$(var).o)
...
I advise you to get it working with a very simple toy rule, before trying to incorporate your python.

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

Resources