I have a simple target in my Makefile:
file1:
touch $#
I can build this target using: make file1
It also builds if I say: make ./file1 ('file1' is up to date)
However if i say: make $HOME/file1 then it tells me:
make: Nothing to be done for '/home/jesaremi/file1'
Is there a way to get consistent results regardless of what path I use?
You could add another rule:
$(shell pwd)/%: %
#:
This will allow the file1 rule to work for "file1", "./file1", "/home/jesaremi/path_to_cwd/file1", "~jesaremi/path_to_cwd/file1" and "~/path_to_cwd/file1".
Related
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 $< $#
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"
I know this could be done in different ways, but I am actually looking for learning more about makefiles.
I want to be able to call make somefile.txt and run a given script.
In my current folder I have:
makefile
%.txt:
# perl -pe "s/#.*//g; s/^\n//g; s/\n/\t/g;" .txt
echo "Hi"
When I call make, I am getting
make: `somefile.txt' is up to date.
I know I would need to use .PHONY, but I am having trouble trying to use it with %.txt.
I already tried things such as
files = *.txt
.PHONY = $(files)
%.txt:
# perl -pe "s/#.*//g; s/^\n//g; s/\n/\t/g;" .txt
echo "Hi"
But that didn't actually work.
The (a) conventional way to do this is to make your real target have a phony one as a prerequisite. Phony targets are always considered initially out of date, so anything that depends on a phony target will also always be considered out of date. "force" is a conventional name for a target used for this purpose.
For example,
.PHONY: force
force:
%.txt: force
echo "Hi at $$(date)" > $#
As demonstrated in the example, this does not require the phony target to have a recipe.
If you don't want to list your targets to be built in your makefile but instead just give them on the command line, you can use this:
.PHONY: $(MAKECMDGOALS)
The variable MAKECMDGOALS will be set to the set of goals you gave make on the command line.
It's important to understand that a makefile is not the shell, and so just sticking *.txt anywhere in your makefile won't always expand it. Only particular areas of the makefile work with shell globs directly.
If you want to always expand it, you can use make's wildcard function like this:
files = $(wildcard *.txt)
The point is that I want to have some dependencies centralized in one variable, but the dependencies themselves are contained in variables.
a=meow
b=squeek
$(a):
touch $#
$(b):
touch $#
targs=$(a) $(b)
all: $(targs)
In the real case rules for a and b differ so I need them to be in separate targets.
When I try to build such a target, only last nested dependency gets executed:
$ make
touch meow
$ ls
. .. Makefile meow
Could anyone please explain me how do I fix the situation or where I'm wrong?
I can make a phony target like targs: $(a) $(b), but if there's a way to keep the structure I mentioned, I'd like to know about it.
Thanks in advance!
UPD: solved. My mistake: instead of running make all I ran make and make executed the first target instead of all.
Make's default is to use the first target in the Makefile. Either move the all target to the beginning or use the following line somewhere in your Makefile
.DEFAULT_GOAL := all
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: ;