This commit is contained in:
swrup 2025-11-11 02:07:51 +01:00
parent aa2ff7b2f0
commit 2f3113f55d
11742 changed files with 1223940 additions and 0 deletions

View file

@ -0,0 +1,26 @@
module V1 = struct
module Version = struct
type t = string
let to_string x = x
end
module Statically_linked_library = struct
type t = string * string option
let name = fst
let version = snd
end
module Statically_linked_libraries = struct
let to_list () = Build_info_data.statically_linked_libraries
let find ~name =
match List.assoc name (to_list ()) with
| exception Not_found -> None
| version -> Some (name, version)
;;
end
let version () = Build_info_data.version
end

View file

@ -0,0 +1,53 @@
(** See {!V1} for the current version. *)
module V1 : sig
(** Provide build-time information.
The entry points in this module are {!version} and
{!Statically_linked_libraries.to_list}.
{e Implementation note:} this module is implemented using special support
from Dune. When an executable is linked, a special "blank" placeholder is
stored as a string. A special post-link phase called
{e artifact substitution} can replace this placeholder with encoded data
that will be decoded by this library.
Artifact substitution happens when an executable is installed or promoted
to the source tree. *)
module Version : sig
(** Version numbers. *)
type t
val to_string : t -> string
end
(** The version at which the current executable was built.
The version is [None] during development, it is only [Some _] once
artifact substitution happened. *)
val version : unit -> Version.t option
module Statically_linked_library : sig
(** A library with an optional version number. *)
type t
(** The most visible name of the library. If it is a public library, this
its public name otherwise it is its private name. *)
val name : t -> string
val version : t -> Version.t option
end
module Statically_linked_libraries : sig
(** Entry points to find {!Statically_linked_library} values. *)
(** All the libraries that where statically linked in *)
val to_list : unit -> Statically_linked_library.t list
(** Find a particular library by name. *)
val find : name:string -> Statically_linked_library.t option
end
end

View file

@ -0,0 +1,4 @@
(* The implementation of this module is generated by dune when linking an
executable *)
val version : string option
val statically_linked_libraries : (string * string option) list

View file

@ -0,0 +1,11 @@
(library
(name build_info)
(public_name dune-build-info)
(modules_without_implementation build_info_data)
(special_builtin_support
(build_info
(data_module build_info_data)
(api_version 1))))
(documentation
(package dune-build-info))

View file

@ -0,0 +1,39 @@
{1 [dune-build-info] - access information generated at build time. }
{2 Introduction}
This library exposes some functions to query pieces of information generated at
build time, in particular:
- the version of the project being built. You can use [dune-build-info] to
implement a [--version] flag.
- the list of libraries an executable is linked against. You can use
[dune-build-info] to write a [--build-info] flag that will display a software
bill of materials listing the libraries used to build an executable.
{2 Example}
This displays the version number and the libraries the executable is statically
linked with:
{[
let version_string v =
match Build_info.V1.version v with
| None -> "n/a"
| Some v -> Build_info.V1.Version.to_string v
in
let version = Build_info.V1.version ();
Printf.printf "version: %s\n" (version_string version);
let libs = Build_info.V1.Statically_linked_libraries.to_list () in
Printf.printf "statically linked libraries:\n";
List.iter
(fun lib ->
let name = Build_info.V1.Statically_linked_library.name lib in
let version = Build_info.V1.Statically_linked_library.version lib in
Printf.printf "- %s (%s)\n" name (version_string version)
) libs
]}
{2 API documentation}
The entry point for this library is {!Build_info.V1}.

View file

@ -0,0 +1,4 @@
(cram
(deps
(package dune)
(package dune-build-info)))

View file

@ -0,0 +1,159 @@
Test embedding of build information
-----------------------------------
$ mkdir -p a b c
$ for i in a b c d; do
> mkdir -p $i
> cat >$i/dune-project <<EOF
> (lang dune 2.0)
> (name $i)
> (package (name $i))
> EOF
> (cd $i;
> git init -q;
> git config user.name "Test Name"
> git config user.email "test@example.com"
> git add .;
> git commit -q -m _;
> git tag -a 1.0+$i -m _)
> done
$ for i in a b; do
> cat >$i/dune <<EOF
> (library
> (public_name $i))
> EOF
> done
$ cat >c/dune <<EOF
> (executable
> (public_name c)
> (promote (until-clean))
> (libraries a b dune-build-info))
> EOF
$ cat >c/c.ml <<EOF
> module B = Build_info.V1
> let pr fmt = Printf.printf (fmt ^^ "\n")
> let get_version = function
> | Some v -> B.Version.to_string v
> | None -> "n/a"
> let () =
> pr "%s" (get_version (B.version ()));
> let process_lib lib =
> let name = B.Statically_linked_library.name lib in
> let version = B.Statically_linked_library.version lib in
> pr "lib %s: %s" name (get_version version)
> in
> List.iter process_lib (B.Statically_linked_libraries.to_list ())
> EOF
$ cat > dune-project << EOF
> (lang dune 2.0)
> EOF
$ dune build
$ dune install --prefix _install
Inside _build, we have no version information:
$ _build/default/c/c.exe | sed 's/build-info: .*/build-info: XXX/'
n/a
lib a: n/a
lib b: n/a
lib dune-build-info: XXX
$ grep version _build/install/default/lib/a/dune-package
[1]
$ grep version _build/install/default/lib/a/META
[1]
Once installed, we have the version information:
$ _install/bin/c | sed 's/build-info: .*/build-info: XXX/'
1.0+c
lib a: 1.0+a
lib b: 1.0+b
lib dune-build-info: XXX
$ grep version _install/lib/a/dune-package
(version 1.0+a)
$ grep version _install/lib/a/META
version = "1.0+a"
Check what the generated build info module looks like:
$ cat _build/default/c/.c.eobjs/build_info__Build_info_data.ml-gen \
> | sed 's/"dune-build-info".*/"dune-build-info", Some "XXX"/'
let eval s =
let s = Bytes.unsafe_to_string (Bytes.unsafe_of_string s) in
let len = String.length s in
if s.[0] = '=' then
let colon_pos = String.index_from s 1 ':' in
let vlen = int_of_string (String.sub s 1 (colon_pos - 1)) in
(* This [min] is because the value might have been truncated
if it was too large *)
let vlen = min vlen (len - colon_pos - 1) in
Some (String.sub s (colon_pos + 1) vlen)
else
None
[@@inline never]
let p1 = eval (Sys.opaque_identity "%%DUNE_PLACEHOLDER:64:vcs-describe:1:a%%%%%%%%%%%%%%%%%%%%%%%%%%")
let p2 = eval (Sys.opaque_identity "%%DUNE_PLACEHOLDER:64:vcs-describe:1:b%%%%%%%%%%%%%%%%%%%%%%%%%%")
let p0 = eval (Sys.opaque_identity "%%DUNE_PLACEHOLDER:64:vcs-describe:1:c%%%%%%%%%%%%%%%%%%%%%%%%%%")
let version = p0
let statically_linked_libraries =
[ "a", p1
; "b", p2
; "dune-build-info", Some "XXX"
]
Test --debug-artifact-substitution
----------------------------------
The order of substitutions printed by `--debug-artifact-substitution`
is not stable across machines since it depends on the order in which
the string constant end up in the binary. To make the test stable, we
craft an example with a single placeholder to make the output stable:
$ cat >d/dune <<EOF
> (executable
> (public_name d)
> (promote (until-clean))
> (libraries dune-build-info))
> EOF
$ cp c/c.ml d/d.ml
$ dune build d/d.install
$ dune install d --prefix _install --debug-artifact-substitution
Found placeholder in _build/install/default/bin/d:
- placeholder: Vcs_describe (In_source_tree "d")
- evaluates to: "1.0+d"
Test substitution when promoting
--------------------------------
$ c/c.exe | sed 's/build-info: .*/build-info: XXX/'
1.0+c
lib a: 1.0+a
lib b: 1.0+b
lib dune-build-info: XXX
Version is picked from dune-project if available
------------------------------------------------
$ echo '(version project-version)' >> c/dune-project
$ dune build
$ dune install --prefix _install
$ _install/bin/c | sed 's/build-info: .*/build-info: XXX/'
project-version
lib a: 1.0+a
lib b: 1.0+b
lib dune-build-info: XXX