28
28
split as the inner path's module, and the rest of the functions will be split as
29
29
the outer path's module. Functions that do not belong to any of the specified
30
30
paths will remain in the primary module.
31
+
32
+ The paths in the paths file can be either absolute or relative, but they should
33
+ match those of 'sources' field in the source map file. Sometimes a source map's
34
+ 'sources' field contains paths relative to a build directory, so source files
35
+ may be recorded as '../src/subdir/test.c', for example. In this case, if you
36
+ want to split the directory src/subdir, you should list it as ../src/subdir. You
37
+ can manually open the source map file and check 'sources' field, but we also an
38
+ option to help that. You can do like
39
+ $ empath-split --print-sources test.wasm
40
+ or
41
+ $ empath-split --print-sources --source-map test.wasm.map
42
+ to print the list of sources in 'sources' field in the source map. Note that
43
+ emscripten's libraries' source files have /emsdk/emscripten prefix, which is a
44
+ fake deterministic prefix to produce reproducible builds across platforms.
31
45
"""
32
46
33
47
import argparse
48
+ import json
34
49
import os
35
50
import sys
36
51
import tempfile
@@ -59,23 +74,35 @@ def parse_args():
59
74
enabling/disabling options. Run 'wasm-split -h' for the list of options. But you
60
75
should NOT add --manifest, because this will be generated from this script.
61
76
""" )
62
- parser .add_argument ('wasm' , help = 'Path to the input wasm file' )
63
- parser .add_argument ('paths_file' , help = 'Path to the input file containing paths' )
77
+ parser .add_argument ('wasm' , nargs = '?' , help = 'Path to the input wasm file' )
78
+ parser .add_argument ('paths_file' , nargs = '?' , help = 'Path to the input file containing paths' )
64
79
parser .add_argument ('-s' , '--sourcemap' , help = 'Force source map file' )
65
80
parser .add_argument ('-v' , '--verbose' , action = 'store_true' ,
66
81
help = 'Print verbose info for debugging this script' )
67
82
parser .add_argument ('--wasm-split' , help = 'Path to wasm-split executable' )
68
83
parser .add_argument ('--preserve-manifest' , action = 'store_true' ,
69
84
help = 'Preserve generated manifest file. This sets --verbose too.' )
70
- args , forwarded_args = parser .parse_known_args ()
85
+ parser .add_argument ('--print-sources' , action = 'store_true' ,
86
+ help = 'Print the list of sources in the source map to help figure out splitting boundaries. Does NOT perform the splitting.' )
71
87
88
+ args , forwarded_args = parser .parse_known_args ()
72
89
if args .preserve_manifest :
73
90
args .verbose = True
74
91
if not args .wasm_split :
75
92
args .wasm_split = os .path .join (building .get_binaryen_bin (), shared .exe_suffix ('wasm-split' ))
76
93
77
94
if '--manifest' in forwarded_args :
78
95
parser .error ('manifest file will be generated by this script and should not be given' )
96
+
97
+ if args .print_sources :
98
+ if not args .wasm and not args .sourcemap :
99
+ parser .error ('--print-sources requires either wasm or --sourcemap' )
100
+ return args , forwarded_args
101
+
102
+ if not args .wasm and not args .paths_file :
103
+ parser .error ("the following arguments are required: wasm, paths_file" )
104
+ if not args .paths_file :
105
+ parser .error ("the following arguments are required: paths_file" )
79
106
if '-o' not in forwarded_args and '--output' not in forwarded_args :
80
107
parser .error ('-o (--output) is required' )
81
108
return args , forwarded_args
@@ -88,22 +115,33 @@ def check_errors(args):
88
115
exit_with_error (f"'{ args .paths_file } ' was not found or not a file" )
89
116
90
117
if args .sourcemap :
91
- if not os .path .isfile (args .sourcemap ):
92
- exit_with_error (f"'{ args .sourcemap } ' was not found or not a file" )
118
+ sourcemap = args .sourcemap
93
119
94
120
if args .wasm :
95
121
with webassembly .Module (args .wasm ) as module :
96
- if not args .sourcemap and not emsymbolizer .get_sourceMappingURL_section (module ):
97
- exit_with_error ('sourceMappingURL section does not exist' )
98
- sourcemap = module .get_sourceMappingURL ()
99
- if not os .path .isfile (sourcemap ):
100
- exit_with_error (f"'{ sourcemap } ' was not found or not a file" )
122
+ if not args .sourcemap :
123
+ if not emsymbolizer .get_sourceMappingURL_section (module ):
124
+ exit_with_error ('sourceMappingURL section does not exist' )
125
+ sourcemap = module .get_sourceMappingURL ()
101
126
if not module .has_name_section ():
102
- exit_with_error ('Name section does not eixst ' )
127
+ exit_with_error ('Name section does not exist ' )
103
128
129
+ if not os .path .isfile (sourcemap ):
130
+ exit_with_error (f"'{ sourcemap } ' was not found or not a file" )
104
131
if not os .path .isfile (args .wasm_split ):
105
132
exit_with_error (f"'{ args .wasm_split } ' was not found or not a file" )
106
133
134
+ # Check source map validity. Just perform simple checks to make sure mandatory
135
+ # fields exist.
136
+ try :
137
+ with open (sourcemap ) as f :
138
+ source_map_data = json .load (f )
139
+ except json .JSONDecodeError :
140
+ exit_with_error (f'Invalid JSON format in file { args .sourcemap } ' )
141
+ for field in ['version' , 'sources' , 'mappings' ]:
142
+ if field not in source_map_data :
143
+ exit_with_error (f"Field '{ field } ' is missing in the source map" )
144
+
107
145
108
146
def get_sourceMappingURL (wasm , arg_sourcemap ):
109
147
if arg_sourcemap :
@@ -112,6 +150,14 @@ def get_sourceMappingURL(wasm, arg_sourcemap):
112
150
return module .get_sourceMappingURL ()
113
151
114
152
153
+ def print_sources (sourcemap ):
154
+ with open (sourcemap ) as f :
155
+ sources = json .load (f ).get ('sources' )
156
+ assert (isinstance (sources , list ))
157
+ for src in sources :
158
+ print (src )
159
+
160
+
115
161
def get_path_to_functions_map (wasm , sourcemap , paths ):
116
162
def is_synthesized_func (func ):
117
163
# TODO There can be more
@@ -202,6 +248,9 @@ def main():
202
248
check_errors (args )
203
249
204
250
sourcemap = get_sourceMappingURL (args .wasm , args .sourcemap )
251
+ if args .print_sources :
252
+ print_sources (sourcemap )
253
+ return
205
254
206
255
paths = utils .read_file (args .paths_file ).splitlines ()
207
256
paths = [utils .normalize_path (path .strip ()) for path in paths if path .strip ()]
@@ -221,7 +270,7 @@ def main():
221
270
if not path_to_funcs [path ]:
222
271
diagnostics .warn (f'{ path } does not match any functions' )
223
272
if args .verbose :
224
- print (path )
273
+ print (f' { path } : { len ( path_to_funcs [ path ]) } functions' )
225
274
for func in path_to_funcs [path ]:
226
275
print (' ' + func )
227
276
print ()
0 commit comments