39
39
from subprocess import PIPE
40
40
41
41
from tools import shared , system_libs , client_mods , js_optimizer , jsrun
42
- from tools .shared import suffix , unsuffixed , unsuffixed_basename , WINDOWS , safe_copy , safe_move , run_process , asbytes , read_and_preprocess , exit_with_error , DEBUG
42
+ from tools .shared import unsuffixed , unsuffixed_basename , WINDOWS , safe_copy , safe_move , run_process , asbytes , read_and_preprocess , exit_with_error , DEBUG
43
43
from tools .response_file import substitute_response_files
44
44
import tools .line_endings
45
45
from tools .toolchain_profiler import ToolchainProfiler
64
64
SOURCE_ENDINGS = C_ENDINGS + CXX_ENDINGS + OBJC_ENDINGS + OBJCXX_ENDINGS + SPECIAL_ENDINGLESS_FILENAMES
65
65
C_ENDINGS = C_ENDINGS + SPECIAL_ENDINGLESS_FILENAMES # consider the special endingless filenames like /dev/null to be C
66
66
67
+ JS_CONTAINING_ENDINGS = ('.js' , '.mjs' , '.html' )
67
68
BITCODE_ENDINGS = ('.bc' , '.o' , '.obj' , '.lo' )
68
69
DYNAMICLIB_ENDINGS = ('.dylib' , '.so' ) # Windows .dll suffix is not included in this list, since those are never linked to directly on the command line.
69
70
STATICLIB_ENDINGS = ('.a' ,)
79
80
80
81
LIB_PREFIXES = ('' , 'lib' )
81
82
82
- JS_CONTAINING_SUFFIXES = ('js' , 'mjs' , 'html' )
83
- EXECUTABLE_SUFFIXES = JS_CONTAINING_SUFFIXES + ('wasm' ,)
84
83
85
84
DEFERRED_RESPONSE_FILES = ('EMTERPRETIFY_BLACKLIST' , 'EMTERPRETIFY_WHITELIST' , 'EMTERPRETIFY_SYNCLIST' )
86
85
@@ -633,12 +632,16 @@ def filter_emscripten_options(argv):
633
632
634
633
# ---------------- Utilities ---------------
635
634
635
+ def suffix (name ):
636
+ """Return the file extension"""
637
+ return os .path .splitext (name )[1 ]
638
+
636
639
seen_names = {}
637
640
638
641
def uniquename (name ):
639
642
if name not in seen_names :
640
643
seen_names [name ] = str (len (seen_names ))
641
- return unsuffixed (name ) + '_' + seen_names [name ] + (( '.' + suffix (name )) if suffix ( name ) else '' )
644
+ return unsuffixed (name ) + '_' + seen_names [name ] + suffix (name )
642
645
643
646
# ---------------- End configs -------------
644
647
@@ -662,28 +665,23 @@ def uniquename(name):
662
665
target = specified_target if specified_target is not None else 'a.out.js' # specified_target is the user-specified one, target is what we will generate
663
666
target_basename = unsuffixed_basename (target )
664
667
665
- if '.' in target :
666
- final_suffix = target .split ('.' )[- 1 ]
667
- else :
668
- final_suffix = ''
668
+ final_suffix = suffix (target )
669
669
670
670
temp_dir = shared .get_emscripten_temp_dir ()
671
671
672
672
def in_temp (name ):
673
673
return os .path .join (temp_dir , os .path .basename (name ))
674
674
675
- # Parses the essential suffix of a filename, discarding Unix-style version numbers in the name. For example for 'libz.so.1.2.8' returns '.so'
676
- def filename_type_suffix (filename ):
677
- for i in reversed (filename .split ('.' )[1 :]):
678
- if not i .isdigit ():
679
- return i
680
- return ''
681
-
682
- def filename_type_ending (filename ):
675
+ def get_file_suffix (filename ):
676
+ """Parses the essential suffix of a filename, discarding Unix-style version
677
+ numbers in the name. For example for 'libz.so.1.2.8' returns '.so'"""
683
678
if filename in SPECIAL_ENDINGLESS_FILENAMES :
684
679
return filename
685
- suffix = filename_type_suffix (filename )
686
- return '' if not suffix else ('.' + suffix )
680
+ while filename :
681
+ filename , suffix = os .path .splitext (filename )
682
+ if not suffix [1 :].isdigit ():
683
+ return suffix
684
+ return ''
687
685
688
686
def optimizing (opts ):
689
687
return '-O0' not in opts
@@ -832,25 +830,25 @@ def detect_fixed_language_mode(args):
832
830
'-current_version' , '-I' , '-L' , '-include-pch' ):
833
831
continue # ignore this gcc-style argument
834
832
835
- if os .path .islink (arg ) and os .path .realpath (arg ). endswith ( SOURCE_ENDINGS + BITCODE_ENDINGS + DYNAMICLIB_ENDINGS + ASSEMBLY_ENDINGS + HEADER_ENDINGS ) :
833
+ if os .path .islink (arg ) and get_file_suffix ( os .path .realpath (arg )) in SOURCE_ENDINGS + BITCODE_ENDINGS + DYNAMICLIB_ENDINGS + ASSEMBLY_ENDINGS + HEADER_ENDINGS :
836
834
arg = os .path .realpath (arg )
837
835
838
836
if not arg .startswith ('-' ):
839
837
if not os .path .exists (arg ):
840
838
exit_with_error ('%s: No such file or directory ("%s" was expected to be an input file, based on the commandline arguments provided)' , arg , arg )
841
839
842
- arg_ending = filename_type_ending (arg )
843
- if arg_ending . endswith ( SOURCE_ENDINGS + BITCODE_ENDINGS + DYNAMICLIB_ENDINGS + ASSEMBLY_ENDINGS + HEADER_ENDINGS ) or shared .Building .is_ar (arg ): # we already removed -o <target>, so all these should be inputs
840
+ file_suffix = get_file_suffix (arg )
841
+ if file_suffix in SOURCE_ENDINGS + BITCODE_ENDINGS + DYNAMICLIB_ENDINGS + ASSEMBLY_ENDINGS + HEADER_ENDINGS or shared .Building .is_ar (arg ): # we already removed -o <target>, so all these should be inputs
844
842
newargs [i ] = ''
845
- if arg_ending .endswith (SOURCE_ENDINGS ):
843
+ if file_suffix .endswith (SOURCE_ENDINGS ):
846
844
input_files .append ((i , arg ))
847
845
has_source_inputs = True
848
- elif arg_ending .endswith (HEADER_ENDINGS ):
846
+ elif file_suffix .endswith (HEADER_ENDINGS ):
849
847
input_files .append ((i , arg ))
850
848
has_header_inputs = True
851
- elif arg_ending .endswith (ASSEMBLY_ENDINGS ) or shared .Building .is_bitcode (arg ): # this should be bitcode, make sure it is valid
849
+ elif file_suffix .endswith (ASSEMBLY_ENDINGS ) or shared .Building .is_bitcode (arg ): # this should be bitcode, make sure it is valid
852
850
input_files .append ((i , arg ))
853
- elif arg_ending .endswith (STATICLIB_ENDINGS + DYNAMICLIB_ENDINGS ):
851
+ elif file_suffix .endswith (STATICLIB_ENDINGS + DYNAMICLIB_ENDINGS ):
854
852
# if it's not, and it's a library, just add it to libs to find later
855
853
l = unsuffixed_basename (arg )
856
854
for prefix in LIB_PREFIXES :
@@ -865,7 +863,7 @@ def detect_fixed_language_mode(args):
865
863
input_files .append ((i , arg ))
866
864
else :
867
865
logger .warning (arg + ' is not valid LLVM bitcode' )
868
- elif arg_ending .endswith (STATICLIB_ENDINGS ):
866
+ elif file_suffix .endswith (STATICLIB_ENDINGS ):
869
867
if not shared .Building .is_ar (arg ):
870
868
if shared .Building .is_bitcode (arg ):
871
869
message = arg + ': File has a suffix of a static library ' + str (STATICLIB_ENDINGS ) + ', but instead is an LLVM bitcode file! When linking LLVM bitcode files, use one of the suffixes ' + str (BITCODE_ENDINGS )
@@ -909,15 +907,14 @@ def detect_fixed_language_mode(args):
909
907
if has_dash_c :
910
908
assert has_source_inputs or has_header_inputs , 'Must have source code or header inputs to use -c'
911
909
target = target_basename + '.o'
912
- final_suffix = 'o'
910
+ final_suffix = '. o'
913
911
if '-E' in newargs :
914
- final_suffix = 'eout' # not bitcode, not js; but just result from preprocessing stage of the input file
912
+ final_suffix = '. eout' # not bitcode, not js; but just result from preprocessing stage of the input file
915
913
if '-M' in newargs or '-MM' in newargs :
916
- final_suffix = 'mout' # not bitcode, not js; but just dependency rule of the input file
917
- final_ending = ('.' + final_suffix ) if len (final_suffix ) else ''
914
+ final_suffix = '.mout' # not bitcode, not js; but just dependency rule of the input file
918
915
919
916
# target is now finalized, can finalize other _target s
920
- if final_suffix == 'mjs' :
917
+ if final_suffix == '. mjs' :
921
918
shared .Settings .EXPORT_ES6 = 1
922
919
shared .Settings .MODULARIZE = 1
923
920
js_target = target
@@ -928,7 +925,7 @@ def detect_fixed_language_mode(args):
928
925
wasm_text_target = asm_target .replace ('.asm.js' , '.wast' ) # ditto, might not be used
929
926
wasm_binary_target = asm_target .replace ('.asm.js' , '.wasm' ) # ditto, might not be used
930
927
931
- if final_suffix == 'html' and not options .separate_asm and 'PRECISE_F32=2' in settings_changes :
928
+ if final_suffix == '. html' and not options .separate_asm and 'PRECISE_F32=2' in settings_changes :
932
929
options .separate_asm = True
933
930
logger .warning ('forcing separate asm output (--separate-asm), because -s PRECISE_F32=2 was passed.' )
934
931
if options .separate_asm :
@@ -958,9 +955,9 @@ def get_last_setting_change(setting):
958
955
959
956
# If not compiling to JS, then we are compiling to an intermediate bitcode objects or library, so
960
957
# ignore dynamic linking, since multiple dynamic linkings can interfere with each other
961
- if filename_type_suffix (target ) not in JS_CONTAINING_SUFFIXES or options .ignore_dynamic_linking :
958
+ if get_file_suffix (target ) not in JS_CONTAINING_ENDINGS or options .ignore_dynamic_linking :
962
959
def check (input_file ):
963
- if filename_type_ending (input_file ) in DYNAMICLIB_ENDINGS :
960
+ if get_file_suffix (input_file ) in DYNAMICLIB_ENDINGS :
964
961
if not options .ignore_dynamic_linking :
965
962
logger .warning ('ignoring dynamic library %s because not compiling to JS or HTML, remember to link it when compiling to JS or HTML at the end' , os .path .basename (input_file ))
966
963
return False
@@ -973,7 +970,7 @@ def check(input_file):
973
970
974
971
newargs = CC_ADDITIONAL_ARGS + newargs
975
972
976
- if options .separate_asm and final_suffix != 'html' :
973
+ if options .separate_asm and final_suffix != '. html' :
977
974
shared .WarningManager .warn ('SEPARATE_ASM' )
978
975
979
976
# Apply optimization level settings
@@ -1000,7 +997,7 @@ def check(input_file):
1000
997
1001
998
if options .bind :
1002
999
# If we are using embind and generating JS, now is the time to link in bind.cpp
1003
- if final_suffix in JS_CONTAINING_SUFFIXES :
1000
+ if final_suffix in JS_CONTAINING_ENDINGS :
1004
1001
input_files .append ((next_arg_index , shared .path_from_root ('system' , 'lib' , 'embind' , 'bind.cpp' )))
1005
1002
next_arg_index += 1
1006
1003
@@ -1099,22 +1096,22 @@ def check(input_file):
1099
1096
shared .Settings .WORKAROUND_IOS_9_RIGHT_SHIFT_BUG = 0
1100
1097
shared .Settings .WORKAROUND_OLD_WEBGL_UNIFORM_UPLOAD_IGNORED_OFFSET_BUG = 0
1101
1098
1102
- if shared .Settings .STB_IMAGE and final_suffix in JS_CONTAINING_SUFFIXES :
1099
+ if shared .Settings .STB_IMAGE and final_suffix in JS_CONTAINING_ENDINGS :
1103
1100
input_files .append ((next_arg_index , shared .path_from_root ('third_party' , 'stb_image.c' )))
1104
1101
next_arg_index += 1
1105
1102
shared .Settings .EXPORTED_FUNCTIONS += ['_stbi_load' , '_stbi_load_from_memory' , '_stbi_image_free' ]
1106
1103
# stb_image 2.x need to have STB_IMAGE_IMPLEMENTATION defined to include the implementation when compiling
1107
1104
newargs .append ('-DSTB_IMAGE_IMPLEMENTATION' )
1108
1105
1109
- if shared .Settings .ASMFS and final_suffix in JS_CONTAINING_SUFFIXES :
1106
+ if shared .Settings .ASMFS and final_suffix in JS_CONTAINING_ENDINGS :
1110
1107
input_files .append ((next_arg_index , shared .path_from_root ('system' , 'lib' , 'fetch' , 'asmfs.cpp' )))
1111
1108
newargs .append ('-D__EMSCRIPTEN_ASMFS__=1' )
1112
1109
next_arg_index += 1
1113
1110
shared .Settings .FILESYSTEM = 0
1114
1111
shared .Settings .FETCH = 1
1115
1112
options .js_libraries .append (shared .path_from_root ('src' , 'library_asmfs.js' ))
1116
1113
1117
- if shared .Settings .FETCH and final_suffix in JS_CONTAINING_SUFFIXES :
1114
+ if shared .Settings .FETCH and final_suffix in JS_CONTAINING_ENDINGS :
1118
1115
input_files .append ((next_arg_index , shared .path_from_root ('system' , 'lib' , 'fetch' , 'emscripten_fetch.cpp' )))
1119
1116
next_arg_index += 1
1120
1117
options .js_libraries .append (shared .path_from_root ('src' , 'library_fetch.js' ))
@@ -1486,31 +1483,31 @@ def check(input_file):
1486
1483
return run_process ([call ] + args , check = False ).returncode
1487
1484
1488
1485
def get_bitcode_file (input_file ):
1489
- if final_suffix not in JS_CONTAINING_SUFFIXES :
1486
+ if final_suffix not in JS_CONTAINING_ENDINGS :
1490
1487
# no need for a temp file, just emit to the right place
1491
1488
if len (input_files ) == 1 :
1492
1489
# can just emit directly to the target
1493
1490
if specified_target :
1494
1491
if specified_target .endswith ('/' ) or specified_target .endswith ('\\ ' ) or os .path .isdir (specified_target ):
1495
1492
return os .path .join (specified_target , os .path .basename (unsuffixed (input_file ))) + options .default_object_extension
1496
1493
return specified_target
1497
- return unsuffixed (input_file ) + final_ending
1494
+ return unsuffixed (input_file ) + final_suffix
1498
1495
else :
1499
1496
if has_dash_c :
1500
1497
return unsuffixed (input_file ) + options .default_object_extension
1501
1498
return in_temp (unsuffixed (uniquename (input_file )) + options .default_object_extension )
1502
1499
1503
1500
# Request LLVM debug info if explicitly specified, or building bitcode with -g, or if building a source all the way to JS with -g
1504
- if use_source_map (options ) or ((final_suffix not in JS_CONTAINING_SUFFIXES or (has_source_inputs and final_suffix in JS_CONTAINING_SUFFIXES )) and options .requested_debug == '-g' ):
1501
+ if use_source_map (options ) or ((final_suffix not in JS_CONTAINING_ENDINGS or (has_source_inputs and final_suffix in JS_CONTAINING_ENDINGS )) and options .requested_debug == '-g' ):
1505
1502
# do not save llvm debug info if js optimizer will wipe it out anyhow (but if source maps are used, keep it)
1506
- if use_source_map (options ) or not (final_suffix in JS_CONTAINING_SUFFIXES and options .js_opts ):
1503
+ if use_source_map (options ) or not (final_suffix in JS_CONTAINING_ENDINGS and options .js_opts ):
1507
1504
newargs .append ('-g' ) # preserve LLVM debug info
1508
1505
options .debug_level = 4
1509
1506
shared .Settings .DEBUG_LEVEL = 4
1510
1507
1511
1508
# Bitcode args generation code
1512
1509
def get_clang_args (input_files ):
1513
- file_ending = filename_type_ending (input_files [0 ])
1510
+ file_ending = get_file_suffix (input_files [0 ])
1514
1511
args = [call ] + newargs + input_files
1515
1512
if file_ending .endswith (CXX_ENDINGS ):
1516
1513
args += shared .EMSDK_CXX_OPTS
@@ -1554,7 +1551,7 @@ def compile_source_file(i, input_file):
1554
1551
1555
1552
# First, generate LLVM bitcode. For each input file, we get base.o with bitcode
1556
1553
for i , input_file in input_files :
1557
- file_ending = filename_type_ending (input_file )
1554
+ file_ending = get_file_suffix (input_file )
1558
1555
if file_ending .endswith (SOURCE_ENDINGS ):
1559
1556
compile_source_file (i , input_file )
1560
1557
else : # bitcode
@@ -1586,7 +1583,7 @@ def compile_source_file(i, input_file):
1586
1583
# Optimize source files
1587
1584
if optimizing (options .llvm_opts ):
1588
1585
for pos , (_ , input_file ) in enumerate (input_files ):
1589
- file_ending = filename_type_ending (input_file )
1586
+ file_ending = get_file_suffix (input_file )
1590
1587
if file_ending .endswith (SOURCE_ENDINGS ):
1591
1588
temp_file = temp_files [pos ][1 ]
1592
1589
logger .debug ('optimizing %s' , input_file )
@@ -1601,7 +1598,8 @@ def compile_source_file(i, input_file):
1601
1598
temp_files [pos ] = (temp_files [pos ][0 ], new_temp_file )
1602
1599
1603
1600
# Decide what we will link
1604
- stop_at_bitcode = final_suffix not in EXECUTABLE_SUFFIXES
1601
+ executable_endings = JS_CONTAINING_ENDINGS + ('.wasm' ,)
1602
+ stop_at_bitcode = final_suffix not in executable_endings
1605
1603
1606
1604
if stop_at_bitcode or not shared .Settings .WASM_BACKEND :
1607
1605
# Filter link flags, keeping only those that shared.Building.link knows
@@ -1617,12 +1615,12 @@ def compile_source_file(i, input_file):
1617
1615
if not specified_target :
1618
1616
assert len (temp_files ) == len (input_files )
1619
1617
for tempf , inputf in zip (temp_files , input_files ):
1620
- safe_move (tempf [1 ], unsuffixed_basename (inputf [1 ]) + final_ending )
1618
+ safe_move (tempf [1 ], unsuffixed_basename (inputf [1 ]) + final_suffix )
1621
1619
else :
1622
1620
if len (input_files ) == 1 :
1623
1621
input_file = input_files [0 ][1 ]
1624
1622
temp_file = temp_files [0 ][1 ]
1625
- bitcode_target = specified_target if specified_target else unsuffixed_basename (input_file ) + final_ending
1623
+ bitcode_target = specified_target if specified_target else unsuffixed_basename (input_file ) + final_suffix
1626
1624
if temp_file != input_file :
1627
1625
safe_move (temp_file , bitcode_target )
1628
1626
else :
@@ -1646,7 +1644,7 @@ def compile_source_file(i, input_file):
1646
1644
logger .debug ('stopping at bitcode' )
1647
1645
if shared .Settings .SIDE_MODULE :
1648
1646
exit_with_error ('SIDE_MODULE must only be used when compiling to an executable shared library, and not when emitting LLVM bitcode. That is, you should be emitting a .wasm file (for wasm) or a .js file (for asm.js). Note that when compiling to a typical native suffix for a shared library (.so, .dylib, .dll; which many build systems do) then Emscripten emits an LLVM bitcode file, which you should then compile to .wasm or .js with SIDE_MODULE.' )
1649
- if final_suffix .lower () in [ ' so' , 'dylib' , 'dll' ] :
1647
+ if final_suffix .lower () in ( '. so' , '. dylib' , '. dll' ) :
1650
1648
logger .warning ('When Emscripten compiles to a typical native suffix for shared libraries (.so, .dylib, .dll) then it emits an LLVM bitcode file. You should then compile that to an emscripten SIDE_MODULE (using that flag) with suffix .wasm (for wasm) or .js (for asm.js). (You may also want to adapt your build system to emit the more standard suffix for a file with LLVM bitcode, \' .bc\' , which would avoid this warning.)' )
1651
1649
return 0
1652
1650
@@ -2109,7 +2107,7 @@ def get_eliminate():
2109
2107
generated_text_files_with_native_eols += [js_target ]
2110
2108
2111
2109
# If we were asked to also generate HTML, do that
2112
- if final_suffix == 'html' :
2110
+ if final_suffix == '. html' :
2113
2111
generate_html (target , options , js_target , target_basename ,
2114
2112
asm_target , wasm_binary_target ,
2115
2113
memfile , optimizer )
0 commit comments