Since July 2007, Coq features a build system overhauled by Pierre Corbineau and Lionel Elie Mamane. --------------------------------------------------------------------- WARNING: In March 2010 this build system has been heavily adapted by Pierre Letouzey. In particular there no more explicit stage1,2. Stage3 was removed some time ago when coqdep was splitted into coqdep_boot and full coqdep. Ideas are still similar to what is describe below, but: 1) .ml4 are explicitely turned into .ml files, which stay after build 2) we let "make" handle the inclusion of .d without trying to guess what could be done at what time. Some initial inclusions hence _fail_, but "make" tries again later and succeed. TODO: remove obsolete sections below and better describe the new approach ----------------------------------------------------------------------- This file documents internals of the implementation of the build system. For what a Coq developer needs to know about the build system, see build-system.txt . .ml4 files ---------- .ml files corresponding to .ml4 files are created to keep ocamldep happy only. To ensure they are not used for compilation, they contain invalid OCaml. multi-stage build ----------------- Le processus de construction est séparé en trois étapes qui correspondent aux outils nécessaires pour calculer les dépendances de cette étape: stage1: ocamldep, sed , camlp4 sans fichiers de Coq stage2: camlp4 avec grammar.cma et/ou q_constr.cmo stage3: coqdep (.vo) Le Makefile a été séparé en plusieurs fichiers : - Makefile: coquille vide qui délègue les cibles à la bonne étape sauf clean et les fichiers pour emacs (car ils sont en quelque sorte en "stage0": aucun calcul de dépendance nécessaire). - Makefile.common : définitions des variables (essentiellement des listes de fichiers) - Makefile.build : les règles de compilation sans inclure de dépendances - Makefile.stage* : fichiers qui incluent les dépendances calculables à cette étape ainsi que Makefile.build. The build needs to be cut in stages because make will not take into account one include when making another include. Parallélisation --------------- Le découpage en étapes veut dire que le makefile est un petit peu moins parallélisable que strictement possible en théorie: par exemple, certaines choses faites en stage2 pourraient être faites en parallèle avec des choses de stage1. Nous essayons de minimiser cet effet, mais nous ne l'avons pas complètement éliminé parce que cela mènerait à un makefile très complexe. La minimisation est principalement que si on demande un objet spécifique (par exemple "make parsing/g_constr.cmx"), il est fait dans l'étape la plus basse possible (simplement), mais si un objet est fait comme dépendance de la cible demandée (par exemple dans un "make world"), il est fait le plus tard possible (par exemple, tout code OCaml non nécessaire pour coqdep ni grammar.cma ni q_constr.cmo est compilé en stage3 lors d'un "make world"; cela permet le parallélisme de compilation de code OCaml et de fichiers Coq (.v)). Le "(simplement)" ci-dessus veut dire que savoir si un fichier non nécessaire pour grammar.cma/q_constr.cmo peut en fait être fait en stage1 est compliqué avec make, alors nous retombons en général sur le stage2. La séparation entre le stage2 et stage3 est plus facile, donc l'optimisation ci-dessus s'y applique pleinement. En d'autres mots, nous avons au niveau conceptuel deux assignations d'étape pour chaque fichier: - l'étape la plus petite où nous savons qu'il peut être fait. - l'étape la plus grande où il peut être fait. Mais seule la première est gérée explicitement, la seconde est implicite. FIND_VCS_CLAUSE --------------- The recommended style of using FIND_VCS_CLAUSE is for example find . $(FIND_VCS_CLAUSE) '(' -name '*.example' ')' -print find . $(FIND_VCS_CLAUSE) '(' -name '*.example' -or -name '*.foo' ')' -print 1) The parentheses even in the one-criteria case is so that if one adds other conditions, e.g. change the first example to the second find . $(FIND_VCS_CLAUSE) '(' -name '*.example' -and -not -name '*.bak.example' ')' -print one is not tempted to write find . $(FIND_VCS_CLAUSE) -name '*.example' -and -not -name '*.bak.example' -print because this will not necessarily work as expected; $(FIND_VCS_CLAUSE) ends with an -or, and how it combines with what comes later depends on operator precedence and all that. Much safer to override it with parentheses. In short, it protects against the -or one doesn't see. 2) As to the -print at the end, yes it is necessary. Here's why. You are used to write: find . -name '*.example' and it works fine. But the following will not: find . $(FIND_VCS_CLAUSE) -name '*.example' it will also list things directly matched by FIND_VCS_CLAUSE (directories we want to prune, in which we don't want to find anything). C'est subtil... Il y a effectivement un -print implicite à la fin, qui fait que la commande habituelle sans print fonctionne bien, mais dès que l'on introduit d'autres commandes dans le lot (le -prune de FIND_VCS_CLAUSE), ça se corse à cause d'histoires de parenthèses du -print implicite par rapport au parenthésage dans la forme recommandée d'utilisation: Si on explicite le -print et les parenthèses implicites, cela devient: find . '(' '(' '(' -name .git -or -name debian ')' -prune ')' -or \ '(' -name '*.example' ')' ')' -print Le print agit TOUT ce qui précède, soit sur ce qui matche "'(' -name .git -or -name debian ')'" ET sur ce qui matche "'(' -name '*.example' ')'". alors qu'ajouter le print explicite change cela en find . '(' '(' -name .git -or -name debian ')' -prune ')' -or \ '(' '(' -name '*.example' ')' -print ')' Le print n'agit plus que sur ce qui matche "'(' -name '*.example' ')'"