feat(link): drive output names and link flags from the object format
This commit is contained in:
4 files changed
+71
-17
No files matched your search
@@ -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
@@ -4,12 +4,18 @@ let sanitize s =
|
|||||||
String.concat "/" (List.map (fun p -> if p = ".." then "__" else p) (String.split_on_char '/' 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 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 fmt p = Binfmt.of_platform p.platform
|
||||||
let dylib_ext p =
|
let exe_ext p = Binfmt.exe_ext (fmt p)
|
||||||
match p.platform with "darwin" -> ".dylib" | "windows" -> ".dll" | _ -> ".so"
|
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 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
|
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
|
in
|
||||||
let flags =
|
let flags =
|
||||||
base @ inherited_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 -> [ "-D"; d ]) t.defines
|
||||||
@ List.concat_map (fun d -> [ "-I"; d ]) (includes_of p t)
|
@ List.concat_map (fun d -> [ "-I"; d ]) (includes_of p t)
|
||||||
in
|
in
|
||||||
@@ -72,14 +78,14 @@ let link_cmd p (t : target) objs =
|
|||||||
| Lib -> Array.of_list ((p.tc.ar :: [ "rcs"; out ]) @ objs)
|
| Lib -> Array.of_list ((p.tc.ar :: [ "rcs"; out ]) @ objs)
|
||||||
| Shared ->
|
| Shared ->
|
||||||
let soname =
|
let soname =
|
||||||
match t.soname with
|
match t.soname with None -> [] | Some s -> Binfmt.soname_flags (fmt p) s
|
||||||
| None -> []
|
in
|
||||||
| Some s ->
|
let implib =
|
||||||
if p.platform = "darwin" then [ "-Wl,-install_name," ^ s ] else [ "-Wl,-soname," ^ s ]
|
match implib_of p t with None -> [] | Some f -> Binfmt.implib_flags (fmt p) f
|
||||||
in
|
in
|
||||||
Array.of_list
|
Array.of_list
|
||||||
(((driver :: [ "-shared" ]) @ objs @ [ "-o"; out ]) @ soname @ link_libs p t @ t.ldflags
|
(((driver :: Binfmt.shared_flags (fmt p)) @ objs @ [ "-o"; out ]) @ soname @ implib
|
||||||
@ p.tc.ldflags @ p.tc.xflags)
|
@ link_libs p t @ t.ldflags @ p.tc.ldflags @ p.tc.xflags)
|
||||||
| Bin | Test ->
|
| Bin | Test ->
|
||||||
Array.of_list (((driver :: objs) @ [ "-o"; out ]) @ link_libs p t @ t.ldflags @ p.tc.ldflags @ p.tc.xflags)
|
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 tag, _ = tag_of t.kind in
|
||||||
let ins = objs @ List.map (fun (d : target) -> out_of p d) (deps_of p t) 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
|
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))
|
Hashtbl.replace outputs t.name (!n - 1))
|
||||||
p.targets;
|
p.targets;
|
||||||
{ g = Graph.build (List.rev !nodes); outputs; p }
|
{ g = Graph.build (List.rev !nodes); outputs; p }
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ let platform_vars env plat arch =
|
|||||||
[
|
[
|
||||||
("platform", plat);
|
("platform", plat);
|
||||||
("arch", arch);
|
("arch", arch);
|
||||||
|
("format", Binfmt.name (Binfmt.of_platform plat));
|
||||||
("linux", if plat = "linux" then "true" else "false");
|
("linux", if plat = "linux" then "true" else "false");
|
||||||
("darwin", if plat = "darwin" then "true" else "false");
|
("darwin", if plat = "darwin" then "true" else "false");
|
||||||
("bsd", if plat = "bsd" then "true" else "false");
|
("bsd", if plat = "bsd" then "true" else "false");
|
||||||
|
|||||||
+7
-4
@@ -8,13 +8,16 @@ let dest_dir p = function
|
|||||||
|
|
||||||
let plan p =
|
let plan p =
|
||||||
let from_targets =
|
let from_targets =
|
||||||
List.filter_map
|
List.concat_map
|
||||||
(fun (t : target) ->
|
(fun (t : target) ->
|
||||||
match t.install with
|
match t.install with
|
||||||
| None -> None
|
| None -> []
|
||||||
| Some where ->
|
| Some where ->
|
||||||
let src = Build.out_of p t in
|
(* An import library is half of the shared library it belongs to,
|
||||||
Some (src, Filename.concat (dest_dir p where) (Filename.basename src)))
|
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
|
p.targets
|
||||||
in
|
in
|
||||||
let from_blocks =
|
let from_blocks =
|
||||||
|
|||||||
Reference in new issue
Block a user