Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
(library
(name hello_ppx)
(public_name hello.ppx)
(kind ppx_rewriter)
(ppx_runtime_libraries hello)
(libraries ppxlib)
(modules hello_ppx))

(library
(public_name hello)
(modules hello)
(instrumentation.backend
(ppx hello.ppx)))
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
(lang dune 3.24)

(package (name hello))
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
let hello s = print_endline (Printf.sprintf "Hello from %s!" s)
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
open Ast_helper

let place = ref None
let file = ref None

let read_file () =
match !file with
| None -> "<none>"
| Some s ->
let ic = open_in s in
(match input_line ic with
| exception End_of_file ->
close_in ic;
"<none>"
| s ->
close_in ic;
s)
;;

let impl str =
let arg =
match !place with
| None -> Exp.ident (Location.mknoloc (Longident.Lident "__MODULE__"))
| Some s -> Exp.constant (Const.string (Printf.sprintf "%s (%s)" s (read_file ())))
in
Str.eval
(Exp.apply
(Exp.ident
(Location.mknoloc
(Longident.Ldot
( { txt = Longident.Lident "Hello"; loc = Location.none }
, { txt = "hello"; loc = Location.none } ))))
[ Nolabel, arg ])
:: str
;;

let () =
Ppxlib.Driver.add_arg
"-place"
(Arg.String (fun s -> place := Some s))
~doc:"PLACE where to say hello from";
Ppxlib.Driver.add_arg
"-file"
(Arg.String (fun s -> file := Some s))
~doc:"Add info from file"
;;

let () = Ppxlib.Driver.register_transformation_using_ocaml_current_ast ~impl "hello"
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
Regression baseline for an unwrapped library declaring
`(instrumentation (backend X))` without `--instrument-with` at
build time. Today, the consumer's compile rule depends on the
lib's full `.cmi` glob over its objdir.

$ make_dune_project 3.24

`middle` declares an instrumentation backend but no
`(preprocess ...)`. With instrumentation disabled at build time,
no `.pp.ml` files are produced.

$ mkdir leaf
$ cat > leaf/dune <<EOF
> (library (name leaf))
> EOF
$ cat > leaf/leaf.ml <<EOF
> type t = int
> let zero : t = 0
> EOF

$ mkdir middle
$ cat > middle/dune <<EOF
> (library
> (name middle)
> (wrapped false)
> (libraries leaf)
> (instrumentation (backend hello)))
> EOF
$ cat > middle/middle.mli <<EOF
> val identity : Leaf.t -> Leaf.t
> EOF
$ cat > middle/middle.ml <<EOF
> let identity x = x
> EOF

$ mkdir consumer
$ cat > consumer/dune <<EOF
> (executable (name consumer) (libraries middle))
> EOF
$ cat > consumer/consumer.ml <<EOF
> let _ = Middle.identity 0
> EOF

Build without `--instrument-with`. Today this succeeds with the
cctx-wide `.cmi` glob covering `leaf.cmi` through `middle`'s objdir
chain.

$ dune build consumer/consumer.exe

The consumer's compile rule today carries a wide `.cmi` glob over
`middle`'s objdir.

$ dune rules --root . --format=json --deps '%{cmo:consumer/consumer}' > deps.json
$ jq -r 'include "dune"; .[] | depsGlobs
> | select(.dir | endswith("middle/.middle.objs/byte"))
> | .dir + " " + .predicate' < deps.json
_build/default/middle/.middle.objs/byte *.cmi
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
A consumer references a constructor of a leaf library's type
through an intermediate library compiled with
`(flags (:standard -open Prelude))`. The intermediate's source
never names `Prelude` (the open hides it), and the consumer never
names `Prelude` either. Pins that the consumer's compile correctly
tracks `prelude`'s `.cmi` as a sandbox-required dep.

$ make_dune_project 3.24

`prelude` exposes a sum type:

$ mkdir prelude
$ cat > prelude/dune <<EOF
> (library (name prelude))
> EOF
$ cat > prelude/prelude.ml <<EOF
> type color = Red | Green | Blue
> EOF

`middle` depends on `prelude` and is compiled with
`(flags (:standard -open Prelude))`, exposing
`val pick : unit -> color` whose `color` resolves through the open
to `Prelude.color`:

$ mkdir middle
$ cat > middle/dune <<EOF
> (library
> (name middle)
> (libraries prelude)
> (flags (:standard -open Prelude)))
> EOF
$ cat > middle/middle.mli <<EOF
> val pick : unit -> color
> EOF
$ cat > middle/middle.ml <<EOF
> let pick () = Green
> EOF

`consumer` depends on `middle` and `prelude` and pattern-matches on
the result of `Middle.pick` against the bare constructors `Green`,
`Red`, `Blue`. `ocamldep` on `middle.{ml,mli}` and `consumer.ml`
reports no `Prelude` token in either case.

$ mkdir consumer
$ cat > consumer/dune <<EOF
> (executable (name consumer) (libraries middle prelude))
> EOF
$ cat > consumer/consumer.ml <<EOF
> let () = match Middle.pick () with
> | Green -> print_endline "g"
> | Red | Blue -> print_endline "nb"
> EOF
Comment thread
robinbb marked this conversation as resolved.

$ dune build --sandbox=copy consumer/consumer.exe
Comment thread
robinbb marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
A single-module local library with no `(libraries ...)` but with
`(preprocess (pps X))` has non-empty *resolved* requires (X's
runtime libs added via `add_pp_runtime_deps`). Pins that the
consumer's compile correctly tracks the ppx runtime lib's `.cmi`
as a sandbox-required dep, even though the consumer never names
the runtime lib syntactically.

$ make_dune_project 3.24

`hello` is the ppx runtime lib (single-module unwrapped, no library
deps of its own). It exposes `Hello.t`:

$ mkdir hello
$ cat > hello/dune <<EOF
> (library (name hello))
> EOF
$ cat > hello/hello.ml <<EOF
> type t = int
> let zero : t = 0
> EOF

`hello_ppx` is a no-op ppx_rewriter declaring `hello` as its
`ppx_runtime_libraries`:

$ mkdir hello_ppx
$ cat > hello_ppx/dune <<EOF
> (library
> (name hello_ppx)
> (kind ppx_rewriter)
> (ppx_runtime_libraries hello)
> (libraries ppxlib))
> EOF
$ cat > hello_ppx/hello_ppx.ml <<EOF
> let () =
> Ppxlib.Driver.register_transformation_using_ocaml_current_ast
> ~impl:(fun s -> s) "noop"
> EOF

`middle` is single-module, has no `(libraries ...)`, and uses
`(preprocess (pps hello_ppx))`. Its interface mentions `Hello.t`:

$ mkdir middle
$ cat > middle/dune <<EOF
> (library
> (name middle)
> (preprocess (pps hello_ppx)))
> EOF
$ cat > middle/middle.mli <<EOF
> val helper : Hello.t -> Hello.t
> EOF
$ cat > middle/middle.ml <<EOF
> let helper x = x
> EOF

`consumer` depends on `middle`; references `Middle.helper` but
never names `Hello` in source.

$ mkdir consumer
$ cat > consumer/dune <<EOF
> (executable (name consumer) (libraries middle))
> EOF
$ cat > consumer/consumer.ml <<EOF
> let _ = Middle.helper 0
> EOF

$ dune build --sandbox=copy consumer/consumer.exe
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
A consumer references a module from a preprocessed library; that
preprocessed module's interface mentions a type from a leaf library
that the consumer never names syntactically. Pins that the consumer's
compile correctly tracks `leaf`'s `.cmi` as a sandbox-required dep.

$ make_dune_project 3.24

`leaf` exposes `Leaf.t`:

$ mkdir leaf
$ cat > leaf/dune <<EOF
> (library (name leaf))
> EOF
$ cat > leaf/leaf.ml <<EOF
> type t = int
> let zero : t = 0
> EOF

`middle` depends on `leaf`; its single module is preprocessed via
`(preprocess (action ...))`, and its interface mentions `Leaf.t`:

$ mkdir middle
$ cat > middle/dune <<EOF
> (library
> (name middle)
> (libraries leaf)
> (preprocess (action (run cat %{input-file}))))
> EOF
$ cat > middle/middle.mli <<EOF
> val identity : Leaf.t -> Leaf.t
> EOF
$ cat > middle/middle.ml <<EOF
> let identity x = x
> EOF

`consumer` depends on `middle`; references `Middle.identity` but
never names `Leaf` in source. Applying `Middle.identity` to a
literal `0` forces the compiler to unify `int` with `Leaf.t`, which
requires loading `leaf.cmi`. `ocamldep` on this source reports
only `Middle`, since `Leaf` is not named.

$ mkdir consumer
$ cat > consumer/dune <<EOF
> (executable (name consumer) (libraries middle))
> EOF
$ cat > consumer/consumer.ml <<EOF
> let _ = Middle.identity 0
> EOF

$ dune build --sandbox=copy consumer/consumer.exe
Loading