Reputation: 1568
I am getting weird behavior in Makefile. Basically for grammar.aps
, it needs to run grammar.generate
to create the file first and then grammar.class
to compile the generated file. If I run the dependencies individually all works. But if I run grammar.aps
it doesn't work.
// Running everything
➜ tests git:(first-follow-tests) ✗ make
scalac -cp .:../../../lib/aps-library-2.12.jar Spec.scala
make: *** No rule to make target 'grammar.class', needed by 'grammar.aps'. Stop.
// Now running first depdency of `grammar.aps` which is `grammar.generate`
➜ tests git:(first-follow-tests) ✗ make grammar.generate
../../../bin/aps2scala -DCOT -p ../..:../../../base grammar
// Now running second depdency of `grammar.aps` which is `grammar.generate`
➜ tests git:(first-follow-tests) ✗ make grammar.class
scalac -cp .:../../../lib/aps-library-2.12.jar grammar.scala
// Okay but why grammar.aps didn't work? ... Makefile continues further now
➜ tests git:(first-follow-tests) ✗ make
scalac -cp .:../../../lib/aps-library-2.12.jar grammar.scala
../../../bin/aps2scala -DCOT -p ../..:../../../base grammar
echo "Building aps"
Building aps
scalac -cp .:../../../lib/aps-library-2.12.jar GrammarUtil.scala
echo "Building GrammarUtil.scala"
Building GrammarUtil.scala
// Same problem with `first.aps`
make: *** No rule to make target 'first.aps', needed by 'FirstSpec.compile'. Stop.
Makefile:
SPECS=First Follow
EXAMPLES_PATH=../..
ROOT_PATH=../${EXAMPLES_PATH}
SCALAV=2.12
APSLIB=${ROOT_PATH}/lib/aps-library-${SCALAV}.jar
SCALA_FLAGS=.:${APSLIB}
APS2SCALA=${ROOT_PATH}/bin/aps2scala
.PHONY:
all: $(addsuffix Spec.compile, $(SPECS))
%.class: %.scala
scalac -cp ${SCALA_FLAGS} $<
%.generate:
${APS2SCALA} -DCOT -p ${EXAMPLES_PATH}:${ROOT_PATH}/base $*
%.aps: %.generate %.class
echo "Building aps"
%.run: %.class
@scala -cp ${SCALA_FLAGS} $<
FirstSpec.compile: Spec.class GrammarUtil.compile first.aps FirstSpec.class
echo "Building FirstSpec.scala"
FollowSpec.compile: Spec.class GrammarUtil.compile follow.aps FollowSpec.class
echo "Building FollowSpec.scala"
GrammarUtil.compile: grammar.aps grammar.class GrammarUtil.class
echo "Building GrammarUtil.scala"
.PHONY:
clean:
rm -f *.class grammar.scala first.scala follow.scala
Upvotes: 0
Views: 47
Reputation: 180256
I am getting weird behavior in Makefile. Basically for grammar.aps, it needs to run grammar.generate to create the file first and then grammar.class to compile the generated file. If I run the dependencies individually all works. But if I run grammar.aps it doesn't work.
You are trying to treat your makefile as if it were a script. It isn't. At the most basic level, it is a declarative description of your project that tells make
how it can construct one or more targets given specific lists of prerequisites for each. Each prerequisite list is only incidentally ordered. That one prerequisite appears lexically ahead of another has no significance. It is up to make
to choose and execute a build plan based on the information in the makefile and the files available.
In particular, make
performs its analysis of which intermediate targets to build based on the prerequisites available at the start of the run, in light of the declared build rules. Furthermore, prerequisite build order is constrained only by prerequisites' own prequisites, and it is not necessarily predictable.
However, make
does give you pretty informative error messages. For example, this ...
make: *** No rule to make target 'grammar.class', needed by 'grammar.aps'. Stop.
... is pretty clear: target grammar.aps
needs to be built, and it has grammar.class
as a prerequisite, but there is no rule for building grammar.class
. That is, there is no rule having grammar.class
as its target. That building grammar.generate
would in fact create grammar.class
is irrelevant because you haven't expressed that to make
.
You could fix this particular issue by converting your rule for %.generate
into a rule for %.class
:
%.class:
${APS2SCALA} -DCOT -p ${EXAMPLES_PATH}:${ROOT_PATH}/base $*
%.aps: %.class
echo "Building aps"
More generally, you should prefer to write rules with real targets over rules with phony ones. Phony targets are not necessarily bad, but they are not a viable substitute for real ones.
Upvotes: 1