blob: 84a56c13547417dac26f60f99955edba493dbfdf [file] [log] [blame]
# Copyright 2019 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Script to emit runtimes.json for Clang toolchain"""
import argparse
import collections
import json
import os
import re
import subprocess
import sys
def read_build_id(readelf, filename):
p = subprocess.Popen([readelf, '-n', filename],
stdout=subprocess.PIPE,
env={'LC_ALL': 'C'})
stdout, _ = p.communicate()
if p.returncode != 0:
raise Exception('failed to read notes')
match = re.search(r'Build ID: ([a-zA-Z0-9_-]+)', stdout)
if not match:
raise Exception('build ID missing')
return match.group(1)
def generate_entry(dirname, readelf, soname, filename):
build_id = read_build_id(
readelf, os.path.realpath(os.path.join(dirname, 'lib', filename)))
return {
'soname': soname,
'dist': filename,
'debug': 'debug/.build-id/%s/%s.debug' % (build_id[0:2], build_id[2:])
}
Target = collections.namedtuple('Target', ['triple', 'aliases'])
class TargetAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
targets = getattr(namespace, 'target')
targets.append(Target(triple=values, aliases=[]))
class AliasAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
targets = getattr(namespace, 'target')
if not targets:
raise argparse.ArgumentError(self, 'missing --target')
targets[-1].aliases.append(values)
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--dir', default=os.getcwd(), help='Clang directory')
parser.add_argument(
'--readelf', required=True, help='path to readelf utility')
parser.add_argument(
'--resource-dir', required=True, help='Clang resource directory')
parser.add_argument(
'--manifest',
action='store_const',
const=True,
default=False,
help='Emit old manifest format instead of JSON')
parser.add_argument(
'--target',
metavar='TRIPLE',
default=[],
action=TargetAction,
help='--target=TRIPLE values to support')
parser.add_argument(
'--alias',
metavar='TRIPLE',
action=AliasAction,
help='--target=TRIPLE alias, applies to preceding --target')
args = parser.parse_args()
runtimes = []
for target in args.target:
runtime_dir = '{resource_dir}/lib/{target}'.format(
resource_dir=args.resource_dir, target=target.triple)
cxx_lib_dir = '{target}/c++'.format(target=target.triple)
manifest = {}
for mode_ldflags in [[], ['-static-libstdc++']]:
for mode_cflags, mode_multilib, mode_runtimes in [
([], '', []),
(['-fsanitize=address'], 'asan/', ['libclang_rt.asan.so']),
(['-fsanitize=undefined'], '', ['libclang_rt.ubsan_standalone.so']),
]:
runtime = [
generate_entry(args.dir, args.readelf, soname,
runtime_dir + '/' + soname)
for soname in mode_runtimes
]
for lib in runtime:
manifest['lib/' + lib['soname']] = lib['dist']
if not mode_ldflags:
cxx_lib = [
generate_entry(args.dir, args.readelf, soname,
cxx_lib_dir + '/' + mode_multilib + soname)
for soname in ['libc++.so.2', 'libc++abi.so.1', 'libunwind.so.1']
]
runtime.extend(cxx_lib)
for lib in cxx_lib:
manifest['lib/' + mode_multilib + lib['soname']] = lib['dist']
runtimes.append({
'target': [target.triple] + target.aliases,
'cflags': mode_cflags,
'ldflags': mode_ldflags,
'runtime': runtime,
})
if args.manifest:
sys.stdout.write(''.join(
sorted('%s=%s\n' % x for x in manifest.iteritems())))
else:
json.dump(runtimes, sys.stdout, indent=2, sort_keys=True)
return 0
if __name__ == '__main__':
sys.exit(main())