Commit 33084248 authored by fpottier's avatar fpottier

Switch to ocamlbuild.

git-svn-id: svn+ssh://scm.gforge.inria.fr/svnroot/menhir@331 0f8b5475-4b4e-0410-85a8-ee3154a6bfe7
parent 6a23aac9
2013/03/02:
Switched to ocamlbuild. Many thanks to Daniel Weil for offering
very useful guidance.
2013/01/16:
"menhir --depend" was broken since someone added new whitespace in the output
of ocamldep. Fixed.
......
......@@ -2,13 +2,8 @@
that was reached? this would allow some people to produce better error
messages (Pippijn van Steenhoven). Incompatible change?
* BUG: le Makefile ne fonctionne pas avec -j (email de Florent Hivert)
* projet amusant: si l'automatique est canonique et si on n'a pas trop
optimisé le contenu de la pile, alors en cas d'erreur, on doit pouvoir
analyser le contenu de la pile pour produire un suffixe de l'entrée qui
aurait conduit à une acceptation. Ça trouerait le C** comme message
d'explication!
* _stage2/menhir.native --interpret fancy-parser.mly
crashes with Stack_overflow when the input is just "grammar:\n"
* Les fichiers dans examples/ ne devraient pas être sous QPL mais libres...
......@@ -21,7 +16,8 @@
non-terminaux), non? (Jacques-Henri.)
* les positions fournies par menhir ne sont pas les mêmes fournies par
ocamlyacc (voir messages de Tiphaine Turpin à partir du 30/08/2011). Est-ce un problème? Peut-on documenter quelles sont les
ocamlyacc (voir messages de Tiphaine Turpin à partir du 30/08/2011).
Est-ce un problème? Peut-on documenter quelles sont les
positions fournies par Menhir? En particulier, pour une production
vide, Menhir utilise _menhir_env.lexer.lex_start_p, c'est-à-dire le
début du dernier token lu par le lexer; en principe c'est le token
......@@ -79,9 +75,6 @@
* Permettre trois modes pour --trace: toujours, si variable d'environnement
activée, ou jamais
* peut-on éviter d'avoir pour les états des "raw numbers" et des "numbers"
totalement différents?
* (petit) BUG: --follow-construction n'affiche pas le contenu des états
initiaux (r0)
......@@ -95,8 +88,6 @@
ou pas; faut-il faire grossir les états existants, ou bien (par exemple) les
supprimer et recommencer leur construction?
* regarder du côté de Tattoo (Julien Cervelle)
* que fait/que doit faire la combinaison --tokens-only --depend?
* Préserver dirname/ dans les directives #line émises.
......@@ -129,8 +120,6 @@
* Appliquer cette même technique aux conflits? Le programmeur liste une phrase
et un token de lookahead, et indique quelle action il veut dans ce cas...
* Réfléchir à GLR
* Faire co-exister l'automate avant et après résolution des conflits;
tenter d'expliquer chaque conflit en termes du second, si impossible
alors en termes du premier; faire en sorte que les numéros d'états
......
.PHONY: clean
COLD += clean
.PHONY: everyday library bootstrap stage1 stage2 stage3 clean
# ----------------------------------------------------------------------------
# Choose a target.
# A few settings differ on Windows versus Unix.
include ../Makefile.arch
ifndef TARGET
TARGET := native
endif
# ----------------------------------------------------------------------------
# Locating the ocaml compilers.
# If ocamlfind is available, then it is used for that purpose.
CAMLTOP := ocaml
CAMLC := $(shell if ocamlfind ocamlc -v >/dev/null 2>&1 ; \
then echo ocamlfind ocamlc ; \
elif ocamlc.opt -v >/dev/null 2>&1 ; \
then echo ocamlc.opt ; \
else echo ocamlc ; fi)
CAMLOPT := $(shell if ocamlfind ocamlopt -v >/dev/null 2>&1 ; \
then echo ocamlfind ocamlopt ; \
elif ocamlopt.opt -v >/dev/null 2>&1 ; \
then echo ocamlopt.opt ; \
else echo ocamlopt ; fi)
CAMLDEP := $(shell if ocamlfind ocamldep -version >/dev/null 2>&1 ; \
then echo ocamlfind ocamldep ; \
elif ocamldep.opt -version >/dev/null 2>&1 ; \
then echo ocamldep.opt ; \
else echo ocamldep ; fi)
CAMLDEPWRAPPER := ../demos/ocamldep.wrapper
CAMLLEX := ocamllex
CAMLYACC := ocamlyacc -v
# -------------------------------------------------------------------------
# Compilation flags.
BFLAGS := -g
OFLAGS := -inline 1000
LNKBFLAGS := -g
LNKOFLAGS :=
BLIBS := unix.cma
OLIBS := unix.cmxa
PGFLAGS := -v -lg 1 -la 1 -lc 1 --comment --infer --error-recovery --stdlib . --strict
# -------------------------------------------------------------------------
# A list of the source files that must be generated prior to dependency
# analysis.
GENERATED := installation.ml lexmli.ml lexer.ml parser.mli parser.ml \
lineCount.ml lexdep.ml sentenceParser.mli sentenceParser.ml sentenceLexer.ml
# -------------------------------------------------------------------------
# A list of the modules that must be linked into the MenhirLib library.
# This library is used both at compile time (i.e., within Menhir itself)
# and at run time (i.e., it is made available to Menhir users, who need
# to link it with their own executables if they have used the --table
# option).
# If you change this list, please also update the files LICENSE and
# GNUmakefile in the toplevel directory.
LIBMODULES := infiniteArray packedIntArray rowDisplacement engineTypes \
engine tableFormat tableInterpreter convert
# Define the files that form the library.
# -------------------------------------------------------------------------
ifeq ($(TARGET),byte)
LIBFILES := menhirLib.cmo
else
LIBFILES := menhirLib.cmo menhirLib.cmx
endif
# A list of the modules that must be linked into the Menhir executable.
# ----------------------------------------------------------------------------
# Ocamlbuild tool and settings.
MODULES := menhirLib Fix stringSet stringMap mark compressedBitSet \
unionFind tarjan patricia misc option \
breadth listMonad dot installation version settings time \
positions error parameters keyword lineCount printer \
action parserAux parser lexer partialGrammar \
parameterizedGrammar reachability unparameterizedPrinter \
preFront codeBits tokenType interface IO lexmli lexdep \
infer nonTerminalDefinitionInlining front grammar item lr0 \
slr lr1 lr1partial derivation conflict invariant codePieces \
sentenceParser sentenceLexer pprint cst \
referenceInterpreter interpret tableBackend codeBackend \
coqBackend traverse inliner back
OCAMLBUILD := ocamlbuild -classic-display -use-ocamlfind -j 0
# -------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# For everyday development.
# Typing "make" will perform just stage 1. This is enough to ensure that
# the source code is correct.
# How to bootstrap.
everyday: stage1
# Set TARGET to byte or opt depending on the desired architecture.
# ----------------------------------------------------------------------------
# Building MenhirLib.
ifndef TARGET
TARGET := opt
endif
library:
$(OCAMLBUILD) $(LIBFILES)
# The variable GOAL is the name of the executable file.
GOAL := menhir.$(TARGET)
# We create a symbolic link of GOAL to MENHIREXE.
$(MENHIREXE): .versioncheck
# Build a stage one executable using ocamlyacc.
$(MAKE) -s PGEN="$(CAMLYACC)" PARSER=parser $(GOAL)
# Remove the ocamlyacc-built parser.
@/bin/rm -f parser.ml parser.mli
# Build a stage two executable using the stage one executable (which is overwritten).
$(MAKE) -s PGEN="./$(GOAL) $(PGFLAGS)" PARSER=fancy-parser $(GOAL)
# Create a stage three parser and make sure that it is identical.
@./$(GOAL) $(PGFLAGS) -b reference fancy-parser.mly 2>/dev/null
@if diff parser.mli reference.mli 2>&1 >/dev/null ; then \
if diff parser.ml reference.ml 2>&1 >/dev/null ; then \
echo "Bootstrap successful." ; \
else \
echo "Bootstrap FAILED: the implementation files differ." && false ; \
fi ; \
else \
echo "Bootstrap FAILED: the interface files differ." && false ; \
fi
@rm -f reference.ml reference.mli
# Rename the stage two executable to the desired name.
# Use a symbolic link, so that further development builds implicitly update
# menhir.
@ln -sf $(GOAL) $@
# -------------------------------------------------------------------------
# Linking.
menhirLib.cmo menhirLib.cmi: $(LIBMODULES:=.cmo)
$(CAMLC) $(BFLAGS) -pack -o menhirLib.cmo $^
menhirLib.cmx menhirLib.o: $(LIBMODULES:=.cmx)
$(CAMLOPT) -pack -o menhirLib.cmx $^
menhir.byte: $(MODULES:=.cmo)
$(CAMLC) -o $@ $(LNKBFLAGS) $(BLIBS) $^
menhir.opt: $(MODULES:=.cmx)
$(CAMLOPT) -o $@ $(LNKOFLAGS) $(OLIBS) $^
# -------------------------------------------------------------------------
# Computing dependencies. This can be done in a simple way, even though
# we exploit --infer, because we compile in two stages. Not a good example
# of how to do it yourself -- have a look at demos/Makefile.shared.
# For completeness, we must force ocamldep to understand that MenhirLib
# is a module name. We do this by creating phantom source files for it.
.depend: $(wildcard *.ml *.mli) $(GENERATED)
@/bin/rm -f .depend
for i in *.ml *.mli; do \
$(CAMLDEPWRAPPER) menhirLib.ml menhirLib.mli - $(CAMLDEP) $$i \
>> $@; \
done
ifeq ($(findstring $(MAKECMDGOALS),$(COLD)),)
-include .depend
endif
# ----------------------------------------------------------------------------
# Building Menhir from scratch (a.k.a. bootstrapping).
# -------------------------------------------------------------------------
bootstrap: .versioncheck stage1 stage2 stage3
# Cleaning up.
# ----------------------------------------------------------------------------
# Checking the version of the OCaml compiler.
clean::
/bin/rm -f menhir.byte menhir.opt $(MENHIREXE)
/bin/rm -f *.cmi *.cmx *.cmo *.$(OBJ) *~ .*~
/bin/rm -f reference.ml reference.mli $(GENERATED)
/bin/rm -f .depend *.conflicts *.automaton *.annot *.output
.versioncheck:
@ echo Checking that Objective Caml is recent enough...
@$(OCAMLBUILD) -build-dir _stage1 checkOCamlVersion.byte
@ _stage1/checkOCamlVersion.byte --verbose --gt "3.09"
@ touch $@
# -------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Stage 1.
# Build Menhir using ocamlyacc.
# Compiling. The parser source is found in $(PARSER).mly and is
# processed using $(PGEN).
stage1:
@$(OCAMLBUILD) -build-dir _stage1 -tag yacc_parser \
menhir.$(TARGET)
# These two default definitions really shouldn't be necessary, but
# there are corner cases where they are needed (e.g. when make is
# invoked without a target and the .depend file is regenerated).
# ----------------------------------------------------------------------------
# Stage 2.
# Build Menhir using Menhir (from stage 1).
ifndef PGEN
PGEN := $(CAMLYACC)
endif
ifndef PARSER
PARSER := parser
endif
FLAGS := -v -lg 1 -la 1 -lc 1 --comment --infer --error-recovery --stdlib . --strict --fixed-exception
%.cmi: %.mli
$(CAMLC) $(BFLAGS) -c $<
%.cmo: %.ml
$(CAMLC) $(BFLAGS) -c $<
# If the module that is being compiled is part of MenhirLib, add the
# -for-pack option to the command line. This is required only when
# compiling to native code (the bytecode compiler accepts but ignores
# this option).
PACK = $(shell if echo $(LIBMODULES) | grep $* >/dev/null ; then echo -for-pack MenhirLib ; else echo ; fi)
%.cmx %.o: %.ml
$(CAMLOPT) $(OFLAGS) $(PACK) -c $<
# The source file for this parser varies. It is either parser.mly or
# fancy-parser.mly.
#
parser.ml parser.mli: $(PARSER).mly
@/bin/rm -f parser.ml parser.mli
$(PGEN) -b parser $<
# This parser must be built with ocamlyacc, because its client
# watches for Parsing.Parse_error!
#
# Using ocamlyacc or Menhir interchangeably would be possible,
# via an ocamlyacc wrapper that adds the definition "exception
# Error = Parsing.Parse_error" at the end of the generated .ml
# and .mli files.
#
sentenceParser.ml sentenceParser.mli : sentenceParser.mly
@/bin/rm -f sentenceParser.ml sentenceParser.mli
$(CAMLYACC) -b sentenceParser $<
%.ml: %.mll
@/bin/rm -f $@
$(CAMLLEX) $<
stage2:
@$(OCAMLBUILD) -build-dir _stage2 -tag fancy_parser \
-use-menhir -menhir "$(shell pwd)/_stage1/menhir.$(TARGET) $(FLAGS)" \
menhir.$(TARGET)
# ----------------------------------------------------------------------------
# Checking the version of the ocaml compiler.
#
# We check the bytecode compiler only, because some architectures don't have
# the native code compiler. We assume that both compilers, if present, are in
# sync.
# We build a bytecode executable (rather than use the toplevel loop) because
# we need to load str.cma and some ocaml ports do not support dynamic loading
# (e.g. ocaml 3.09, MacOS/Intel).
# Stage 3 (optional).
# Re-generate Menhir's parser using Menhir (from stage 2) and check that it
# is identical to the stage 2 parser.
stage3:
@$(OCAMLBUILD) -build-dir _stage3 -tag fancy_parser \
-use-menhir -menhir "$(shell pwd)/_stage2/menhir.$(TARGET) $(FLAGS)" \
parser.ml parser.mli
@for i in parser.ml parser.mli ; do \
if ! diff _stage2/$$i _stage3/$$i 2>&1 >/dev/null ; then \
echo "Bootstrap FAILED: $$i did not reach a fixed point."; exit 1 ; \
fi ; \
done; \
echo "Bootstrap successful."
.versioncheck:
@ echo Checking that Objective Caml is recent enough...
@ $(CAMLC) -o check-ocaml-version str.cma checkOCamlVersion.ml
@ ./check-ocaml-version --verbose --gt "3.09"
@ rm check-ocaml-version
@ touch .versioncheck
clean::
rm -f .versioncheck
# ----------------------------------------------------------------------------
# Cleaning up.
clean:
rm -rf .versioncheck _build _stage1 _stage2 _stage3
# Tag both parser source files with origin_parser.
<{yacc-parser,fancy-parser}.mly>:origin_parser
# Menhir needs the Unix library.
<menhir.{byte,native}>: use_unix
# checkOCamlVersion needs the Str library.
<checkOCamlVersion.byte>: use_str
<sentenceParser.{ml,mli}>: use_ocamlyacc
# Build and link with -g.
<**/*.{cmo,cmx}>:debug
<**/*.byte>:debug
<**/*.native>:debug
# Every module that is part of MenhirLib must be tagged as such.
# If you change this list, please also update the files LICENSE
# and GNUmakefile in the toplevel directory.
<infiniteArray.cmx>: for-pack(MenhirLib)
<packedIntArray.cmx>: for-pack(MenhirLib)
<rowDisplacement.cmx>: for-pack(MenhirLib)
<engineTypes.cmx>: for-pack(MenhirLib)
<engine.cmx>: for-pack(MenhirLib)
<tableFormat.cmx>: for-pack(MenhirLib)
<tableInterpreter.cmx>: for-pack(MenhirLib)
<convert.cmx>: for-pack(MenhirLib)
(* The main program. *)
(* Everything is in [Back]. *)
open Back
# If you change this list, please also update the files LICENSE
# and GNUmakefile in the toplevel directory.
InfiniteArray
PackedIntArray
RowDisplacement
EngineTypes
Engine
TableFormat
TableInterpreter
Convert
open Ocamlbuild_plugin
open Command
(* ---------------------------------------------------------------------------- *)
(* Compilation flags. *)
let flags () =
(* -inline 1000 *)
flag ["ocaml"; "compile"; "native"] (S [A "-inline"; A "1000"])
(* ---------------------------------------------------------------------------- *)
(* A command for copying a file. *)
let copy_file_from_tag src dst env build =
Cmd (S [A "cp"; T (tags_of_pathname src); P dst])
(* ---------------------------------------------------------------------------- *)
(* Dealing with the two parsers. *)
(* Just for fun, Menhir comes with two parsers for its own input files. One is
called [yacc-parser.mly] and is built using [ocamlyacc]. The other is called
[fancy-parser.mly] and is built using Menhir. It depends on [standard.mly].
The choice between the two parsers is determined by the presence of the tag
[yacc_parser] or [fancy_parser]. *)
let parser_rule () =
(* The three dependencies. *)
flag_and_dep ["origin_parser"; "yacc_parser"] (P "yacc-parser.mly");
flag_and_dep ["origin_parser"; "fancy_parser"] (P "fancy-parser.mly");
dep ["origin_parser"; "fancy_parser"] ["standard.mly"];
(* The two rules. *)
rule "yacc-parser -> parser" ~prod:"parser.mly" (copy_file_from_tag "yacc-parser.mly" "parser.mly");
rule "fancy-parser -> parser" ~prod:"parser.mly" (copy_file_from_tag "fancy-parser.mly" "parser.mly")
(* ---------------------------------------------------------------------------- *)
(* Define custom compilation rules. *)
let () =
dispatch (function After_rules ->
(* Add our rules after the standard ones. *)
parser_rule();
flags();
| _ -> ()
)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment