makefile with creation of c- and h-file from perlscript - makefile

I like to create a c- and h-file from a perlscript. So i created the following rule:
abc.[ch]:
#perl makestrings abc
I got this error message:
File `abc.h' does not exist.
When i used the rule abc.h: it will work.
I think i got a problem that the c file is not included afterwards. So i needed to restart make when abc.h or abc.c are created.

abc.[ch] is a wildcard for abc.c or abc.h. But it is a wildcard, that is, if the files do not exist, it expands as the string abc.[ch] (not what you want). And if only one exists, it expands as this one (not what you want). You could try something like:
.PHONY: abc_ch
abc_ch: abc.c abc.h
abc.c abc.h:
#perl makestrings abc

Your Makefile is correct but you should add a plus rule.
abc.o: abc.c abc.h
${CC} -o abc.o abc.c
In this case abc.o requires abc.c and abc.h too so make will create abc.c and abc.h first and after it try to build abc.o.
A plus suggestion: I would add a dependency to abc.[ch]: the makestrings perl-script. And maybe any other files that are used by makestrings.

Related

Makefile: no target error even when target and dependency exist

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

Including a newly generated file each time in gnu make makefile? Deleting tempory file not working?

I have a Makefile like so:
T:=$(shell mktemp)
include ${T}
I:=$(shell rm ${T})
all:
echo done
In theory, mktemp should create an empty file and return its name. The next line should include that file. The following line should delete it.
When I run it I get:
make: *** No rule to make target `/tmp/tmp.Cwe7kiNBA3'. Stop.
If I comment out the third line like so:
T:=$(shell mktemp)
include ${T}
#I:=$(shell rm ${T})
all:
echo done
The Makefile works as expected, but leaves the temporary file behind.
Why doesn't the original example work as expected?
Your Makefile seems good without the include ${T} command. As described by GNU, the include directive is useful to:
suspend reading the current makefile and read one or more other
makefiles before continuing.
So, the following Makefile:
T:=$(shell mktemp)
I:=$(shell rm ${T})
all:
echo done
will produce this output and it will not report errors:
echo done
done
Make is trying to remake your included Makefile - for example, it works if you replace include with -include (which doesn't complain when the remake fails). You can fix it by adding an empty recipe for it: ${T}: ;.

Percentage used in the Makefile rule that aims at renaming all .c files

I think percentage in Makefile means wildcard. As a try, I test a contrive Makefile that aims at changing any .c file to 'hi'. This is my Makefile rule:
%.c:
mv $# hi
I save the file above to 'Makefile', and then type in the terminal
touch hello.c
make
The terminal says
make: `hello.c' is up to date.
which is certainly not what I wanted. Two naive questions:
a) Why does makefile determine that 'hello.c' is actually "up to date"?
b) How can we enforce the rule to be applied anyway?
You have not defined any dependencies in your rule. The hello.c already exists and none of the dependencies have newer timestamp than hello.c.
There are rules with no dependencies like clean. In this case the file clean does not exist and make tries to create it by executing the rule's set of commands. However, as mentioned in GNU make documentation this will not work in the case where clean file is created. The solution on this is to define clean as "Phony Target".
Additionally the output of the command is file hi and not %.c
The Makefile should look like:
%.hi : %.c
mv $< $#

Simple Makefile reporting circular dependency -- possibly from suffix rules?

I'm using mingw32-make and attempting to create a simple rule to run windres to include an icon for a Windows executable.
The structure consists of a simple C program in a.c, an a.rs file containing only the line:
1 ICON "a.ico"
..the icon file itself, and the Makefile.
The Makefile:
CC = gcc
all: a
%.rc.o: %.rc
windres $< $#
a: a.o a.rc.o
The output I get:
>make
gcc -c -o a.o a.c
make: Circular a.rc <- a.rc.o dependency dropped.
windres a.rc a.rc.o
gcc a.o a.rc.o -o a
The output files are all created correctly, but I can't figure out how to write the .rc->.rc.o rule to get rid of the circular dependency message. From what I can tell it is interpreting it as a suffix rule where %.rc.o indicates the rule is intended to create %.rc from %.o, thus the dependency on a %.rc is circular...
I can use .rco instead of .rc.o and it doesn't generate this error, but I prefer keeping it to the compound extension if possible.
Is there any way to create a pattern rule giving outputs with an extension of the .ext1.ext2 sort, without having it be interpreted as a suffix rule?
The problem is that make has a built-in rule to build an executable file foo from an object file foo.o. In your situation make matches the rule %.rc.o for the target a.rc.o. Then it tries to find a rule that will update a.rc and when it looks it sees that a.rc.o will exist, and so it matches the rule % : %.o, but then realizes that it has a circular dependency for a.rc.o : a.rc and a.rc : a.rc.o.
The simplest thing to do is define an explicit rule for a.rc so that it won't look for a pattern rule:
a.rc : ;
Alternatively, if you don't need the built-in rule to create an executable from an object file, you can cancel it by adding:
%: %.o
with no recipe.

Make command using default target name 'Makefile'

Why is the following makefile using Makefile target?
Makefile1:
Initially I have the following makefile which worked as expected when invoked as make abc xyz -s.
%::
echo $#
I would get
abc
xyz
Makefile2:
Now after adding an empty rule named test.
%:: test
echo $#
test:
the following invocation
make abc xyz -s
results in
Makefile
abc
xyz
Why am I getting Makefile as my output even though I am giving only abc and xyz as targets? Thanks in advance.
Because make always tries to rebuild the build files before building the actual targets. If it finds a rule for Makefile and if it is out-of-date, it will be rebuilt and reloaded and the requested targets will be built according to the new makefile. This is a feature so that if the build-files are themselves generated (rather common with autotools, cmake and similar), it won't use stale build instructions.
For more details see GNU Make Manual section 3.5
In the specific examples above the rule has target % and that matches absolutely anything, including Makefile. So make will find it as rule for remaking makefile and will evaluate it.
Now in the first case Makefile exists and is newer than all of it's dependencies trivially because there are none and none of it's dependencies need to be remade also because there are none. So make will conclude that Makefile does not need to be remade.
In the second case however Makefile exists, but it's dependency test needs to be remade. So make runs the (empty) rule and than comes back and runs the rule for Makefile. Because make does not check the timestamps after making dependencies. It simply assumes that when it remade them, the dependent targets need to be remade as well.

Resources