Use '%z' instead of '%Z' on printf functions
[glibc.git] / scripts / move-symbol-to-libc.py
blob8696a0ae2c953525ac2255fa1a475b1d0f2d879f
1 #!/usr/bin/python3
2 # Move symbols from other shared objects into libc.so.
3 # Copyright (C) 2020-2022 Free Software Foundation, Inc.
4 # This file is part of the GNU C Library.
6 # The GNU C Library is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU Lesser General Public
8 # License as published by the Free Software Foundation; either
9 # version 2.1 of the License, or (at your option) any later version.
11 # The GNU C Library is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # Lesser General Public License for more details.
16 # You should have received a copy of the GNU Lesser General Public
17 # License along with the GNU C Library; if not, see
18 # <https://www.gnu.org/licenses/>.
20 """Move symbols from other shared objects into libc.so.
22 This script moves ABI symbols from non-libc abilists in to
23 libc.abilist. Symbol versions are preserved. The script must be
24 called from the top of the glibc source tree.
26 """
28 import argparse
29 import os.path
30 import sys
32 # Make available glibc Python modules.
33 sys.path.append(os.path.dirname(os.path.realpath(__file__)))
35 import glibcsymbols
37 def add_to_libc_path(path, new_symbols):
38 """Add SYMBOLS to the abilist file PATH.
40 NEW_SYMBOLS is a dictionary from glibcsymbols.VersionedSymbol
41 objects to their flags.
43 """
44 original_symbols = glibcsymbols.read_abilist(path)
45 updated_symbols = original_symbols.copy()
46 updated_symbols.update(new_symbols)
47 if updated_symbols != original_symbols:
48 sys.stdout.write('updating libc abilist {}\n'.format(path))
49 glibcsymbols.replace_file(
50 path, glibcsymbols.abilist_lines(updated_symbols))
52 # The name of the libc.so abilist file.
53 libc_abilist = 'libc.abilist'
55 def add_to_libc_fallback(directory, subdirs, symbol_lines):
56 """Add SYMBOL_LINES to the libc.abilist files in SUBDIRS in DIRECTORY.
58 All subdirectories must exist. If they do, return True. If not,
59 skip processing and return False.
61 """
62 abilists = [os.path.join(directory, subdir, libc_abilist)
63 for subdir in subdirs]
64 for abilist in abilists:
65 if not os.path.exists(abilist):
66 return False
67 for abilist in abilists:
68 add_to_libc_path(abilist, symbol_lines)
69 return True
71 def add_to_libc(directory, symbol_lines):
73 """Add SYMBOL_LINES (a list of strings) to libc.abilist in DIRECTORY.
75 Try specific subdirectories as well if libc.abilist is not found
76 in DIRECTORY.
78 """
79 libc_path = os.path.join(directory, libc_abilist)
80 if os.path.exists(libc_path):
81 add_to_libc_path(libc_path, symbol_lines)
82 return
84 # Special case for powerpc32 and mips32 variants.
85 if add_to_libc_fallback(directory, ('fpu', 'nofpu'), symbol_lines):
86 return
88 # Special case for mips64.
89 if add_to_libc_fallback(directory, ('n32', 'n64'), symbol_lines):
90 return
92 raise IOError('No libc.abilist found for: {}'.format(directory))
94 def move_symbols_1(path, to_move, moved_symbols):
95 """Move SYMBOLS from the abilist file PATH to MOVED_SYMBOLS.
97 TO_MOVE must be a set of strings. MOVED_SYMBOLS is a dictionary.
99 """
100 suffix = '.abilist'
101 assert path.endswith('.abilist')
102 library = os.path.basename(path)[:-len(suffix)]
103 placeholder = '__{}_version_placeholder'.format(library)
105 new_lines = []
106 changed = False
108 old_symbols = glibcsymbols.read_abilist(path)
109 old_versions = set(versym.version for versym in old_symbols.keys())
110 matching_symbols = dict(e for e in old_symbols.items()
111 if e[0].symbol in to_move)
112 if matching_symbols:
113 sys.stdout.write('updating {} abilist {}\n'.format(library, path))
114 new_symbols = dict(e for e in old_symbols.items()
115 if e[0].symbol not in to_move)
117 # Add placeholder symbols to prevent symbol versions from
118 # going away completely.
119 new_versions = set(versym.version for versym in new_symbols.keys())
120 for missing_version in old_versions - new_versions:
121 new_symbols[glibcsymbols.VersionedSymbol(
122 placeholder, missing_version)] = 'F'
124 glibcsymbols.replace_file(
125 path, glibcsymbols.abilist_lines(new_symbols))
127 moved_symbols.update(matching_symbols)
129 def move_symbols(directory, files, symbols):
130 """Move SYMBOLS from FILES (a list of abilist file names) in DIRECTORY.
132 SYMBOLS must be a set of strings.
135 moved_symbols = {}
136 for filename in files:
137 move_symbols_1(os.path.join(directory, filename), symbols,
138 moved_symbols)
139 if moved_symbols:
140 add_to_libc(directory, moved_symbols)
142 def get_parser():
143 """Return an argument parser for this module."""
144 parser = argparse.ArgumentParser(description=__doc__)
145 parser.add_argument('--only-linux', action='store_true',
146 help='Restrict the operation to Linux abilists')
147 parser.add_argument('symbols', help='name of the symbol to move',
148 nargs='+')
149 return parser
151 def main(argv):
152 """The main entry point."""
153 parser = get_parser()
154 opts = parser.parse_args(argv)
155 if opts.only_linux:
156 sysdeps = 'sysdeps/unix/sysv/linux'
157 else:
158 sysdeps = 'sysdeps'
160 symbols = frozenset(opts.symbols)
162 for directory, dirs, files in os.walk(sysdeps):
163 move_symbols(directory, [name for name in files
164 if name != 'libc.abilist'
165 and name.endswith('.abilist')], symbols)
167 if __name__ == '__main__':
168 main(sys.argv[1:])