@@ -1236,17 +1236,20 @@ def warn_if_duplicate_entries(archive_contents, archive_filename_hint=''):
1236
1236
logging .warning (' duplicate: %s' % curr )
1237
1237
warned .add (curr )
1238
1238
1239
+ # N.B. This function creates a temporary directory specified by the 'dir' field in the returned dictionary. Caller
1240
+ # is responsible for cleaning up those files after done.
1239
1241
def extract_archive_contents (f ):
1240
1242
try :
1241
1243
cwd = os .getcwd ()
1242
- temp_dir = os . path . join ( tempfile .gettempdir (), f . replace ( '/ ' , '_' ). replace ( ' \\ ' , '_' ). replace ( ':' , '_' ) + '.archive_contents' ) # TODO: Make sure this is nice and sane
1244
+ temp_dir = tempfile .mkdtemp ( '_archive_contents ' , 'emscripten_temp_' )
1243
1245
safe_ensure_dirs (temp_dir )
1244
1246
os .chdir (temp_dir )
1245
1247
contents = filter (lambda x : len (x ) > 0 , Popen ([LLVM_AR , 't' , f ], stdout = PIPE ).communicate ()[0 ].split ('\n ' ))
1246
1248
warn_if_duplicate_entries (contents , f )
1247
1249
if len (contents ) == 0 :
1248
1250
logging .debug ('Archive %s appears to be empty (recommendation: link an .so instead of .a)' % f )
1249
1251
return {
1252
+ 'returncode' : 0 ,
1250
1253
'dir' : temp_dir ,
1251
1254
'files' : []
1252
1255
}
@@ -1257,10 +1260,15 @@ def extract_archive_contents(f):
1257
1260
dirname = os .path .dirname (content )
1258
1261
if dirname :
1259
1262
safe_ensure_dirs (dirname )
1260
- Popen ([LLVM_AR , 'xo' , f ], stdout = PIPE ).communicate () # if absolute paths, files will appear there. otherwise, in this directory
1261
- contents = filter (os .path .exists , map (os .path .abspath , contents ))
1262
- contents = filter (Building .is_bitcode , contents )
1263
+ proc = Popen ([LLVM_AR , 'xo' , f ], stdout = PIPE , stderr = PIPE )
1264
+ stdout , stderr = proc .communicate () # if absolute paths, files will appear there. otherwise, in this directory
1265
+ contents = map (os .path .abspath , contents )
1266
+ nonexisting_contents = filter (lambda x : not os .path .exists (x ), contents )
1267
+ if len (nonexisting_contents ) != 0 :
1268
+ raise Exception ('llvm-ar failed to extract file(s) ' + str (nonexisting_contents ) + ' from archive file ' + f + '! Error:' + str (stdout ) + str (stderr ))
1269
+
1263
1270
return {
1271
+ 'returncode' : proc .returncode ,
1264
1272
'dir' : temp_dir ,
1265
1273
'files' : contents
1266
1274
}
@@ -1270,20 +1278,23 @@ def extract_archive_contents(f):
1270
1278
os .chdir (cwd )
1271
1279
1272
1280
return {
1281
+ 'returncode' : 1 ,
1273
1282
'dir' : None ,
1274
1283
'files' : []
1275
1284
}
1276
1285
1277
1286
class ObjectFileInfo :
1278
- def __init__ (self , defs , undefs , commons ):
1287
+ def __init__ (self , returncode , output , defs = set (), undefs = set (), commons = set ()):
1288
+ self .returncode = returncode
1289
+ self .output = output
1279
1290
self .defs = defs
1280
1291
self .undefs = undefs
1281
1292
self .commons = commons
1282
1293
1283
1294
# Due to a python pickling issue, the following two functions must be at top level, or multiprocessing pool spawn won't find them.
1284
1295
1285
1296
def g_llvm_nm_uncached (filename ):
1286
- return Building .llvm_nm_uncached (filename , stdout = PIPE , stderr = None )
1297
+ return Building .llvm_nm_uncached (filename )
1287
1298
1288
1299
def g_multiprocessing_initializer (* args ):
1289
1300
for item in args :
@@ -1608,6 +1619,8 @@ def parallel_llvm_nm(files):
1608
1619
object_contents = pool .map (g_llvm_nm_uncached , files )
1609
1620
1610
1621
for i in range (len (files )):
1622
+ if object_contents [i ].returncode != 0 :
1623
+ raise Exception ('llvm-nm failed on file ' + files [i ] + ': return code ' + str (object_contents [i ].returncode ) + ', error: ' + object_contents [i ].output )
1611
1624
Building .uninternal_nm_cache [files [i ]] = object_contents [i ]
1612
1625
return object_contents
1613
1626
@@ -1629,9 +1642,16 @@ def read_link_inputs(files):
1629
1642
# Archives contain objects, so process all archives first in parallel to obtain the object files in them.
1630
1643
pool = Building .get_multiprocessing_pool ()
1631
1644
object_names_in_archives = pool .map (extract_archive_contents , archive_names )
1645
+ def clean_temporary_archive_contents_directory (directory ):
1646
+ def clean_at_exit ():
1647
+ try_delete (directory )
1648
+ if directory : atexit .register (clean_at_exit )
1632
1649
1633
1650
for n in range (len (archive_names )):
1651
+ if object_names_in_archives [n ]['returncode' ] != 0 :
1652
+ raise Exception ('llvm-ar failed on archive ' + archive_names [n ] + '!' )
1634
1653
Building .ar_contents [archive_names [n ]] = object_names_in_archives [n ]['files' ]
1654
+ clean_temporary_archive_contents_directory (object_names_in_archives [n ]['dir' ])
1635
1655
1636
1656
for o in object_names_in_archives :
1637
1657
for f in o ['files' ]:
@@ -1873,27 +1893,34 @@ def parse_symbols(output, include_internal=False):
1873
1893
( include_internal and status in ['W' , 't' , 'T' , 'd' , 'D' ]): # FIXME: using WTD in the previous line fails due to llvm-nm behavior on OS X,
1874
1894
# so for now we assume all uppercase are normally defined external symbols
1875
1895
defs .append (symbol )
1876
- return ObjectFileInfo (set (defs ), set (undefs ), set (commons ))
1896
+ return ObjectFileInfo (0 , None , set (defs ), set (undefs ), set (commons ))
1877
1897
1878
1898
internal_nm_cache = {} # cache results of nm - it can be slow to run
1879
1899
uninternal_nm_cache = {}
1880
1900
ar_contents = {} # Stores the object files contained in different archive files passed as input
1881
1901
1882
1902
@staticmethod
1883
- def llvm_nm_uncached (filename , stdout = PIPE , stderr = None , include_internal = False ):
1903
+ def llvm_nm_uncached (filename , stdout = PIPE , stderr = PIPE , include_internal = False ):
1884
1904
# LLVM binary ==> list of symbols
1885
- output = Popen ([LLVM_NM , filename ], stdout = stdout , stderr = stderr ).communicate ()[0 ]
1886
- return Building .parse_symbols (output , include_internal )
1905
+ proc = Popen ([LLVM_NM , filename ], stdout = stdout , stderr = stderr )
1906
+ stdout , stderr = proc .communicate ()
1907
+ if proc .returncode == 0 :
1908
+ return Building .parse_symbols (stdout , include_internal )
1909
+ else :
1910
+ return ObjectFileInfo (proc .returncode , str (stdout ) + str (stderr ))
1887
1911
1888
1912
@staticmethod
1889
- def llvm_nm (filename , stdout = PIPE , stderr = None , include_internal = False ):
1913
+ def llvm_nm (filename , stdout = PIPE , stderr = PIPE , include_internal = False ):
1890
1914
if include_internal and filename in Building .internal_nm_cache :
1891
1915
return Building .internal_nm_cache [filename ]
1892
1916
elif not include_internal and filename in Building .uninternal_nm_cache :
1893
1917
return Building .uninternal_nm_cache [filename ]
1894
1918
1895
1919
ret = Building .llvm_nm_uncached (filename , stdout , stderr , include_internal )
1896
1920
1921
+ if ret .returncode != 0 :
1922
+ raise Exception ('llvm-nm failed on file ' + filename + ': return code ' + str (ret .returncode ) + ', error: ' + ret .output )
1923
+
1897
1924
if include_internal : Building .internal_nm_cache [filename ] = ret
1898
1925
else : Building .uninternal_nm_cache [filename ] = ret
1899
1926
0 commit comments