From 23819b686c19c9cf6e31b598ef241ed768ad688f Mon Sep 17 00:00:00 2001 From: Antonio Nuno Monteiro Date: Sat, 23 May 2026 19:59:26 -0700 Subject: [PATCH] feat(single-context): add melange.libraries --- src/dune_rules/stanzas/buildable.ml | 7 ++ src/dune_rules/stanzas/buildable.mli | 1 + src/dune_rules/stanzas/library.ml | 30 ++++- src/dune_rules/stanzas/parameter.ml | 1 + .../melange/conditional-libraries.t | 111 ++++++++++++++++++ 5 files changed, 146 insertions(+), 4 deletions(-) create mode 100644 test/blackbox-tests/test-cases/melange/conditional-libraries.t diff --git a/src/dune_rules/stanzas/buildable.ml b/src/dune_rules/stanzas/buildable.ml index a3dd02df397..0a095bca008 100644 --- a/src/dune_rules/stanzas/buildable.ml +++ b/src/dune_rules/stanzas/buildable.ml @@ -12,6 +12,7 @@ type t = ; melange_modules : Ordered_set_lang.Unexpanded.t option ; empty_module_interface_if_absent : bool ; libraries : Lib_dep.t list + ; melange_libraries : Lib_dep.t list option ; foreign_archives : (Loc.t * Foreign.Archive.t) list ; extra_objects : Foreign.Objects.t ; foreign_stubs : Foreign.Stubs.t list @@ -125,6 +126,11 @@ let decode (for_ : for_) = >>> enter (maybe string)))) and+ libraries = field "libraries" (Lib_dep.L.decode ~allow_re_export:in_library) ~default:[] + and+ melange_libraries = + field_o + "melange.libraries" + (Dune_lang.Syntax.since Stanza.syntax (3, 24) + >>> Lib_dep.L.decode ~allow_re_export:in_library) and+ flags = decode_ocaml_flags and+ js_of_ocaml = field @@ -210,6 +216,7 @@ let decode (for_ : for_) = ; foreign_archives ; extra_objects ; libraries + ; melange_libraries ; flags ; js_of_ocaml = { js = js_of_ocaml; wasm = wasm_of_ocaml } ; allow_overlapping_dependencies diff --git a/src/dune_rules/stanzas/buildable.mli b/src/dune_rules/stanzas/buildable.mli index 4f27153be80..4c7df6a82e9 100644 --- a/src/dune_rules/stanzas/buildable.mli +++ b/src/dune_rules/stanzas/buildable.mli @@ -11,6 +11,7 @@ type t = ; melange_modules : Ordered_set_lang.Unexpanded.t option ; empty_module_interface_if_absent : bool ; libraries : Lib_dep.t list + ; melange_libraries : Lib_dep.t list option ; foreign_archives : (Loc.t * Foreign.Archive.t) list ; extra_objects : Foreign.Objects.t ; foreign_stubs : Foreign.Stubs.t list diff --git a/src/dune_rules/stanzas/library.ml b/src/dune_rules/stanzas/library.ml index 47d4be61a34..c0c3064a83e 100644 --- a/src/dune_rules/stanzas/library.ml +++ b/src/dune_rules/stanzas/library.ml @@ -453,6 +453,25 @@ let to_lib_id ~src_dir t = Lib_id.Local.make ~loc ~src_dir (Lib_name.of_local t.name) ;; +let library_deps ~loc ~field ~modes ~libs ~melange_libs = + let ocaml, melange = + let { Lib_mode.Map.ocaml = { byte; native }; melange } = modes in + let ocaml_libraries = if byte || native then libs else [] in + let melange_libraries = + match melange, melange_libs with + | true, Some melange_libraries -> melange_libraries + | true, None -> libs + | false, None -> [] + | false, Some _ -> + User_error.raise + ~loc + [ Pp.textf "Cannot specify `%s' without `melange' mode" field ] + in + ocaml_libraries, melange_libraries + in + { Compilation_mode.By_mode.ocaml; melange } +;; + let to_lib_info conf ~expander @@ -576,14 +595,17 @@ let to_lib_info | Public (_, pkg) -> Package.version pkg | Installed_private | Installed | Private _ -> None in + let loc = conf.buildable.loc in let requires = - { Compilation_mode.By_mode.ocaml = conf.buildable.libraries - ; melange = conf.buildable.libraries - } + library_deps + ~loc + ~field:"melange.libraries" + ~modes + ~libs:conf.buildable.libraries + ~melange_libs:conf.buildable.melange_libraries in let parameters = conf.parameters in let allow_unused_libraries = conf.buildable.allow_unused_libraries in - let loc = conf.buildable.loc in let kind = conf.kind in let src_dir = dir in let orig_src_dir = None in diff --git a/src/dune_rules/stanzas/parameter.ml b/src/dune_rules/stanzas/parameter.ml index 08f174822a3..b19286a1354 100644 --- a/src/dune_rules/stanzas/parameter.ml +++ b/src/dune_rules/stanzas/parameter.ml @@ -67,6 +67,7 @@ let decode = ; modules ; empty_module_interface_if_absent = false ; libraries + ; melange_libraries = None ; melange_modules = None ; foreign_archives = [] ; extra_objects = Foreign.Objects.empty diff --git a/test/blackbox-tests/test-cases/melange/conditional-libraries.t b/test/blackbox-tests/test-cases/melange/conditional-libraries.t new file mode 100644 index 00000000000..0d98be434bd --- /dev/null +++ b/test/blackbox-tests/test-cases/melange/conditional-libraries.t @@ -0,0 +1,111 @@ +`melange.libraries` applies only to Melange compilation. + +The field is available starting in Dune 3.24. + + $ mkdir old + $ cat > old/dune-project < (lang dune 3.23) + > (using melange 0.1) + > EOF + $ cat > old/dune < (library + > (name old) + > (modes melange) + > (melange.libraries dep)) + > EOF + $ dune build --root old + Entering directory 'old' + File "dune", line 4, characters 1-24: + 4 | (melange.libraries dep)) + ^^^^^^^^^^^^^^^^^^^^^^^ + Error: 'melange.libraries' is only available since version 3.24 of the dune + language. Please update your dune-project file to have (lang dune 3.24). + Leaving directory 'old' + [1] + $ rm -rf old + + $ cat > dune-project < (lang dune 3.24) + > (using melange 0.1) + > EOF + + $ mkdir lib_for_melange lib_for_native app + $ cat > lib_for_melange/dune < (library + > (modes melange) + > (name lib_for_melange)) + > EOF + $ cat > lib_for_melange/foo.ml < let x = "lib for melange" + > EOF + + $ cat > lib_for_native/dune < (library + > (modes :standard) + > (name lib_for_native)) + > EOF + $ cat > lib_for_native/foo.ml < let x = "lib for native" + > EOF + + $ cat > app/dune < (library + > (modes melange :standard) + > (name app) + > (modules app common_intf) + > (libraries lib_for_native) + > (melange.libraries lib_for_melange)) + > + > (melange.emit + > (target out) + > (modules main) + > (emit_stdlib false) + > (libraries app)) + > + > (executable + > (name main) + > (modules main) + > (libraries app)) + > EOF + + $ cat > app/common_intf.mli < val print : string -> unit + > EOF + $ cat > app/common_intf.ml < let message = Lib_for_native.Foo.x + > let print prefix = Format.eprintf "%s%s@." prefix message + > EOF + $ cat > app/common_intf.melange.ml < let message = Lib_for_melange.Foo.x + > let print prefix = Js.log2 prefix message + > EOF + $ cat > app/app.ml < let say_hello () = Common_intf.print "message: " + > EOF + $ cat > app/main.ml < let () = App.say_hello () + > EOF + + $ dune build @app/melange app/main.exe + $ node _build/default/app/out/app/main.js + message: lib for melange + $ _build/default/app/main.exe + message: lib for native + +The field is rejected without Melange mode. + + $ mkdir no-melange + $ cat > no-melange/dune < (library + > (modes :standard) + > (name no_melange) + > (melange.libraries lib_for_melange)) + > EOF + $ dune build no-melange + File "no-melange/dune", lines 1-4, characters 0-84: + 1 | (library + 2 | (modes :standard) + 3 | (name no_melange) + 4 | (melange.libraries lib_for_melange)) + Error: Cannot specify `melange.libraries' without `melange' mode + [1]