From ff0ec188e27000dc80bdba80a6876ccf26c8f4ae Mon Sep 17 00:00:00 2001
From: Allan Blanchard <allan.blanchard@cea.fr>
Date: Wed, 20 Apr 2022 16:12:36 +0200
Subject: [PATCH] [dune] Generate Eva API

---
 src/plugins/value/{Eva.ml => Eva.ml.in} |  12 +-
 src/plugins/value/Eva.mli               | 548 ------------------------
 src/plugins/value/Eva.mli.in            |  53 +++
 src/plugins/value/dune                  |  10 +
 src/plugins/value/gen-api.sh            |  37 +-
 5 files changed, 93 insertions(+), 567 deletions(-)
 rename src/plugins/value/{Eva.ml => Eva.ml.in} (87%)
 delete mode 100644 src/plugins/value/Eva.mli
 create mode 100644 src/plugins/value/Eva.mli.in

diff --git a/src/plugins/value/Eva.ml b/src/plugins/value/Eva.ml.in
similarity index 87%
rename from src/plugins/value/Eva.ml
rename to src/plugins/value/Eva.ml.in
index 4c12fdc8182..612736cbcd2 100644
--- a/src/plugins/value/Eva.ml
+++ b/src/plugins/value/Eva.ml.in
@@ -2,7 +2,7 @@
 (*                                                                        *)
 (*  This file is part of Frama-C.                                         *)
 (*                                                                        *)
-(*  Copyright (C) 2007-2020                                               *)
+(*  Copyright (C) 2007-2022                                               *)
 (*    CEA (Commissariat à l'énergie atomique et aux énergies              *)
 (*         alternatives)                                                  *)
 (*                                                                        *)
@@ -44,13 +44,3 @@ module Private = struct
   module Eval_annots = Eva__Eval_annots
   module Eva_dynamic = Eva_dynamic
 end
-
-module Analysis = Analysis
-module Results = Results
-module Parameters = Parameters
-module Eva_annotations = Eva_annotations
-module Eval = Eval
-module Builtins = Builtins
-module Eval_terms = Eval_terms
-module Eva_results = Eva_results
-module Unit_tests = Unit_tests
diff --git a/src/plugins/value/Eva.mli b/src/plugins/value/Eva.mli
deleted file mode 100644
index bcb8c30652c..00000000000
--- a/src/plugins/value/Eva.mli
+++ /dev/null
@@ -1,548 +0,0 @@
-(**************************************************************************)
-(*                                                                        *)
-(*  This file is part of Frama-C.                                         *)
-(*                                                                        *)
-(*  Copyright (C) 2007-2021                                               *)
-(*    CEA (Commissariat à l'énergie atomique et aux énergies              *)
-(*         alternatives)                                                  *)
-(*                                                                        *)
-(*  you can redistribute it and/or modify it under the terms of the GNU   *)
-(*  Lesser General Public License as published by the Free Software       *)
-(*  Foundation, version 2.1.                                              *)
-(*                                                                        *)
-(*  It is distributed in the hope that it will be useful,                 *)
-(*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *)
-(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *)
-(*  GNU Lesser General Public License for more details.                   *)
-(*                                                                        *)
-(*  See the GNU Lesser General Public License version 2.1                 *)
-(*  for more details (enclosed in the file licenses/LGPLv2.1).            *)
-(*                                                                        *)
-(**************************************************************************)
-
-(** ../.. *)
-
-(** For internal use *)
-(* Private first so that we do not override internal modules with public ones *)
-
-module Private: sig
-  module Abstractions = Abstractions
-  module Analysis = Analysis
-  module Alarmset = Alarmset
-  module Parameters = Parameters
-  module Main_values = Main_values
-  module Eval = Eval
-  module Eva_utils = Eva_utils
-  module Eva_results = Eva_results
-  module Self = Self
-  module Eval_terms = Eval_terms
-  module Red_statuses = Red_statuses
-  module Abstract_value = Abstract_value
-  module Abstract_domain = Abstract_domain
-  module Mark_noresults = Mark_noresults
-  module Simple_memory = Simple_memory
-  module Structure = Structure
-  module Eval_typ = Eval_typ
-  module Eval_op = Eval_op
-  module Domain_builder = Domain_builder
-  module Main_locations = Main_locations
-  module Eval_annots = Eval_annots
-  module Eva_dynamic = Eva_dynamic
-end
-
-(** ../.. *)
-
-
-(** Eva public API.
-
-    The main modules are:
-    - Analysis: run the analysis.
-    - Results: access analysis results, especially the values of expressions
-      and memory locations of lvalues at each program point.
-
-    The following modules allow configuring the Eva analysis:
-    - Parameters: change the configuration of the analysis.
-    - Eva_annotations: add local annotations to guide the analysis.
-    - Builtins: register ocaml builtins to be used by the cvalue domain
-       instead of analysing the body of some C functions.
-
-    Other modules are for internal use only. *)
-
-(* This file is generated. Do not edit. *)
-
-module Analysis: sig
-  val compute : unit -> unit
-  (** Computes the Eva analysis, if not already computed, using the entry point
-      of the current project. You may set it with {!Globals.set_entry_point}.
-      @raise Globals.No_such_entry_point if the entry point is incorrect
-      @raise Db.Value.Incorrect_number_of_arguments if some arguments are
-      specified for the entry point using {!Db.Value.fun_set_args}, and
-      an incorrect number of them is given.
-      @plugin development guide *)
-
-  val is_computed : unit -> bool
-  (** Return [true] iff the Eva analysis has been done. *)
-
-  val self : State.t
-  (** Internal state of Eva analysis from projects viewpoint. *)
-
-end
-
-module Results: sig
-
-  (** Eva's result API is a work-in-progress interface to allow accessing the
-      analysis results once its completed. It is experimental and is very likely
-      to change in the future. It aims at replacing [Db.Value] but does not
-      completely covers all its usages yet. As for now, this interface has some
-      advantages over Db's :
-
-      - evaluations uses every available domains and not only Cvalue;
-      - the caller may distinguish failure cases when a request is unsucessful;
-      - working with callstacks is easy;
-      - some common shortcuts are provided (e.g. for extracting ival directly);
-      - overall, individual functions are simpler.
-
-      The idea behind this API is that requests must be decomposed in several
-      steps. For instance, to evaluate an expression :
-
-      1. first, you have to state where you want to evaluate it,
-      2. optionally, you may specify in which callstack,
-      3. you choose the expression to evaluate,
-      4. you require a destination type to evaluate into.
-
-      Usage sketch :
-
-      Eva.Results.(
-        before stmt |> in_callstack cs |>
-        eval_var vi |> as_int |> default 0)
-
-      or equivalently, if you prefer
-
-      Eva.Results.(
-        default O (as_int (eval_var vi (in_callstack cs (before stmt))))
-  *)
-
-
-  type callstack = (Cil_types.kernel_function * Cil_types.kinstr) list
-
-  type request
-
-  type value
-  type address
-  type 'a evaluation
-
-  type error = Bottom | Top | DisabledDomain
-  type 'a result = ('a,error) Result.t
-
-
-  (** Results handling *)
-
-  (** Translates an error to a human readable string. *)
-  val string_of_error : error -> string
-
-  (** Pretty printer for errors. *)
-  val pretty_error : Format.formatter -> error -> unit
-
-  (** Pretty printer for API's results. *)
-  val pretty_result : (Format.formatter -> 'a -> unit) ->
-    Format.formatter -> 'a result -> unit
-
-  (** [default d r] extracts the value of [r] if [r] is Ok,
-      or use the default value [d] otherwise.
-      Equivalent to [Result.value ~default:d r] *)
-  val default : 'a -> 'a result -> 'a
-
-
-  (** Control point selection *)
-
-  (** At the start of the analysis, but after the initialization of globals. *)
-  val at_start : request
-
-  (** At the end of the analysis, after the main function has returned. *)
-  val at_end : unit -> request
-
-  (** At the start of the given function. *)
-  val at_start_of : Cil_types.kernel_function -> request
-
-  (** At the end of the given function.
-      @raises Kernel_function.No_statement if the function has no body. *)
-  val at_end_of : Cil_types.kernel_function -> request
-
-  (** Just before a statement is executed. *)
-  val before : Cil_types.stmt -> request
-
-  (** Just after a statement is executed. *)
-  val after : Cil_types.stmt -> request
-
-  (** Just before a statement or at the start of the analysis. *)
-  val before_kinstr : Cil_types.kinstr -> request
-
-
-  (** Callstack selection *)
-
-  (** Only consider the given callstack.
-      Replaces previous calls to [in_callstack] or [in_callstacks]. *)
-  val in_callstack : callstack -> request -> request
-
-  (** Only consider the callstacks from the given list.
-      Replaces previous calls to [in_callstack] or [in_callstacks]. *)
-  val in_callstacks : callstack list -> request -> request
-
-  (** Only consider callstacks satisfying the given predicate. Several filters
-      can be added. If callstacks are also selected with [in_callstack] or
-      [in_callstacks], only the selected callstacks will be filtered. *)
-  val filter_callstack : (callstack -> bool) -> request -> request
-
-
-  (** Working with callstacks *)
-
-  (** Returns the list of reachable callstacks from the given request.
-      An empty list is returned if the request control point has not been
-      reached by the analysis, or if no information has been saved at this point
-      (for instance with the -eva-no-results option).
-      Use [is_empty request] to distinguish these two cases. *)
-  val callstacks : request -> callstack list
-
-  (** Returns a list of subrequests for each reachable callstack from
-      the given request. *)
-  val by_callstack : request -> (callstack * request) list
-
-
-  (** State requests *)
-
-  (** Returns the list of expressions which have been inferred to be equal to
-      the given expression by the Equality domain. *)
-  val equality_class : Cil_types.exp -> request -> Cil_types.exp list result
-
-  (** Returns the Cvalue state. Error cases are converted into the bottom or top
-      cvalue state accordingly. *)
-  val get_cvalue_model : request -> Cvalue.Model.t
-
-  (** Returns the Cvalue model. *)
-  val get_cvalue_model_result : request -> Cvalue.Model.t result
-
-
-  (** Dependencies *)
-
-  (** Computes (an overapproximation of) the memory zones that must be read to
-      evaluate the given expression, including all adresses computations. *)
-  val expr_deps : Cil_types.exp -> request -> Locations.Zone.t
-
-  (** Computes (an overapproximation of) the memory zones that must be read to
-      evaluate the given lvalue, including the lvalue zone itself. *)
-  val lval_deps : Cil_types.lval -> request -> Locations.Zone.t
-
-  (** Computes (an overapproximation of) the memory zones that must be read to
-      evaluate the given lvalue, excluding the lvalue zone itself. *)
-  val address_deps : Cil_types.lval -> request -> Locations.Zone.t
-
-
-  (** Evaluation *)
-
-  (** Returns (an overapproximation of) the possible values of the variable. *)
-  val eval_var : Cil_types.varinfo -> request -> value evaluation
-
-  (** Returns (an overapproximation of) the possible values of the lvalue. *)
-  val eval_lval : Cil_types.lval -> request -> value evaluation
-
-  (** Returns (an overapproximation of) the possible values of the expression. *)
-  val eval_exp : Cil_types.exp -> request -> value evaluation
-
-
-  (** Returns (an overapproximation of) the possible addresses of the lvalue. *)
-  val eval_address : ?for_writing:bool ->
-    Cil_types.lval -> request -> address evaluation
-
-
-  (** Returns the kernel functions into which the given expression may evaluate.
-      If the callee expression doesn't always evaluate to a function, those
-      spurious values are ignored. If it always evaluate to a non-function value
-      then the returned list is empty.
-      Raises [Stdlib.Invalid_argument] if the callee expression is not an lvalue
-      without offset.
-      Also see [callee] for a function which applies directly on Call
-      statements. *)
-  val eval_callee : Cil_types.exp -> request -> Kernel_function.t list result
-
-
-  (** Evaluated values conversion *)
-
-  (** In all functions below, if the abstract value inferred by Eva does not fit
-      in the required type, [Error Top] is returned, as Top is the only possible
-      over-approximation of the request. *)
-
-  (** Converts the value into a singleton ocaml int. *)
-  val as_int : value evaluation -> int result
-
-  (** Converts the value into a singleton unbounded integer. *)
-  val as_integer : value evaluation -> Integer.t result
-
-  (** Converts the value into a floating point number. *)
-  val as_float : value evaluation -> float result
-
-  (** Converts the value into a C number abstraction. *)
-  val as_ival : value evaluation -> Ival.t result
-
-  (** Converts the value into a floating point abstraction. *)
-  val as_fval : value evaluation -> Fval.t result
-
-  (** Converts the value into a Cvalue abstraction. Converts error cases
-      into bottom and top values accordingly. *)
-  val as_cvalue : value evaluation -> Cvalue.V.t
-
-  (** Converts the value into a Cvalue abstraction. *)
-  val as_cvalue_result : value evaluation -> Cvalue.V.t result
-
-  (** Converts the value into a Cvalue abstraction with 'undefined' and 'escaping
-    addresses' flags. *)
-   val as_cvalue_or_uninitialized : value evaluation -> Cvalue.V_Or_Uninitialized.t
-
-
-  (** Converts into a C location abstraction. *)
-  val as_location : address evaluation -> Locations.location result
-
-  (** Converts into a Zone. Error cases are converted into bottom or top zones
-      accordingly. *)
-  val as_zone: address evaluation -> Locations.Zone.t
-
-  (** Converts into a Zone result. *)
-  val as_zone_result : address evaluation -> Locations.Zone.t result
-
-
-  (** Evaluation properties *)
-
-
-  (** Does the evaluated abstraction represents only one possible C value or
-    memory location? *)
-  val is_singleton : 'a evaluation -> bool
-
-  (** Returns whether the evaluated value is initialized or not. If the value have
-      been evaluated from a Cil expression, it is always initialized. *)
-  val is_initialized : value evaluation -> bool
-
-  (** Returns the set of alarms emitted during the evaluation. *)
-  val alarms : 'a evaluation -> Alarms.t list
-
-
-  (** Reachability *)
-
-  (** Returns true if there are no reachable states for the given request. *)
-  val is_empty : request -> bool
-
-  (** Returns true if an evaluation leads to bottom, i.e. if the given expression
-      or lvalue cannot be evaluated to a valid result for the given request. *)
-  val is_bottom : 'a evaluation -> bool
-
-  (** Returns true if the function has been analyzed. *)
-  val is_called : Cil_types.kernel_function -> bool
-
-  (** Returns true if the statement has been reached by the analysis. *)
-  val is_reachable : Cil_types.stmt -> bool
-
-  (** Returns true if the statement has been reached by the analysis, or if
-      the main function has been analyzed for [Kglobal]. *)
-  val is_reachable_kinstr : Cil_types.kinstr -> bool
-
-  val condition_truth_value: Cil_types.stmt -> bool * bool
-  (** Provided [stmt] is an 'if' construct, [fst (condition_truth_value stmt)]
-      (resp. snd) is true if and only if the condition of the 'if' has been
-      evaluated to true (resp. false) at least once during the analysis. *)
-
-  (*** Callers / Callees / Callsites *)
-
-  (** Returns the list of inferred callers of the given function. *)
-  val callers : Cil_types.kernel_function -> Cil_types.kernel_function list
-
-  (** Returns the list of inferred callers, and for each of them, the list
-      of callsites (the call statements) inside. *)
-  val callsites : Cil_types.kernel_function ->
-    (Cil_types.kernel_function * Cil_types.stmt list) list
-
-
-  (** Returns the kernel functions called in the given statement.
-      If the callee expression doesn't always evaluate to a function, those
-      spurious values are ignored. If it always evaluate to a non-function value
-      then the returned list is empty.
-      Raises [Stdlib.Invalid_argument] if the statement is not a [Call]
-      instruction or a [Local_init] with [ConsInit] initializer. *)
-  val callee : Cil_types.stmt -> Kernel_function.t list
-
-end
-
-module Parameters: sig
-
-  (** Configuration of the analysis. *)
-
-  (** Returns the list (name, descr) of currently enabled abstract domains. *)
-  val enabled_domains: unit -> (string * string) list
-
-  (** [use_builtin kf name] instructs the analysis to use the builtin [name]
-      to interpret calls to function [kf].
-      Raises [Not_found] if there is no builtin of name [name]. *)
-  val use_builtin: Cil_types.kernel_function -> string -> unit
-
-  (** [use_global_value_partitioning vi] instructs the analysis to use
-      value partitioning on the global variable [vi]. *)
-  val use_global_value_partitioning: Cil_types.varinfo -> unit
-end
-
-module Eva_annotations: sig
-
-  (** Register special annotations to locally guide the Eva analysis:
-
-      - slevel annotations: "slevel default", "slevel merge" and "slevel i"
-      - loop unroll annotations: "loop unroll term"
-      - value partitioning annotations: "split term" and "merge term"
-      - subdivision annotations: "subdivide i"
-  *)
-
-  (** Annotations tweaking the behavior of the -eva-slevel parameter. *)
-  type slevel_annotation =
-    | SlevelMerge        (** Join all states separated by slevel. *)
-    | SlevelDefault      (** Use the limit defined by -eva-slevel. *)
-    | SlevelLocal of int (** Use the given limit instead of -eva-slevel. *)
-    | SlevelFull         (** Remove the limit of number of separated states. *)
-
-  (** Loop unroll annotations. *)
-  type unroll_annotation =
-    | UnrollAmount of Cil_types.term (** Unroll the n first iterations. *)
-    | UnrollFull (** Unroll amount defined by -eva-default-loop-unroll. *)
-
-  type split_kind = Static | Dynamic
-
-  type split_term =
-    | Expression of Cil_types.exp
-    | Predicate of Cil_types.predicate
-
-  (** Split/merge annotations for value partitioning.  *)
-  type flow_annotation =
-    | FlowSplit of split_term * split_kind
-    (** Split states according to a term. *)
-    | FlowMerge of split_term
-    (** Merge states separated by a previous split. *)
-
-  type allocation_kind = By_stack | Fresh | Fresh_weak | Imprecise
-
-  val get_slevel_annot : Cil_types.stmt -> slevel_annotation option
-  val get_unroll_annot : Cil_types.stmt -> unroll_annotation list
-  val get_flow_annot : Cil_types.stmt -> flow_annotation list
-  val get_subdivision_annot : Cil_types.stmt -> int list
-  val get_allocation: Cil_types.stmt -> allocation_kind
-
-  val add_slevel_annot : emitter:Emitter.t ->
-    Cil_types.stmt -> slevel_annotation -> unit
-  val add_unroll_annot : emitter:Emitter.t ->
-    Cil_types.stmt -> unroll_annotation -> unit
-  val add_flow_annot : emitter:Emitter.t ->
-    Cil_types.stmt -> flow_annotation -> unit
-  val add_subdivision_annot : emitter:Emitter.t ->
-    Cil_types.stmt -> int -> unit
-end
-
-module Eval: sig
-
-  (** Can the results of a function call be cached with memexec? *)
-  type cacheable =
-    | Cacheable      (** Functions whose result can be safely cached. *)
-    | NoCache        (** Functions whose result should not be cached, but for
-                         which the caller can still be cached. Typically,
-                         functions printing something during the analysis. *)
-    | NoCacheCallers (** Functions for which neither the call, neither the
-                         callers, can be cached. *)
-end
-
-module Builtins: sig
-
-  (** Eva analysis builtins for the cvalue domain, more efficient than their
-      equivalent in C. *)
-
-  open Cil_types
-
-  exception Invalid_nb_of_args of int
-  exception Outside_builtin_possibilities
-
-  (* Signature of a builtin: type of the result, and type of the arguments. *)
-  type builtin_type = unit -> typ * typ list
-
-  (** Can the results of a builtin be cached? See {eval.mli} for more details.*)
-  type cacheable = Eval.cacheable = Cacheable | NoCache | NoCacheCallers
-
-  type full_result = {
-    c_values: (Cvalue.V.t option * Cvalue.Model.t) list;
-    (** A list of results, consisting of:
-        - the value returned (ie. what is after the 'return' C keyword)
-        - the memory state after the function has been executed. *)
-    c_clobbered: Base.SetLattice.t;
-    (** An over-approximation of the bases in which addresses of local variables
-        might have been written *)
-    c_from: (Function_Froms.froms * Locations.Zone.t) option;
-    (** If not None, the froms of the function, and its sure outputs;
-        i.e. the dependencies of the result and of each zone written to. *)
-  }
-
-  (** The result of a builtin can be given in different forms. *)
-  type call_result =
-    | States of Cvalue.Model.t list
-    (** A disjunctive list of post-states at the end of the C function.
-        Can only be used if the C function does not write the address of local
-        variables, does not read other locations than the call arguments, and
-        does not write other locations than the result. *)
-    | Result of Cvalue.V.t list
-    (** A disjunctive list of resulting values. The specification is used to
-        compute the post-state, in which the result is replaced by the values
-        computed by the builtin. *)
-    | Full of full_result
-    (** See [full_result] type. *)
-
-  (** Type of a cvalue builtin, whose arguments are:
-      - the memory state at the beginning of the function call;
-      - the list of arguments of the function call. *)
-  type builtin = Cvalue.Model.t -> (exp * Cvalue.V.t) list -> call_result
-
-  (** [register_builtin name ?replace ?typ cacheable f] registers the function [f]
-      as a builtin to be used instead of the C function of name [name].
-      If [replace] is provided, the builtin is also used instead of the C function
-      of name [replace], unless option -eva-builtin-auto is disabled.
-      If [typ] is provided, consistency between the expected [typ] and the type of
-      the C function is checked before using the builtin.
-      The results of the builtin are cached according to [cacheable]. *)
-  val register_builtin:
-    string -> ?replace:string -> ?typ:builtin_type -> cacheable -> builtin -> unit
-
-  (** Has a builtin been registered with the given name? *)
-  val is_builtin: string -> bool
-end
-
-module Eval_terms: sig
-
-  (** [annot_predicate_deps ~pre ~here p] computes the logic dependencies needed
-      to evaluate the predicate [p] in a code annotation in cvalue state [here],
-      in a function whose pre-state is [pre].
-      Returns None on either an evaluation error or on unsupported construct. *)
-  val annot_predicate_deps:
-    pre:Cvalue.Model.t -> here:Cvalue.Model.t ->
-    Cil_types.predicate -> Locations.Zone.t option
-end
-
-module Eva_results: sig
-  type results
-
-  val get_results: unit -> results
-  val set_results: results -> unit
-  val merge: results -> results -> results
-  val change_callstacks:
-    (Value_types.callstack -> Value_types.callstack) -> results -> results
-    (** Change the callstacks for the results for which this is meaningful.
-        For technical reasons, the top of the callstack must currently
-        be preserved. *)
-
-end
-
-module Unit_tests: sig
-
-  (** Currently tested by this module:
-      - semantics of sign values. *)
-
-  (** Runs some programmatic tests on Eva. *)
-  val run: unit -> unit
-end
diff --git a/src/plugins/value/Eva.mli.in b/src/plugins/value/Eva.mli.in
new file mode 100644
index 00000000000..5c256dbae1f
--- /dev/null
+++ b/src/plugins/value/Eva.mli.in
@@ -0,0 +1,53 @@
+(**************************************************************************)
+(*                                                                        *)
+(*  This file is part of Frama-C.                                         *)
+(*                                                                       *)
+(*  Copyright (C) 2007-2022                                               *)
+(*    CEA (Commissariat à l'énergie atomique et aux énergies              *)
+(*         alternatives)                                                  *)
+(*                                                                        *)
+(*  you can redistribute it and/or modify it under the terms of the GNU   *)
+(*  Lesser General Public License as published by the Free Software       *)
+(*  Foundation, version 2.1.                                              *)
+(*                                                                        *)
+(*  It is distributed in the hope that it will be useful,                 *)
+(*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *)
+(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *)
+(*  GNU Lesser General Public License for more details.                   *)
+(*                                                                        *)
+(*  See the GNU Lesser General Public License version 2.1                 *)
+(*  for more details (enclosed in the file licenses/LGPLv2.1).            *)
+(*                                                                        *)
+(**************************************************************************)
+
+(** ../.. *)
+
+(** For internal use *)
+(* Private first so that we do not override internal modules with public ones *)
+
+module Private: sig
+  module Abstractions = Abstractions
+  module Analysis = Analysis
+  module Alarmset = Alarmset
+  module Parameters = Parameters
+  module Main_values = Main_values
+  module Eval = Eval
+  module Eva_utils = Eva_utils
+  module Eva_results = Eva_results
+  module Self = Self
+  module Eval_terms = Eval_terms
+  module Red_statuses = Red_statuses
+  module Abstract_value = Abstract_value
+  module Abstract_domain = Abstract_domain
+  module Mark_noresults = Mark_noresults
+  module Simple_memory = Simple_memory
+  module Structure = Structure
+  module Eval_typ = Eval_typ
+  module Eval_op = Eval_op
+  module Domain_builder = Domain_builder
+  module Main_locations = Main_locations
+  module Eval_annots = Eval_annots
+  module Eva_dynamic = Eva_dynamic
+end
+
+(** ../.. *)
diff --git a/src/plugins/value/dune b/src/plugins/value/dune
index b7b65be682c..a50ec626d08 100644
--- a/src/plugins/value/dune
+++ b/src/plugins/value/dune
@@ -130,6 +130,16 @@
 
 (plugin (optional) (name eva) (libraries frama-c-eva.core) (site (frama-c plugins)))
 
+(rule
+  (targets Eva.ml Eva.mli)
+  (deps
+    gen-api.sh Eva.ml.in Eva.mli.in
+    analysis.mli results.mli parameters.mli eva_annotations.mli eval.mli
+    builtins.mli eval_terms.mli eva_results.mli unit_tests.mli
+  )
+  (action (run %{deps}))
+)
+
 ( library
   (name numerors)
   (public_name frama-c-eva.numerors)
diff --git a/src/plugins/value/gen-api.sh b/src/plugins/value/gen-api.sh
index d00c16fdd4a..ba77beceaea 100755
--- a/src/plugins/value/gen-api.sh
+++ b/src/plugins/value/gen-api.sh
@@ -1,7 +1,13 @@
 #!/usr/bin/env bash
 set -eu
 
-printf '(** Eva public API.
+dir=$(dirname $0)
+
+# Generate MLI
+
+cat $dir/Eva.mli.in >> Eva.mli
+
+printf '\n(** Eva public API.
 
    The main modules are:
    - Analysis: run the analysis.
@@ -14,15 +20,30 @@ printf '(** Eva public API.
    - Builtins: register ocaml builtins to be used by the cvalue domain
        instead of analysing the body of some C functions.
 
-   Other modules are for internal use only. *)\n'
+   Other modules are for internal use only. *)\n' >> Eva.mli
+
+printf '\n(* This file is generated. Do not edit. *)\n' >> Eva.mli
+
+for i in "$@"
+do
+    if [[ ! "$i" =~ [.]in$ ]]; then
+        file=$(basename $i)
+        module=${file%.*}
+        printf '\nmodule %s: sig\n' ${module^}  >> Eva.mli
+        awk '/\[@@@ api_start\]/{flag=1;next} /\[@@@ api_end\]/{flag=0} flag{ print (NF ? "  ":"") $0 }' $i  >> Eva.mli
+        printf 'end\n' >> Eva.mli
+    fi
+done
+
+# Generate ML
 
-printf '\n(* This file is generated. Do not edit. *)\n'
+cat $dir/Eva.ml.in >> Eva.ml
 
 for i in "$@"
 do
-    file=$(basename $i)
-    module=${file%.*}
-    printf '\nmodule %s: sig\n' ${module^}
-    awk '/\[@@@ api_start\]/{flag=1;next} /\[@@@ api_end\]/{flag=0} flag{ print (NF ? "  ":"") $0 }' $i
-    printf 'end\n'
+    if [[ ! "$i" =~ [.]in$ ]]; then
+        file=$(basename $i)
+        module=${file%.*}
+        printf '\nmodule %s = %s\n' ${module^} ${module^} >> Eva.ml
+    fi
 done
-- 
GitLab