Skip to content

Commit

Permalink
Library extensions are now based on ocamlc -config output
Browse files Browse the repository at this point in the history
  • Loading branch information
Lupus committed Nov 11, 2024
1 parent 9e9f1fe commit 4501c93
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 22 deletions.
81 changes: 60 additions & 21 deletions bin/Dune_cargo_build.ml
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,49 @@ let rustify_crate_name crate_name =
String.map (fun c -> if c = '-' then '_' else c) crate_name
;;

let check_suffixes ~suffixes name =
suffixes |> List.fold_left (fun acc x -> acc || Filename.check_suffix name x) false
;;

(*
OCaml expects .so suffix even on macos:
```
Run opam exec -- ocamlc -config
version: 4.14.1
architecture: arm64
system: macosx
ext_exe:
ext_obj: .o
ext_asm: .s
ext_lib: .a
ext_dll: .so
os_type: Unix
```
While cargo produces .dylib on macos, so we match whatever suffixes are expected
on any platform, and rename them to whatever OCaml expects for this specific
platform later.
*)
let classify src =
let base = Filename.basename src in
if String.length base >= 3 && String.sub base 0 3 = "lib"
then
if check_suffixes ~suffixes:[ ".a" ] base
then (
(* Copy static lib without renaming *)
let name_no_ext = Filename.chop_extension base in
Some (`Static name_no_ext))
else if check_suffixes ~suffixes:[ ".dylib"; ".so"; ".dll" ] base
then (
(* Rename dynamic lib files from lib<name>.XXX to dll<name>.XXX *)
let rest = String.sub base 3 (String.length base - 3) in
let name_no_ext = Filename.chop_extension rest in
Some (`Dynamic ("dll" ^ name_no_ext)))
else None
else None
;;

let process_cargo_output cmdline target output_dir =
let in_source_workspace_root = Workspace_root.get () in
let cd_to =
Expand Down Expand Up @@ -196,29 +239,25 @@ let process_cargo_output cmdline target output_dir =
| Some json when is_compiler_artifact json && filter json ->
let filenames = Cargo_json.get_filenames json in
pf "Filenames: %s" (String.concat ", " filenames);
let ext_lib = Ocamlc_config.get "ext_lib" in
let ext_dll = Ocamlc_config.get "ext_dll" in
List.iter
(fun src ->
let base = Filename.basename src in
if String.length base >= 3 && String.sub base 0 3 = "lib"
then (
let rest = String.sub base 3 (String.length base - 3) in
if Filename.check_suffix base ".a"
then (
(* Copy .a files without renaming *)
let dst = Filename.concat output_dir base in
Util.copy_file src dst;
incr count;
pf "COPY %s => %s" src dst;
Printf.printf "Copied %s to %s\n" src dst)
else if Filename.check_suffix base ".so"
then (
(* Rename .so files from lib<name>.so to dll<name>.so *)
let name_no_ext = Filename.chop_extension rest in
let dst = Filename.concat output_dir ("dll" ^ name_no_ext ^ ".so") in
Util.copy_file src dst;
incr count;
pf "COPY + RENAME %s => %s" src dst;
Printf.printf "Copied %s to %s\n" src dst)))
let dst_name =
classify src
|> Option.map (fun src ->
match src with
| `Static name -> name ^ ext_lib
| `Dynamic name -> name ^ ext_dll)
in
match dst_name with
| Some name ->
let dst = Filename.concat output_dir name in
Util.copy_file src dst;
incr count;
pf "COPY %s => %s" src dst;
Printf.printf "Copied %s to %s\n" src dst
| None -> ())
filenames;
let executable = Cargo_json.get_executable json in
pf "Executable: %s" (Option.value ~default:"(none)" executable);
Expand Down
32 changes: 32 additions & 0 deletions bin/Ocamlc_config.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
module String_map = Map.Make (String)

let load () =
let ic = Unix.open_process_in "ocamlc -config" in
let rec read_lines map =
try
let line = input_line ic in
match String.index_opt line ':' with
| Some idx ->
let key = String.trim (String.sub line 0 idx) in
let value =
String.trim (String.sub line (idx + 1) (String.length line - idx - 1))
in
read_lines (String_map.add key value map)
| None -> read_lines map
with
| End_of_file -> map
in
let config_map = read_lines String_map.empty in
let _ = Unix.close_process_in ic in
config_map
;;

let config = lazy (load ())

let get key =
let cfg = Lazy.force config in
match String_map.find_opt key cfg with
| Some value -> value
| None ->
failwith (Printf.sprintf "key `%s` was not found in `ocamlc -config` output" key)
;;
1 change: 1 addition & 0 deletions bin/Ocamlc_config.mli
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
val get : string -> string
5 changes: 4 additions & 1 deletion src/Rust_staticlib.ml
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,10 @@ let generate_dune_content ~crate_name ~dune_staticlib_name =
; see https://github.com/rust-lang/cargo/issues/6790
|};
pf "(rule";
pf " (targets lib%s.a dll%s.so)" lib_name lib_name;
pf
" (targets\n \"lib%s%%{ocaml-config:ext_lib}\"\n \"dll%s%%{ocaml-config:ext_dll}\")"
lib_name
lib_name;
pf " (deps";
pf " (alias rust-universe) ; rebuild only if Rust bits change, linking is slow";
pf " Cargo.toml)";
Expand Down

0 comments on commit 4501c93

Please sign in to comment.