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 is not ambiguous when the first parent directory to contain a
|
||||||
``<package>.opam`` file contains exactly one ``<package>.opam`` file
|
``<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
|
Common items
|
||||||
============
|
============
|
||||||
|
|
||||||
|
|
|
@ -479,34 +479,34 @@ let fold_one_step t ~init:acc ~f =
|
||||||
| Mkdir _ -> acc
|
| Mkdir _ -> acc
|
||||||
|
|
||||||
let rec map t ~fs ~fp =
|
let rec map t ~fs ~fp =
|
||||||
match t with
|
match t with
|
||||||
| Run (This prog, args) ->
|
| Run (This prog, args) ->
|
||||||
Run (This (fp prog), List.map args ~f:fs)
|
Run (This (fp prog), List.map args ~f:fs)
|
||||||
| Run (Not_found _ as nf, args) ->
|
| Run (Not_found _ as nf, args) ->
|
||||||
Run (nf, List.map args ~f:fs)
|
Run (nf, List.map args ~f:fs)
|
||||||
| Chdir (fn, t) ->
|
| Chdir (fn, t) ->
|
||||||
Chdir (fp fn, map t ~fs ~fp)
|
Chdir (fp fn, map t ~fs ~fp)
|
||||||
| Setenv (var, value, t) ->
|
| Setenv (var, value, t) ->
|
||||||
Setenv (fs var, fs value, map t ~fs ~fp)
|
Setenv (fs var, fs value, map t ~fs ~fp)
|
||||||
| Redirect (outputs, fn, t) ->
|
| Redirect (outputs, fn, t) ->
|
||||||
Redirect (outputs, fp fn, map t ~fs ~fp)
|
Redirect (outputs, fp fn, map t ~fs ~fp)
|
||||||
| Ignore (outputs, t) ->
|
| Ignore (outputs, t) ->
|
||||||
Ignore (outputs, map t ~fs ~fp)
|
Ignore (outputs, map t ~fs ~fp)
|
||||||
| Progn l -> Progn (List.map l ~f:(fun t -> map t ~fs ~fp))
|
| Progn l -> Progn (List.map l ~f:(fun t -> map t ~fs ~fp))
|
||||||
| Echo x -> Echo (fs x)
|
| Echo x -> Echo (fs x)
|
||||||
| Cat x -> Cat (fp x)
|
| Cat x -> Cat (fp x)
|
||||||
| Create_file x -> Create_file (fp x)
|
| Create_file x -> Create_file (fp x)
|
||||||
| Copy (x, y) -> Copy (fp x, fp y)
|
| Copy (x, y) -> Copy (fp x, fp y)
|
||||||
| Symlink (x, y) ->
|
| Symlink (x, y) ->
|
||||||
Symlink (fp x, fp y)
|
Symlink (fp x, fp y)
|
||||||
| Copy_and_add_line_directive (x, y) ->
|
| Copy_and_add_line_directive (x, y) ->
|
||||||
Copy_and_add_line_directive (fp x, fp y)
|
Copy_and_add_line_directive (fp x, fp y)
|
||||||
| System x -> System (fs x)
|
| System x -> System (fs x)
|
||||||
| Bash x -> Bash (fs x)
|
| Bash x -> Bash (fs x)
|
||||||
| Update_file (x, y) -> Update_file (fp x, fs y)
|
| Update_file (x, y) -> Update_file (fp x, fs y)
|
||||||
| Rename (x, y) -> Rename (fp x, fp y)
|
| Rename (x, y) -> Rename (fp x, fp y)
|
||||||
| Remove_tree x -> Remove_tree (fp x)
|
| Remove_tree x -> Remove_tree (fp x)
|
||||||
| Mkdir x -> Mkdir (fp x)
|
| Mkdir x -> Mkdir (fp x)
|
||||||
|
|
||||||
let updated_files =
|
let updated_files =
|
||||||
let rec loop acc t =
|
let rec loop acc t =
|
||||||
|
|
|
@ -3,13 +3,14 @@ open Jbuild
|
||||||
|
|
||||||
type t =
|
type t =
|
||||||
{ context : Context.t
|
{ context : Context.t
|
||||||
; local_bins : String_set.t
|
; local_bins : Path.t String_map.t
|
||||||
; local_libs : Public_lib.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 =
|
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 ->
|
~f:(fun acc x ->
|
||||||
List.fold_left (f x) ~init:acc
|
List.fold_left (f x) ~init:acc
|
||||||
~f:(fun (local_bins, local_libs) stanza ->
|
~f:(fun (local_bins, local_libs) stanza ->
|
||||||
|
@ -22,7 +23,28 @@ let create context l ~f =
|
||||||
| Some s -> s
|
| Some s -> s
|
||||||
| None -> Filename.basename src
|
| None -> Filename.basename src
|
||||||
in
|
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)
|
local_libs)
|
||||||
| Library { public = Some pub; _ } ->
|
| Library { public = Some pub; _ } ->
|
||||||
(local_bins,
|
(local_bins,
|
||||||
|
@ -39,9 +61,9 @@ let binary t ?hint ?(in_the_tree=true) name =
|
||||||
if not (Filename.is_relative name) then
|
if not (Filename.is_relative name) then
|
||||||
Ok (Path.absolute name)
|
Ok (Path.absolute name)
|
||||||
else if in_the_tree then begin
|
else if in_the_tree then begin
|
||||||
if String_set.mem name t.local_bins then
|
match String_map.find name t.local_bins with
|
||||||
Ok (Path.relative (Config.local_install_bin_dir ~context:t.context.name) name)
|
| Some path -> Ok path
|
||||||
else
|
| None ->
|
||||||
match Context.which t.context name with
|
match Context.which t.context name with
|
||||||
| Some p -> Ok p
|
| Some p -> Ok p
|
||||||
| None ->
|
| None ->
|
||||||
|
@ -92,12 +114,11 @@ let file_of_lib t ~from ~lib ~file =
|
||||||
assert false
|
assert false
|
||||||
}
|
}
|
||||||
|
|
||||||
let file_of_lib t ~from name =
|
let file_of_lib t ~loc ~from name =
|
||||||
let lib, file =
|
let lib, file =
|
||||||
match String.lsplit2 name ~on:':' with
|
match String.lsplit2 name ~on:':' with
|
||||||
| None ->
|
| None ->
|
||||||
Loc.fail (Loc.in_file (Path.to_string (Path.relative from "jbuild")))
|
Loc.fail loc "invalid ${lib:...} form: %s" name
|
||||||
"invalid ${lib:...} form: %s" name
|
|
||||||
| Some x -> x
|
| Some x -> x
|
||||||
in
|
in
|
||||||
(lib, file_of_lib t ~from ~lib ~file)
|
(lib, file_of_lib t ~from ~lib ~file)
|
||||||
|
|
|
@ -27,6 +27,7 @@ val binary
|
||||||
*)
|
*)
|
||||||
val file_of_lib
|
val file_of_lib
|
||||||
: t
|
: t
|
||||||
|
-> loc:Loc.t
|
||||||
-> from:Path.t
|
-> from:Path.t
|
||||||
-> string
|
-> string
|
||||||
-> string * (Path.t, fail) result
|
-> string * (Path.t, fail) result
|
||||||
|
|
|
@ -17,3 +17,4 @@ val best_prog : Path.t -> string -> Path.t option
|
||||||
|
|
||||||
(** "make" program *)
|
(** "make" program *)
|
||||||
val make : Path.t option
|
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)
|
Path.append install_dir (Install.Entry.relative_installed_path entry ~package)
|
||||||
in
|
in
|
||||||
SC.add_rule sctx (Build.symlink ~src:entry.src ~dst);
|
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 install_file package_path package entries =
|
||||||
let entries =
|
let entries =
|
||||||
|
|
|
@ -57,11 +57,31 @@ module Entry = struct
|
||||||
}
|
}
|
||||||
|
|
||||||
let make section ?dst src =
|
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
|
{ src
|
||||||
; dst
|
; dst
|
||||||
; section
|
; section
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let set_src t src = { t with src }
|
||||||
|
|
||||||
module Paths = struct
|
module Paths = struct
|
||||||
let lib = Path.(relative root) "lib"
|
let lib = Path.(relative root) "lib"
|
||||||
let libexec = Path.(relative root) "lib"
|
let libexec = Path.(relative root) "lib"
|
||||||
|
|
|
@ -19,13 +19,14 @@ module Section : sig
|
||||||
end
|
end
|
||||||
|
|
||||||
module Entry : sig
|
module Entry : sig
|
||||||
type t =
|
type t = private
|
||||||
{ src : Path.t
|
{ src : Path.t
|
||||||
; dst : string option
|
; dst : string option
|
||||||
; section : Section.t
|
; section : Section.t
|
||||||
}
|
}
|
||||||
|
|
||||||
val make : Section.t -> ?dst:string -> Path.t -> 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
|
val relative_installed_path : t -> package:string -> Path.t
|
||||||
end
|
end
|
||||||
|
|
|
@ -18,7 +18,7 @@ let in_build_dir ~ctx =
|
||||||
|
|
||||||
let runtime_file ~sctx ~dir fname =
|
let runtime_file ~sctx ~dir fname =
|
||||||
let _lib, file =
|
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)
|
(sprintf "js_of_ocaml-compiler:%s" fname)
|
||||||
in
|
in
|
||||||
match file with
|
match file with
|
||||||
|
|
|
@ -203,6 +203,7 @@ let bootstrap () =
|
||||||
; "--subst" , Unit subst , " substitute watermarks in source files"
|
; "--subst" , Unit subst , " substitute watermarks in source files"
|
||||||
]
|
]
|
||||||
anon "Usage: boot.exe [-j JOBS] [--dev]\nOptions are:";
|
anon "Usage: boot.exe [-j JOBS] [--dev]\nOptions are:";
|
||||||
|
Clflags.debug_dep_path := true;
|
||||||
let log = Log.create () in
|
let log = Log.create () in
|
||||||
Future.Scheduler.go ~log
|
Future.Scheduler.go ~log
|
||||||
(setup ~log ~workspace:{ merlin_context = Some "default"; contexts = [Default] }
|
(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
|
; 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 =
|
let add_artifact ?lib_dep acc ~key result =
|
||||||
(match lib_dep with
|
(match lib_dep with
|
||||||
| None -> ()
|
| None -> ()
|
||||||
| Some (lib, kind) ->
|
| Some (lib, kind) -> add_lib_dep acc lib kind);
|
||||||
acc.lib_deps <- String_map.add acc.lib_deps ~key:lib ~data:kind);
|
|
||||||
match result with
|
match result with
|
||||||
| Ok exp ->
|
| Ok exp ->
|
||||||
acc.artifacts <- String_map.add acc.artifacts ~key ~data:exp;
|
acc.artifacts <- String_map.add acc.artifacts ~key ~data:exp;
|
||||||
|
@ -487,7 +489,8 @@ module Action = struct
|
||||||
acc.failures <- fail :: acc.failures;
|
acc.failures <- fail :: acc.failures;
|
||||||
None
|
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 ok_string x = Ok (Action.Var_expansion.Strings ([x], Concat))
|
||||||
|
|
||||||
let map_result = function
|
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 ("path" , s) -> add_artifact acc ~key (ok_path (Path.relative dir s))
|
||||||
| Some ("bin" , s) ->
|
| Some ("bin" , s) ->
|
||||||
add_artifact acc ~key (A.binary (artifacts sctx) s |> map_result)
|
add_artifact acc ~key (A.binary (artifacts sctx) s |> map_result)
|
||||||
| Some ("lib" , s)
|
| Some ("lib" , s) ->
|
||||||
| Some ("libexec" , s) ->
|
let lib_dep, res = A.file_of_lib (artifacts sctx) ~loc ~from:dir s in
|
||||||
let lib_dep, res = A.file_of_lib (artifacts sctx) ~from:dir s in
|
|
||||||
add_artifact acc ~key ~lib_dep:(lib_dep, dep_kind) (map_result res)
|
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) ->
|
| Some ("lib-available", lib) ->
|
||||||
add_artifact acc ~key ~lib_dep:(lib, Optional)
|
add_artifact acc ~key ~lib_dep:(lib, Optional)
|
||||||
(ok_string (string_of_bool (Libs.lib_is_available sctx ~from:dir lib)))
|
(ok_string (string_of_bool (Libs.lib_is_available sctx ~from:dir lib)))
|
||||||
(* CR-someday jdimino: allow this only for (jbuild_version jane_street) *)
|
(* CR-someday jdimino: allow this only for (jbuild_version jane_street) *)
|
||||||
| Some ("findlib" , s) ->
|
| Some ("findlib" , s) ->
|
||||||
let lib_dep, res =
|
let lib_dep, res =
|
||||||
A.file_of_lib (artifacts sctx) ~from:dir s
|
A.file_of_lib (artifacts sctx) ~loc ~from:dir s
|
||||||
in
|
in
|
||||||
add_artifact acc ~key ~lib_dep:(lib_dep, Required) (map_result res)
|
add_artifact acc ~key ~lib_dep:(lib_dep, Required) (map_result res)
|
||||||
| Some ("version", s) -> begin
|
| Some ("version", s) -> begin
|
||||||
|
|
Loading…
Reference in New Issue