Makefile: no target error even when target and dependency exist - bash

My makefile:
./corpus/%.spacy : ./assets/%.json
python3 ./scripts/convert.py $< $#
Two questions:
Even if A.spacy and A.json exist and A.json is updated more recently than A.spacy, I get the following output.
$ make
$ make: *** No targets. Stop.
What to add to have it make A.spacy if only A.json exists? I tried the below code, which didn't work and I feel I'm not fully understanding targets and dependencies in makefiles.
convert : ./corpus/%.spacy
python3 ./scripts/convert.py $(./scripts/$*.json) $<
./corpus/%.spacy: ./assets/%.json
echo $?
Didn't work as in gave the following output
$ make convert
$ make: *** No rule to make target `corpus/%.spacy', needed by `convert'. Stop.

You seem to be thinking that declaring a pattern rule will cause make to go spelunking your directory looking for all possible ways to use that pattern, as if it were a wildcard or something akin to ls *.spacy.
That's not what a pattern rule is.
A pattern rule is a template that make can apply if it wants to build a given target and it doesn't know how to build that target.
If you have the above makefile it just tells make "hey, if you happened to want to create a target that matches the pattern ./corpus/%.spacy then here's a way to do it". If you type make with no arguments, then you haven't told make that you want to build anything so it won't use your pattern rule.
If you type:
$ make ./corpus/A.spacy
now you've told make you want to actually build something (./corpus/A.spacy), so now make will try to build that thing, and it will see your pattern rule and it will try to use it.
As for the other, this:
convert : ./corpus/%.spacy
python3 ./scripts/convert.py $(./scripts/$*.json) $<
is not a pattern rule. A pattern rule must have a pattern character (%) in the target; this is defining a target convert that depends on a file named, explicitly, ./corpus/%.spacy of which you don't have any file with that name, so you get that error.
You didn't actually describe what you wanted to do, but I think maybe you want to do something like this:
# Find all the .json files
JSONS := $(wildcard ./assets/*.json)
# Now figure out all the output files we want
SPACYS := $(patsubst ./assets/%.json,./corpus/%.spacy,$(JSONS))
# Now create a target that depends on the stuff we want to create
all: $(SPACYS)
# And here's a pattern that tells make how to create ONE spacy file:
./corpus/%.spacy : ./assets/%.json
python3 ./scripts/convert.py $< $#

Related

How can you make a % wildcard make rule phony?

I have the following wildcard "programming" make rule that uploads a binary to a device. This obviously does not produce a real file, so should be marked phony. However, how do you mark a % percent wildcard rule phony?
%-tangnano-prog: %-tangnano.fs
openFPGALoader -b tangnano $^
.PHONY: %-tangnano-prog clean all
The phony rule does not give any error whatever you put there, so hard to tell if it worked. But I believe it did not:
$ touch blinky-tangnano-prog
$ make blinky-tangnano-prog
make: 'blinky-tangnano-prog' is up to date.
Thee are basically two possibilities:
You know in advance what %-tangnano-prog targets you can encounter. Just assign all their prefixes to a make variable, use make functions to compute the full target names and declare them as phony:
P := blinky foo bar
T := $(addsuffix -tangnano-prog,$(P))
.PHONY: tangnano-prog $(T)
tangnano-prog: $(T)
%-tangnano-prog: %-tangnano.fs
openFPGALoader -b tangnano $^
You do not know in advance what targets you can encounter. Use the same Makefile but pass the list of target prefixes to build on the command line:
$ make tangnano-prog P="blinky foo bar"

Target dependency: Makefile no rule to make target error

Here is the make file that I am running,
.PHONY: build
build: pre_build_script $(OUTPUTDIR)/%.cpp
$(OUTPUTDIR)/%.cpp: $(INTXTDIR)/%.txt
python.exe $(SOMEDIR)/somepythonscript.py $(INTXTDIR) $(OUTPUTDIR)
.PHONY: pre_build_script
pre_build_script:
pythonscript.exe $(PREBUILDDIR)
This is the output that I get:
$ make build
pythonscript.exe $(SAMPLEDIR)
make: *** No rule to make target '../obj/CPP/%.cpp', needed by 'build'. Stop.
Looks like I'm missing on some sytanx as I get this error inspite of declaring the target dependency. Any suggestions?
This means make cannot find a file named $(OUTPUTDIR)/%.cpp, a prerequisite for the first rule.
You cannot use % as a wildcard anywhere in a rules like this:
build: pre_build_script $(OUTPUTDIR)/%.cpp
it needs to be a part of pattern rule or a static pattern rule.
You can use $(wildcard $(OUTPUTDIR)/*.cpp) to get a complete list of files, but it's an anti-pattern (pun intended). You are supposed to either exactly know what files are used in what rules, or (know it even better and) create a generic pattern rule.
The second pattern rule (one using somepythonscript.py) is supposed to work on a single source-target file pair, $(INTXTDIR)/%.txt -> $(OUTPUTDIR)/%.cpp. The command seems to process all the files in the directory, which is not incremental: it will redo all the work even if only one file was updated.

make .SECONDEXPANSION recipe execute twice

Using GNU make, I am trying to solve a problem similar to make recipe execute twice — that is, to have a Makefile recipe run twice. In my case, however, the recipe is run under the .SECONDEXPANSION target, and the two different runs will be called with different parameters to generate different versions of the output file from the same input file. That is, with input file foo, this example Makefile should be callable via make foo.pdf or make foo.expanded.pdf to build one .pdf file, or make all to build both .pdf files:
.PHONY: all
all: foo.pdf foo.expanded.pdf
.SECONDEXPANSION:
%.expanded.pdf %.pdf: %
#echo building $(basename $#)
Of the two solutions given in that answer, the first is unsuitable because it always runs the rule twice; I want it run twice when the user asks for it.
The second solution posted there is conceptually what I am looking for and have implemented in the above example Makefile, with only the small problem that it doesn't work: although the all target lists both .pdf files as dependencies, only one is built when make all is run.
Is there a way to tell GNU make to build two different files using the same rule under a .SECONDEXPANSION?
EDIT: Clarified in problem description that the same input file is used to build both versions of the output file, and modified sample Makefile to include this dependency.
EDIT: I would like a solution as scalable as possible; that is, it should work if the input filename contains dots, specifying additional output file foo.reduced.pdf should require only adjusting the targets and recipe as appropriate, etc. This limits performing string surgery that relies on the filenames appearing exactly as given in this narrow example (e.g., changing the rule to %.pdf: $$(firstword $$(subst ., ,$$*)) fails if the input file could be either foo or foo.bar).
You are probably looking for Pattern-specific Variable Values. Let's assume your recipe depends on a make variable named BUILDFLAGS that takes value normal by default and special for the "expanded" targets. Then this Makefile:
BUILDER := builder
BUILDFLAGS := normal
.PHONY: all
all: foo.pdf foo.expanded.pdf
%.expanded.pdf: BUILDFLAGS := special
%.pdf:
$(BUILDER) $(BUILDFLAGS) $#
should do about what you want with the same rule for all targets, plus one pattern-specific variable value declaration. Replace builder, normal and special with what makes sense in your case. Demo:
$ make foo.pdf
builder normal foo.pdf
$ make foo.expanded.pdf
builder special foo.expanded.pdf
$ make
builder normal foo.pdf
builder special foo.expanded.pdf
Your problem has nothing to do with .SECONDEXPANSION. You can just drop that and the problem will be the same.
Your problem is that you are using a pattern rule with multiple target patterns, and expecting that it works similar to an explicit rule with multiple targets. But it does not (and in fact you cannot have a rule with both pattern and explicit targets).
For a pattern rule with multiple target patterns, Make matches the same pattern to all the %, including multiple times in the targets, and then assumes that it just has to execute the recipe with that pattern once, and it will make all the matched targets.
In your case the best way is to use multiple rules (I changed your recipe because using echo as a Make recipe is a bad idea):
.PHONY: all
all: foo.expanded.pdf foo.pdf
RECIPE = touch $#
%.expanded.pdf:
$(RECIPE)
%.pdf:
$(RECIPE)

makefile: from 3 input generate one output

I have this version of makefile
[sbsuser#compute-00-01 415]$ make --version GNU Make 3.81
I have directory SOMATIC where I have 3 file . I want to produce a only one output. This is what I wrote.
`
OUTSOMATIC=SOMATIC
FINAL=FINAL
INPUT=$(wildcard $(OUTSOMATIC)/*.vcf)
OUTSORT2= $(patsubst $(OUTSOMATIC)/%.vcf,$(FINAL)/%somatic.ensemble.gz,$(INPUT))
$(info lista $(OUTSORT2))
$(info lista $(INPUT))
.PHONY: all
all: $(INPUT) $(OUTSOMATIC) $(OUTSORT2) $(FINAL)
$(FINAL)/%somatic.ensemble.gz: $(OUTSOMATIC)/%.vcf $(INPUT)
~/jdk1.8.0_121/bin/java -XX:+UseSerialGC -Xms1g -Xmx10g -jar /illumina/software/PROG2/bcbio-variation-recall-0.1.7 ensemble -n 1 $(FINAL)/somatic_ensemble.gz /illumina/software/database/database_2016/hg19_primary.fa $^
`
With this script make 3 time the same files. I don't understand how to create only one output from list of input to use in the same time.
What is the best way to do this?
If I change $(FINAL)/%somatic.ensemble.gz: in $(FINAL)/somatic.ensemble.gz I have this error:
make: *** No rule to make target FINAL/415_merge_mutect2.somaticsomatic.ensemble.gz', needed byall'. Stop`
You probably should review the GNU make manual introductory sections where they describe how make works.
Let's look at your makefile; first you define some variables. Let's assume that you have the files SOMATIC/foo.vcf, SOMATIC/bar.vcf, and SOMATIC/baz.vcf. Then the variables you created will have these values, after they are expanded:
OUTSOMATIC = SOMATIC
FINAL = FINAL
INPUT = SOMATIC/foo.vcf SOMATIC/bar.vcf SOMATIC/baz.vcf
Now your patsubst finds all words in INPUT that match the pattern SOMATIC/%.vcf and replace that with FINAL/%somatic.ensemble.gz, where the part that matches the % in the input is substituted into the output:
OUTSORT2 = FINAL/foosomatic.ensemble.gz FINAL/barsomatic.ensemble.gz FINAL/bazsomatic.ensemble.gz
Now, make sees that you've defined an all target. Since it's the first target in the makefile this is the target that will be run by default. After expansion, it will look like this:
all: SOMATIC/foo.vcf SOMATIC/bar.vcf SOMATIC/baz.vcf SOMATIC FINAL/foosomatic.ensemble.gz FINAL/barsomatic.ensemble.gz FINAL/bazsomatic.ensemble.gz FINAL
So, make will try to build every prerequisite of the all target to be sure it's up to date. First it tries to build the SOMATIC/*.vcf files. Those files already exist and make doesn't have any rules about how to rebuild them, so it assumes they're up to date.
Next it tries to build the SOMATIC file. This is a directory and it also has no rule to be built, so make assumes that's up to date as well.
Next make tries to build the target FINAL/foosomatic.ensemble.gz. Make does have a rule that can build it, you've created one:
$(FINAL)/%somatic.ensemble.gz: $(OUTSOMATIC)/%.vcf $(INPUT)
~/jdk1.8.0_121/bin/java ...
This matches the target you want to build, with a % value of foo, so then make substitutes the % in the prerequisite for foo and finds that SOMATIC/foo.vcf exists and doesn't need to be rebuilt, so it runs your recipe. However your recipe doesn't actually create the target FINAL/foosomatic.ensemble.gz; it creates the target FINAL/somatic_ensemble.gz. So this rule is broken because it tells make it will do one thing, but it does something else.
You should always ensure all your recipes build the file represented by the automatic variable $#; that will ensure that you and make agree on the meaning of your rule. If you want your recipe to build some other file, then your rule is written incorrectly.
Next make does the same thing with the next prerequisite of all: FINAL/barsomatic.ensemble.gz. Since that file doesn't exist, make tries to build it using the pattern rule, but again that creates the same output file.
And again for the third .gz file FINAL/bazsomatic.ensemble.gz. That's why things are run three times.
If you change the pattern rule to an explicit rule building FINAL/somatic.ensemble.gz, which is what you want, then make can't find any way to build the prerequisites of the all target so it gives this error.
Your problem is the creation of OUTSORT2. You want to create only one output file, but you've set OUTSORT2 to contain three different files, so make tries to create all three files. You want this:
OUTSOMATIC = SOMATIC
FINAL = FINAL
INPUT = $(wildcard $(OUTSOMATIC)/*.vcf)
OUTSORT2 = $(FINAL)/somatic.ensemble.gz
.PHONY: all
all: $(OUTSORT2)
$(OUTSORT2): $(INPUT)
~/jdk1.8.0_121/bin/java -XX:+UseSerialGC -Xms1g -Xmx10g -jar /illumina/software/PROG2/bcbio-variation-recall-0.1.7 ensemble -n 1 $# /illumina/software/database/database_2016/hg19_primary.fa $^

Using Make with force snippet to override other file

I've been trying to get a makefile, a, to include another makefile, b, if the target specified is not found in file a. I'm using this snippet to try and achieve this, but from echos I've put into the file I can see that makefile b is being accessed even when the target is found in a and run.
The snippet I'm using from the link above is:
foo:
frobnicate > foo
%: force
#echo "No target found locally, running default makefile"
#$(MAKE) -f Makefile $#
force: ;
Specifically I'm getting "Nothing to be done" outputs when makefile b is being used, and makefile a is behaving as expected. This is shown below:
$ make all # all target appears in both make files
No target found locally, running default makefile
make[1]: Entering directory `/home/user/currdir' # (b)
make[1]: Nothing to be done for `Makefile'.
make[1]: Leaving directory `/home/user/currdir'
Local all # (a)
Is there a better way to be doing this?
addition: After adding another echo to the % rule, I've found that $# is "Makefile", when it should be the target trying to be built.
I don't really understand your question based on the example you gave; there is no "a" or "b" in that example, just one Makefile.
However, the behavior you're seeing is due to GNU make's re-making makefiles capability. When you create match-anything pattern rules as you've done, you have to consider that every single target or prerequisite that make wants to build will match that rule. That's a large burden.
You can avoid having remade makefiles match by creating explicit rules for them, such as:
Makefile: ;

Resources