| #!/usr/bin/env python3 | |
| """Script to generate Chromium's Abseil .def files at roll time. | |
| This script generates //third_party/abseil-app/absl/symbols_*.def at Abseil | |
| roll time. | |
| Since Abseil doesn't export symbols, Chromium is forced to consider all | |
| Abseil's symbols as publicly visible. On POSIX it is possible to use | |
| -fvisibility=default but on Windows a .def file with all the symbols | |
| is needed. | |
| Unless you are on a Windows machine, you need to set up your Chromium | |
| checkout for cross-compilation by following the instructions at | |
| https://chromium.googlesource.com/chromium/src.git/+/main/docs/win_cross.md. | |
| If you are on Windows, you may need to tweak this script to run, e.g. by | |
| changing "gn" to "gn.bat", changing "llvm-nm" to the name of your copy of | |
| llvm-nm, etc. | |
| """ | |
| import fnmatch | |
| import logging | |
| import os | |
| import re | |
| import subprocess | |
| import sys | |
| import tempfile | |
| import time | |
| assert sys.platform != 'win32', \ | |
| "This doesn't work on Windows, https://crbug.com/379023022" | |
| # Matches mangled symbols containing 'absl' or starting with 'Absl'. This is | |
| # a good enough heuristic to select Abseil symbols to list in the .def file. | |
| # See https://learn.microsoft.com/en-us/cpp/build/reference/decorated-names, | |
| # which describes decorations under different calling conventions. We mostly | |
| # just attempt to handle any leading underscore for C names (as in __cdecl). | |
| ABSL_SYM_RE = r'0* [BT] (?P<symbol>[?]+[^?].*absl.*|_?Absl.*)' | |
| def _DebugOrRelease(is_debug): | |
| return 'dbg' if is_debug else 'rel' | |
| def _GenerateDefFileBuild(cpu, is_debug, use_cxx23, extra_gn_args, suffix, out_dir, cwd): | |
| if extra_gn_args: | |
| assert suffix != None, 'suffix is needed when extra_gn_args is used' | |
| flavor = _DebugOrRelease(is_debug) | |
| gn_args = [ | |
| 'ffmpeg_branding = "Chrome"', | |
| 'is_component_build = true', | |
| 'is_debug = {}'.format(str(is_debug).lower()), | |
| 'proprietary_codecs = true', | |
| 'use_cxx23={}'.format(str(use_cxx23).lower()), | |
| 'symbol_level = 0', | |
| 'target_cpu = "{}"'.format(cpu), | |
| 'target_os = "win"', | |
| 'use_remoteexec = true', | |
| ] | |
| gn_args.extend(extra_gn_args) | |
| gn = 'gn' | |
| autoninja = 'autoninja' | |
| llvm_nm = ['third_party/llvm-build/Release+Asserts/bin/llvm-nm'] | |
| if sys.platform == 'win32': | |
| gn = 'gn.bat' | |
| autoninja = 'autoninja.bat' | |
| llvm_nm += '.exe' | |
| logging.info('[%s - %s] Creating tmp out dir in %s', cpu, flavor, out_dir) | |
| subprocess.check_call([gn, 'gen', out_dir, '--args=' + ' '.join(gn_args)], | |
| cwd=cwd) | |
| logging.info('[%s - %s] gn gen completed', cpu, flavor) | |
| subprocess.check_call([ | |
| autoninja, '-C', out_dir, 'third_party/abseil-cpp:absl_component_deps' | |
| ], | |
| cwd=os.getcwd()) | |
| logging.info('[%s - %s] autoninja completed', cpu, flavor) | |
| obj_files = [] | |
| for root, _dirnames, filenames in os.walk( | |
| os.path.join(out_dir, 'obj', 'third_party', 'abseil-cpp')): | |
| matched_files = fnmatch.filter(filenames, '*.obj') | |
| obj_files.extend((os.path.join(root, f) for f in matched_files)) | |
| logging.info('[%s - %s] Found %d object files.', cpu, flavor, | |
| len(obj_files)) | |
| absl_symbols = set() | |
| for f in obj_files: | |
| stdout = subprocess.check_output(llvm_nm + [f], cwd=os.getcwd()) | |
| for line in stdout.splitlines(): | |
| line = line.decode('utf-8') | |
| match = re.match(ABSL_SYM_RE, line) | |
| if match: | |
| symbol = match.group('symbol') | |
| assert symbol.count(' ') == 0, ( | |
| 'Regex matched too much, probably got ' | |
| 'undecorated name as well') | |
| # Avoid to export deleting dtors since they trigger | |
| # "lld-link: error: export of deleting dtor" linker errors, see | |
| # crbug.com/1201277. | |
| if symbol.startswith('??_G'): | |
| continue | |
| # Strip any leading underscore for C names (as in __cdecl). It's only | |
| # there on x86, but the x86 toolchain falls over when you include it! | |
| if cpu == 'x86' and symbol.startswith('_'): | |
| symbol = symbol[1:] | |
| absl_symbols.add(symbol) | |
| logging.info('[%s - %s] Found %d absl symbols.', cpu, flavor, | |
| len(absl_symbols)) | |
| if extra_gn_args: | |
| def_file = os.path.join('third_party', 'abseil-cpp', | |
| 'symbols_{}_{}_{}'.format(cpu, flavor, suffix)) | |
| else: | |
| def_file = os.path.join('third_party', 'abseil-cpp', | |
| 'symbols_{}_{}'.format(cpu, flavor)) | |
| if use_cxx23: | |
| def_file += "_cxx23" | |
| def_file += ".def" | |
| with open(def_file, 'w', newline='') as f: | |
| f.write('EXPORTS\n') | |
| for s in sorted(absl_symbols): | |
| f.write(' {}\n'.format(s)) | |
| logging.info('[%s - %s] .def file successfully generated.', cpu, flavor) | |
| def _GenerateDefFile(chromium_dir, | |
| cpu, | |
| is_debug, | |
| use_cxx23, | |
| extra_gn_args=[], | |
| suffix=None): | |
| """Generates a .def file for the absl component build on the specified CPU.""" | |
| with tempfile.TemporaryDirectory( | |
| dir=os.path.join(chromium_dir, 'out')) as out_dir: | |
| _GenerateDefFileBuild(cpu, is_debug, use_cxx23, extra_gn_args, suffix, | |
| out_dir, chromium_dir) | |
| # Hack, it looks like there is a race in the directory cleanup. | |
| time.sleep(10) | |
| def generate_all(chromium_dir): | |
| for use_cxx23 in (True, False): | |
| _GenerateDefFile(chromium_dir, 'x64', False, use_cxx23, | |
| ['is_asan = true'], 'asan') | |
| for arch in ('x86', 'x64', 'arm64'): | |
| for is_debug in (True, False): | |
| _GenerateDefFile(chromium_dir, arch, is_debug, use_cxx23) | |
| if __name__ == '__main__': | |
| logging.getLogger().setLevel(logging.INFO) | |
| chromium_dir = os.getcwd() | |
| if not chromium_dir.endswith('src') or not os.path.exists( | |
| 'chrome/browser'): | |
| logging.error('Run this script from a chromium/src/ directory.') | |
| exit(1) | |
| generate_all(chromium_dir) |