Node.JS
Node.JS

Reputation: 1570

Simplify Makefile without changing its logic

I am wondering is there a way to refactor these 3 lines without changing the logic?

Makefile

SPECS=FirstSpec FollowSpec
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
all: $(addsuffix .run, $(SPECS))

.PHONY: clean
clean:
    rm -f *.class grammar.scala first.scala follow.scala

# for anything.scala it compiles it to create class file
%.class: %.scala
    scalac -cp ${SCALA_FLAGS} $<

# for anything.scala that does not already exist, it generates it
%.scala:
    ${APS2SCALA} -DCOT -p ${EXAMPLES_PATH}:${ROOT_PATH}/base $*

# for anything.run it needs to be compiled first before running
%.run: %.class
    scala -cp ${SCALA_FLAGS} $(basename $<)

# for GrammarUtil.class it needs to generate and compile grammar.class and then compile itself
GrammarUtil.class: grammar.class
    scalac -cp ${SCALA_FLAGS} GrammarUtil.scala
    # How to avoid above line: scalac -cp ${SCALA_FLAGS} GrammarUtil.scala

# for FirstSpec.class it needs to compile Spec.class, GrammarUtil.class and compile and then generate first.class
FirstSpec.class: Spec.class GrammarUtil.class first.class
    scalac -cp ${SCALA_FLAGS} FirstSpec.scala
    # How to avoid above line: scalac -cp ${SCALA_FLAGS} FirstSpec.scala

# for FollowSpec.class it needs to compile Spec.class, GrammarUtil.class and compile and then generate follow.class
FollowSpec.class: Spec.class GrammarUtil.class follow.class
    scalac -cp ${SCALA_FLAGS} FollowSpec.scala
    # How to avoid above line: scalac -cp ${SCALA_FLAGS} FollowSpec.scala 

Upvotes: 0

Views: 71

Answers (1)

gilhad
gilhad

Reputation: 609

I hope, that the answer could look like that (put it to some clean directory and just run make, then look at those files with text editor/wiever):

SPECS=FirstSpec FollowSpec
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
all: $(addsuffix .run, $(SPECS))

.PHONY: clean
clean:
    rm -f *.class grammar.scala first.scala follow.scala

# for anything.scala it compiles it to create class file
#  Lets use ALL prequisities ($^) and create target by name (--output $@)
%.class: %.scala
    echo "scalac -cp ${SCALA_FLAGS} $^ --output $@" > $@

# for anything.scala that does not already exist, it generates it
%.scala:
    echo "${APS2SCALA} -DCOT -p ${EXAMPLES_PATH}:${ROOT_PATH}/base $*" >$@

# for anything.run it needs to be compiled first before running
%.run: %.class
    echo "scala -cp ${SCALA_FLAGS} $(basename $<)" >$@

# for GrammarUtil.class it needs to generate and compile grammar.class and then compile itself
# for FirstSpec.class it needs to compile Spec.class, GrammarUtil.class and compile and then generate first.class
# for FollowSpec.class it needs to compile Spec.class, GrammarUtil.class and compile and then generate follow.class
GrammarUtil.class: grammar.class

FirstSpec.class: Spec.class GrammarUtil.class first.class

FollowSpec.class: Spec.class GrammarUtil.class follow.class

I have no scala, so I could not try it, but I let it put commands to create each file to that file for inspection - so it may be enought just to delete those echo " and " >$@ to get the desired result.

Also I hope, that the scalacp command have some way to place output to explicitly named file - I used hypotetical --output filename switch for that. Or that is somehow get it from its first file parametr right (so the --outpu filename is not needed)

There are used 3 "tricks"

  • to use all from dependencies there is $^ variable
  • to get name of target file is variable $@
  • there can be more dependencies lines (like those 3 at bottom) and they use the same rule for the target, if it meets the same pattern

Upvotes: 1

Related Questions