aboutsummaryrefslogtreecommitdiffstats
path: root/build/scripts/process_whole_archive_option.py
diff options
context:
space:
mode:
authoralexv-smirnov <alex@ydb.tech>2023-06-13 11:05:01 +0300
committeralexv-smirnov <alex@ydb.tech>2023-06-13 11:05:01 +0300
commitbf0f13dd39ee3e65092ba3572bb5b1fcd125dcd0 (patch)
tree1d1df72c0541a59a81439842f46d95396d3e7189 /build/scripts/process_whole_archive_option.py
parent8bfdfa9a9bd19bddbc58d888e180fbd1218681be (diff)
downloadydb-bf0f13dd39ee3e65092ba3572bb5b1fcd125dcd0.tar.gz
add ymake export to ydb
Diffstat (limited to 'build/scripts/process_whole_archive_option.py')
-rw-r--r--build/scripts/process_whole_archive_option.py183
1 files changed, 183 insertions, 0 deletions
diff --git a/build/scripts/process_whole_archive_option.py b/build/scripts/process_whole_archive_option.py
new file mode 100644
index 0000000000..84d29869e9
--- /dev/null
+++ b/build/scripts/process_whole_archive_option.py
@@ -0,0 +1,183 @@
+import os
+
+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