Skip to content

Commit

Permalink
feature: introduce public_headers
Browse files Browse the repository at this point in the history
This field works like install_c_headers except it allows full file names
and allows to customize the destination paths

Signed-off-by: Rudi Grinberg <me@rgrinberg.com>

<!-- ps-id: cf542cda-1684-4719-bffd-fdb6a8bc2d63 -->
  • Loading branch information
rgrinberg committed Apr 10, 2023
1 parent 258058c commit 987647e
Show file tree
Hide file tree
Showing 18 changed files with 226 additions and 118 deletions.
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
Unreleased
----------

- Introduce a `public_headers` field on libraries. This field is like
`install_c_headers`, but it allows to choose the extension and choose the
paths for the installed headers. (#7512, @rgrinberg)

- Load the host context `findlib.conf` when cross-compiling (#7428, fixes
#1701, @rgrinberg, @anmonteiro)

Expand Down
23 changes: 17 additions & 6 deletions src/dune_rules/dune_file.ml
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,7 @@ module Library = struct
; visibility : visibility
; synopsis : string option
; install_c_headers : (Loc.t * string) list
; public_headers : Loc.t * Dep_conf.t list
; ppx_runtime_libraries : (Loc.t * Lib_name.t) list
; modes : Mode_conf.Lib.Set.t
; kind : Lib_kind.t
Expand Down Expand Up @@ -599,6 +600,11 @@ module Library = struct
and+ synopsis = field_o "synopsis" string
and+ install_c_headers =
field "install_c_headers" (repeat (located string)) ~default:[]
and+ public_headers =
field "public_headers"
(Dune_lang.Syntax.since Stanza.syntax (3, 8)
>>> located (repeat Dep_conf.decode))
~default:(stanza_loc, [])
and+ ppx_runtime_libraries =
field "ppx_runtime_libraries"
(repeat (located Lib_name.decode))
Expand Down Expand Up @@ -734,6 +740,7 @@ module Library = struct
; visibility
; synopsis
; install_c_headers
; public_headers
; ppx_runtime_libraries
; modes
; kind
Expand Down Expand Up @@ -986,15 +993,19 @@ module Library = struct
let entry_modules = Lib_info.Source.Local in
let melange_runtime_deps =
let loc, runtime_deps = conf.melange_runtime_deps in
Lib_info.Runtime_deps.Local (loc, runtime_deps)
Lib_info.File_deps.Local (loc, runtime_deps)
in
let public_headers =
let loc, public_headers = conf.public_headers in
Lib_info.File_deps.Local (loc, public_headers)
in
Lib_info.create ~loc ~path_kind:Local ~name ~kind ~status ~src_dir
~orig_src_dir ~obj_dir ~version ~synopsis ~main_module_name ~sub_systems
~requires ~foreign_objects ~plugins ~archives ~ppx_runtime_deps
~foreign_archives ~native_archives ~foreign_dll_files ~jsoo_runtime
~preprocess ~enabled ~virtual_deps ~dune_version ~virtual_ ~entry_modules
~implements ~default_implementation ~modes ~modules:Local ~wrapped
~special_builtin_support ~exit_module ~instrumentation_backend
~requires ~foreign_objects ~public_headers ~plugins ~archives
~ppx_runtime_deps ~foreign_archives ~native_archives ~foreign_dll_files
~jsoo_runtime ~preprocess ~enabled ~virtual_deps ~dune_version ~virtual_
~entry_modules ~implements ~default_implementation ~modes ~modules:Local
~wrapped ~special_builtin_support ~exit_module ~instrumentation_backend
~melange_runtime_deps
end

Expand Down
1 change: 1 addition & 0 deletions src/dune_rules/dune_file.mli
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ module Library : sig
; visibility : visibility
; synopsis : string option
; install_c_headers : (Loc.t * string) list
; public_headers : Loc.t * Dep_conf.t list
; ppx_runtime_libraries : (Loc.t * Lib_name.t) list
; modes : Mode_conf.Lib.Set.t
; kind : Lib_kind.t
Expand Down
27 changes: 17 additions & 10 deletions src/dune_rules/dune_package.ml
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,21 @@ module Lib = struct
let modes = Lib_info.modes info in
let synopsis = Lib_info.synopsis info in
let obj_dir = Lib_info.obj_dir info in
let additional_paths (paths : _ Lib_info.File_deps.t) =
match paths with
| Local _ -> assert false
| External paths ->
let lib_dir = Obj_dir.dir obj_dir in
List.map paths ~f:(fun p ->
Path.as_in_build_dir_exn p |> Path.Build.drop_build_context_exn
|> Path.append_source lib_dir)
in
let orig_src_dir = Lib_info.orig_src_dir info in
let implements = Lib_info.implements info in
let ppx_runtime_deps = Lib_info.ppx_runtime_deps info in
let default_implementation = Lib_info.default_implementation info in
let special_builtin_support = Lib_info.special_builtin_support info in
let public_headers = additional_paths (Lib_info.public_headers info) in
let archives = Lib_info.archives info in
let sub_systems = Lib_info.sub_systems info in
let plugins = Lib_info.plugins info in
Expand All @@ -63,13 +73,7 @@ module Lib = struct
| Local -> None
in
let melange_runtime_deps =
match Lib_info.melange_runtime_deps info with
| Local _ -> assert false
| External paths ->
let lib_dir = Obj_dir.dir obj_dir in
List.map paths ~f:(fun p ->
Path.as_in_build_dir_exn p |> Path.Build.drop_build_context_exn
|> Path.append_source lib_dir)
additional_paths (Lib_info.melange_runtime_deps info)
in
let jsoo_runtime = Lib_info.jsoo_runtime info in
let virtual_ = Option.is_some (Lib_info.virtual_ info) in
Expand Down Expand Up @@ -97,6 +101,7 @@ module Lib = struct
; mode_paths "archives" archives
; mode_paths "plugins" plugins
; paths "foreign_objects" foreign_objects
; paths "public_headers" public_headers
; field_i "foreign_archives" (Mode.Map.encode path)
(Lib_info.foreign_archives info)
; paths "foreign_dll_files" foreign_dll_files
Expand Down Expand Up @@ -155,6 +160,7 @@ module Lib = struct
and+ archives = mode_paths "archives"
and+ plugins = mode_paths "plugins"
and+ foreign_objects = paths "foreign_objects"
and+ public_headers = paths "public_headers"
and+ foreign_archives =
if lang.version >= (3, 5) then
let+ field_o = field_o "foreign_archives" (Mode.Map.decode path) in
Expand Down Expand Up @@ -199,6 +205,7 @@ module Lib = struct
let version = None in
let main_module_name = Lib_info.Inherited.This main_module_name in
let foreign_objects = Lib_info.Source.External foreign_objects in
let public_headers = Lib_info.File_deps.External public_headers in
let preprocess = Preprocess.Per_module.no_preprocessing () in
let virtual_deps = [] in
let dune_version = None in
Expand All @@ -211,12 +218,12 @@ module Lib = struct
let entry_modules = Lib_info.Source.External (Ok entry_modules) in
let modules = Lib_info.Source.External (Some modules) in
let melange_runtime_deps =
Lib_info.Runtime_deps.External melange_runtime_deps
Lib_info.File_deps.External melange_runtime_deps
in
Lib_info.create ~path_kind:External ~loc ~name ~kind ~status ~src_dir
~orig_src_dir ~obj_dir ~version ~synopsis ~main_module_name
~sub_systems ~requires ~foreign_objects ~plugins ~archives
~ppx_runtime_deps ~foreign_archives
~sub_systems ~requires ~foreign_objects ~public_headers ~plugins
~archives ~ppx_runtime_deps ~foreign_archives
~native_archives:(Files native_archives) ~foreign_dll_files
~jsoo_runtime ~preprocess ~enabled ~virtual_deps ~dune_version
~virtual_ ~entry_modules ~implements ~default_implementation ~modes
Expand Down
7 changes: 4 additions & 3 deletions src/dune_rules/findlib/findlib.ml
Original file line number Diff line number Diff line change
Expand Up @@ -487,9 +487,10 @@ end = struct
| _ -> None
in
let foreign_objects = Lib_info.Source.External [] in
let public_headers = Lib_info.File_deps.External [] in
let plugins = plugins t in
let jsoo_runtime = jsoo_runtime t in
let melange_runtime_deps = Lib_info.Runtime_deps.External [] in
let melange_runtime_deps = Lib_info.File_deps.External [] in
let preprocess = Preprocess.Per_module.no_preprocessing () in
let virtual_ = None in
let default_implementation = None in
Expand Down Expand Up @@ -572,8 +573,8 @@ end = struct
let modules = Lib_info.Source.External None in
Lib_info.create ~path_kind:External ~loc ~name:t.name ~kind ~status
~src_dir ~orig_src_dir ~obj_dir ~version ~synopsis ~main_module_name
~sub_systems ~requires ~foreign_objects ~plugins ~archives
~ppx_runtime_deps ~foreign_archives
~sub_systems ~requires ~foreign_objects ~public_headers ~plugins
~archives ~ppx_runtime_deps ~foreign_archives
~native_archives:(Files native_archives) ~foreign_dll_files:[]
~jsoo_runtime ~preprocess ~enabled ~virtual_deps ~dune_version
~virtual_ ~implements ~default_implementation ~modes ~modules ~wrapped
Expand Down
2 changes: 1 addition & 1 deletion src/dune_rules/foreign_rules.ml
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ let build_o_files ~sctx ~foreign_sources ~(dir : Path.Build.t) ~expander
(let open Resolve.O in
let+ libs = requires in
Command.Args.S
[ Lib_flags.L.c_include_flags libs
[ Lib_flags.L.c_include_flags libs sctx
; Hidden_deps (Lib_file_deps.deps libs ~groups:[ Header ])
])
]
Expand Down
50 changes: 22 additions & 28 deletions src/dune_rules/install_rules.ml
Original file line number Diff line number Diff line change
Expand Up @@ -173,14 +173,13 @@ end = struct
in
make_entry ?sub_dir Lib source ?dst))
in
let* melange_runtime_entries =
let loc, melange_runtime_deps = lib.melange_runtime_deps in
let+ melange_runtime_deps =
let additional_deps (loc, deps) =
let+ deps =
let* expander = Super_context.expander sctx ~dir:lib_src_dir in
Melange_rules.Runtime_deps.eval ~expander ~loc
~paths:(Disallow_external lib_name) melange_runtime_deps
Lib_file_deps.eval deps ~expander ~loc
~paths:(Disallow_external lib_name)
in
Path.Set.to_list_map melange_runtime_deps ~f:(fun path ->
Path.Set.to_list_map deps ~f:(fun path ->
let path = Path.as_in_build_dir_exn path in
let sub_dir =
let src_dir = Path.Build.parent_exn path in
Expand All @@ -193,6 +192,8 @@ end = struct
in
make_entry ?sub_dir Lib path)
in
let* melange_runtime_entries = additional_deps lib.melange_runtime_deps
and+ public_headers = additional_deps lib.public_headers in
let { Lib_config.has_native; ext_obj; _ } = lib_config in
let { Lib_mode.Map.ocaml = { Mode.Dict.byte; native } as ocaml; melange } =
Dune_file.Mode_conf.Lib.Set.eval lib.modes ~has_native
Expand Down Expand Up @@ -266,12 +267,12 @@ end = struct
let dll_files = dll_files ~modes:ocaml ~dynlink:lib.dynlink ~ctx info in
(lib_files, dll_files)
in
let+ execs = lib_ppxs ctx ~scope ~lib in
let install_c_headers =
List.rev_map lib.install_c_headers ~f:(fun (loc, base) ->
Path.Build.relative dir (base ^ Foreign_language.header_extension)
|> make_entry ~loc Lib)
in
let+ execs = lib_ppxs ctx ~scope ~lib in
List.concat
[ sources
; melange_runtime_entries
Expand All @@ -283,6 +284,7 @@ end = struct
let entry = Install.Entry.make ~kind:`File Stublibs a in
Install.Entry.Sourced.create ~loc entry)
; install_c_headers
; public_headers
]

let keep_if expander ~scope stanza =
Expand Down Expand Up @@ -563,17 +565,19 @@ end = struct
{ loc; old_public_name; new_public_name } ))
| Library lib ->
let info = Lib.Local.info lib in
let* dir_contents =
let dir = Lib_info.src_dir info in
Dir_contents.get sctx ~dir
in
let dir = Lib_info.src_dir info in
let* dir_contents = Dir_contents.get sctx ~dir in
let obj_dir = Lib.Local.obj_dir lib in
let lib_src_dir =
let info = Lib.Local.info lib in
Lib_info.src_dir info
in
let lib = Lib.Local.to_lib lib in
let name = Lib.name lib in
let* expander = Super_context.expander sctx ~dir in
let file_deps (deps : _ Lib_info.File_deps.t) =
match deps with
| External _paths -> assert false
| Local (loc, dep_conf) ->
Lib_file_deps.eval ~expander ~loc ~paths:Allow_all dep_conf
>>| Path.Set.to_list
in
let* foreign_objects =
(* We are writing the list of .o files to dune-package, but we
actually only install them for virtual libraries. See
Expand All @@ -590,22 +594,12 @@ end = struct
Dir_contents.ocaml dir_contents
>>| Ml_sources.modules ~for_:(Library name)
and* melange_runtime_deps =
match Lib_info.melange_runtime_deps info with
| External _paths -> assert false
| Local (loc, dep_conf) ->
let+ melange_runtime_deps =
let* expander =
Super_context.expander sctx ~dir:lib_src_dir
in
Melange_rules.Runtime_deps.eval ~expander ~loc
~paths:Allow_all dep_conf
in
Path.Set.to_list melange_runtime_deps
in
file_deps (Lib_info.melange_runtime_deps info)
and* public_headers = file_deps (Lib_info.public_headers info) in
let+ sub_systems =
Lib.to_dune_lib lib
~dir:(Path.build (lib_root lib))
~modules ~foreign_objects ~melange_runtime_deps
~modules ~foreign_objects ~melange_runtime_deps ~public_headers
>>= Resolve.read_memo
in
Some (name, Dune_package.Entry.Library sub_systems))
Expand Down
5 changes: 3 additions & 2 deletions src/dune_rules/lib.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1956,7 +1956,8 @@ module DB = struct
end

let to_dune_lib ({ info; _ } as lib) ~modules ~foreign_objects
~melange_runtime_deps ~dir : Dune_package.Lib.t Resolve.Memo.t =
~melange_runtime_deps ~public_headers ~dir :
Dune_package.Lib.t Resolve.Memo.t =
let loc = Lib_info.loc info in
let mangled_name lib =
match Lib_info.status lib.info with
Expand Down Expand Up @@ -2009,7 +2010,7 @@ let to_dune_lib ({ info; _ } as lib) ~modules ~foreign_objects
let info =
Lib_info.for_dune_package info ~name ~ppx_runtime_deps ~requires
~foreign_objects ~obj_dir ~implements ~default_implementation ~sub_systems
~modules ~melange_runtime_deps
~modules ~melange_runtime_deps ~public_headers
in
Dune_package.Lib.of_dune_lib ~info ~main_module_name

Expand Down
1 change: 1 addition & 0 deletions src/dune_rules/lib.mli
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ val to_dune_lib :
-> modules:Modules.t
-> foreign_objects:Path.t list
-> melange_runtime_deps:Path.t list
-> public_headers:Path.t list
-> dir:Path.t
-> Dune_package.Lib.t Resolve.Memo.t

Expand Down
32 changes: 32 additions & 0 deletions src/dune_rules/lib_file_deps.ml
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,35 @@ let deps_with_exts =
Dep.Set.union_map ~f:(fun (lib, groups) -> deps_of_lib lib ~groups)

let deps libs ~groups = Dep.Set.union_map libs ~f:(deps_of_lib ~groups)

type path_specification =
| Allow_all
| Disallow_external of Lib_name.t

let raise_disallowed_external_path ~loc lib_name path =
User_error.raise ~loc
[ Pp.textf
"Public library %s depends on external path `%s'. This is not allowed."
(Lib_name.to_string lib_name)
(Path.to_string path)
]
~hints:
[ Pp.textf
"Move the external dependency to the workspace and use a relative \
path."
]

let eval ~loc ~expander ~paths:path_spec (deps : Dep_conf.t list) =
let runtime_deps, sandbox = Dep_conf_eval.unnamed_get_paths ~expander deps in
Option.iter sandbox ~f:(fun _ ->
User_error.raise ~loc [ Pp.text "sandbox settings are not allowed" ]);
let open Memo.O in
let+ paths, _ = Action_builder.run runtime_deps Lazy in
(match path_spec with
| Allow_all -> ()
| Disallow_external lib_name ->
Path.Set.iter paths ~f:(fun path ->
match Path.as_external path with
| None -> ()
| Some _ -> raise_disallowed_external_path ~loc lib_name path));
paths
13 changes: 13 additions & 0 deletions src/dune_rules/lib_file_deps.mli
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,16 @@ end
val deps : Lib.t list -> groups:Group.t list -> Dep.Set.t

val deps_with_exts : (Lib.t * Group.t list) list -> Dep.Set.t

type path_specification =
| Allow_all
| Disallow_external of Lib_name.t

val raise_disallowed_external_path : loc:Loc.t -> Lib_name.t -> Path.t -> 'a

val eval :
loc:Loc.t
-> expander:Expander.t
-> paths:path_specification
-> Dep_conf.t list
-> Path.Set.t Memo.t
Loading

0 comments on commit 987647e

Please sign in to comment.