@@ -34,26 +34,36 @@ let header formatter ~custom_header =
3434 | Some c -> Pretty_print. string formatter (c ^ " \n " )
3535
3636let jsoo_header formatter build_info =
37- Pretty_print. string formatter " // Generated by js_of_ocaml \n " ;
37+ Pretty_print. string formatter ( Printf. sprintf " %s \n " Global_constant. header) ;
3838 Pretty_print. string formatter (Build_info. to_string build_info)
3939
40+ type source_map_output =
41+ | No_sourcemap
42+ | Inline
43+ | File of string
44+
45+ let source_map_enabled = function
46+ | No_sourcemap -> false
47+ | Inline | File _ -> true
48+
4049let output_gen ~standalone ~custom_header ~build_info ~source_map output_file f =
4150 let f chan k =
4251 let fmt = Pretty_print. to_out_channel chan in
4352 Driver. configure fmt;
4453 if standalone then header ~custom_header fmt;
4554 if Config.Flag. header () then jsoo_header fmt build_info;
46- let sm = f ~standalone ~source_map: ( Option. map ~f: snd source_map) (k, fmt) in
55+ let sm = f ~standalone ~source_map (k, fmt) in
4756 match source_map, sm with
48- | None , _ | _ , None -> ()
49- | Some ( output_file , _ ), Some sm ->
50- let sm = `Standard sm in
57+ | No_sourcemap , _ | _ , None -> ()
58+ | (( Inline | File _ ) as output ), Some sm ->
59+ if Debug. find " invariant " () then Source_map. invariant sm;
5160 let urlData =
52- match output_file with
53- | None ->
61+ match output with
62+ | No_sourcemap -> assert false
63+ | Inline ->
5464 let data = Source_map. to_string sm in
5565 " data:application/json;base64," ^ Base64. encode_exn data
56- | Some output_file ->
66+ | File output_file ->
5767 Source_map. to_file sm output_file;
5868 Filename. basename output_file
5969 in
@@ -65,6 +75,50 @@ let output_gen ~standalone ~custom_header ~build_info ~source_map output_file f
6575 | `Stdout -> f stdout `Stdout
6676 | `Name name -> Filename. gen_file name (fun chan -> f chan `File )
6777
78+ let find_source file =
79+ match Builtins. find file with
80+ | Some f -> Some (Source_map.Source_content. create (Builtins.File. content f))
81+ | None ->
82+ if Sys. file_exists file && not (Sys. is_directory file)
83+ then
84+ let content = Fs. read_file file in
85+ Some (Source_map.Source_content. create content)
86+ else None
87+
88+ let sourcemap_section_of_info
89+ ~(base : Source_map.Standard.t )
90+ { Source_map. sources; names; mappings } =
91+ let sources_content =
92+ match base.sources_content with
93+ | None -> None
94+ | Some _ -> Some (List. map ~f: find_source sources)
95+ in
96+ let sources =
97+ List. map sources ~f: (fun filename ->
98+ match Builtins. find filename with
99+ | None -> filename
100+ | Some _ -> Filename. concat " /builtin" filename)
101+ in
102+ let offset, mappings = Source_map.Mappings. encode_with_offset mappings in
103+ let map =
104+ { (base : Source_map.Standard.t ) with sources; sources_content; names; mappings }
105+ in
106+ { Source_map.Index. offset; map }
107+
108+ let sourcemap_of_infos ~base l =
109+ match base with
110+ | None -> None
111+ | Some (base : Source_map.Standard.t ) ->
112+ let sections = List. map l ~f: (sourcemap_section_of_info ~base ) in
113+ Some
114+ (Source_map. Index
115+ { Source_map.Index. version = base.Source_map.Standard. version
116+ ; file = base.file
117+ ; sections
118+ })
119+
120+ let sourcemap_of_info ~base info = sourcemap_of_infos ~base [ info ]
121+
68122let run
69123 { Cmd_arg. common
70124 ; profile
@@ -89,6 +143,13 @@ let run
89143 ; keep_unit_names
90144 ; include_runtime
91145 } =
146+ let source_map_base = Option. map ~f: snd source_map in
147+ let source_map =
148+ match source_map with
149+ | None -> No_sourcemap
150+ | Some (None, _ ) -> Inline
151+ | Some (Some file , _ ) -> File file
152+ in
92153 let include_cmis = toplevel && not no_cmis in
93154 let custom_header = common.Jsoo_cmdline.Arg. custom_header in
94155 Config. set_target `JavaScript ;
@@ -148,9 +209,9 @@ let run
148209 Linker. check_deps () ;
149210 if times () then Format. eprintf " parsing js: %a@." Timer. print t1;
150211 if times () then Format. eprintf " Start parsing...@." ;
151- let need_debug = Option. is_some source_map || Config.Flag. debuginfo () in
212+ let need_debug = source_map_enabled source_map || Config.Flag. debuginfo () in
152213 let check_debug (one : Parse_bytecode.one ) =
153- if Option. is_some source_map && Parse_bytecode.Debug. is_empty one.debug
214+ if source_map_enabled source_map && Parse_bytecode.Debug. is_empty one.debug
154215 then
155216 warn
156217 " Warning: '--source-map' is enabled but the bytecode program was compiled with \
@@ -202,7 +263,7 @@ let run
202263 ?profile
203264 ~link
204265 ~wrap_with_fun
205- ? source_map
266+ ~ source_map: (source_map_enabled source_map)
206267 ~formatter
207268 one.debug
208269 code
@@ -226,7 +287,7 @@ let run
226287 ?profile
227288 ~link
228289 ~wrap_with_fun
229- ? source_map
290+ ~ source_map: (source_map_enabled source_map)
230291 ~formatter
231292 one.debug
232293 code
@@ -310,7 +371,8 @@ let run
310371 ~source_map
311372 ~standalone
312373 ~link: `All
313- output_file)
374+ output_file
375+ |> sourcemap_of_info ~base: source_map_base)
314376 | (`Stdin | `File _ ) as bytecode ->
315377 let kind, ic, close_ic, include_dirs =
316378 match bytecode with
@@ -348,7 +410,15 @@ let run
348410 ~build_info: (Build_info. create `Exe )
349411 ~source_map
350412 (fst output_file)
351- (output code ~check_sourcemap: true ~link: (if linkall then `All else `Needed ))
413+ (fun ~standalone ~source_map output_file ->
414+ output
415+ code
416+ ~check_sourcemap: true
417+ ~standalone
418+ ~source_map
419+ ~link: (if linkall then `All else `Needed )
420+ output_file
421+ |> sourcemap_of_info ~base: source_map_base)
352422 | `Cmo cmo ->
353423 let output_file =
354424 match output_file, keep_unit_names with
@@ -379,12 +449,14 @@ let run
379449 ~source_map
380450 output_file
381451 (fun ~standalone ~source_map output ->
382- let source_map =
383- if not include_runtime
384- then source_map
385- else output_partial_runtime ~standalone ~source_map output
386- in
387- output_partial cmo code ~standalone ~source_map output)
452+ match include_runtime with
453+ | true ->
454+ let sm1 = output_partial_runtime ~standalone ~source_map output in
455+ let sm2 = output_partial cmo code ~standalone ~source_map output in
456+ sourcemap_of_infos ~base: source_map_base [ sm1; sm2 ]
457+ | false ->
458+ output_partial cmo code ~standalone ~source_map output
459+ |> sourcemap_of_info ~base: source_map_base)
388460 | `Cma cma when keep_unit_names ->
389461 (if include_runtime
390462 then
@@ -406,7 +478,8 @@ let run
406478 ~source_map
407479 (`Name output_file)
408480 (fun ~standalone ~source_map output ->
409- output_partial_runtime ~standalone ~source_map output));
481+ output_partial_runtime ~standalone ~source_map output
482+ |> sourcemap_of_info ~base: source_map_base));
410483 List. iter cma.lib_units ~f: (fun cmo ->
411484 let output_file =
412485 match output_file with
@@ -440,32 +513,43 @@ let run
440513 ~build_info: (Build_info. create `Cma )
441514 ~source_map
442515 (`Name output_file)
443- (output_partial cmo code))
516+ (fun ~standalone ~source_map output ->
517+ output_partial ~standalone ~source_map cmo code output
518+ |> sourcemap_of_info ~base: source_map_base))
444519 | `Cma cma ->
445520 let f ~standalone ~source_map output =
446- let source_map =
521+ let source_map_runtime =
447522 if not include_runtime
448- then source_map
449- else output_partial_runtime ~standalone ~source_map output
523+ then None
524+ else Some (output_partial_runtime ~standalone ~source_map output)
525+ in
526+
527+ let source_map_units =
528+ List. map cma.lib_units ~f: (fun cmo ->
529+ let t1 = Timer. make () in
530+ let code =
531+ Parse_bytecode. from_cmo
532+ ~includes: include_dirs
533+ ~include_cmis
534+ ~debug: need_debug
535+ cmo
536+ ic
537+ in
538+ if times ()
539+ then
540+ Format. eprintf
541+ " parsing: %a (%s)@."
542+ Timer. print
543+ t1
544+ (Ocaml_compiler.Cmo_format. name cmo);
545+ output_partial ~standalone ~source_map cmo code output)
546+ in
547+ let sm =
548+ match source_map_runtime with
549+ | None -> source_map_units
550+ | Some x -> x :: source_map_units
450551 in
451- List. fold_left cma.lib_units ~init: source_map ~f: (fun source_map cmo ->
452- let t1 = Timer. make () in
453- let code =
454- Parse_bytecode. from_cmo
455- ~includes: include_dirs
456- ~include_cmis
457- ~debug: need_debug
458- cmo
459- ic
460- in
461- if times ()
462- then
463- Format. eprintf
464- " parsing: %a (%s)@."
465- Timer. print
466- t1
467- (Ocaml_compiler.Cmo_format. name cmo);
468- output_partial cmo ~standalone ~source_map code output)
552+ sourcemap_of_infos ~base: source_map_base sm
469553 in
470554 output_gen
471555 ~standalone: false
0 commit comments