Skip to content

Commit fae1e6b

Browse files
authored
Compiler: allow to link cmo.js into a cma.js (#1428)
This is useful to achieve better incrementatlity during sepearate compilation.
1 parent cecc30f commit fae1e6b

File tree

6 files changed

+96
-13
lines changed

6 files changed

+96
-13
lines changed

CHANGES.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
# dev
2+
## Features/Changes
3+
* Compiler: jsoo link archive with -a (#1428)
4+
5+
## Bug fixes
6+
17
# 5.1.1 (2023-03-15) - Lille
28
## Bug fixes
39
* Compiler: fix jsoo link in presence of --disable use-js-string (#1430)

compiler/bin-js_of_ocaml/link.ml

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ type t =
2828
; output_file : string option
2929
; resolve_sourcemap_url : bool
3030
; linkall : bool
31+
; mklib : bool
32+
; toplevel : bool
3133
}
3234

3335
let options =
@@ -65,6 +67,17 @@ let options =
6567
let doc = "Link all compilation units." in
6668
Arg.(value & flag & info [ "linkall" ] ~doc)
6769
in
70+
let mklib =
71+
let doc =
72+
"Build a library (.cma.js file) with the js files (.cmo.js files) given on the \
73+
command line. Similar to ocamlc -a."
74+
in
75+
Arg.(value & flag & info [ "a" ] ~doc)
76+
in
77+
let toplevel =
78+
let doc = "Compile a toplevel." in
79+
Arg.(value & flag & info [ "toplevel" ] ~doc)
80+
in
6881
let build_t
6982
common
7083
no_sourcemap
@@ -74,7 +87,9 @@ let options =
7487
output_file
7588
resolve_sourcemap_url
7689
js_files
77-
linkall =
90+
linkall
91+
mklib
92+
toplevel =
7893
let chop_extension s = try Filename.chop_extension s with Invalid_argument _ -> s in
7994
let source_map =
8095
if (not no_sourcemap) && (sourcemap || sourcemap_inline_in_js)
@@ -97,7 +112,16 @@ let options =
97112
} )
98113
else None
99114
in
100-
`Ok { common; output_file; js_files; source_map; resolve_sourcemap_url; linkall }
115+
`Ok
116+
{ common
117+
; output_file
118+
; js_files
119+
; source_map
120+
; resolve_sourcemap_url
121+
; linkall
122+
; mklib
123+
; toplevel
124+
}
101125
in
102126
let t =
103127
Term.(
@@ -110,19 +134,37 @@ let options =
110134
$ output_file
111135
$ resolve_sourcemap_url
112136
$ js_files
113-
$ linkall)
137+
$ linkall
138+
$ mklib
139+
$ toplevel)
114140
in
115141
Term.ret t
116142

117-
let f { common; output_file; source_map; resolve_sourcemap_url; js_files; linkall } =
143+
let f
144+
{ common
145+
; output_file
146+
; source_map
147+
; resolve_sourcemap_url
148+
; js_files
149+
; linkall
150+
; mklib
151+
; toplevel
152+
} =
118153
Jsoo_cmdline.Arg.eval common;
119154
let with_output f =
120155
match output_file with
121156
| None -> f stdout
122157
| Some file -> Filename.gen_file file f
123158
in
124159
with_output (fun output ->
125-
Link_js.link ~output ~linkall ~files:js_files ~source_map ~resolve_sourcemap_url)
160+
Link_js.link
161+
~output
162+
~linkall
163+
~mklib
164+
~toplevel
165+
~files:js_files
166+
~source_map
167+
~resolve_sourcemap_url)
126168

127169
let info =
128170
Info.make

compiler/lib/build_info.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ let create kind =
6161
]
6262
|> List.fold_left ~init:StringMap.empty ~f:(fun acc (k, v) -> StringMap.add k v acc)
6363

64+
let with_kind t kind = StringMap.add "kind" (string_of_kind kind) t
65+
6466
let prefix = "//# buildInfo:"
6567

6668
let to_string info =

compiler/lib/build_info.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ val to_string : t -> string
3434

3535
val parse : string -> t option
3636

37+
val with_kind : t -> kind -> t
38+
3739
exception
3840
Incompatible_build_info of
3941
{ key : string

compiler/lib/link_js.ml

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ module Line_writer : sig
101101

102102
val write : ?source:Line_reader.t -> t -> string -> unit
103103

104+
val write_lines : ?source:Line_reader.t -> t -> string -> unit
105+
104106
val lnum : t -> int
105107
end = struct
106108
type t =
@@ -134,6 +136,16 @@ end = struct
134136
t.source <- source;
135137
t.lnum <- t.lnum + lnum_off
136138

139+
let write_lines ?source t lines =
140+
let l = String.split_on_char ~sep:'\n' lines in
141+
let rec w = function
142+
| [ "" ] | [] -> ()
143+
| s :: xs ->
144+
write ?source t s;
145+
w xs
146+
in
147+
w l
148+
137149
let lnum t = t.lnum
138150
end
139151

@@ -231,7 +243,10 @@ end = struct
231243
build_info, units
232244
end
233245

234-
let link ~output ~linkall ~files ~resolve_sourcemap_url ~source_map =
246+
let link ~output ~linkall ~mklib ~toplevel ~files ~resolve_sourcemap_url ~source_map =
247+
(* we currently don't do anything with [toplevel]. It could be used
248+
to conditionally include link_info ?*)
249+
ignore (toplevel : bool);
235250
let t = Timer.make () in
236251
let oc = Line_writer.of_channel output in
237252
let warn_effects = ref false in
@@ -255,6 +270,7 @@ let link ~output ~linkall ~files ~resolve_sourcemap_url ~source_map =
255270
~f:(fun (info : Unit_info.t) (requires, to_link, all) ->
256271
let all = StringSet.union all info.provides in
257272
if (not (Config.Flag.auto_link ()))
273+
|| mklib
258274
|| cmo_file
259275
|| linkall
260276
|| info.force_link
@@ -266,7 +282,7 @@ let link ~output ~linkall ~files ~resolve_sourcemap_url ~source_map =
266282
else requires, to_link, all))
267283
in
268284
let skip = StringSet.diff all to_link in
269-
if not (StringSet.is_empty missing)
285+
if (not (StringSet.is_empty missing)) && not mklib
270286
then
271287
failwith
272288
(Printf.sprintf
@@ -290,6 +306,8 @@ let link ~output ~linkall ~files ~resolve_sourcemap_url ~source_map =
290306
: int);
291307
sym_js := s :: !sym_js)
292308
u.Unit_info.provides));
309+
310+
let build_info_emitted = ref false in
293311
List.iter files ~f:(fun (file, (build_info_for_file, units)) ->
294312
let sm_for_file = ref None in
295313
let ic = Line_reader.open_ file in
@@ -311,7 +329,14 @@ let link ~output ~linkall ~files ~resolve_sourcemap_url ~source_map =
311329
file
312330
line
313331
with
314-
| Keep | Build_info _ -> copy ic oc
332+
| Keep -> copy ic oc
333+
| Build_info bi ->
334+
skip ic;
335+
if not !build_info_emitted
336+
then (
337+
let bi = if mklib then Build_info.with_kind bi `Cma else bi in
338+
Line_writer.write_lines oc (Build_info.to_string bi);
339+
build_info_emitted := true)
315340
| Drop -> skip ic
316341
| Unit ->
317342
let u = Units.read ic Unit_info.empty in
@@ -327,7 +352,11 @@ let link ~output ~linkall ~files ~resolve_sourcemap_url ~source_map =
327352
then
328353
Format.eprintf
329354
"Copy %s@."
330-
(String.concat ~sep:"," (StringSet.elements u.provides)))
355+
(String.concat ~sep:"," (StringSet.elements u.provides));
356+
if mklib
357+
then
358+
let u = if linkall then { u with force_link = true } else u in
359+
Line_writer.write_lines oc (Unit_info.to_string u))
331360
else (
332361
if debug ()
333362
then
@@ -345,7 +374,7 @@ let link ~output ~linkall ~files ~resolve_sourcemap_url ~source_map =
345374
skip ic
346375
done)
347376
| Source_map x ->
348-
Line_reader.drop ic;
377+
skip ic;
349378
sm_for_file := Some x);
350379
read ()
351380
in
@@ -380,7 +409,7 @@ let link ~output ~linkall ~files ~resolve_sourcemap_url ~source_map =
380409
(Parse_bytecode.Debug.create ~include_cmis:false false)
381410
code;
382411
let content = Buffer.contents b in
383-
String.split_on_char ~sep:'\n' content |> List.iter ~f:(Line_writer.write oc));
412+
Line_writer.write_lines oc content);
384413
(match !sm_for_file with
385414
| None -> ()
386415
| Some x -> sm := (x, !reloc) :: !sm);
@@ -424,8 +453,8 @@ let link ~output ~linkall ~files ~resolve_sourcemap_url ~source_map =
424453
Line_writer.write oc s));
425454
if times () then Format.eprintf " sourcemap: %a@." Timer.print t
426455

427-
let link ~output ~linkall ~files ~resolve_sourcemap_url ~source_map =
428-
try link ~output ~linkall ~files ~resolve_sourcemap_url ~source_map
456+
let link ~output ~linkall ~mklib ~toplevel ~files ~resolve_sourcemap_url ~source_map =
457+
try link ~output ~linkall ~toplevel ~mklib ~files ~resolve_sourcemap_url ~source_map
429458
with Build_info.Incompatible_build_info { key; first = f1, v1; second = f2, v2 } ->
430459
let string_of_v = function
431460
| None -> "<empty>"

compiler/lib/link_js.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
val link :
2121
output:out_channel
2222
-> linkall:bool
23+
-> mklib:bool
24+
-> toplevel:bool
2325
-> files:string list
2426
-> resolve_sourcemap_url:bool
2527
-> source_map:(string option * Source_map.t) option

0 commit comments

Comments
 (0)