@@ -118,12 +118,6 @@ def extract_archive_contents(archive_file):
118
118
}
119
119
120
120
121
- # Due to a python pickling issue, the following two functions must be at top
122
- # level, or multiprocessing pool spawn won't find them.
123
- def g_llvm_nm_uncached (filename ):
124
- return llvm_nm_uncached (filename )
125
-
126
-
127
121
def g_multiprocessing_initializer (* args ):
128
122
for item in args :
129
123
(key , value ) = item .split ('=' , 1 )
@@ -364,20 +358,82 @@ def make_paths_absolute(f):
364
358
return os .path .abspath (f )
365
359
366
360
367
- # Runs llvm-nm in parallel for the given list of files.
361
+ # Runs llvm-nm for the given list of files.
368
362
# The results are populated in nm_cache
369
- # multiprocessing_pool: An existing multiprocessing pool to reuse for the operation, or None
370
- # to have the function allocate its own.
371
- def parallel_llvm_nm (files ):
372
- with ToolchainProfiler .profile_block ('parallel_llvm_nm' ):
373
- pool = get_multiprocessing_pool ()
374
- object_contents = pool .map (g_llvm_nm_uncached , files )
363
+ def llvm_nm_multiple (files ):
364
+ with ToolchainProfiler .profile_block ('llvm_nm_multiple' ):
365
+ if len (files ) == 0 :
366
+ return []
367
+ # Run llvm-nm on files that we haven't cached yet
368
+ llvm_nm_files = [f for f in files if f not in nm_cache ]
369
+
370
+ # We can issue multiple files in a single llvm-nm calls, but only if those
371
+ # files are all .o or .bc files. Because of llvm-nm output format, we cannot
372
+ # llvm-nm multiple .a files in one call, but those must be individually checked.
373
+ if len (llvm_nm_files ) > 1 :
374
+ llvm_nm_files = [f for f in files if f .endswith ('.o' ) or f .endswith ('.bc' )]
375
+
376
+ if len (llvm_nm_files ) > 0 :
377
+ cmd = [LLVM_NM ] + llvm_nm_files
378
+ results = run_process (cmd , stdout = PIPE , stderr = PIPE , check = False )
379
+
380
+ # If one or more of the input files cannot be processed, llvm-nm will return a non-zero error code, but it will still process and print
381
+ # out all the other files in order. So even if process return code is non zero, we should always look at what we got to stdout.
382
+ if results .returncode != 0 :
383
+ logger .debug ('Subcommand ' + ' ' .join (cmd ) + ' failed with return code ' + str (results .returncode ) + '! (An input file was corrupt?)' )
384
+
385
+ results = results .stdout
386
+
387
+ # llvm-nm produces a single listing of form
388
+ # file1.o:
389
+ # 00000001 T __original_main
390
+ # U __stack_pointer
391
+ #
392
+ # file2.o:
393
+ # 0000005d T main
394
+ # U printf
395
+ #
396
+ # ...
397
+ # so loop over the report to extract the results
398
+ # for each individual file.
399
+
400
+ filename = llvm_nm_files [0 ]
401
+
402
+ # When we dispatched more than one file, we must manually parse
403
+ # the file result delimiters (like shown structured above)
404
+ if len (llvm_nm_files ) > 1 :
405
+ file_start = 0
406
+ i = 0
407
+
408
+ while True :
409
+ nl = results .find ('\n ' , i )
410
+ if nl < 0 :
411
+ break
412
+ colon = results .rfind (':' , i , nl )
413
+ if colon >= 0 and results [colon + 1 ] == '\n ' : # New file start?
414
+ nm_cache [filename ] = parse_symbols (results [file_start :i - 1 ])
415
+ filename = results [i :colon ].strip ()
416
+ file_start = colon + 2
417
+ i = nl + 1
418
+
419
+ nm_cache [filename ] = parse_symbols (results [file_start :])
420
+ else :
421
+ # We only dispatched a single file, we can just parse that directly
422
+ # to the output.
423
+ nm_cache [filename ] = parse_symbols (results )
424
+
425
+ # Any .a files that have multiple .o files will have hard time parsing. Scan those
426
+ # sequentially to confirm. TODO: Move this to use run_multiple_processes()
427
+ # when available.
428
+ for f in files :
429
+ if f not in nm_cache :
430
+ nm_cache [f ] = llvm_nm (f )
431
+
432
+ return [nm_cache [f ] for f in files ]
433
+
375
434
376
- for i , file in enumerate (files ):
377
- if object_contents [i ].returncode != 0 :
378
- logger .debug ('llvm-nm failed on file ' + file + ': return code ' + str (object_contents [i ].returncode ) + ', error: ' + object_contents [i ].output )
379
- nm_cache [file ] = object_contents [i ]
380
- return object_contents
435
+ def llvm_nm (file ):
436
+ return llvm_nm_multiple ([file ])[0 ]
381
437
382
438
383
439
def read_link_inputs (files ):
@@ -417,7 +473,7 @@ def clean_at_exit():
417
473
418
474
# Next, extract symbols from all object files (either standalone or inside archives we just extracted)
419
475
# The results are not used here directly, but populated to llvm-nm cache structure.
420
- parallel_llvm_nm (object_names )
476
+ llvm_nm_multiple (object_names )
421
477
422
478
423
479
def llvm_backend_args ():
@@ -754,34 +810,6 @@ def parse_symbols(output):
754
810
return ObjectFileInfo (0 , None , set (defs ), set (undefs ), set (commons ))
755
811
756
812
757
- def llvm_nm_uncached (filename , stdout = PIPE , stderr = PIPE ):
758
- # LLVM binary ==> list of symbols
759
- proc = run_process ([LLVM_NM , filename ], stdout = stdout , stderr = stderr , check = False )
760
- if proc .returncode == 0 :
761
- return parse_symbols (proc .stdout )
762
- else :
763
- return ObjectFileInfo (proc .returncode , str (proc .stdout ) + str (proc .stderr ))
764
-
765
-
766
- def llvm_nm (filename , stdout = PIPE , stderr = PIPE ):
767
- # Always use absolute paths to maximize cache usage
768
- filename = os .path .abspath (filename )
769
-
770
- if filename in nm_cache :
771
- return nm_cache [filename ]
772
-
773
- ret = llvm_nm_uncached (filename , stdout , stderr )
774
-
775
- if ret .returncode != 0 :
776
- logger .debug ('llvm-nm failed on file ' + filename + ': return code ' + str (ret .returncode ) + ', error: ' + ret .output )
777
-
778
- # Even if we fail, write the results to the NM cache so that we don't keep trying to llvm-nm the
779
- # failing file again later.
780
- nm_cache [filename ] = ret
781
-
782
- return ret
783
-
784
-
785
813
def emcc (filename , args = [], output_filename = None , stdout = None , stderr = None , env = None ):
786
814
if output_filename is None :
787
815
output_filename = filename + '.o'
0 commit comments