process_whole_archive_option.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. import os
  2. import sys
  3. import process_command_files as pcf
  4. class ProcessWholeArchiveOption():
  5. def __init__(self, arch, peers=None, libs=None):
  6. self.arch = arch.upper()
  7. self.peers = { x : 0 for x in peers } if peers else None
  8. self.libs = { x : 0 for x in libs } if libs else None
  9. self.start_wa_marker = '--start-wa'
  10. self.end_wa_marker = '--end-wa'
  11. def _match_peer_lib(self, arg, ext):
  12. key = None
  13. if arg.endswith(ext):
  14. key = os.path.dirname(arg)
  15. return key if key and self.peers and key in self.peers else None
  16. def _match_lib(self, arg):
  17. return arg if self.libs and arg in self.libs else None
  18. def _process_arg(self, arg, ext='.a'):
  19. peer_key = self._match_peer_lib(arg, ext)
  20. lib_key = self._match_lib(arg)
  21. if peer_key:
  22. self.peers[peer_key] += 1
  23. if lib_key:
  24. self.libs[lib_key] += 1
  25. return peer_key if peer_key else lib_key
  26. def _check_peers(self):
  27. if self.peers:
  28. for key, value in self.peers.items():
  29. assert value > 0, '"{}" specified in WHOLE_ARCHIVE() macro is not used on link command'.format(key)
  30. def _construct_cmd_apple(self, args):
  31. force_load_flag = '-Wl,-force_load,'
  32. is_inside_wa_markers = False
  33. cmd = []
  34. for arg in args:
  35. if arg.startswith(force_load_flag):
  36. cmd.append(arg)
  37. elif arg == self.start_wa_marker:
  38. is_inside_wa_markers = True
  39. elif arg == self.end_wa_marker:
  40. is_inside_wa_markers = False
  41. elif is_inside_wa_markers:
  42. cmd.append(force_load_flag + arg)
  43. else:
  44. key = self._process_arg(arg)
  45. cmd.append(force_load_flag + arg if key else arg)
  46. self._check_peers()
  47. return cmd
  48. def _construct_cmd_win(self, args):
  49. whole_archive_prefix = '/WHOLEARCHIVE:'
  50. is_inside_wa_markers = False
  51. def add_prefix(arg, need_check_peers_and_libs):
  52. key = self._process_arg(arg, '.lib') if need_check_peers_and_libs else arg
  53. return whole_archive_prefix + arg if key else arg
  54. def add_whole_archive_prefix(arg, need_check_peers_and_libs):
  55. if not pcf.is_cmdfile_arg(arg):
  56. return add_prefix(arg, need_check_peers_and_libs)
  57. cmd_file_path = pcf.cmdfile_path(arg)
  58. cf_args = pcf.read_from_command_file(cmd_file_path)
  59. with open(cmd_file_path, 'w') as afile:
  60. for cf_arg in cf_args:
  61. afile.write(add_prefix(cf_arg, need_check_peers_and_libs) + "\n")
  62. return arg
  63. cmd = []
  64. for arg in args:
  65. if arg == self.start_wa_marker:
  66. is_inside_wa_markers = True
  67. elif arg == self.end_wa_marker:
  68. is_inside_wa_markers = False
  69. elif is_inside_wa_markers:
  70. cmd.append(add_whole_archive_prefix(arg, False))
  71. continue
  72. elif self.peers or self.libs:
  73. cmd.append(add_whole_archive_prefix(arg, True))
  74. else:
  75. cmd.append(arg)
  76. self._check_peers()
  77. return cmd
  78. def _construct_cmd_linux(self, args):
  79. whole_archive_flag = '-Wl,--whole-archive'
  80. no_whole_archive_flag = '-Wl,--no-whole-archive'
  81. def replace_markers(arg):
  82. if arg == self.start_wa_marker:
  83. return whole_archive_flag
  84. if arg == self.end_wa_marker:
  85. return no_whole_archive_flag
  86. return arg
  87. args = [replace_markers(arg) for arg in args]
  88. cmd = []
  89. is_inside_whole_archive = False
  90. is_whole_archive = False
  91. # We are trying not to create excessive sequences of consecutive flags
  92. # -Wl,--no-whole-archive -Wl,--whole-archive ('externally' specified
  93. # flags -Wl,--[no-]whole-archive are not taken for consideration in this
  94. # optimization intentionally)
  95. for arg in args:
  96. if arg == whole_archive_flag:
  97. is_inside_whole_archive = True
  98. is_whole_archive = False
  99. elif arg == no_whole_archive_flag:
  100. is_inside_whole_archive = False
  101. is_whole_archive = False
  102. else:
  103. key = self._process_arg(arg)
  104. if not is_inside_whole_archive:
  105. if key:
  106. if not is_whole_archive:
  107. cmd.append(whole_archive_flag)
  108. is_whole_archive = True
  109. elif is_whole_archive:
  110. cmd.append(no_whole_archive_flag)
  111. is_whole_archive = False
  112. cmd.append(arg)
  113. if is_whole_archive:
  114. cmd.append(no_whole_archive_flag)
  115. self._check_peers()
  116. return cmd
  117. def construct_cmd(self, args):
  118. if self.arch in ('DARWIN', 'IOS', 'IOSSIM'):
  119. return self._construct_cmd_apple(args)
  120. if self.arch == 'WINDOWS':
  121. return self._construct_cmd_win(args)
  122. return self._construct_cmd_linux(args)
  123. def get_whole_archive_peers_and_libs(args):
  124. remaining_args = []
  125. peers = []
  126. libs = []
  127. peers_flag = '--whole-archive-peers'
  128. libs_flag = '--whole-archive-libs'
  129. next_is_peer = False
  130. next_is_lib = False
  131. for arg in args:
  132. if arg == peers_flag:
  133. next_is_peer = True
  134. elif arg == libs_flag:
  135. next_is_lib = True
  136. elif next_is_peer:
  137. peers.append(arg)
  138. next_is_peer = False
  139. elif next_is_lib:
  140. libs.append(arg)
  141. next_is_lib = False
  142. else:
  143. remaining_args.append(arg)
  144. return remaining_args, peers, libs