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,13 @@
(executable
(name foo)
(libraries bar impl2)
(modules foo))
(library
(name bar)
(libraries impl1)
(modules))
(alias
(name default)
(action (run ./foo.exe)))

View file

@ -0,0 +1 @@
let () = print_endline "should not run"

View file

@ -0,0 +1,3 @@
(library
(name impl1)
(implements vlib))

View file

@ -0,0 +1 @@
let run () = print_endline "impl1"

View file

@ -0,0 +1,3 @@
(library
(name impl2)
(implements vlib))

View file

@ -0,0 +1 @@
let run () = print_endline "impl1"

View file

@ -0,0 +1,12 @@
Executable that tries to use two implementations for the same virtual lib
$ dune build
Error: Conflicting implementations for virtual library "vlib" in
_build/default/vlib:
- "impl1" in _build/default/impl1
-> required by library "bar" in _build/default
- "impl2" in _build/default/impl2
This cannot work.
-> required by executable foo in dune:2
-> required by _build/default/foo.exe
-> required by alias default in dune:11
[1]

View file

@ -0,0 +1,3 @@
(library
(name vlib)
(virtual_modules vlib))

View file

@ -0,0 +1,4 @@
(alias
(name default)
(action
(echo %{read:foo.dune-package})))

View file

@ -0,0 +1,4 @@
(library
(name impl)
(public_name foo.impl)
(implements vlib))

View file

@ -0,0 +1 @@
let run () = print_endline "Impl's Vmd.run ()"

View file

@ -0,0 +1,81 @@
Include variants and implementation information in dune-package
$ dune build | sed "s/(lang dune .*)/(lang dune <version>)/" | dune_cmd sanitize
(lang dune <version>)
(name foo)
(sections (lib .) (libexec .))
(files
(lib
(META
dune-package
impl/impl$ext_lib
impl/impl.cma
impl/impl.cmxa
impl/vlib.cmi
impl/vlib.cmx
impl/vlib__Vmod.cmi
impl/vlib__Vmod.cmt
impl/vlib__Vmod.cmx
impl/vlib__impl__.cmi
impl/vlib__impl__.cmt
impl/vlib__impl__.cmx
impl/vlib__impl__.ml
impl/vmod.ml
opam
vlib/vlib.cmi
vlib/vlib.cmo
vlib/vlib.cmt
vlib/vlib.cmx
vlib/vlib.ml
vlib/vlib$ext_obj
vlib/vlib__Vmod.cmi
vlib/vlib__Vmod.cmti
vlib/vmod.mli))
(libexec (impl/impl.cmxs)))
(library
(name foo.impl)
(kind normal)
(archives (byte impl/impl.cma) (native impl/impl.cmxa))
(plugins (byte impl/impl.cma) (native impl/impl.cmxs))
(native_archives impl/impl$ext_lib)
(requires foo.vlib)
(implements foo.vlib)
(main_module_name Vlib)
(modes byte native)
(modules
(wrapped
(group
(alias
(obj_name vlib__impl__)
(visibility public)
(kind alias)
(source (path Vlib__impl__) (impl (path impl/vlib__impl__.ml-gen))))
(name Vlib)
(modules
(module
(obj_name vlib__Vmod)
(visibility public)
(kind impl_vmodule)
(source (path Vmod) (impl (path impl/vmod.ml))))))
(wrapped true))))
(library
(name foo.vlib)
(kind normal)
(virtual)
(main_module_name Vlib)
(modes byte native)
(modules
(wrapped
(group
(alias
(obj_name vlib)
(visibility public)
(kind alias)
(source (path Vlib) (impl (path vlib/vlib.ml-gen))))
(name Vlib)
(modules
(module
(obj_name vlib__Vmod)
(visibility public)
(kind virtual)
(source (path Vmod) (intf (path vlib/vmod.mli))))))
(wrapped true))))

View file

@ -0,0 +1,4 @@
(library
(name vlib)
(public_name foo.vlib)
(virtual_modules vmod))

View file

@ -0,0 +1,54 @@
Virtual library implementations are not correctly recorded when pulled through
other implementations.
Reproduces the issue reported in #10460
$ cat >dune-project <<EOF
> (lang dune 3.15)
> EOF
$ cat >dune <<EOF
> (executable
> (name main)
> (libraries impl2 impl1))
> EOF
$ touch main.ml
$ mkdir vlib1 vlib2 impl1 impl2 lib
$ cat >vlib1/dune <<EOF
> (library
> (name vlib1)
> (virtual_modules vlib1))
> EOF
$ touch vlib1/vlib1.mli
$ cat >impl1/dune <<EOF
> (library
> (name impl1)
> (implements vlib1))
> EOF
$ touch impl1/vlib1.ml
$ cat >vlib2/dune <<EOF
> (library
> (name vlib2)
> (virtual_modules vlib2))
> EOF
$ touch vlib2/vlib2.mli
$ cat >impl2/dune <<EOF
> (library
> (name impl2)
> (implements vlib2)
> (libraries lib))
> EOF
$ touch impl2/vlib2.ml
$ cat >lib/dune <<EOF
> (library
> (name lib)
> (libraries vlib1))
> EOF
$ dune build main.exe

View file

@ -0,0 +1,42 @@
Reproduction of the issue in #2896
We have a dependency cycle of the form impl <- lib <- vlib
where vlib is a virtual library, and impl implements this library.
$ echo "(lang dune 2.3)" > dune-project
$ mkdir vlib impl lib
$ touch impl/vlib.ml
$ echo "val run : unit -> unit" > vlib/vlib.mli
$ cat >vlib/dune <<EOF
> (library (name vlib) (virtual_modules vlib))
> EOF
$ echo "let bar () = Vlib.run ();;" > lib/lib.ml
$ cat >lib/dune <<EOF
> (library (name lib) (libraries vlib))
> EOF
$ echo "let run () = Lib.bar ();;" > impl/vlib.ml
$ cat >impl/dune <<EOF
> (library (name impl) (implements vlib) (libraries lib))
> EOF
$ dune build @all
Error: Library "vlib" was pulled in.
-> required by library "lib" in _build/default/lib
-> required by library "impl" in _build/default/impl
-> required by _build/default/impl/.impl.objs/byte/vlib.cmo
-> required by _build/default/impl/impl.cma
-> required by alias impl/all
[1]
The implementation impl was built, but it's not usable:
$ echo 'Vlib.run ()' > foo.ml
$ echo "(executable (name foo) (libraries impl))" > dune
$ dune exec ./foo.exe
Error: Library "vlib" was pulled in.
-> required by library "lib" in _build/default/lib
-> required by library "impl" in _build/default/impl
-> required by executable foo in dune:1
-> required by _build/default/.foo.eobjs/native/dune__exe__Foo.cmx
-> required by _build/default/foo.exe
[1]

View file

@ -0,0 +1,3 @@
(library
(name impl)
(implements vlib))

View file

@ -0,0 +1,14 @@
Implementations may not provide a library interface module unless it is virtual.
There should be an error message that clarifies this.
$ dune build
File "impl/dune", lines 1-3, characters 0-41:
1 | (library
2 | (name impl)
3 | (implements vlib))
Error: Implementations of wrapped libraries cannot introduce new public
modules.
The following modules:
- Vlib
must all be marked as private using the (private_modules ..) field.
[1]

View file

@ -0,0 +1,3 @@
(library
(name vlib)
(virtual_modules foo))

View file

@ -0,0 +1,25 @@
Test that trying to implement external libraries that aren't virtual results in
an appropriate error message.
$ mkdir external
$ echo "(lang dune 2.5)" > external/dune-project
$ touch external/foodummy.opam
$ cat >external/dune <<EOF
> (library (public_name foodummy))
> EOF
$ dune build --root external @install
Entering directory 'external'
Leaving directory 'external'
$ mkdir test
$ echo "(lang dune 2.5)" > test/dune-project
$ cat >test/dune <<EOF
> (library (implements foodummy) (name bar))
> EOF
$ OCAMLPATH=$PWD/external/_build/install/default/lib dune build --root test @all
Entering directory 'test'
File "dune", line 1, characters 21-29:
1 | (library (implements foodummy) (name bar))
^^^^^^^^
Error: Library "foodummy" is not virtual. It cannot be implemented by "bar".
Leaving directory 'test'
[1]

View file

@ -0,0 +1,3 @@
(alias
(name default)
(deps (alias_rec all)))

View file

@ -0,0 +1,3 @@
(library
(name impl)
(implements lib))

View file

@ -0,0 +1,9 @@
Test that trying to implement libraries that aren't virtual results in an
appropriate error message.
$ dune build
File "impl/dune", line 3, characters 13-16:
3 | (implements lib))
^^^
Error: Library "lib" is not virtual. It cannot be implemented by "impl".
-> required by alias default in dune:1
[1]

View file

@ -0,0 +1,7 @@
(executable
(name test)
(libraries foo_impl))
(alias
(name default)
(action (run ./test.exe)))

View file

@ -0,0 +1,3 @@
let run () =
Priv.run ();
print_endline "implementing bar"

View file

@ -0,0 +1,4 @@
(library
(name foo_impl)
(private_modules priv)
(implements foo))

View file

@ -0,0 +1 @@
let run () = print_endline "Private module Baz"

View file

@ -0,0 +1,25 @@
They can only introduce private modules:
$ dune build --debug-dependency-path
Private module Baz
implementing bar
Note the aliasing scheme for implementations differs form other libraries. In
particular, we use a longer prefix for private modules of implementations so
that they never collide with modules present in the virtual library.
$ cat _build/default/impl/foo__foo_impl__.ml-gen
(* generated by dune *)
(** @canonical Foo.Bar *)
module Bar = Foo__Bar
(** @canonical Foo.Priv *)
module Priv = Foo__foo_impl__Priv
Here we look at the raw artifacts for our implementation and verify it matches
the alias:
$ ls _build/default/impl/.foo_impl.objs/byte/*.cmi
_build/default/impl/.foo_impl.objs/byte/foo__Bar.cmi
_build/default/impl/.foo_impl.objs/byte/foo__foo_impl__.cmi
_build/default/impl/.foo_impl.objs/byte/foo__foo_impl__Priv.cmi

View file

@ -0,0 +1,3 @@
(library
(name foo)
(virtual_modules bar))

View file

@ -0,0 +1,21 @@
$ cat >dune-project <<EOF
> (lang dune 3.3)
> EOF
$ mkdir vlib impl
$ touch vlib/foo.mli
$ cat >vlib/dune <<EOF
> (library
> (name foo)
> (virtual_modules foo)
> (wrapped false))
> EOF
$ touch impl/foo.ml impl/new_public_module.ml
$ cat >impl/dune <<EOF
> (library
> (name bar)
> (implements foo))
> EOF
$ dune build

View file

@ -0,0 +1 @@
let run () = print_endline "implementing bar"

View file

@ -0,0 +1 @@
(* this module isn't allowed as it introduces a new interface *)

View file

@ -0,0 +1,3 @@
(library
(name foo_impl)
(implements foo))

View file

@ -0,0 +1,12 @@
Implementations cannot introduce new modules to the library's interface
$ dune build
File "impl/dune", lines 1-3, characters 0-44:
1 | (library
2 | (name foo_impl)
3 | (implements foo))
Error: Implementations of wrapped libraries cannot introduce new public
modules.
The following modules:
- Baz
must all be marked as private using the (private_modules ..) field.
[1]

View file

@ -0,0 +1,3 @@
(library
(name foo)
(virtual_modules bar))

View file

@ -0,0 +1,7 @@
(executable
(name test)
(libraries impl))
(alias
(name default)
(action (run ./test.exe)))

View file

@ -0,0 +1,3 @@
(library
(name impl)
(implements vlib))

View file

@ -0,0 +1,3 @@
let run () =
Bar.bar ();
print_endline "Foo.run implemented"

View file

@ -0,0 +1,23 @@
Implementations may refer to virtual library's modules
$ dune build
bar from vlib
Foo.run implemented
$ find _build -iname "*.ml-gen" | sort | while read file; do echo "contents of $file"; cat $file; echo "--------"; done;
contents of _build/default/impl/vlib__impl__.ml-gen
(* generated by dune *)
(** @canonical Vlib.Bar *)
module Bar = Vlib__Bar
(** @canonical Vlib.Foo *)
module Foo = Vlib__Foo
--------
contents of _build/default/vlib/vlib.ml-gen
(* generated by dune *)
(** @canonical Vlib.Bar *)
module Bar = Vlib__Bar
(** @canonical Vlib.Foo *)
module Foo = Vlib__Foo
--------

View file

@ -0,0 +1 @@
let bar () = print_endline "bar from vlib"

View file

@ -0,0 +1,3 @@
(library
(name vlib)
(virtual_modules foo))

View file

@ -0,0 +1,13 @@
(library
(name impl_intf_only)
(modules :standard \ run)
(implements vlib.intfonly))
(executable
(name run)
(libraries impl_intf_only)
(modules run))
(alias
(name default)
(action (run ./run.exe)))

View file

@ -0,0 +1,2 @@
let () =
Printf.printf "magic number: %d\n" (Vlib_intfonly.implme ())

View file

@ -0,0 +1,5 @@
module X : Foo.S = struct
let mli_only = print_endline
end
let implme () = X.mli_only "implemented mli only"; 42

View file

@ -0,0 +1,13 @@
(library
(name impl_native_only)
(modules :standard \ run)
(implements vlib.nativeonly))
(executable
(name run)
(libraries impl_native_only)
(modules run))
(alias
(name default)
(action (run ./run.exe)))

View file

@ -0,0 +1,2 @@
let () =
Vlib_native_only.run_native ()

View file

@ -0,0 +1,13 @@
(library
(name impl_privatemodule)
(modules :standard \ run)
(implements vlib.privatemodule))
(executable
(name run)
(libraries impl_privatemodule)
(modules run))
(alias
(name default)
(action (run ./run.exe)))

View file

@ -0,0 +1,7 @@
(executable
(name test)
(libraries impl))
(alias
(name default)
(action (run ./test.exe)))

View file

@ -0,0 +1,3 @@
(lang dune 1.7)
(package (name dune-vlib))

View file

@ -0,0 +1,4 @@
(library
(name impl)
(public_name dune-vlib.impl)
(implements vlib))

View file

@ -0,0 +1,3 @@
let run () =
Bar.bar ();
print_endline "Foo.run implemented"

View file

@ -0,0 +1,55 @@
Test that we can implement external libraries.
First we create an external library
$ dune build --root vlib @install
Entering directory 'vlib'
Leaving directory 'vlib'
Then we make sure that we can implement it
$ env OCAMLPATH=vlib/_build/install/default/lib dune build @default @install --root impl
Entering directory 'impl'
bar from vlib
Foo.run implemented
Leaving directory 'impl'
Make sure that we can also implement native only variants
$ env OCAMLPATH=vlib/_build/install/default/lib dune build --root impl-native-only --debug-dependency-path
Entering directory 'impl-native-only'
implement virtual module
Leaving directory 'impl-native-only'
We can implement external variants with mli only modules
$ env OCAMLPATH=vlib/_build/install/default/lib dune build --root impl-intf-only --debug-dependency-path
Entering directory 'impl-intf-only'
implemented mli only
magic number: 42
Leaving directory 'impl-intf-only'
Implement external virtual libraries with private modules
$ env OCAMLPATH=vlib/_build/install/default/lib dune build --root impl-private-module --debug-dependency-path
Entering directory 'impl-private-module'
Name: implement virtual module. Magic number: 42
Leaving directory 'impl-private-module'
Now we test the following use case:
- A virtual library and its implementation are installed
- We are able to use the implementation as an external dependency in a project
Currently, dune's behavior is broken in this situation. The virtual library's
modules remain hidden.
$ export OCAMLPATH=$PWD/vlib/_build/install/default/lib:$PWD/impl/_build/install/default/lib
$ mkdir use-external-impl && cd use-external-impl
$ cat >dune-project <<EOF
> (lang dune 3.0)
> EOF
$ cat >dune <<EOF
> (executable
> (name blah)
> (libraries dune-vlib.impl))
> EOF
$ cat >blah.ml <<EOF
> Vlib.Foo.run ()
> EOF
$ dune exec ./blah.exe
bar from vlib
Foo.run implemented
$ cd ..

View file

@ -0,0 +1 @@
let bar () = print_endline "bar from vlib"

View file

@ -0,0 +1,3 @@
(library
(public_name vlib)
(virtual_modules foo))

View file

@ -0,0 +1,5 @@
(library
(name vlib_intfonly)
(public_name vlib.intfonly)
(modules_without_implementation foo)
(virtual_modules vlib_intfonly))

View file

@ -0,0 +1,3 @@
module type S = sig
val mli_only : string -> unit
end

View file

@ -0,0 +1,5 @@
(library
(name vlib_native_only)
(public_name vlib.nativeonly)
(virtual_modules virt_module)
(modes native))

View file

@ -0,0 +1,2 @@
let run_native () =
print_endline Virt_module.v

View file

@ -0,0 +1,5 @@
(library
(name vlib_privatemodule)
(public_name vlib.privatemodule)
(virtual_modules virt_module)
(private_modules privatemodule))

View file

@ -0,0 +1,3 @@
let run () =
Printf.printf "Name: %s. Magic number: %d\n"
Virt_module.name Privatemodule.number

View file

@ -0,0 +1,50 @@
Reproduce a bug where an implementation's module archive isn't correctly
constructed. A virtual module's implementation can be excluded from the
archive.
https://github.com/ocaml/dune/issues/7027
$ cat >dune-project <<EOF
> (lang dune 3.7)
> EOF
$ mkdir vlib
$ cat >vlib/dune <<EOF
> (library
> (name vlib)
> (wrapped false)
> (virtual_modules x))
> EOF
$ cat >vlib/a.ml <<EOF
> let f = X.make ()
> EOF
$ cat >vlib/x.mli <<EOF
> type t
> val make : unit -> t
> EOF
$ mkdir impl
$ cat >impl/dune <<EOF
> (library
> (name impl)
> (implements vlib))
> EOF
$ cat >impl/x.ml <<EOF
> type t = unit
> let make () = ()
> EOF
$ cat >impl/z.ml <<EOF
> let g = A.f
> EOF
$ cat >dune <<EOF
> (executable
> (modes byte)
> (name foo)
> (libraries impl))
> EOF
$ cat >foo.ml <<EOF
> let _ = X.make ()
> EOF
$ dune exec ./foo.exe

View file

@ -0,0 +1,6 @@
(alias
(name default)
(action
(progn
(echo "%{read:vlib.install}")
(echo "%{read:impl.install}"))))

View file

@ -0,0 +1,3 @@
(library
(public_name impl)
(implements vlib))

Some files were not shown because too many files have changed in this diff Show more