@@ -108,31 +108,24 @@ class Mode(Enum):
108
108
COMPILE_AND_LINK = auto ()
109
109
110
110
111
+ class LinkFlag :
112
+ """Used to represent a linker flag.
113
+
114
+ The flag value is stored along with a bool that distingingishes input
115
+ files from non-files.
116
+
117
+ A list of these is return by separate_linker_flags.
118
+ """
119
+ def __init__ (self , value , is_file ):
120
+ self .value = value
121
+ self .is_file = is_file
122
+
123
+
111
124
class EmccState :
112
125
def __init__ (self , args ):
113
126
self .mode = Mode .COMPILE_AND_LINK
114
127
# Using tuple here to prevent accidental mutation
115
128
self .orig_args = tuple (args )
116
- # List of link options paired with their position on the command line [(i, option), ...].
117
- self .link_flags = []
118
- self .lib_dirs = []
119
-
120
- def has_link_flag (self , f ):
121
- return f in [x for _ , x in self .link_flags ]
122
-
123
- def add_link_flag (self , i , flag ):
124
- if flag .startswith ('-L' ):
125
- self .lib_dirs .append (flag [2 :])
126
- # Link flags should be adding in strictly ascending order
127
- assert not self .link_flags or i > self .link_flags [- 1 ][0 ], self .link_flags
128
- self .link_flags .append ((i , flag ))
129
-
130
- def append_link_flag (self , flag ):
131
- if self .link_flags :
132
- index = self .link_flags [- 1 ][0 ] + 1
133
- else :
134
- index = 1
135
- self .add_link_flag (index , flag )
136
129
137
130
138
131
class EmccOptions :
@@ -190,6 +183,7 @@ def __init__(self):
190
183
self .nostartfiles = False
191
184
self .sanitize_minimal_runtime = False
192
185
self .sanitize = set ()
186
+ self .lib_dirs = []
193
187
194
188
195
189
def create_reproduce_file (name , args ):
@@ -662,20 +656,21 @@ def run(args):
662
656
if state .mode == Mode .POST_LINK_ONLY :
663
657
if len (options .input_files ) != 1 :
664
658
exit_with_error ('--post-link requires a single input file' )
665
- separate_linker_flags (state , newargs )
659
+ linker_args = separate_linker_flags (newargs )[1 ]
660
+ linker_args = [f .value for f in linker_args ]
666
661
# Delay import of link.py to avoid processing this file when only compiling
667
662
from tools import link
668
- link .run_post_link (options .input_files [0 ], options , state )
663
+ link .run_post_link (options .input_files [0 ], options , linker_args )
669
664
return 0
670
665
671
666
# Compile source code to object files
672
667
# When only compiling this function never returns.
673
- linker_inputs = phase_compile_inputs (options , state , newargs )
668
+ linker_args = phase_compile_inputs (options , state , newargs )
674
669
675
670
if state .mode == Mode .COMPILE_AND_LINK :
676
671
# Delay import of link.py to avoid processing this file when only compiling
677
672
from tools import link
678
- return link .run (linker_inputs , options , state )
673
+ return link .run (options , linker_args )
679
674
else :
680
675
logger .debug ('stopping after compile phase' )
681
676
return 0
@@ -747,26 +742,21 @@ def phase_parse_arguments(state):
747
742
return options , newargs
748
743
749
744
750
- def separate_linker_flags (state , newargs ):
751
- """Process argument list separating out input files, compiler flags
752
- and linker flags.
753
-
754
- - Linker flags are stored in state.link_flags
755
- - Input files and compiler-only flags are returned as two separate lists.
745
+ def separate_linker_flags (newargs ):
746
+ """Process argument list separating out compiler args and linker args.
756
747
757
- Both linker flags and input files are stored as pairs of (i, entry) where
758
- `i` is the orginal index in the command line arguments. This allow the two
759
- lists to be recombined in the correct order by the linker code (link.py).
760
-
761
- Note that this index can have a fractional part for input arguments that
762
- expand into multiple processed arguments, as in -Wl,-f1,-f2.
748
+ - Linker flags include input files and are returned a list of LinkFlag objects.
749
+ - Compiler flags are those to be passed to `clang -c`.
763
750
"""
764
751
765
752
if settings .RUNTIME_LINKED_LIBS :
766
753
newargs += settings .RUNTIME_LINKED_LIBS
767
754
768
- input_files = []
769
755
compiler_args = []
756
+ linker_args = []
757
+
758
+ def add_link_arg (flag , is_file = False ):
759
+ linker_args .append (LinkFlag (flag , is_file ))
770
760
771
761
skip = False
772
762
for i in range (len (newargs )):
@@ -789,30 +779,24 @@ def get_next_arg():
789
779
# https://bugs.python.org/issue1311
790
780
if not os .path .exists (arg ) and arg not in (os .devnull , '-' ):
791
781
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 )
792
- input_files . append (( i , arg ) )
782
+ add_link_arg ( arg , True )
793
783
elif arg == '-z' :
794
- state . add_link_flag ( i , newargs [ i ] )
795
- state . add_link_flag ( i + 1 , get_next_arg ())
784
+ add_link_arg ( arg )
785
+ add_link_arg ( get_next_arg ())
796
786
elif arg .startswith ('-Wl,' ):
797
- # Multiple comma separated link flags can be specified. Create fake
798
- # fractional indices for these: -Wl,a,b,c,d at index 4 becomes:
799
- # (4, a), (4.25, b), (4.5, c), (4.75, d)
800
- link_flags_to_add = arg .split (',' )[1 :]
801
- for flag_index , flag in enumerate (link_flags_to_add ):
802
- state .add_link_flag (i + float (flag_index ) / len (link_flags_to_add ), flag )
787
+ for flag in arg .split (',' )[1 :]:
788
+ add_link_arg (flag )
803
789
elif arg == '-Xlinker' :
804
- state .add_link_flag (i + 1 , get_next_arg ())
805
- elif arg == '-s' :
806
- state .add_link_flag (i , newargs [i ])
790
+ add_link_arg (get_next_arg ())
807
791
elif arg == '-s' or arg .startswith (('-l' , '-L' , '--js-library=' , '-z' )):
808
- state . add_link_flag ( i , arg )
792
+ add_link_arg ( arg )
809
793
elif not arg .startswith ('-o' ) and arg not in ('-nostdlib' , '-nostartfiles' , '-nolibc' , '-nodefaultlibs' , '-s' ):
810
794
# All other flags are for the compiler
811
795
compiler_args .append (arg )
812
796
if skip :
813
797
compiler_args .append (get_next_arg ())
814
798
815
- return compiler_args , input_files
799
+ return compiler_args , linker_args
816
800
817
801
818
802
@ToolchainProfiler .profile_block ('setup' )
@@ -955,8 +939,7 @@ def get_clang_command_asm():
955
939
# filter out the link flags
956
940
assert state .mode == Mode .COMPILE_AND_LINK
957
941
assert not options .dash_c
958
- compile_args , input_files = separate_linker_flags (state , newargs )
959
- linker_inputs = []
942
+ compile_args , linker_args = separate_linker_flags (newargs )
960
943
seen_names = {}
961
944
962
945
def uniquename (name ):
@@ -967,10 +950,9 @@ def uniquename(name):
967
950
def get_object_filename (input_file ):
968
951
return in_temp (shared .replace_suffix (uniquename (input_file ), '.o' ))
969
952
970
- def compile_source_file (i , input_file ):
953
+ def compile_source_file (input_file ):
971
954
logger .debug (f'compiling source file: { input_file } ' )
972
955
output_file = get_object_filename (input_file )
973
- linker_inputs .append ((i , output_file ))
974
956
if get_file_suffix (input_file ) in ASSEMBLY_EXTENSIONS :
975
957
cmd = get_clang_command_asm ()
976
958
elif get_file_suffix (input_file ) in PREPROCESSED_EXTENSIONS :
@@ -993,28 +975,29 @@ def compile_source_file(i, input_file):
993
975
assert os .path .exists (output_file )
994
976
if options .save_temps :
995
977
shutil .copyfile (output_file , shared .unsuffixed_basename (input_file ) + '.o' )
978
+ return output_file
996
979
997
- # First, generate LLVM bitcode. For each input file, we get base.o with bitcode
998
- for i , input_file in input_files :
980
+ # Compile input files individually to temporary locations.
981
+ for arg in linker_args :
982
+ if not arg .is_file :
983
+ continue
984
+ input_file = arg .value
999
985
file_suffix = get_file_suffix (input_file )
1000
986
if file_suffix in SOURCE_EXTENSIONS | ASSEMBLY_EXTENSIONS or (options .dash_c and file_suffix == '.bc' ):
1001
- compile_source_file (i , input_file )
987
+ arg . value = compile_source_file (input_file )
1002
988
elif file_suffix in DYLIB_EXTENSIONS :
1003
989
logger .debug (f'using shared library: { input_file } ' )
1004
- linker_inputs .append ((i , input_file ))
1005
990
elif building .is_ar (input_file ):
1006
991
logger .debug (f'using static library: { input_file } ' )
1007
- linker_inputs .append ((i , input_file ))
1008
992
elif options .input_language :
1009
- compile_source_file (i , input_file )
993
+ arg . value = compile_source_file (input_file )
1010
994
elif input_file == '-' :
1011
995
exit_with_error ('-E or -x required when input is from standard input' )
1012
996
else :
1013
997
# Default to assuming the inputs are object files and pass them to the linker
1014
- logger .debug (f'using object file: { input_file } ' )
1015
- linker_inputs .append ((i , input_file ))
998
+ pass
1016
999
1017
- return linker_inputs
1000
+ return [ f . value for f in linker_args ]
1018
1001
1019
1002
1020
1003
def version_string ():
@@ -1319,6 +1302,8 @@ def consume_arg_file():
1319
1302
'encountered. If this is to a local system header/library, it may '
1320
1303
'cause problems (local system files make sense for compiling natively '
1321
1304
'on your system, but not necessarily to JavaScript).' )
1305
+ if arg .startswith ('-L' ):
1306
+ options .lib_dirs .append (path_name )
1322
1307
elif check_flag ('--emrun' ):
1323
1308
options .emrun = True
1324
1309
elif check_flag ('--cpuprofiler' ):
0 commit comments