From d3b4623ef0cc71dcd77f4513fcdd0fec43752ac9 Mon Sep 17 00:00:00 2001 From: David MICHEL Date: Tue, 12 Dec 2023 18:34:29 +0100 Subject: [PATCH] Les makefiles c'est de la m... --- Makefile | 131 ++++---------- Makefile.include | 146 ---------------- examples/dgfip_c/ml_primitif/Makefile | 169 ------------------ makefiles/c_backend.mk | 238 ++++++++++++++++++++++++++ makefiles/functions.mk | 40 ++++- makefiles/mlang.mk | 105 ++++++++++++ makefiles/variables.mk | 158 +++++++++++++++++ 7 files changed, 568 insertions(+), 419 deletions(-) delete mode 100644 Makefile.include delete mode 100644 examples/dgfip_c/ml_primitif/Makefile create mode 100644 makefiles/c_backend.mk create mode 100644 makefiles/mlang.mk create mode 100644 makefiles/variables.mk diff --git a/Makefile b/Makefile index 8d1a01bf..51f241ca 100644 --- a/Makefile +++ b/Makefile @@ -1,116 +1,47 @@ # Check Makefile.config.template if you want to override some of the flags # in this Makefile. -include Makefile.include - -include makefiles/functions.mk --include makefiles/svn.mk - -ifeq ($(CODE_COVERAGE), 1) - CODE_COVERAGE_FLAG=--code_coverage -else - CODE_COVERAGE_FLAG= -endif - -ifeq ($(TEST_FILTER), 1) - TEST_FILTER_FLAG=--dgfip_test_filter -else - TEST_FILTER_FLAG= +ifndef ROOT_DIR + ROOT_DIR:=$(realpath $(dir $(realpath $(lastword $(MAKEFILE_LIST))))) endif -TEST_ERROR_MARGIN?=0. - -MLANG_INTERPRETER_OPTS=\ - --test_error_margin=$(TEST_ERROR_MARGIN) \ - --mpp_function=$(MPP_FUNCTION) - -MLANG=$(MLANG_BIN) $(MLANG_DEFAULT_OPTS) $(MLANG_INTERPRETER_OPTS) $(CODE_COVERAGE_FLAG) - -default: build - -################################################## -# Initializing the project -################################################## - -# Workaround for Opam 2.0 bug. Empty switch creation then installation could be a one line -# "opam switch create . --deps-only" otherwise -create-switch: - opam switch create . --empty - -init-without-switch: - opam install . --deps-only - git submodule update --init - -init: create-switch init-without-switch - -deps: - opam switch reinstall --deps-only - git submodule update - -################################################## -# Building the compiler -################################################## +CURR_DIR:=$(realpath $(shell pwd)) -format: - dune build @fmt --auto-promote | true +include $(ROOT_DIR)/makefiles/functions.mk +include $(ROOT_DIR)/makefiles/variables.mk +-include $(ROOT_DIR)/makefiles/svn.mk +include $(ROOT_DIR)/makefiles/mlang.mk +include $(ROOT_DIR)/makefiles/c_backend.mk -build: format dune +.PHONY: default \ + create-switch init-without-switch init deps \ + format dune build build-static \ + doc \ + test tests quick_test test_one \ + calc_dir info_c calc_o dgfip_c_backend compile_dgfip_c_backend \ + backend_tests test_dgfip_c_backend \ + clean_backend clean_backend_c clean_backend_exe clean_backend_tmp clean_backend_res clean_backend_all \ + test_java_backend -dune: - dune build $(DUNE_OPTIONS) - -# Run only in an opam switch with musl and static options activated -build-static: DUNE_OPTIONS+=--profile=static -build-static: build - -dgfip_c_backend: build - $(MAKE) -C examples/dgfip_c/ml_primitif calc/enchain.c - -compile_dgfip_c_backend: dgfip_c_backend - $(MAKE) -C examples/dgfip_c/ml_primitif cal - -################################################## -# Testing the compiler -################################################## - -# use: TEST_FILE=bla make test -test: build - $(MLANG) --run_test=$(TEST_FILE) $(SOURCE_FILES) $(SOURCE_EXT_FILES) - -# use: TESTS_DIR=bla make test -tests: build - $(MLANG) $(MLANGOPTS) --run_all_tests=$(TESTS_DIR) $(TEST_FILTER_FLAG) $(SOURCE_FILES) $(SOURCE_EXT_FILES) - -test_java_backend: build -ifeq ($(OPTIMIZE), 0) - @echo "\033[0;31mWarning, non-optimized Java files cannot be executed for now (too many constants for the JVM)\033[0m" -else -endif - $(MAKE) -C examples/java/ run_tests - -test_dgfip_c_backend: build - $(MAKE) -C examples/dgfip_c/ml_primitif backend_tests - -quick_test: build - $(MLANG) --backend interpreter --function_spec $(M_SPEC_FILE) $(SOURCE_FILES) $(SOURCE_EXT_FILES) +FORCE: -test_one: build - $(MLANG) --backend interpreter --run_test=$(TEST_ONE) $(SOURCE_FILES) $(SOURCE_EXT_FILES) +.DEFAULT_GOAL:=default -all: tests test_java_backend test_dgfip_c_backend quick_test +default: FORCE build -################################################## -# Doc -################################################## +test_java_backend: FORCE build + @echo "\033[0;31mWarning: Java backend not supported\033[0m" +#ifeq ($(OPTIMIZE), 0) +# @echo "\033[0;31mWarning, non-optimized Java files cannot be executed for now (too many constants for the JVM)\033[0m" +#else +#endif +# $(MAKE) -C examples/java/ run_tests -doc: FORCE build - dune build @doc - ln -fs $(shell pwd)/_build/default/_doc/_html/index.html doc/doc.html +all: FORCE quick_test tests test_dgfip_c_backend test_java_backend -clean: - $(MAKE) -C examples/dgfip_c/ml_primitif cleanall - $(MAKE) -C examples/java clean +clean: FORCE + $(call make_in,$(DGFIP_DIR),clean_backend_all) +# $(MAKE) -C examples/java clean rm -f doc/doc.html dune clean -FORCE: diff --git a/Makefile.include b/Makefile.include deleted file mode 100644 index f47a6f79..00000000 --- a/Makefile.include +++ /dev/null @@ -1,146 +0,0 @@ -################################################## -# Local customization -################################################## - -# WARNING: Use of simple expansion here (":=" operator) is important to ensure the value of SELF_DIR -# is not evaluated again after inclusion of other makefiles. If these files are in -# another directory, this directory would have been the new SELF_DIR after them. You probably -# do not want that. Replace by "=" only if you understand this paragraph and know you need it. -SELF_DIR:=$(realpath $(dir $(realpath $(lastword $(MAKEFILE_LIST))))) - --include $(SELF_DIR)/Makefile.config - -################################################## -# Tax computation configuration -################################################## - -define source_dir - $(1)tgvI.m $(1)errI.m $(shell find $(1) -name \*.m ! -name err\*.m ! -name tgv\*.m | sort) -endef - -define source_dir_ext - $(shell find $(1) -name \*.m | sort) -endef - -SOURCE_DIR_2015:=$(call source_dir,$(SELF_DIR)/ir-calcul/sources2015m_4_6/) -SOURCE_DIR_2016:=$(call source_dir,$(SELF_DIR)/ir-calcul/sources2016m_4_5/) -SOURCE_DIR_2017:=$(call source_dir,$(SELF_DIR)/ir-calcul/sources2017m_6_10/) -SOURCE_DIR_2018:=$(call source_dir,$(SELF_DIR)/ir-calcul/sources2018m_6_7/) -SOURCE_DIR_2019:=$(call source_dir,$(SELF_DIR)/ir-calcul/sources2019m_8_0/) -SOURCE_DIR_2020:=$(call source_dir,$(SELF_DIR)/ir-calcul/sources2020m_6_5/) -SOURCE_DIR_2021:=$(call source_dir,$(SELF_DIR)/ir-calcul/sources2021m_20_6/) -SOURCE_DIR_2022:=$(call source_dir,$(SELF_DIR)/ir-calcul/sources2022m_22_1/) - -SOURCE_EXT_DIR_2015:=$(call source_dir_ext,$(SELF_DIR)/mpp_specs/m_ext/2015/) -SOURCE_EXT_DIR_2016:=$(call source_dir_ext,$(SELF_DIR)/mpp_specs/m_ext/2016/) -SOURCE_EXT_DIR_2017:=$(call source_dir_ext,$(SELF_DIR)/mpp_specs/m_ext/2017/) -SOURCE_EXT_DIR_2018:=$(call source_dir_ext,$(SELF_DIR)/mpp_specs/m_ext/2018/) -SOURCE_EXT_DIR_2019:=$(call source_dir_ext,$(SELF_DIR)/mpp_specs/m_ext/2019/) -SOURCE_EXT_DIR_2020:=$(call source_dir_ext,$(SELF_DIR)/mpp_specs/m_ext/2020/) -SOURCE_EXT_DIR_2021:=$(call source_dir_ext,$(SELF_DIR)/mpp_specs/m_ext/2021/) -SOURCE_EXT_DIR_2022:=$(call source_dir_ext,$(SELF_DIR)/mpp_specs/m_ext/2022/) - -YEAR?=2020 - -ifeq ($(YEAR), 2018) - SOURCE_FILES?=$(SOURCE_DIR_2018) - SOURCE_EXT_FILES?=$(SOURCE_EXT_DIR_2018) - MPP_FILE?=$(SELF_DIR)/mpp_specs/2018_6_7.mpp - TESTS_DIR?=$(SELF_DIR)/tests/2018/fuzzing/ - TEST_ONE?=$(SELF_DIR)/tests/2020/fuzzing/fuzzer_10019.m_test - M_SPEC_FILE?=$(SELF_DIR)/m_specs/complex_case_with_ins_outs_2018.m_spec - MPP_FUNCTION?=compute_double_liquidation_pvro -else ifeq ($(YEAR), 2019) - SOURCE_FILES?=$(SOURCE_DIR_2019) - SOURCE_EXT_FILES?=$(SOURCE_EXT_DIR_2019) - MPP_FILE?=$(SELF_DIR)/mpp_specs/2019_8_0.mpp - TESTS_DIR?=$(SELF_DIR)/tests/2019/fuzzing/ - TEST_ONE?=$(SELF_DIR)/tests/2019/fuzzing/fuzzer_10029.m_test - M_SPEC_FILE?=m_specs/complex_case_with_ins_outs_2019.m_spec - MPP_FUNCTION?=traite_double_liquidation_2_interpreteur -else ifeq ($(YEAR), 2020) - SOURCE_FILES?=$(SOURCE_DIR_2020) - SOURCE_EXT_FILES?=$(SOURCE_EXT_DIR_2020) - MPP_FILE?=$(SELF_DIR)/mpp_specs/2020_6_5.mpp - TESTS_DIR?=$(SELF_DIR)/tests/2020/fuzzing/ - TEST_ONE?=$(SELF_DIR)/tests/2020/fuzzing/fuzzer_1001.m_test - M_SPEC_FILE?=$(SELF_DIR)/m_specs/complex_case_with_ins_outs_2020.m_spec - MPP_FUNCTION?=traite_double_liquidation_2_interpreteur -else ifeq ($(YEAR), 2021) - SOURCE_FILES?=$(SOURCE_DIR_2021) - SOURCE_EXT_FILES?=$(SOURCE_EXT_DIR_2021) - MPP_FILE?=$(SELF_DIR)/mpp_specs/2020_6_5.mpp - TESTS_DIR?=$(SELF_DIR)/tests/2021/fuzzing/ - TEST_ONE?=$(SELF_DIR)/tests/2021/fuzzing/fuzzer_10004.m_test - M_SPEC_FILE?=$(SELF_DIR)/m_specs/complex_case_with_ins_outs_2020.m_spec - MPP_FUNCTION?=traite_double_liquidation_2_interpreteur -else ifeq ($(YEAR), 2022) - SOURCE_FILES?=$(SOURCE_DIR_2022) - SOURCE_EXT_FILES?=$(SOURCE_EXT_DIR_2022) - MPP_FILE?=$(SELF_DIR)/mpp_specs/2020_6_5.mpp - TESTS_DIR?=$(SELF_DIR)/tests/2022/fuzzing/ - TEST_ONE?=$(SELF_DIR)/tests/2022/fuzzing/fuzzer_10004.m_test - M_SPEC_FILE?=$(SELF_DIR)/m_specs/complex_case_with_ins_outs_2020.m_spec - MPP_FUNCTION?=traite_double_liquidation_2_interpreteur -else - $(warning WARNING: there is no default configuration for year: $(YEAR)) - $(warning WARNING: example specification files and fuzzer tests are not included for year: $(YEAR)) -endif - -################################################## -# Mlang configuration -################################################## - -ifeq ($(OPTIMIZE), 0) - OPTIMIZE_FLAG= -else - OPTIMIZE_FLAG=-O -endif - -MLANG_BIN=dune exec $(SELF_DIR)/_build/default/src/main.exe -- - -PRECISION?=double -MLANG_DEFAULT_OPTS=\ - --display_time --debug \ - --precision $(PRECISION) \ - $(OPTIMIZE_FLAG) - -################################################## -# C backend configuration -################################################## - -# CC is a GNU make default variable defined to CC -# It so can't be overriden by conditional operator ?= -# We check the origin of CC value to not override CL argument or explicit environment. -ifeq ($(origin CC),default) - CC=clang -endif - -# Options pour le compilateur C -# Attention, très long à compiler avec GCC en O2/O3 -COMMON_CFLAGS?=-std=c89 -pedantic -ifeq ($(CC), clang) - COMPILER_SPECIFIC_CFLAGS=-O2 -else ifeq ($(CC), gcc) - COMPILER_SPECIFIC_CFLAGS=-O1 -endif -BACKEND_CFLAGS=$(COMMON_CFLAGS) $(COMPILER_SPECIFIC_CFLAGS) - -# Directory of the driver sources for tax calculator -DRIVER_DIR?=ml_driver/ -# Driver sources for tax calculator (must be manually ordered for OCaml compiler) -DRIVER_FILES?=irdata.c stubs.c common.ml m.ml read_test.ml main.ml - -# Flag to disable binary dump comparison -NO_BINARY_COMPARE?=1 - -################################################## -# Exports to call backends from main Makefile -################################################## - -# common -export SOURCE_FILES SOURCE_EXT_FILES TESTS_DIR TEST_ONE MLANG_BIN MLANG_DEFAULT_OPTS -# for C backend (Java compilation is year-independent) -export YEAR CC BACKEND_CFLAGS DRIVER_DIR DRIVER_FILES NO_BINARY_COMPARE -# for Java backend (C overload these now) -export MPP_FUNCTION MPP_FILE diff --git a/examples/dgfip_c/ml_primitif/Makefile b/examples/dgfip_c/ml_primitif/Makefile deleted file mode 100644 index 09a3d90a..00000000 --- a/examples/dgfip_c/ml_primitif/Makefile +++ /dev/null @@ -1,169 +0,0 @@ -ifeq ($(MAKELEVEL), 0) - include ../../../Makefile.include -endif - -ifeq ($(TEST_FILTER), 1) - TEST_FILES=$(TESTS_DIR)[A-Z]* -else - TEST_FILES=$(TESTS_DIR)* -endif - -# DGFiP C backend works only with these specifications at the moment. -MPP_FUNCTION=traite_double_liquidation_2 - -MLANG_DGFIP_C_OPTS=\ - --mpp_function=$(MPP_FUNCTION) - -# Options supplémentaires pour le backend Mlang/DGFiP spécifiques à la cible -# Par défaut ici pour l'autotest Mlang et l'intégration continue. -# Note : compilation avec -g et -k OBLIGATOIREMENT -# -g : informations pour tests et débogage -# -kN : nombre de segment pour la table de débogage. -# N=1 à 4 pour le pilotage Mlang ml_primitif -# N=4 pour utiliser le pilotage DGFiP. -# Note : compilation avec -O (optimisation par inlining) -DGFIP_TARGET_FLAGS?=-g,-O,-k4 -# Options supplémentaires pour le backend Mlang/DGFiP communes à tous les build : -# Note: les flags -Ailiad, -g et -k sont déjà définis -# -Ailiad : ensemble de règles sélectionné ("Application ciblée") -# -m : millésime de calculette compilé (année des revenus taxés) -# -X : génération de fonctions d'extraction globale dans l'interface, -# bouclant sur la table des variables restituables (IN_init_extraction). -DGFIP_COMMON_FLAGS=-Ailiad,-m$(YEAR),-X - -MLANG=$(MLANG_BIN) $(MLANG_DEFAULT_OPTS) $(MLANG_DGFIP_C_OPTS) -QUIET=>/dev/null # Uncomment to suppress output - -# Options pour le compilateur OCaml -OCAMLFLAGS= -#OCAMLFLAGS="-g -inline 0" -# Pour instrumenter la couverture de code, il est nécessaire d'installer le paquet OCaml bisect_ppx -# Utiliser l'indicateur WITH_BISECT=1 pour activer l'instrumentation nécessaire à l'analyse de la couverture de code -# lors des étapes de compilation. -WITH_BISECT?=0 -ifeq ($(WITH_BISECT), 1) - BISECT_PATH:=$(shell ocamlfind query bisect_ppx) - ifeq ($(BISECT_PATH),) - $(error $(BISECT_PATH) \ - Pour instrumenter la couverture de code, il est nécessaire d'installer le paquet OCaml bisect_ppx) - endif -endif - -.DEFAULT_GOAL := cal - -################################################## -# Generating C files from M sources with Mlang -################################################## - -calc/enchain.c: $(SOURCE_FILES) $(SOURCE_EXT_FILES) - mkdir -p calc - @echo "Compilation des fichiers M avec Mlang (MPP_FUNCTION=$(MPP_FUNCTION), DGFIP_TARGET_FLAGS=$(DGFIP_TARGET_FLAGS), DGFIP_COMMON_FLAGS=$(DGFIP_COMMON_FLAGS))" - @$(MLANG) \ - --dgfip_options=$(DGFIP_TARGET_FLAGS),$(DGFIP_COMMON_FLAGS)\ - --backend dgfip_c --output $@ \ - $(SOURCE_FILES) $(SOURCE_EXT_FILES) $(QUIET) - @echo "Compilation terminée" - -################################################# -# Compiling the generated C -################################################## - -# list existing C file from M equivalent (Useful idea to improve upon) -M_C_FILES=$(filter-out tgv%.c err%.c,$(notdir $(SOURCE_FILES:.m=.c))) - -# ADDITIONAL_C_SOURCES_TARGETS allows to create new targets in configuration to produce or load in the source folder before compiling. -calc/enchain.o: calc/enchain.c $(ADDITIONAL_C_SOURCES_TARGETS) - @echo "Compilation des fichiers C issus des fichiers M (CC=$(CC), BACKEND_CFLAGS=$(BACKEND_CFLAGS))" -# If calc/ directory was not cleaned between builds, some driver C files are present that mustn't be compiled at this stage. -# We use find to scan the directory and keep every .c except files which are in DRIVER_FILES list. -# To exclude files string1, string2 and string3 from the match, the syntax is '-not \( -name "string1" -o -name "string2" -o -name "string3" \)' -# so we use string substitution to replace the space separator by the '" -o -name "' between the file names. -# $() is an empty variable, canonical way to force make to take into account the space as the string to be replaced. - cd calc && find ./ -name "*.c" -not \( -name "$(subst $() ," -o -name ",$(DRIVER_FILES))" \) \ - -exec $(CC) $(BACKEND_CFLAGS) -c \ - {} + -# irdata.c enchain.c var.c contexte.c famille.c revenu.c revcor.c penalite.c variatio.c tableg??.c restitue.c \ - chap-*.c res-ser*.c coc*.c coi*.c horiz*.c - -################################################# -# Final targets -################################################## - -# Build derivative file lists -DRIVER_TARGETS:=$(foreach file,$(DRIVER_FILES),calc/$(file)) -DRIVER_TEMP:=$(DRIVER_FILES:.ml=.o) -DRIVER_OBJECT_FILES:=$(DRIVER_TEMP:.c=.o) -# TODO: use &: when upgraded to GNU Make 4.3+ -$(DRIVER_TARGETS) : - @echo "Copie des sources du pilote depuis $(DRIVER_DIR)" - cp $(DRIVER_DIR)* calc/ - -# Ml_primitif (current main build) -# ----------------------------- -cal: calc/enchain.o $(DRIVER_TARGETS) - @echo "Compilation de la calculette primitive (OCAMLFLAGS=$(OCAMLFLAGS), WITH_BISECT=$(WITH_BISECT))" - cd calc && rm -f $(DRIVER_OBJECT_FILES) -ifeq ($(WITH_BISECT), 1) - cd calc && ocamlopt -cc $(CC) -ccopt -std=c99 -ccopt -fno-common \ - -I $(BISECT_PATH)/common -I $(BISECT_PATH)/runtime \ - -ppx "$(BISECT_PATH)/ppx.exe --as-ppx" \ - unix.cmxa bisect_common.cmxa bisect.cmxa *.o $(DRIVER_FILES) -o cal -else - cd calc && ocamlopt -cc $(CC) $(OCAMLFLAGS) -ccopt -std=c99 -ccopt -fno-common \ - unix.cmxa *.o $(DRIVER_FILES) -o ../cal -endif - -################################################## -# Running the tests -################################################## - -# Ml_primitif (current main build) -# ----------------------------- -run_tests: cal - ./cal ${TEST_FILES} - -backend_tests: FORCE run_tests - -################################################## -# Cleaners -################################################## - -clean: - @echo "Nettoyage des fichiers binaires intermédiaires" - rm -f calc/*.o - rm -f calc/*.cm* - -# To keep in mind -# rm -f $(M_C_FILES) $(M_C_FILES:.c=.o) \ - contexte.* famille.* penalite.* restitue.* revcor.* \ - revenu.* tableg*.* tablev.* variatio.* var.* \ - conf.h annee.h desc.h desc_inv.h -cleanc: - @echo "Nettoyage des sources" - rm -f calc/*.[ch] - rm -f calc/*.inc - rm -f calc/version.* - rm -f calc/*.ml - -cleanexe: - @echo "Nettoyage des exécutables" - rm -f cal - rm -f *.exe - -cleantmp: - @echo "Nettoyage des fichiers temporaires" - rm -f *.tmp - -cleanres: - @echo "Nettoyage des résultats de test" - rm -f *.output/*.tgv - -cleanall: clean cleanc cleanexe cleanres - rm -f vars.txt - rm -f tests.m_spec - -################################################## -# Utilities -################################################## -# Really, we can hope to be cutting edge enough for .PHONY -FORCE: diff --git a/makefiles/c_backend.mk b/makefiles/c_backend.mk new file mode 100644 index 00000000..c0299298 --- /dev/null +++ b/makefiles/c_backend.mk @@ -0,0 +1,238 @@ +############################################### +# C backend # +############################################### + +DGFIP_DIR?=examples/dgfip_c/ml_primitif + +MPP_FUNCTION_BACKEND?=traite_double_liquidation_2 + +MLANG_DGFIP_C_OPTS=--mpp_function=$(MPP_FUNCTION_BACKEND) + +# Options supplémentaires pour le backend Mlang/DGFiP spécifiques à la cible +# Par défaut ici pour l'autotest Mlang et l'intégration continue. +# Note : compilation avec -g et -k OBLIGATOIREMENT +# -g : informations pour tests et débogage +# -kN : nombre de segment pour la table de débogage. +# N=1 à 4 pour le pilotage Mlang ml_primitif +# N=4 pour utiliser le pilotage DGFiP. +# Note : compilation avec -O (optimisation par inlining) +DGFIP_TARGET_FLAGS?=-g,-O,-k4 +# Options supplémentaires pour le backend Mlang/DGFiP communes à tous les build : +# Note: les flags -Ailiad, -g et -k sont déjà définis +# -Ailiad : ensemble de règles sélectionné ("Application ciblée") +# -m : millésime de calculette compilé (année des revenus taxés) +# -X : génération de fonctions d'extraction globale dans l'interface, +# bouclant sur la table des variables restituables (IN_init_extraction). +DGFIP_COMMON_FLAGS=-Ailiad,-m$(YEAR),-X + +MLANG_DGFIP=$(MLANG_BIN) $(MLANG_DEFAULT_OPTS) $(MLANG_DGFIP_C_OPTS) + +QUIET=>/dev/null # Uncomment to suppress output + +# Options pour le compilateur OCaml +OCAMLFLAGS= +#OCAMLFLAGS="-g -inline 0" +# Pour instrumenter la couverture de code, il est nécessaire d'installer +# le paquet OCaml bisect_ppx +# Utiliser l'indicateur WITH_BISECT=1 pour activer l'instrumentation nécessaire +# à l'analyse de la couverture de code lors des étapes de compilation. +WITH_BISECT?=0 +ifeq ($(WITH_BISECT), 1) + BISECT_PATH:=$(shell ocamlfind query bisect_ppx) + ifeq ($(BISECT_PATH),) + $(error $(BISECT_PATH) Pour instrumenter la couverture de code, il faut \ + installer le paquet OCaml bisect_ppx) + endif +endif + +################################################## +# Building the backend +################################################## + +ifeq ($(call is_in,$(DGFIP_DIR)),1) +calc_dir: FORCE + $(call make_in,$(DGFIP_DIR),$@) +endif + +ifeq ($(call is_in,$(DGFIP_DIR)),1) +$(SOURCE_FILES) $(SOURCE_EXT_FILES): FORCE +endif + +ifeq ($(call is_in,$(DGFIP_DIR)/calc),1) +%.o: %.c + $(CC) $(BACKEND_CFLAGS) -c $< -o $@ +endif + +ifeq ($(call is_in,$(DGFIP_DIR)),1) +calc/mlang.h: $(SOURCE_FILES) $(SOURCE_EXT_FILES) | calc_dir + $(call check_in,$(DGFIP_DIR),$@) + @echo "Compilation des fichiers M avec Mlang:" + @echo " MPP_FUNCTION=$(MPP_FUNCTION_BACKEND)" + @echo " DGFIP_TARGET_FLAGS=$(DGFIP_TARGET_FLAGS)" + @echo " DGFIP_COMMON_FLAGS=$(DGFIP_COMMON_FLAGS)" + @$(MLANG_DGFIP) \ + --dgfip_options=$(DGFIP_TARGET_FLAGS),$(DGFIP_COMMON_FLAGS) \ + --backend dgfip_c \ + --output calc/enchain.c \ + $(SOURCE_FILES) $(SOURCE_EXT_FILES) $(QUIET) +endif + +ifeq ($(call is_in,$(DGFIP_DIR)),1) +info_c: + $(call check_in,$(DGFIP_DIR),$@) + @echo "Compilation des fichiers C issus des fichiers M:" + @echo " CC=$(CC)" + @echo " BACKEND_CFLAGS=$(BACKEND_CFLAGS)" +# If calc/ directory was not cleaned between builds, some driver C files are +# present that mustn't be compiled at this stage. +# We use find to scan the directory and keep every .c except files which are in +# DRIVER_FILES list. +# To exclude files string1, string2 and string3 from the match, the syntax is +# '-not \( -name "string1" -o -name "string2" -o -name "string3" \)' so we use +# string substitution to replace the space separator by the '" -o -name "' +# between the file names. +# $() is an empty variable, canonical way to force make to take into account +# the space as the string to be replaced. +endif + +ifeq ($(call is_in,$(DGFIP_DIR)),1) +calc_o: + $(eval override C_FILES:=$(shell cd calc && ls -1 *.c) $(ADDITIONAL_C_SOURCES_TARGETS)) + cd calc && rm -f $(DRIVER_FILES) + @for I in $(C_FILES:.c=.o) ; \ + do \ + $(MAKE) --no-print-directory -f $(ROOT_DIR)/Makefile -C $(ROOT_DIR)/$(DGFIP_DIR)/calc ROOT_DIR=$(ROOT_DIR) $$I ; \ + done +endif + +# Build derivative file lists +DRIVER_TARGETS:=$(foreach file,$(DRIVER_FILES),calc/$(file)) +DRIVER_TEMP:=$(DRIVER_FILES:.ml=.o) +DRIVER_OBJECT_FILES:=$(DRIVER_TEMP:.c=.o) +# TODO: use &: when upgraded to GNU Make 4.3+ + +ifeq ($(call is_in,$(DGFIP_DIR)),1) +$(DRIVER_TARGETS): + @echo "Copie des sources du pilote depuis $(DRIVER_DIR)" + cp $(DRIVER_DIR)/* calc/ +endif + +# Ml_primitif (current main build) +# ----------------------------- +ifeq ($(call is_in,$(DGFIP_DIR)),1) +cal: $(DRIVER_TARGETS) + @echo "Compilation de la calculette primitive:" + @echo " OCAMLFLAGS=$(OCAMLFLAGS)" + @echo " WITH_BISECT=$(WITH_BISECT)" + cd calc && rm -f $(DRIVER_OBJECT_FILES) +ifeq ($(WITH_BISECT), 1) + cd calc && ocamlopt -cc $(CC) -ccopt -std=c99 -ccopt -fno-common \ + -I $(BISECT_PATH)/common -I $(BISECT_PATH)/runtime \ + -ppx "$(BISECT_PATH)/ppx.exe --as-ppx" \ + unix.cmxa bisect_common.cmxa bisect.cmxa *.o $(DRIVER_FILES) -o cal +else + cd calc && ocamlopt -cc $(CC) $(OCAMLFLAGS) -ccopt -std=c99 -ccopt -fno-common \ + unix.cmxa *.o $(DRIVER_FILES) -o ../cal +endif + @echo "Compilation terminée" +endif + +ifeq ($(call is_in,$(DGFIP_DIR)),1) +dgfip_c_backend: FORCE | build calc/mlang.h +else +dgfip_c_backend: FORCE + $(call make_in,$(DGFIP_DIR),$@) +endif + +ifeq ($(call is_in,$(DGFIP_DIR)),1) +compile_dgfip_c_backend: FORCE | dgfip_c_backend info_c calc_o cal +else +compile_dgfip_c_backend: FORCE + $(call make_in,$(DGFIP_DIR),$@) +endif + +################################################## +# Testing the backend +################################################## + +ifeq ($(call is_in,$(DGFIP_DIR)),1) +backend_tests: compile_dgfip_c_backend + ./cal ${TEST_FILES} +endif + +ifeq ($(call is_in,$(DGFIP_DIR)),1) +test_dgfip_c_backend: FORCE backend_tests +else +test_dgfip_c_backend: FORCE + $(call make_in,$(DGFIP_DIR),$@) +endif + + +################################################## +# Cleaners +################################################## + +ifeq ($(call is_in,$(DGFIP_DIR)),1) +clean_backend: FORCE + @echo "Nettoyage des fichiers binaires intermédiaires" + rm -f calc/*.o + rm -f calc/*.cm* +else +clean_backend: FORCE + $(call make_in,$(DGFIP_DIR),$@) +endif + +# To keep in mind +# rm -f $(M_C_FILES) $(M_C_FILES:.c=.o) \ + contexte.* famille.* penalite.* restitue.* revcor.* \ + revenu.* tableg*.* tablev.* variatio.* var.* \ + conf.h annee.h desc.h desc_inv.h +ifeq ($(call is_in,$(DGFIP_DIR)),1) +clean_backend_c: FORCE + @echo "Nettoyage des sources" + rm -f calc/*.[ch] + rm -f calc/*.inc + rm -f calc/version.* + rm -f calc/*.ml +else +clean_backend_c: FORCE + $(call make_in,$(DGFIP_DIR),$@) +endif + +ifeq ($(call is_in,$(DGFIP_DIR)),1) +clean_backend_exe: FORCE + @echo "Nettoyage des exécutables" + rm -f cal + rm -f *.exe +else +clean_backend_exe: FORCE + $(call make_in,$(DGFIP_DIR),$@) +endif + +ifeq ($(call is_in,$(DGFIP_DIR)),1) +clean_backend_tmp: FORCE + @echo "Nettoyage des fichiers temporaires" + rm -f *.tmp +else +clean_backend_tmp: FORCE + $(call make_in,$(DGFIP_DIR),$@) +endif + +ifeq ($(call is_in,$(DGFIP_DIR)),1) +clean_backend_res: FORCE + @echo "Nettoyage des résultats de test" + rm -f *.output/*.tgv +else +clean_backend_res: FORCE + $(call make_in,$(DGFIP_DIR),$@) +endif + +ifeq ($(call is_in,$(DGFIP_DIR)),1) +clean_backend_all: FORCE clean_backend clean_backend_c clean_backend_exe clean_backend_res + rm -f vars.txt + rm -f tests.m_spec +else +clean_backend_all: FORCE + $(call make_in,$(DGFIP_DIR),$@) +endif + diff --git a/makefiles/functions.mk b/makefiles/functions.mk index a73477bc..0dd2305f 100644 --- a/makefiles/functions.mk +++ b/makefiles/functions.mk @@ -2,16 +2,22 @@ # Fonctions utiles # ################################## -$(info Functions) - -define eq -$(if $(or $(1),$(2)),$(and $(findstring $(1),$(2)),$(findstring $(2),$(1))),1) +define to_bool +$(if $(1),1,) endef define not $(if $(1),,1) endef +define eq +$(call to_bool,$(if $(or $(1),$(2)),$(and $(findstring $(1),$(2)),$(findstring $(2),$(1))),1)) +endef + +define neq +$(call not,$(call eq,$(1),$(2))) +endef + define lt $(shell [ $(1) -lt $(2) ] && echo "1") endef @@ -28,3 +34,29 @@ define ge $(shell [ $(1) -ge $(2) ] && echo "1") endef +define is_in +$(call eq,$(CURR_DIR)$(if $(1),,/),$(ROOT_DIR)/$(1)) +endef + +define make_in +$(if $(call not,$(call is_in,$(1))), \ + @$(MAKE) --no-print-directory -f $(ROOT_DIR)/Makefile -C $(ROOT_DIR)/$(1) ROOT_DIR=$(ROOT_DIR) $(2)) +endef + +define make_in_raw +$(MAKE) --no-print-directory -f $(ROOT_DIR)/Makefile -C $(ROOT_DIR)/$(1) ROOT_DIR=$(ROOT_DIR) $(2) +endef + +define check_in +$(if $(call not,$(call is_in,$(1))), \ + $(error Rule $(2) forbidden in directory $(CURR_DIR), must be $$(ROOT_DIR)/$(1))) +endef + +define source_dir +$(1)tgvI.m $(1)errI.m $(shell find $(1) -name \*.m ! -name err\*.m ! -name tgv\*.m | sort) +endef + +define source_dir_ext +$(shell find $(1) -name \*.m | sort) +endef + diff --git a/makefiles/mlang.mk b/makefiles/mlang.mk new file mode 100644 index 00000000..14b25fff --- /dev/null +++ b/makefiles/mlang.mk @@ -0,0 +1,105 @@ +############################################### +# Init project & build compiler # +############################################### + +################################################## +# Initializing the project +################################################## + +# Workaround for Opam 2.0 bug. Empty switch creation then installation could be a one line +# "opam switch create . --deps-only" otherwise +create-switch: FORCE +ifeq ($(call is_in,),) + $(call make_in,,$@) +else + opam switch create . --empty +endif + +init-without-switch: FORCE +ifeq ($(call is_in,),) + $(call make_in,,$@) +else + opam install . --deps-only + git submodule update --init +endif + +init: FORCE create-switch init-without-switch + +deps: FORCE +ifeq ($(call is_in,),) + $(call make_in,,$@) +else + opam switch reinstall --deps-only + git submodule update +endif + +################################################## +# Building the compiler +################################################## + +format: FORCE +ifeq ($(call is_in,),) + $(call make_in,,$@) +else + dune build @fmt --auto-promote | true +endif + +dune: FORCE +ifeq ($(call is_in,),) + $(call make_in,,$@) +else + dune build $(DUNE_OPTIONS) +endif + +build: FORCE | format dune + +# Run only in an opam switch with musl and static options activated +build-static: DUNE_OPTIONS+=--profile=static +build-static: FORCE build + +################################################## +# Testing the compiler +################################################## + +# use: TEST_FILE=bla make test +test: FORCE build +ifeq ($(call is_in,),) + $(call make_in,,$@) +else + $(MLANG_TEST) --run_test=$(TEST_FILE) $(SOURCE_FILES) $(SOURCE_EXT_FILES) +endif + +# use: TESTS_DIR=bla make test +tests: FORCE build +ifeq ($(call is_in,),) + $(call make_in,,$@) +else + $(MLANG_TEST) $(MLANGOPTS) --run_all_tests=$(TESTS_DIR) $(TEST_FILTER_FLAG) $(SOURCE_FILES) $(SOURCE_EXT_FILES) +endif + +quick_test: FORCE build +ifeq ($(call is_in,),) + $(call make_in,,$@) +else + $(MLANG_TEST) --backend interpreter --function_spec $(M_SPEC_FILE) $(SOURCE_FILES) $(SOURCE_EXT_FILES) +endif + +test_one: FORCE build +ifeq ($(call is_in,),) + $(call make_in,,$@) +else + $(MLANG_TEST) --backend interpreter --run_test=$(TEST_ONE) $(SOURCE_FILES) $(SOURCE_EXT_FILES) +endif + +################################################## +# Doc +################################################## + +doc: FORCE build +ifeq ($(call is_in,),) + $(call make_in,,$@) +else + dune build @doc + ln -fs $(shell pwd)/_build/default/_doc/_html/index.html doc/doc.html +endif + diff --git a/makefiles/variables.mk b/makefiles/variables.mk new file mode 100644 index 00000000..b8b34aa1 --- /dev/null +++ b/makefiles/variables.mk @@ -0,0 +1,158 @@ +################################### +# Variables # +################################### + +################################################## +# Tax computation configuration +################################################## + +SOURCE_DIR_2015:=$(call source_dir,$(ROOT_DIR)/ir-calcul/sources2015m_4_6/) +SOURCE_DIR_2016:=$(call source_dir,$(ROOT_DIR)/ir-calcul/sources2016m_4_5/) +SOURCE_DIR_2017:=$(call source_dir,$(ROOT_DIR)/ir-calcul/sources2017m_6_10/) +SOURCE_DIR_2018:=$(call source_dir,$(ROOT_DIR)/ir-calcul/sources2018m_6_7/) +SOURCE_DIR_2019:=$(call source_dir,$(ROOT_DIR)/ir-calcul/sources2019m_8_0/) +SOURCE_DIR_2020:=$(call source_dir,$(ROOT_DIR)/ir-calcul/sources2020m_6_5/) +SOURCE_DIR_2021:=$(call source_dir,$(ROOT_DIR)/ir-calcul/sources2021m_20_6/) +SOURCE_DIR_2022:=$(call source_dir,$(ROOT_DIR)/ir-calcul/sources2022m_22_1/) + +SOURCE_EXT_DIR_2015:=$(call source_dir_ext,$(ROOT_DIR)/mpp_specs/m_ext/2015/) +SOURCE_EXT_DIR_2016:=$(call source_dir_ext,$(ROOT_DIR)/mpp_specs/m_ext/2016/) +SOURCE_EXT_DIR_2017:=$(call source_dir_ext,$(ROOT_DIR)/mpp_specs/m_ext/2017/) +SOURCE_EXT_DIR_2018:=$(call source_dir_ext,$(ROOT_DIR)/mpp_specs/m_ext/2018/) +SOURCE_EXT_DIR_2019:=$(call source_dir_ext,$(ROOT_DIR)/mpp_specs/m_ext/2019/) +SOURCE_EXT_DIR_2020:=$(call source_dir_ext,$(ROOT_DIR)/mpp_specs/m_ext/2020/) +SOURCE_EXT_DIR_2021:=$(call source_dir_ext,$(ROOT_DIR)/mpp_specs/m_ext/2021/) +SOURCE_EXT_DIR_2022:=$(call source_dir_ext,$(ROOT_DIR)/mpp_specs/m_ext/2022/) + +YEAR?=2020 + +ifeq ($(YEAR), 2018) + SOURCE_FILES?=$(SOURCE_DIR_2018) + SOURCE_EXT_FILES?=$(SOURCE_EXT_DIR_2018) + MPP_FILE?=$(ROOT_DIR)/mpp_specs/2018_6_7.mpp + TESTS_DIR?=$(ROOT_DIR)/tests/2018/fuzzing/ + TEST_ONE?=$(ROOT_DIR)/tests/2020/fuzzing/fuzzer_10019.m_test + M_SPEC_FILE?=$(ROOT_DIR)/m_specs/complex_case_with_ins_outs_2018.m_spec + MPP_FUNCTION?=compute_double_liquidation_pvro +else ifeq ($(YEAR), 2019) + SOURCE_FILES?=$(SOURCE_DIR_2019) + SOURCE_EXT_FILES?=$(SOURCE_EXT_DIR_2019) + MPP_FILE?=$(ROOT_DIR)/mpp_specs/2019_8_0.mpp + TESTS_DIR?=$(ROOT_DIR)/tests/2019/fuzzing/ + TEST_ONE?=$(ROOT_DIR)/tests/2019/fuzzing/fuzzer_10029.m_test + M_SPEC_FILE?=m_specs/complex_case_with_ins_outs_2019.m_spec + MPP_FUNCTION?=traite_double_liquidation_2_interpreteur +else ifeq ($(YEAR), 2020) + SOURCE_FILES?=$(SOURCE_DIR_2020) + SOURCE_EXT_FILES?=$(SOURCE_EXT_DIR_2020) + MPP_FILE?=$(ROOT_DIR)/mpp_specs/2020_6_5.mpp + TESTS_DIR?=$(ROOT_DIR)/tests/2020/fuzzing/ + TEST_ONE?=$(ROOT_DIR)/tests/2020/fuzzing/fuzzer_1001.m_test + M_SPEC_FILE?=$(ROOT_DIR)/m_specs/complex_case_with_ins_outs_2020.m_spec + MPP_FUNCTION?=traite_double_liquidation_2_interpreteur +else ifeq ($(YEAR), 2021) + SOURCE_FILES?=$(SOURCE_DIR_2021) + SOURCE_EXT_FILES?=$(SOURCE_EXT_DIR_2021) + MPP_FILE?=$(ROOT_DIR)/mpp_specs/2020_6_5.mpp + TESTS_DIR?=$(ROOT_DIR)/tests/2021/fuzzing/ + TEST_ONE?=$(ROOT_DIR)/tests/2021/fuzzing/fuzzer_10004.m_test + M_SPEC_FILE?=$(ROOT_DIR)/m_specs/complex_case_with_ins_outs_2020.m_spec + MPP_FUNCTION?=traite_double_liquidation_2_interpreteur +else ifeq ($(YEAR), 2022) + SOURCE_FILES?=$(SOURCE_DIR_2022) + SOURCE_EXT_FILES?=$(SOURCE_EXT_DIR_2022) + MPP_FILE?=$(ROOT_DIR)/mpp_specs/2020_6_5.mpp + TESTS_DIR?=$(ROOT_DIR)/tests/2022/fuzzing/ + TEST_ONE?=$(ROOT_DIR)/tests/2022/fuzzing/fuzzer_10004.m_test + M_SPEC_FILE?=$(ROOT_DIR)/m_specs/complex_case_with_ins_outs_2020.m_spec + MPP_FUNCTION?=traite_double_liquidation_2_interpreteur +else + $(warning WARNING: there is no default configuration for year: $(YEAR)) + $(warning WARNING: example specification files and fuzzer tests are not included for year: $(YEAR)) +endif + +################################################## +# Mlang configuration +################################################## + +ifeq ($(OPTIMIZE), 0) + OPTIMIZE_FLAG= +else + OPTIMIZE_FLAG=-O +endif + +MLANG_BIN=dune exec $(ROOT_DIR)/_build/default/src/main.exe -- + +PRECISION?=double +MLANG_DEFAULT_OPTS=\ + --display_time --debug\ + --precision $(PRECISION)\ + $(OPTIMIZE_FLAG) + +################################################## +# C backend configuration +################################################## + +# CC is a GNU make default variable defined to CC +# It so can't be overriden by conditional operator ?= +# We check the origin of CC value to not override CL argument or explicit environment. +ifeq ($(origin CC),default) + CC=clang +endif + +# Options pour le compilateur C +# Attention, très long à compiler avec GCC en O2/O3 +COMMON_CFLAGS?=-std=c89 -pedantic +ifeq ($(CC), clang) + COMPILER_SPECIFIC_CFLAGS=-O2 +else ifeq ($(CC), gcc) + COMPILER_SPECIFIC_CFLAGS=-O1 +endif +BACKEND_CFLAGS=$(COMMON_CFLAGS) $(COMPILER_SPECIFIC_CFLAGS) + +# Directory of the driver sources for tax calculator +DRIVER_DIR?=ml_driver +# Driver sources for tax calculator (must be manually ordered for OCaml compiler) +DRIVER_FILES?=irdata.c stubs.c common.ml m.ml read_test.ml main.ml + +# Flag to disable binary dump comparison +NO_BINARY_COMPARE?=1 + +################################################## +# Etc. +################################################## + +ifeq ($(CODE_COVERAGE), 1) + CODE_COVERAGE_FLAG=--code_coverage +else + CODE_COVERAGE_FLAG= +endif + +ifeq ($(TEST_FILTER), 1) + TEST_FILTER_FLAG=--dgfip_test_filter + TEST_FILES=$(TESTS_DIR)[A-Z]* +else + TEST_FILTER_FLAG= + TEST_FILES=$(TESTS_DIR)* +endif + +TEST_ERROR_MARGIN?=0. + +MLANG_INTERPRETER_OPTS=\ + --test_error_margin=$(TEST_ERROR_MARGIN) \ + --mpp_function=$(MPP_FUNCTION) + +MLANG_TEST=$(MLANG_BIN) $(MLANG_DEFAULT_OPTS) $(MLANG_INTERPRETER_OPTS) $(CODE_COVERAGE_FLAG) + + +################################################## +# Exports to call backends from main Makefile +################################################## + +# common +export SOURCE_FILES SOURCE_EXT_FILES TESTS_DIR TEST_ONE MLANG_BIN MLANG_DEFAULT_OPTS +# for C backend (Java compilation is year-independent) +export YEAR CC BACKEND_CFLAGS DRIVER_DIR DRIVER_FILES NO_BINARY_COMPARE +# for Java backend (C overload these now) +export MPP_FUNCTION MPP_FILE +