Automatically install executable with extension `.exe` on Windows (#123)
- Automatically add exe extension when installing executables - Look for local binaries with .exe extension on Windows
This commit is contained in:
parent
1a64983402
commit
2e2a707d4b
|
@ -487,6 +487,18 @@ instance, to install a file ``mylib.el`` as
|
|||
package is not ambiguous when the first parent directory to contain a
|
||||
``<package>.opam`` file contains exactly one ``<package>.opam`` file
|
||||
|
||||
Handling of the .exe extension on Windows
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Under Microsoft Windows, executables must be suffixed with
|
||||
``.exe``. Jbuilder tries to make sure that executables are always
|
||||
installed with this extension on Windows.
|
||||
|
||||
More precisely, when installing a file via an ``(install ...)``
|
||||
stanza, if the source file has extension ``.exe`` or ``.bc``, then
|
||||
Jbuilder implicitly adds the ``.exe`` extension to the destination, if
|
||||
not already present.
|
||||
|
||||
Common items
|
||||
============
|
||||
|
||||
|
|
|
@ -479,34 +479,34 @@ let fold_one_step t ~init:acc ~f =
|
|||
| Mkdir _ -> acc
|
||||
|
||||
let rec map t ~fs ~fp =
|
||||
match t with
|
||||
| Run (This prog, args) ->
|
||||
Run (This (fp prog), List.map args ~f:fs)
|
||||
| Run (Not_found _ as nf, args) ->
|
||||
Run (nf, List.map args ~f:fs)
|
||||
| Chdir (fn, t) ->
|
||||
Chdir (fp fn, map t ~fs ~fp)
|
||||
| Setenv (var, value, t) ->
|
||||
Setenv (fs var, fs value, map t ~fs ~fp)
|
||||
| Redirect (outputs, fn, t) ->
|
||||
Redirect (outputs, fp fn, map t ~fs ~fp)
|
||||
| Ignore (outputs, t) ->
|
||||
Ignore (outputs, map t ~fs ~fp)
|
||||
| Progn l -> Progn (List.map l ~f:(fun t -> map t ~fs ~fp))
|
||||
| Echo x -> Echo (fs x)
|
||||
| Cat x -> Cat (fp x)
|
||||
| Create_file x -> Create_file (fp x)
|
||||
| Copy (x, y) -> Copy (fp x, fp y)
|
||||
| Symlink (x, y) ->
|
||||
Symlink (fp x, fp y)
|
||||
| Copy_and_add_line_directive (x, y) ->
|
||||
Copy_and_add_line_directive (fp x, fp y)
|
||||
| System x -> System (fs x)
|
||||
| Bash x -> Bash (fs x)
|
||||
| Update_file (x, y) -> Update_file (fp x, fs y)
|
||||
| Rename (x, y) -> Rename (fp x, fp y)
|
||||
| Remove_tree x -> Remove_tree (fp x)
|
||||
| Mkdir x -> Mkdir (fp x)
|
||||
match t with
|
||||
| Run (This prog, args) ->
|
||||
Run (This (fp prog), List.map args ~f:fs)
|
||||
| Run (Not_found _ as nf, args) ->
|
||||
Run (nf, List.map args ~f:fs)
|
||||
| Chdir (fn, t) ->
|
||||
Chdir (fp fn, map t ~fs ~fp)
|
||||
| Setenv (var, value, t) ->
|
||||
Setenv (fs var, fs value, map t ~fs ~fp)
|
||||
| Redirect (outputs, fn, t) ->
|
||||
Redirect (outputs, fp fn, map t ~fs ~fp)
|
||||
| Ignore (outputs, t) ->
|
||||
Ignore (outputs, map t ~fs ~fp)
|
||||
| Progn l -> Progn (List.map l ~f:(fun t -> map t ~fs ~fp))
|
||||
| Echo x -> Echo (fs x)
|
||||
| Cat x -> Cat (fp x)
|
||||
| Create_file x -> Create_file (fp x)
|
||||
| Copy (x, y) -> Copy (fp x, fp y)
|
||||
| Symlink (x, y) ->
|
||||
Symlink (fp x, fp y)
|
||||
| Copy_and_add_line_directive (x, y) ->
|
||||
Copy_and_add_line_directive (fp x, fp y)
|
||||
| System x -> System (fs x)
|
||||
| Bash x -> Bash (fs x)
|
||||
| Update_file (x, y) -> Update_file (fp x, fs y)
|
||||
| Rename (x, y) -> Rename (fp x, fp y)
|
||||
| Remove_tree x -> Remove_tree (fp x)
|
||||
| Mkdir x -> Mkdir (fp x)
|
||||
|
||||
let updated_files =
|
||||
let rec loop acc t =
|
||||
|
|
|
@ -3,13 +3,14 @@ open Jbuild
|
|||
|
||||
type t =
|
||||
{ context : Context.t
|
||||
; local_bins : String_set.t
|
||||
; local_bins : Path.t String_map.t
|
||||
; local_libs : Public_lib.t String_map.t
|
||||
}
|
||||
|
||||
let create context l ~f =
|
||||
let create (context : Context.t) l ~f =
|
||||
let bin_dir = Config.local_install_bin_dir ~context:context.name in
|
||||
let local_bins, local_libs =
|
||||
List.fold_left l ~init:(String_set.empty, String_map.empty)
|
||||
List.fold_left l ~init:(String_map.empty, String_map.empty)
|
||||
~f:(fun acc x ->
|
||||
List.fold_left (f x) ~init:acc
|
||||
~f:(fun (local_bins, local_libs) stanza ->
|
||||
|
@ -22,7 +23,28 @@ let create context l ~f =
|
|||
| Some s -> s
|
||||
| None -> Filename.basename src
|
||||
in
|
||||
String_set.add name acc),
|
||||
let key =
|
||||
if Sys.win32 && Filename.extension name = ".exe" then
|
||||
String.sub name ~pos:0 ~len:(String.length name - 4)
|
||||
else
|
||||
name
|
||||
in
|
||||
let in_bin_dir =
|
||||
let fn =
|
||||
if Sys.win32 then
|
||||
match Filename.extension src with
|
||||
| ".exe" | ".bc" ->
|
||||
if Filename.extension name <> ".exe" then
|
||||
name ^ ".exe"
|
||||
else
|
||||
name
|
||||
| _ -> name
|
||||
else
|
||||
name
|
||||
in
|
||||
Path.relative bin_dir fn
|
||||
in
|
||||
String_map.add acc ~key ~data:in_bin_dir),
|
||||
local_libs)
|
||||
| Library { public = Some pub; _ } ->
|
||||
(local_bins,
|
||||
|
@ -39,9 +61,9 @@ let binary t ?hint ?(in_the_tree=true) name =
|
|||
if not (Filename.is_relative name) then
|
||||
Ok (Path.absolute name)
|
||||
else if in_the_tree then begin
|
||||
if String_set.mem name t.local_bins then
|
||||
Ok (Path.relative (Config.local_install_bin_dir ~context:t.context.name) name)
|
||||
else
|
||||
match String_map.find name t.local_bins with
|
||||
| Some path -> Ok path
|
||||
| None ->
|
||||
match Context.which t.context name with
|
||||
| Some p -> Ok p
|
||||
| None ->
|
||||
|
@ -92,12 +114,11 @@ let file_of_lib t ~from ~lib ~file =
|
|||
assert false
|
||||
}
|
||||
|
||||
let file_of_lib t ~from name =
|
||||
let file_of_lib t ~loc ~from name =
|
||||
let lib, file =
|
||||
match String.lsplit2 name ~on:':' with
|
||||
| None ->
|
||||
Loc.fail (Loc.in_file (Path.to_string (Path.relative from "jbuild")))
|
||||
"invalid ${lib:...} form: %s" name
|
||||
Loc.fail loc "invalid ${lib:...} form: %s" name
|
||||
| Some x -> x
|
||||
in
|
||||
(lib, file_of_lib t ~from ~lib ~file)
|
||||
|
|
|
@ -27,6 +27,7 @@ val binary
|
|||
*)
|
||||
val file_of_lib
|
||||
: t
|
||||
-> loc:Loc.t
|
||||
-> from:Path.t
|
||||
-> string
|
||||
-> string * (Path.t, fail) result
|
||||
|
|
|
@ -17,3 +17,4 @@ val best_prog : Path.t -> string -> Path.t option
|
|||
|
||||
(** "make" program *)
|
||||
val make : Path.t option
|
||||
|
||||
|
|
|
@ -906,7 +906,7 @@ Add it to your jbuild file to remove this warning.
|
|||
Path.append install_dir (Install.Entry.relative_installed_path entry ~package)
|
||||
in
|
||||
SC.add_rule sctx (Build.symlink ~src:entry.src ~dst);
|
||||
{ entry with src = dst })
|
||||
Install.Entry.set_src entry dst)
|
||||
|
||||
let install_file package_path package entries =
|
||||
let entries =
|
||||
|
|
|
@ -57,11 +57,31 @@ module Entry = struct
|
|||
}
|
||||
|
||||
let make section ?dst src =
|
||||
let dst =
|
||||
if Sys.win32 then
|
||||
let src_base = Path.basename src in
|
||||
let dst' =
|
||||
match dst with
|
||||
| None -> src_base
|
||||
| Some s -> s
|
||||
in
|
||||
match Filename.extension src_base with
|
||||
| ".exe" | ".bc" ->
|
||||
if Filename.extension dst' <> ".exe" then
|
||||
Some (dst' ^ ".exe")
|
||||
else
|
||||
dst
|
||||
| _ -> dst
|
||||
else
|
||||
dst
|
||||
in
|
||||
{ src
|
||||
; dst
|
||||
; section
|
||||
}
|
||||
|
||||
let set_src t src = { t with src }
|
||||
|
||||
module Paths = struct
|
||||
let lib = Path.(relative root) "lib"
|
||||
let libexec = Path.(relative root) "lib"
|
||||
|
|
|
@ -19,13 +19,14 @@ module Section : sig
|
|||
end
|
||||
|
||||
module Entry : sig
|
||||
type t =
|
||||
type t = private
|
||||
{ src : Path.t
|
||||
; dst : string option
|
||||
; section : Section.t
|
||||
}
|
||||
|
||||
val make : Section.t -> ?dst:string -> Path.t -> t
|
||||
val set_src : t -> Path.t -> t
|
||||
|
||||
val relative_installed_path : t -> package:string -> Path.t
|
||||
end
|
||||
|
|
|
@ -18,7 +18,7 @@ let in_build_dir ~ctx =
|
|||
|
||||
let runtime_file ~sctx ~dir fname =
|
||||
let _lib, file =
|
||||
Artifacts.file_of_lib (SC.artifacts sctx) ~from:dir
|
||||
Artifacts.file_of_lib (SC.artifacts sctx) ~loc:Loc.none ~from:dir
|
||||
(sprintf "js_of_ocaml-compiler:%s" fname)
|
||||
in
|
||||
match file with
|
||||
|
|
|
@ -203,6 +203,7 @@ let bootstrap () =
|
|||
; "--subst" , Unit subst , " substitute watermarks in source files"
|
||||
]
|
||||
anon "Usage: boot.exe [-j JOBS] [--dev]\nOptions are:";
|
||||
Clflags.debug_dep_path := true;
|
||||
let log = Log.create () in
|
||||
Future.Scheduler.go ~log
|
||||
(setup ~log ~workspace:{ merlin_context = Some "default"; contexts = [Default] }
|
||||
|
|
|
@ -474,11 +474,13 @@ module Action = struct
|
|||
; mutable vdeps : (unit, Action.Var_expansion.t) Build.t String_map.t
|
||||
}
|
||||
|
||||
let add_lib_dep acc lib kind =
|
||||
acc.lib_deps <- String_map.add acc.lib_deps ~key:lib ~data:kind
|
||||
|
||||
let add_artifact ?lib_dep acc ~key result =
|
||||
(match lib_dep with
|
||||
| None -> ()
|
||||
| Some (lib, kind) ->
|
||||
acc.lib_deps <- String_map.add acc.lib_deps ~key:lib ~data:kind);
|
||||
| Some (lib, kind) -> add_lib_dep acc lib kind);
|
||||
match result with
|
||||
| Ok exp ->
|
||||
acc.artifacts <- String_map.add acc.artifacts ~key ~data:exp;
|
||||
|
@ -487,7 +489,8 @@ module Action = struct
|
|||
acc.failures <- fail :: acc.failures;
|
||||
None
|
||||
|
||||
let ok_path x = Ok (Action.Var_expansion.Paths ([x], Concat))
|
||||
let path_exp path = (Action.Var_expansion.Paths ([path], Concat))
|
||||
let ok_path x = Ok (path_exp x)
|
||||
let ok_string x = Ok (Action.Var_expansion.Strings ([x], Concat))
|
||||
|
||||
let map_result = function
|
||||
|
@ -512,17 +515,39 @@ module Action = struct
|
|||
| Some ("path" , s) -> add_artifact acc ~key (ok_path (Path.relative dir s))
|
||||
| Some ("bin" , s) ->
|
||||
add_artifact acc ~key (A.binary (artifacts sctx) s |> map_result)
|
||||
| Some ("lib" , s)
|
||||
| Some ("libexec" , s) ->
|
||||
let lib_dep, res = A.file_of_lib (artifacts sctx) ~from:dir s in
|
||||
| Some ("lib" , s) ->
|
||||
let lib_dep, res = A.file_of_lib (artifacts sctx) ~loc ~from:dir s in
|
||||
add_artifact acc ~key ~lib_dep:(lib_dep, dep_kind) (map_result res)
|
||||
| Some ("libexec" , s) -> begin
|
||||
let lib_dep, res = A.file_of_lib (artifacts sctx) ~loc ~from:dir s in
|
||||
add_lib_dep acc lib_dep dep_kind;
|
||||
match res with
|
||||
| Error e ->
|
||||
acc.failures <- e :: acc.failures;
|
||||
None
|
||||
| Ok path ->
|
||||
if not Sys.win32 || Filename.extension s = ".exe" then begin
|
||||
let exp = path_exp path in
|
||||
acc.artifacts <- String_map.add acc.artifacts ~key ~data:exp;
|
||||
Some exp
|
||||
end else begin
|
||||
let path_exe = Path.extend_basename path ~suffix:".exe" in
|
||||
let dep =
|
||||
Build.if_file_exists path_exe
|
||||
~then_:(Build.path path_exe >>^ fun _ -> path_exp path_exe)
|
||||
~else_:(Build.path path >>^ fun _ -> path_exp path)
|
||||
in
|
||||
acc.vdeps <- String_map.add acc.vdeps ~key ~data:dep;
|
||||
None
|
||||
end
|
||||
end
|
||||
| Some ("lib-available", lib) ->
|
||||
add_artifact acc ~key ~lib_dep:(lib, Optional)
|
||||
(ok_string (string_of_bool (Libs.lib_is_available sctx ~from:dir lib)))
|
||||
(* CR-someday jdimino: allow this only for (jbuild_version jane_street) *)
|
||||
| Some ("findlib" , s) ->
|
||||
let lib_dep, res =
|
||||
A.file_of_lib (artifacts sctx) ~from:dir s
|
||||
A.file_of_lib (artifacts sctx) ~loc ~from:dir s
|
||||
in
|
||||
add_artifact acc ~key ~lib_dep:(lib_dep, Required) (map_result res)
|
||||
| Some ("version", s) -> begin
|
||||
|
|
Loading…
Reference in New Issue