123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186 |
- import os, sys
- # Explicitly enable local imports
- # Don't forget to add imported scripts to inputs of the calling command!
- sys.path.append(os.path.dirname(os.path.abspath(__file__)))
- import process_command_files as pcf
- class ProcessWholeArchiveOption:
- def __init__(self, arch, peers=None, libs=None):
- self.arch = arch.upper()
- self.peers = {x: 0 for x in peers} if peers else None
- self.libs = {x: 0 for x in libs} if libs else None
- self.start_wa_marker = '--start-wa'
- self.end_wa_marker = '--end-wa'
- def _match_peer_lib(self, arg, ext):
- key = None
- if arg.endswith(ext):
- key = os.path.dirname(arg)
- return key if key and self.peers and key in self.peers else None
- def _match_lib(self, arg):
- return arg if self.libs and arg in self.libs else None
- def _process_arg(self, arg, ext='.a'):
- peer_key = self._match_peer_lib(arg, ext)
- lib_key = self._match_lib(arg)
- if peer_key:
- self.peers[peer_key] += 1
- if lib_key:
- self.libs[lib_key] += 1
- return peer_key if peer_key else lib_key
- def _check_peers(self):
- if self.peers:
- for key, value in self.peers.items():
- assert value > 0, '"{}" specified in WHOLE_ARCHIVE() macro is not used on link command'.format(key)
- def _construct_cmd_apple(self, args):
- force_load_flag = '-Wl,-force_load,'
- is_inside_wa_markers = False
- cmd = []
- for arg in args:
- if arg.startswith(force_load_flag):
- cmd.append(arg)
- elif arg == self.start_wa_marker:
- is_inside_wa_markers = True
- elif arg == self.end_wa_marker:
- is_inside_wa_markers = False
- elif is_inside_wa_markers:
- cmd.append(force_load_flag + arg)
- else:
- key = self._process_arg(arg)
- cmd.append(force_load_flag + arg if key else arg)
- self._check_peers()
- return cmd
- def _construct_cmd_win(self, args):
- whole_archive_prefix = '/WHOLEARCHIVE:'
- is_inside_wa_markers = False
- def add_prefix(arg, need_check_peers_and_libs):
- key = self._process_arg(arg, '.lib') if need_check_peers_and_libs else arg
- return whole_archive_prefix + arg if key else arg
- def add_whole_archive_prefix(arg, need_check_peers_and_libs):
- if not pcf.is_cmdfile_arg(arg):
- return add_prefix(arg, need_check_peers_and_libs)
- cmd_file_path = pcf.cmdfile_path(arg)
- cf_args = pcf.read_from_command_file(cmd_file_path)
- with open(cmd_file_path, 'w') as afile:
- for cf_arg in cf_args:
- afile.write(add_prefix(cf_arg, need_check_peers_and_libs) + "\n")
- return arg
- cmd = []
- for arg in args:
- if arg == self.start_wa_marker:
- is_inside_wa_markers = True
- elif arg == self.end_wa_marker:
- is_inside_wa_markers = False
- elif is_inside_wa_markers:
- cmd.append(add_whole_archive_prefix(arg, False))
- continue
- elif self.peers or self.libs:
- cmd.append(add_whole_archive_prefix(arg, True))
- else:
- cmd.append(arg)
- self._check_peers()
- return cmd
- def _construct_cmd_linux(self, args):
- whole_archive_flag = '-Wl,--whole-archive'
- no_whole_archive_flag = '-Wl,--no-whole-archive'
- def replace_markers(arg):
- if arg == self.start_wa_marker:
- return whole_archive_flag
- if arg == self.end_wa_marker:
- return no_whole_archive_flag
- return arg
- args = [replace_markers(arg) for arg in args]
- cmd = []
- is_inside_whole_archive = False
- is_whole_archive = False
- # We are trying not to create excessive sequences of consecutive flags
- # -Wl,--no-whole-archive -Wl,--whole-archive ('externally' specified
- # flags -Wl,--[no-]whole-archive are not taken for consideration in this
- # optimization intentionally)
- for arg in args:
- if arg == whole_archive_flag:
- is_inside_whole_archive = True
- is_whole_archive = False
- elif arg == no_whole_archive_flag:
- is_inside_whole_archive = False
- is_whole_archive = False
- else:
- key = self._process_arg(arg)
- if not is_inside_whole_archive:
- if key:
- if not is_whole_archive:
- cmd.append(whole_archive_flag)
- is_whole_archive = True
- elif is_whole_archive:
- cmd.append(no_whole_archive_flag)
- is_whole_archive = False
- cmd.append(arg)
- if is_whole_archive:
- cmd.append(no_whole_archive_flag)
- # There can be an empty sequence of archive files between
- # -Wl, --whole-archive and -Wl, --no-whole-archive flags.
- # As a result an unknown option error may occur, therefore to
- # prevent this case we need to remove both flags from cmd.
- # These flags affects only on subsequent archive files.
- if len(cmd) == 2:
- return []
- self._check_peers()
- return cmd
- def construct_cmd(self, args):
- if self.arch in ('DARWIN', 'IOS', 'IOSSIM'):
- return self._construct_cmd_apple(args)
- if self.arch == 'WINDOWS':
- return self._construct_cmd_win(args)
- return self._construct_cmd_linux(args)
- def get_whole_archive_peers_and_libs(args):
- remaining_args = []
- peers = []
- libs = []
- peers_flag = '--whole-archive-peers'
- libs_flag = '--whole-archive-libs'
- next_is_peer = False
- next_is_lib = False
- for arg in args:
- if arg == peers_flag:
- next_is_peer = True
- elif arg == libs_flag:
- next_is_lib = True
- elif next_is_peer:
- peers.append(arg)
- next_is_peer = False
- elif next_is_lib:
- libs.append(arg)
- next_is_lib = False
- else:
- remaining_args.append(arg)
- return remaining_args, peers, libs
|