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 13, 2023
1 parent aaf675d commit 5fc72f2
Show file tree
Hide file tree
Showing 22 changed files with 263 additions and 126 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
12 changes: 11 additions & 1 deletion doc/stanzas/library.rst
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,17 @@ order to declare a multi-directory library, you need to use the

- ``(install_c_headers (<names>))`` - if your library has public C header files
that must be installed, you must list them in this field, without the ``.h``
extension.
extension. You should favor the ``public_headers`` field starting from 3.8.

- ``(public_headers (<files>))`` - if your library has public C header files
that must be installed, you must list them in this field. This field accepts
globs in the form of ``(glob_files_rec <glob>)`` and ``(glob_files <glob>)``
fields to specify multiple files.

The advantage of this field over ``install_c_headers`` is that it preserves
the directory structures of the headers relative to the library stanza.
Additionally, it allows to specify the extensions of the header files, which
allows alternative extensions such as ``.hh`` or ``.hpp``.

- ``(modes <modes>)`` is for modes which should be built by default. The most
common use for this feature is to disable native compilation when writing
Expand Down
27 changes: 20 additions & 7 deletions src/dune_rules/dep_conf.ml
Original file line number Diff line number Diff line change
Expand Up @@ -47,22 +47,30 @@ let decode_sandbox_config =
in
Sandbox_config.Partial.merge ~loc x

let decode =
let decode files =
let files_only =
match files with
| `Allow -> return ()
| `Forbid ->
let* loc = loc in
User_error.raise ~loc
[ Pp.text "only files are allowed in this position" ]
in
let decode =
let sw = String_with_vars.decode in
sum ~force_parens:true
[ ("file", sw >>| fun x -> File x)
; ("alias", sw >>| fun x -> Alias x)
; ("alias_rec", sw >>| fun x -> Alias_rec x)
; ("alias", files_only >>> sw >>| fun x -> Alias x)
; ("alias_rec", files_only >>> sw >>| fun x -> Alias_rec x)
; ( "glob_files"
, sw >>| fun glob -> Glob_files { Glob_files.glob; recursive = false }
)
; ( "glob_files_rec"
, let+ () = Dune_lang.Syntax.since Stanza.syntax (3, 0)
and+ glob = sw in
Glob_files { Glob_files.glob; recursive = true } )
; ("package", sw >>| fun x -> Package x)
; ("universe", return Universe)
; ("package", files_only >>> sw >>| fun x -> Package x)
; ("universe", files_only >>> return Universe)
; ( "files_recursively_in"
, let+ () =
Dune_lang.Syntax.renamed_in Stanza.syntax (1, 0) ~to_:"source_tree"
Expand All @@ -72,8 +80,9 @@ let decode =
, let+ () = Dune_lang.Syntax.since Stanza.syntax (1, 0)
and+ x = sw in
Source_tree x )
; ("env_var", sw >>| fun x -> Env_var x)
; ("sandbox", decode_sandbox_config >>| fun x -> Sandbox_config x)
; ("env_var", files_only >>> sw >>| fun x -> Env_var x)
; ( "sandbox"
, files_only >>> decode_sandbox_config >>| fun x -> Sandbox_config x )
; ( "include"
, let+ () = Dune_lang.Syntax.since Stanza.syntax (3, 1)
and+ filename = filename in
Expand All @@ -84,6 +93,10 @@ let decode =
<|> let+ x = String_with_vars.decode in
File x

let decode_no_files = decode `Forbid

let decode = decode `Allow

open Dune_lang

let encode = function
Expand Down
2 changes: 2 additions & 0 deletions src/dune_rules/dep_conf.mli
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,6 @@ val remove_locs : t -> t

include Dune_lang.Conv.S with type t := t

val decode_no_files : t Dune_lang.Decoder.t

val to_dyn : t Dyn.builder
2 changes: 2 additions & 0 deletions src/dune_rules/dep_conf_eval.ml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ let add_sandbox_config acc (dep : Dep_conf.t) =

let rec dep expander = function
| Include s ->
(* TODO this is wrong. we shouldn't allow bindings here if we are in an
unnamed expansion *)
let deps = expand_include ~expander s in
Other
(let* deps = deps in
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 @@ -563,6 +563,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 @@ -600,6 +601,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_no_files))
~default:(stanza_loc, [])
and+ ppx_runtime_libraries =
field "ppx_runtime_libraries"
(repeat (located Lib_name.decode))
Expand Down Expand Up @@ -735,6 +741,7 @@ module Library = struct
; visibility
; synopsis
; install_c_headers
; public_headers
; ppx_runtime_libraries
; modes
; kind
Expand Down Expand Up @@ -987,15 +994,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
Loading

0 comments on commit 5fc72f2

Please sign in to comment.