Skip to content

Commit 80b7c8c

Browse files
Add explicit mode for -output-complete-exe (#3076)
Signed-off-by: Jeremie Dimino <jeremie@dimino.org> Co-authored-by: Rudi Grinberg <me@rgrinberg.com>
1 parent ff4710f commit 80b7c8c

File tree

10 files changed

+281
-185
lines changed

10 files changed

+281
-185
lines changed

CHANGES.md

+4
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@
3535
- `make` now prints a message explaining the main targets available
3636
(#3085, fix #3078, @diml)
3737

38+
- Add a `byte_complete` executable mode to build programs as
39+
self-contained bytecode programs
40+
(#3076, fixes #1519, @diml)
41+
3842
2.1.3 (16/01/2020)
3943
------------------
4044

doc/dune-files.rst

+28-20
Original file line numberDiff line numberDiff line change
@@ -716,36 +716,44 @@ For instance the following ``modes`` fields are all equivalent:
716716
(best object)
717717
(best shared_object)))
718718
719+
And finally, you can use the special mode ``byte_complete`` for
720+
building a bytecode executable as a native self-contained
721+
executable. I.e. an executable that does not require the ``ocamlrun``
722+
program to run and does not requires the C stubs to be installed as
723+
shared object files.
724+
719725
The extensions for the various linking modes are chosen as follows:
720726

721-
================ ============= =================
722-
compilation mode binary kind extensions
723-
---------------- ------------- -----------------
724-
byte exe .bc and .bc.js
725-
native/best exe .exe
726-
byte object .bc%{ext_obj}
727-
native/best object .exe%{ext_obj}
728-
byte shared_object .bc%{ext_dll}
729-
native/best shared_object %{ext_dll}
730-
byte c .bc.c
731-
byte js .bc.js
732-
================ ============= =================
727+
=========================== =================
728+
linking mode extensions
729+
--------------------------- -----------------
730+
byte .bc
731+
native/best .exe
732+
byte_complete .bc.exe
733+
(byte object) .bc%{ext_obj}
734+
(native/best object) .exe%{ext_obj}
735+
(byte shared_object) .bc%{ext_dll}
736+
(native/best shared_object) %{ext_dll}
737+
c .bc.c
738+
js .bc.js
739+
=========================== =================
733740

734741
Where ``%{ext_obj}`` and ``%{ext_dll}`` are the extensions for object
735742
and shared object files. Their value depends on the OS, for instance
736743
on Unix ``%{ext_obj}`` is usually ``.o`` and ``%{ext_dll}`` is usually
737744
``.so`` while on Windows ``%{ext_obj}`` is ``.obj`` and ``%{ext_dll}``
738745
is ``.dll``.
739746

740-
Note that when ``(byte exe)`` is specified but neither ``(best exe)``
741-
nor ``(native exe)`` are specified, Dune still knows how to build
742-
an executable with the extension ``.exe``. In such case, the ``.exe``
743-
version is the same as the ``.bc`` one except that it is linked with
744-
the ``-custom`` option of the compiler. You should always use the
745-
``.exe`` rather that the ``.bc`` inside build rules.
747+
Up to version 3.0 of the dune language, when ``byte`` is specified but
748+
none of ``native``, ``exe`` or ``byte_complete`` are specified Dune
749+
implicitely adds a linking mode that is the same as ``byte_complete``
750+
but using the extension ``.exe``. ``.bc`` files require additional
751+
files at runtime that are not currently tracked by Dune, so you should
752+
not run ``.bc`` files during the build. Run the ``.bc.exe`` or
753+
``.exe`` ones instead as these are self-contained.
746754

747-
Lastly, note that ``.bc`` executables cannot contain C stubs. If your executable
748-
contains C stubs you may want to use ``(modes exe)``.
755+
Lastly, note that ``.bc`` executables cannot contain C stubs. If your
756+
executable contains C stubs you may want to use ``(modes exe)``.
749757

750758
executables
751759
-----------

src/dune/dune_file.ml

+101-56
Original file line numberDiff line numberDiff line change
@@ -1354,40 +1354,38 @@ module Executables = struct
13541354
module Link_mode = struct
13551355
module T = struct
13561356
type t =
1357-
{ mode : Mode_conf.t
1358-
; kind : Binary_kind.t
1359-
; loc : Loc.t
1360-
}
1357+
| Byte_complete
1358+
| Other of
1359+
{ mode : Mode_conf.t
1360+
; kind : Binary_kind.t
1361+
}
13611362

13621363
let compare a b =
1363-
match Poly.compare a.mode b.mode with
1364-
| Eq -> Poly.compare a.kind b.kind
1365-
| ne -> ne
1364+
match (a, b) with
1365+
| Byte_complete, Byte_complete -> Eq
1366+
| Byte_complete, _ -> Lt
1367+
| _, Byte_complete -> Gt
1368+
| Other a, Other b -> (
1369+
match Poly.compare a.mode b.mode with
1370+
| Eq -> Poly.compare a.kind b.kind
1371+
| ne -> ne )
13661372

13671373
let to_dyn _ = Dyn.opaque
13681374
end
13691375

13701376
include T
13711377

1372-
let make mode kind = { mode; kind; loc = Loc.none }
1378+
let make mode kind = Other { mode; kind }
13731379

13741380
let exe = make Best Exe
13751381

13761382
let object_ = make Best Object
13771383

13781384
let shared_object = make Best Shared_object
13791385

1380-
let byte_exe = make Byte Exe
1386+
let byte = make Byte Exe
13811387

1382-
let native_exe = make Native Exe
1383-
1384-
let native_object = make Native Object
1385-
1386-
let native_shared_object = make Native Shared_object
1387-
1388-
let byte = byte_exe
1389-
1390-
let native = native_exe
1388+
let native = make Native Exe
13911389

13921390
let js = make Byte Js
13931391

@@ -1400,6 +1398,7 @@ module Executables = struct
14001398
; ("byte", byte)
14011399
; ("native", native)
14021400
; ("js", js)
1401+
; ("byte_complete", Byte_complete)
14031402
]
14041403

14051404
let simple = Dune_lang.Decoder.enum simple_representations
@@ -1409,9 +1408,8 @@ module Executables = struct
14091408
~then_:
14101409
(enter
14111410
(let+ mode = Mode_conf.decode
1412-
and+ kind = Binary_kind.decode
1413-
and+ loc = loc in
1414-
{ mode; kind; loc }))
1411+
and+ kind = Binary_kind.decode in
1412+
make mode kind))
14151413
~else_:simple
14161414

14171415
let simple_encode link_mode =
@@ -1422,46 +1420,93 @@ module Executables = struct
14221420
let encode link_mode =
14231421
match simple_encode link_mode with
14241422
| Some s -> s
1425-
| None ->
1426-
let { mode; kind; loc = _ } = link_mode in
1427-
Dune_lang.Encoder.pair Mode_conf.encode Binary_kind.encode (mode, kind)
1423+
| None -> (
1424+
match link_mode with
1425+
| Byte_complete -> assert false
1426+
| Other { mode; kind } ->
1427+
Dune_lang.Encoder.pair Mode_conf.encode Binary_kind.encode (mode, kind)
1428+
)
1429+
1430+
let to_dyn t =
1431+
match t with
1432+
| Byte_complete -> Dyn.Variant ("Byte_complete", [])
1433+
| Other { mode; kind } ->
1434+
let open Dyn.Encoder in
1435+
Variant
1436+
( "Other"
1437+
, [ record
1438+
[ ("mode", Mode_conf.to_dyn mode)
1439+
; ("kind", Binary_kind.to_dyn kind)
1440+
]
1441+
] )
14281442

1429-
let to_dyn { mode; kind; loc = _ } =
1430-
let open Dyn.Encoder in
1431-
record
1432-
[ ("mode", Mode_conf.to_dyn mode); ("kind", Binary_kind.to_dyn kind) ]
1443+
let extension t ~loc ~ext_obj ~ext_dll =
1444+
match t with
1445+
| Byte_complete -> ".bc.exe"
1446+
| Other { mode; kind } -> (
1447+
let same_as_mode : Mode.t =
1448+
match mode with
1449+
| Byte -> Byte
1450+
| Native
1451+
| Best ->
1452+
(* From the point of view of the extension, [native] and [best] are
1453+
the same *)
1454+
Native
1455+
in
1456+
match (same_as_mode, kind) with
1457+
| Byte, C -> ".bc.c"
1458+
| Native, C ->
1459+
User_error.raise ~loc
1460+
[ Pp.text "C file generation only supports bytecode!" ]
1461+
| Byte, Exe -> ".bc"
1462+
| Native, Exe -> ".exe"
1463+
| Byte, Object -> ".bc" ^ ext_obj
1464+
| Native, Object -> ".exe" ^ ext_obj
1465+
| Byte, Shared_object -> ".bc" ^ ext_dll
1466+
| Native, Shared_object -> ext_dll
1467+
| Byte, Js -> ".bc.js"
1468+
| Native, Js ->
1469+
User_error.raise ~loc
1470+
[ Pp.text "Javascript generation only supports bytecode!" ] )
14331471

14341472
module O = Comparable.Make (T)
14351473

1436-
module Set = struct
1437-
include O.Set
1474+
module Map = struct
1475+
include O.Map
14381476

14391477
let decode =
1440-
located (repeat decode) >>| fun (loc, l) ->
1478+
located (repeat (located decode)) >>| fun (loc, l) ->
14411479
match l with
14421480
| [] -> User_error.raise ~loc [ Pp.textf "No linking mode defined" ]
14431481
| l ->
1444-
let t = of_list l in
1445-
if
1446-
(mem t native_exe && mem t exe)
1447-
|| (mem t native_object && mem t object_)
1448-
|| (mem t native_shared_object && mem t shared_object)
1449-
then
1482+
let t =
1483+
List.fold_left l ~init:empty ~f:(fun acc (loc, link_mode) ->
1484+
set acc link_mode loc)
1485+
in
1486+
( match
1487+
String.Map.of_list_map (to_list t) ~f:(fun (lm, loc) ->
1488+
(extension lm ~loc ~ext_obj:".OBJ" ~ext_dll:".DLL", lm))
1489+
with
1490+
| Ok _ -> ()
1491+
| Error (_ext, (lm1, _), (lm2, _)) ->
14501492
User_error.raise ~loc
14511493
[ Pp.textf
1452-
"It is not allowed use both native and best for the same \
1453-
binary kind."
1454-
]
1455-
else
1456-
t
1494+
"It is not allowed use both %s and %s together as they use \
1495+
the same file extension."
1496+
(Dune_lang.to_string (encode lm1))
1497+
(Dune_lang.to_string (encode lm2))
1498+
] );
1499+
t
1500+
1501+
let byte_and_exe = of_list_exn [ (byte, Loc.none); (exe, Loc.none) ]
14571502

14581503
let default_for_exes ~version =
14591504
if version < (2, 0) then
1460-
of_list [ byte; exe ]
1505+
byte_and_exe
14611506
else
1462-
singleton exe
1507+
singleton exe Loc.none
14631508

1464-
let default_for_tests = of_list [ byte; exe ]
1509+
let default_for_tests = byte_and_exe
14651510

14661511
let best_install_mode t = List.find ~f:(mem t) installable_modes
14671512
end
@@ -1471,7 +1516,7 @@ module Executables = struct
14711516
{ names : (Loc.t * string) list
14721517
; link_flags : Ordered_set_lang.Unexpanded.t
14731518
; link_deps : Dep_conf.t list
1474-
; modes : Link_mode.Set.t
1519+
; modes : Loc.t Link_mode.Map.t
14751520
; optional : bool
14761521
; buildable : Buildable.t
14771522
; variants : (Loc.t * Variant.Set.t) option
@@ -1498,8 +1543,8 @@ module Executables = struct
14981543
and+ link_deps = field "link_deps" (repeat Dep_conf.decode) ~default:[]
14991544
and+ link_flags = Ordered_set_lang.Unexpanded.field "link_flags"
15001545
and+ modes =
1501-
field "modes" Link_mode.Set.decode
1502-
~default:(Link_mode.Set.default_for_exes ~version:dune_version)
1546+
field "modes" Link_mode.Map.decode
1547+
~default:(Link_mode.Map.default_for_exes ~version:dune_version)
15031548
and+ optional =
15041549
field_b "optional" ~check:(Dune_lang.Syntax.since Stanza.syntax (2, 0))
15051550
and+ variants = variants_field
@@ -1541,7 +1586,7 @@ module Executables = struct
15411586
let has_public_name = Names.has_public_name names in
15421587
let private_names = Names.names names in
15431588
let install_conf =
1544-
match Link_mode.Set.best_install_mode modes with
1589+
match Link_mode.Map.best_install_mode modes with
15451590
| None when has_public_name ->
15461591
User_error.raise ~loc:buildable.loc
15471592
[ Pp.textf "No installable mode found for %s."
@@ -1556,11 +1601,11 @@ module Executables = struct
15561601
| None -> None
15571602
| Some mode ->
15581603
let ext =
1559-
match mode.mode with
1560-
| Native
1561-
| Best ->
1562-
".exe"
1563-
| Byte -> ".bc"
1604+
match mode with
1605+
| Byte_complete
1606+
| Other { mode = Byte; _ } ->
1607+
".bc"
1608+
| Other { mode = Native | Best; _ } -> ".exe"
15641609
in
15651610
Names.install_conf names ~ext
15661611
in
@@ -2013,8 +2058,8 @@ module Tests = struct
20132058
and+ package = field_o "package" Pkg.decode
20142059
and+ locks = field "locks" (repeat String_with_vars.decode) ~default:[]
20152060
and+ modes =
2016-
field "modes" Executables.Link_mode.Set.decode
2017-
~default:Executables.Link_mode.Set.default_for_tests
2061+
field "modes" Executables.Link_mode.Map.decode
2062+
~default:Executables.Link_mode.Map.default_for_tests
20182063
and+ deps =
20192064
field "deps" (Bindings.decode Dep_conf.decode) ~default:Bindings.empty
20202065
and+ enabled_if = enabled_if ~since:(Some (1, 4))

src/dune/dune_file.mli

+9-8
Original file line numberDiff line numberDiff line change
@@ -254,10 +254,11 @@ end
254254
module Executables : sig
255255
module Link_mode : sig
256256
type t =
257-
{ mode : Mode_conf.t
258-
; kind : Binary_kind.t
259-
; loc : Loc.t
260-
}
257+
| Byte_complete
258+
| Other of
259+
{ mode : Mode_conf.t
260+
; kind : Binary_kind.t
261+
}
261262

262263
include Dune_lang.Conv.S with type t := t
263264

@@ -271,22 +272,22 @@ module Executables : sig
271272

272273
val native : t
273274

274-
val byte_exe : t
275-
276275
val js : t
277276

278277
val compare : t -> t -> Ordering.t
279278

280279
val to_dyn : t -> Dyn.t
281280

282-
module Set : Set.S with type elt = t
281+
val extension : t -> loc:Loc.t -> ext_obj:string -> ext_dll:string -> string
282+
283+
module Map : Map.S with type key = t
283284
end
284285

285286
type t =
286287
{ names : (Loc.t * string) list
287288
; link_flags : Ordered_set_lang.Unexpanded.t
288289
; link_deps : Dep_conf.t list
289-
; modes : Link_mode.Set.t
290+
; modes : Loc.t Link_mode.Map.t
290291
; optional : bool
291292
; buildable : Buildable.t
292293
; variants : (Loc.t * Variant.Set.t) option

0 commit comments

Comments
 (0)