feat(link): drive output names and link flags from the object format

This commit is contained in:
milner committed 2022-07-18 07:56:15 +00:00
1 parent 3b38d20522
commit b8d3b7ebb1
4 files changed
+71 -17

No files matched your search

+43
View File
@@ -0,0 +1,43 @@
(* Output naming and linker flags follow the object file format, not the
operating system: the same triple can name a platform whose format decides
whether a shared library carries a lib prefix, needs an import library, or
has any notion of a soname at all. *)
type t = Elf | Macho | Coff | Wasm
let of_platform = function
| "darwin" -> Macho
| "windows" -> Coff
| "wasm" -> Wasm
| _ -> Elf
let name = function Elf -> "elf" | Macho -> "macho" | Coff -> "coff" | Wasm -> "wasm"
let exe_ext = function Coff -> ".exe" | Wasm -> ".wasm" | Elf | Macho -> ""
(* Archives are written by ar and read back through -l, so they are named the
same way everywhere, including for the gnu ABI on Windows. *)
let static_name n = "lib" ^ n ^ ".a"
(* COFF keeps the plain name and links through a separate import library, while
the other formats carry the prefix in the shared object name itself. *)
let shared_name fmt n =
match fmt with
| Elf -> "lib" ^ n ^ ".so"
| Macho -> "lib" ^ n ^ ".dylib"
| Coff -> n ^ ".dll"
| Wasm -> "lib" ^ n ^ ".wasm"
let import_name fmt n = match fmt with Coff -> Some ("lib" ^ n ^ ".dll.a") | _ -> None
(* COFF and wasm are position independent by construction, and their drivers
warn about a flag that cannot mean anything to them. *)
let pic_flags = function Elf | Macho -> [ "-fPIC" ] | Coff | Wasm -> []
let shared_flags = function Macho -> [ "-dynamiclib" ] | Elf | Coff | Wasm -> [ "-shared" ]
let soname_flags fmt s =
match fmt with
| Elf -> [ "-Wl,-soname," ^ s ]
| Macho -> [ "-Wl,-install_name," ^ s ]
| Coff | Wasm -> []
let implib_flags fmt path =
match fmt with Coff -> [ "-Wl,--out-implib," ^ path ] | Elf | Macho | Wasm -> []
+20 -13
View File
@@ -4,12 +4,18 @@ let sanitize s =
String.concat "/" (List.map (fun p -> if p = ".." then "__" else p) (String.split_on_char '/' s))
let obj_of p (t : target) src = p.tc.builddir ^ "/obj/" ^ t.name ^ "/" ^ sanitize src ^ ".o"
let lib_of p (t : target) = p.tc.builddir ^ "/lib" ^ t.name ^ ".a"
let dylib_ext p =
match p.platform with "darwin" -> ".dylib" | "windows" -> ".dll" | _ -> ".so"
let fmt p = Binfmt.of_platform p.platform
let exe_ext p = Binfmt.exe_ext (fmt p)
let lib_of p (t : target) = p.tc.builddir ^ "/" ^ Binfmt.static_name t.name
let so_of p (t : target) = p.tc.builddir ^ "/" ^ Binfmt.shared_name (fmt p) t.name
(* Formats that cannot be linked against directly leave an import library
beside the shared one, which is what dependents resolve -l against. *)
let implib_of p (t : target) =
if t.kind <> Shared then None
else
Option.map (fun n -> p.tc.builddir ^ "/" ^ n) (Binfmt.import_name (fmt p) t.name)
let exe_ext p = if p.platform = "windows" then ".exe" else ""
let so_of p (t : target) = p.tc.builddir ^ "/lib" ^ t.name ^ dylib_ext p
let bin_of p (t : target) = p.tc.builddir ^ "/bin/" ^ t.name ^ exe_ext p
let test_of p (t : target) = p.tc.builddir ^ "/test/" ^ t.name ^ exe_ext p
@@ -49,7 +55,7 @@ let compile_cmd p ~pic (t : target) src obj =
in
let flags =
base @ inherited_flags
@ (if Hashtbl.mem pic t.name then [ "-fPIC" ] else [])
@ (if Hashtbl.mem pic t.name then Binfmt.pic_flags (fmt p) else [])
@ List.concat_map (fun d -> [ "-D"; d ]) t.defines
@ List.concat_map (fun d -> [ "-I"; d ]) (includes_of p t)
in
@@ -72,14 +78,14 @@ let link_cmd p (t : target) objs =
| Lib -> Array.of_list ((p.tc.ar :: [ "rcs"; out ]) @ objs)
| Shared ->
let soname =
match t.soname with
| None -> []
| Some s ->
if p.platform = "darwin" then [ "-Wl,-install_name," ^ s ] else [ "-Wl,-soname," ^ s ]
match t.soname with None -> [] | Some s -> Binfmt.soname_flags (fmt p) s
in
let implib =
match implib_of p t with None -> [] | Some f -> Binfmt.implib_flags (fmt p) f
in
Array.of_list
(((driver :: [ "-shared" ]) @ objs @ [ "-o"; out ]) @ soname @ link_libs p t @ t.ldflags
@ p.tc.ldflags @ p.tc.xflags)
(((driver :: Binfmt.shared_flags (fmt p)) @ objs @ [ "-o"; out ]) @ soname @ implib
@ link_libs p t @ t.ldflags @ p.tc.ldflags @ p.tc.xflags)
| Bin | Test ->
Array.of_list (((driver :: objs) @ [ "-o"; out ]) @ link_libs p t @ t.ldflags @ p.tc.ldflags @ p.tc.xflags)
@@ -125,7 +131,8 @@ let of_project p =
let tag, _ = tag_of t.kind in
let ins = objs @ List.map (fun (d : target) -> out_of p d) (deps_of p t) in
let label = match t.kind with Lib | Shared -> Filename.basename out | _ -> t.name in
add (Graph.make ~id:!n ~tag ~label ~cmd:(link_cmd p t objs) ~outs:[ out ] ~ins ());
let outs = out :: Option.to_list (implib_of p t) in
add (Graph.make ~id:!n ~tag ~label ~cmd:(link_cmd p t objs) ~outs ~ins ());
Hashtbl.replace outputs t.name (!n - 1))
p.targets;
{ g = Graph.build (List.rev !nodes); outputs; p }
+1
View File
@@ -96,6 +96,7 @@ let platform_vars env plat arch =
[
("platform", plat);
("arch", arch);
("format", Binfmt.name (Binfmt.of_platform plat));
("linux", if plat = "linux" then "true" else "false");
("darwin", if plat = "darwin" then "true" else "false");
("bsd", if plat = "bsd" then "true" else "false");
+7 -4
View File
@@ -8,13 +8,16 @@ let dest_dir p = function
let plan p =
let from_targets =
List.filter_map
List.concat_map
(fun (t : target) ->
match t.install with
| None -> None
| None -> []
| Some where ->
let src = Build.out_of p t in
Some (src, Filename.concat (dest_dir p where) (Filename.basename src)))
(* An import library is half of the shared library it belongs to,
so it travels with it. *)
List.map
(fun src -> (src, Filename.concat (dest_dir p where) (Filename.basename src)))
(Build.out_of p t :: Option.to_list (Build.implib_of p t)))
p.targets
in
let from_blocks =