blob: a96d5c4fee1b579b382da7a423823006a609a5ee [file] [log] [blame]
# Copyright 2018 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
from . import util
def build_command_buffer(api, chrome_dir, skia_dir, out):
api.run(api.python, 'build command_buffer',
script=skia_dir.join('tools', 'build_command_buffer.py'),
args=[
'--chrome-dir', chrome_dir,
'--output-dir', out,
'--extra-gn-args', 'mac_sdk_min="10.13"',
'--no-sync', '--no-hooks', '--make-output-dir'])
def compile_swiftshader(api, extra_tokens, swiftshader_root, cc, cxx, out):
"""Build SwiftShader with CMake.
Building SwiftShader works differently from any other Skia third_party lib.
See discussion in skia:7671 for more detail.
Args:
swiftshader_root: root of the SwiftShader checkout.
cc, cxx: compiler binaries to use
out: target directory for libEGL.so and libGLESv2.so
"""
swiftshader_opts = [
'-DSWIFTSHADER_BUILD_TESTS=OFF',
'-DSWIFTSHADER_WARNINGS_AS_ERRORS=OFF',
'-DREACTOR_ENABLE_MEMORY_SANITIZER_INSTRUMENTATION=OFF', # Way too slow.
]
cmake_bin = str(api.vars.workdir.join('cmake_linux', 'bin'))
env = {
'CC': cc,
'CXX': cxx,
'PATH': '%%(PATH)s:%s' % cmake_bin,
# We arrange our MSAN/TSAN prebuilts a little differently than
# SwiftShader's CMakeLists.txt expects, so we'll just keep our custom
# setup (everything mentioning libcxx below) and point SwiftShader's
# CMakeLists.txt at a harmless non-existent path.
'SWIFTSHADER_MSAN_INSTRUMENTED_LIBCXX_PATH': '/totally/phony/path',
}
# Extra flags for MSAN/TSAN, if necessary.
san = None
if 'MSAN' in extra_tokens:
san = ('msan','memory')
elif 'TSAN' in extra_tokens:
san = ('tsan','thread')
if san:
short,full = san
clang_linux = str(api.vars.workdir.join('clang_linux'))
libcxx = clang_linux + '/' + short
cflags = ' '.join([
'-fsanitize=' + full,
'-stdlib=libc++',
'-L%s/lib' % libcxx,
'-lc++abi',
'-I%s/include' % libcxx,
'-I%s/include/c++/v1' % libcxx,
])
swiftshader_opts.extend([
'-DSWIFTSHADER_{}=ON'.format(short.upper()),
'-DCMAKE_C_FLAGS=%s' % cflags,
'-DCMAKE_CXX_FLAGS=%s' % cflags,
])
# Build SwiftShader.
api.file.ensure_directory('makedirs swiftshader_out', out)
with api.context(cwd=out, env=env):
api.run(api.step, 'swiftshader cmake',
cmd=['cmake'] + swiftshader_opts + [swiftshader_root, '-GNinja'])
api.run(api.step, 'swiftshader ninja',
cmd=['ninja', '-C', out, 'libEGL.so', 'libGLESv2.so'])
def compile_fn(api, checkout_root, out_dir):
skia_dir = checkout_root.join('skia')
compiler = api.vars.builder_cfg.get('compiler', '')
configuration = api.vars.builder_cfg.get('configuration', '')
extra_tokens = api.vars.extra_tokens
os = api.vars.builder_cfg.get('os', '')
target_arch = api.vars.builder_cfg.get('target_arch', '')
clang_linux = str(api.vars.workdir.join('clang_linux'))
win_toolchain = str(api.vars.workdir.join('win_toolchain'))
cc, cxx, ccache = None, None, None
extra_cflags = []
extra_ldflags = []
args = {'werror': 'true'}
env = {}
if os == 'Mac':
# XCode build is listed in parentheses after the version at
# https://developer.apple.com/news/releases/, or on Wikipedia here:
# https://en.wikipedia.org/wiki/Xcode#Version_comparison_table
# Use lowercase letters.
# https://chrome-infra-packages.appspot.com/p/infra_internal/ios/xcode
XCODE_BUILD_VERSION = '12c33'
if compiler == 'Xcode11.4.1':
XCODE_BUILD_VERSION = '11e503a'
extra_cflags.append(
'-DREBUILD_IF_CHANGED_xcode_build_version=%s' % XCODE_BUILD_VERSION)
mac_toolchain_cmd = api.vars.workdir.join(
'mac_toolchain', 'mac_toolchain')
xcode_app_path = api.vars.cache_dir.join('Xcode.app')
# Copied from
# https://chromium.googlesource.com/chromium/tools/build/+/e19b7d9390e2bb438b566515b141ed2b9ed2c7c2/scripts/slave/recipe_modules/ios/api.py#322
with api.step.nest('ensure xcode') as step_result:
step_result.presentation.step_text = (
'Ensuring Xcode version %s in %s' % (
XCODE_BUILD_VERSION, xcode_app_path))
install_xcode_cmd = [
mac_toolchain_cmd, 'install',
# "ios" is needed for simulator builds
# (Build-Mac-Clang-x64-Release-iOS).
'-kind', 'ios',
'-xcode-version', XCODE_BUILD_VERSION,
'-output-dir', xcode_app_path,
]
api.step('install xcode', install_xcode_cmd)
api.step('select xcode', [
'sudo', 'xcode-select', '-switch', xcode_app_path])
if 'iOS' in extra_tokens:
# Can't compile for Metal before 11.0.
env['IPHONEOS_DEPLOYMENT_TARGET'] = '11.0'
else:
# We have some bots on 10.13.
env['MACOSX_DEPLOYMENT_TARGET'] = '10.13'
if 'CheckGeneratedFiles' in extra_tokens:
compiler = 'Clang'
args['skia_compile_processors'] = 'true'
args['skia_compile_sksl_tests'] = 'true'
args['skia_generate_workarounds'] = 'true'
# ccache + clang-tidy.sh chokes on the argument list.
if (api.vars.is_linux or os == 'Mac' or os == 'Mac10.15.5' or os == 'Mac10.15.7') and 'Tidy' not in extra_tokens:
if api.vars.is_linux:
ccache = api.vars.workdir.join('ccache_linux', 'bin', 'ccache')
# As of 2020-02-07, the sum of each Debian10-Clang-x86
# non-flutter/android/chromebook build takes less than 75G cache space.
env['CCACHE_MAXSIZE'] = '75G'
else:
ccache = api.vars.workdir.join('ccache_mac', 'bin', 'ccache')
# As of 2020-02-10, the sum of each Build-Mac-Clang- non-android build
# takes ~30G cache space.
env['CCACHE_MAXSIZE'] = '50G'
args['cc_wrapper'] = '"%s"' % ccache
env['CCACHE_DIR'] = api.vars.cache_dir.join('ccache')
env['CCACHE_MAXFILES'] = '0'
# Compilers are unpacked from cipd with bogus timestamps, only contribute
# compiler content to hashes. If Ninja ever uses absolute paths to changing
# directories we'll also need to set a CCACHE_BASEDIR.
env['CCACHE_COMPILERCHECK'] = 'content'
if compiler == 'Clang' and api.vars.is_linux:
cc = clang_linux + '/bin/clang'
cxx = clang_linux + '/bin/clang++'
extra_cflags .append('-B%s/bin' % clang_linux)
extra_ldflags.append('-B%s/bin' % clang_linux)
extra_ldflags.append('-fuse-ld=lld')
extra_cflags.append('-DPLACEHOLDER_clang_linux_version=%s' %
api.run.asset_version('clang_linux', skia_dir))
if 'Static' in extra_tokens:
extra_ldflags.extend(['-static-libstdc++', '-static-libgcc'])
elif compiler == 'Clang':
cc, cxx = 'clang', 'clang++'
if 'Tidy' in extra_tokens:
# Swap in clang-tidy.sh for clang++, but update PATH so it can find clang++.
cxx = skia_dir.join("tools/clang-tidy.sh")
env['PATH'] = '%s:%%(PATH)s' % (clang_linux + '/bin')
# Increase ClangTidy code coverage by enabling features.
args.update({
'skia_enable_fontmgr_empty': 'true',
'skia_enable_pdf': 'true',
'skia_use_expat': 'true',
'skia_use_freetype': 'true',
'skia_use_vulkan': 'true',
})
if 'Coverage' in extra_tokens:
# See https://clang.llvm.org/docs/SourceBasedCodeCoverage.html for
# more info on using llvm to gather coverage information.
extra_cflags.append('-fprofile-instr-generate')
extra_cflags.append('-fcoverage-mapping')
extra_ldflags.append('-fprofile-instr-generate')
extra_ldflags.append('-fcoverage-mapping')
if compiler != 'MSVC' and configuration == 'Debug':
extra_cflags.append('-O1')
if 'Exceptions' in extra_tokens:
extra_cflags.append('/EHsc')
if 'Fast' in extra_tokens:
extra_cflags.extend(['-march=native', '-fomit-frame-pointer', '-O3',
'-ffp-contract=off'])
if len(extra_tokens) == 1 and extra_tokens[0].startswith('SK'):
extra_cflags.append('-D' + extra_tokens[0])
# If we're limiting Skia at all, drop skcms to portable code.
if 'SK_CPU_LIMIT' in extra_tokens[0]:
extra_cflags.append('-DSKCMS_PORTABLE')
if 'MSAN' in extra_tokens:
extra_ldflags.append('-L' + clang_linux + '/msan')
elif 'TSAN' in extra_tokens:
extra_ldflags.append('-L' + clang_linux + '/tsan')
elif api.vars.is_linux:
extra_ldflags.append('-L' + clang_linux + '/lib')
if configuration != 'Debug':
args['is_debug'] = 'false'
if 'Dawn' in extra_tokens:
args['skia_use_dawn'] = 'true'
args['skia_use_gl'] = 'false'
# Dawn imports jinja2, which imports markupsafe. Along with DEPS, make it
# importable.
env['PYTHONPATH'] = api.path.pathsep.join([
str(skia_dir.join('third_party', 'externals')), '%%(PYTHONPATH)s'])
if 'ANGLE' in extra_tokens:
args['skia_use_angle'] = 'true'
if 'SwiftShader' in extra_tokens:
swiftshader_root = skia_dir.join('third_party', 'externals', 'swiftshader')
swiftshader_out = out_dir.join('swiftshader_out')
compile_swiftshader(api, extra_tokens, swiftshader_root, cc, cxx, swiftshader_out)
args['skia_use_egl'] = 'true'
extra_cflags.extend([
'-DGR_EGL_TRY_GLES3_THEN_GLES2',
'-I%s' % skia_dir.join(
'third_party', 'externals', 'egl-registry', 'api'),
'-I%s' % skia_dir.join(
'third_party', 'externals', 'opengl-registry', 'api'),
])
extra_ldflags.extend([
'-L%s' % swiftshader_out,
])
if 'CommandBuffer' in extra_tokens:
# CommandBuffer runs against GLES version of CommandBuffer also, so
# include both.
args.update({
'skia_gl_standard': '""',
})
chrome_dir = checkout_root
api.run.run_once(build_command_buffer, api, chrome_dir, skia_dir, out_dir)
if 'MSAN' in extra_tokens:
args['skia_use_fontconfig'] = 'false'
if 'ASAN' in extra_tokens:
args['skia_enable_spirv_validation'] = 'false'
if 'NoDEPS' in extra_tokens:
args.update({
'is_official_build': 'true',
'skia_enable_fontmgr_empty': 'true',
'skia_enable_gpu': 'true',
'skia_enable_pdf': 'false',
'skia_use_expat': 'false',
'skia_use_freetype': 'false',
'skia_use_harfbuzz': 'false',
'skia_use_libjpeg_turbo_decode': 'false',
'skia_use_libjpeg_turbo_encode': 'false',
'skia_use_libpng_decode': 'false',
'skia_use_libpng_encode': 'false',
'skia_use_libwebp_decode': 'false',
'skia_use_libwebp_encode': 'false',
'skia_use_vulkan': 'false',
'skia_use_zlib': 'false',
})
if 'Shared' in extra_tokens:
args['is_component_build'] = 'true'
if 'Vulkan' in extra_tokens and not 'Android' in extra_tokens:
args['skia_use_vulkan'] = 'true'
args['skia_enable_vulkan_debug_layers'] = 'true'
args['skia_use_gl'] = 'false'
if 'Direct3D' in extra_tokens:
args['skia_use_direct3d'] = 'true'
args['skia_use_gl'] = 'false'
if 'Metal' in extra_tokens:
args['skia_use_metal'] = 'true'
args['skia_use_gl'] = 'false'
if 'iOS' in extra_tokens:
# Bots use Chromium signing cert.
args['skia_ios_identity'] = '".*GS9WA.*"'
# Get mobileprovision via the CIPD package.
args['skia_ios_profile'] = '"%s"' % api.vars.workdir.join(
'provisioning_profile_ios',
'Upstream_Testing_Provisioning_Profile.mobileprovision')
if compiler == 'Clang' and 'Win' in os:
args['clang_win'] = '"%s"' % api.vars.workdir.join('clang_win')
extra_cflags.append('-DPLACEHOLDER_clang_win_version=%s' %
api.run.asset_version('clang_win', skia_dir))
sanitize = ''
for t in extra_tokens:
if t.endswith('SAN'):
sanitize = t
if api.vars.is_linux and t == 'ASAN':
# skia:8712 and skia:8713
extra_cflags.append('-DSK_ENABLE_SCOPED_LSAN_SUPPRESSIONS')
if 'SafeStack' in extra_tokens:
assert sanitize == ''
sanitize = 'safe-stack'
if 'Wuffs' in extra_tokens:
args['skia_use_wuffs'] = 'true'
for (k,v) in {
'cc': cc,
'cxx': cxx,
'sanitize': sanitize,
'target_cpu': target_arch,
'target_os': 'ios' if 'iOS' in extra_tokens else '',
'win_sdk': win_toolchain + '/win_sdk' if 'Win' in os else '',
'win_vc': win_toolchain + '/VC' if 'Win' in os else '',
}.iteritems():
if v:
args[k] = '"%s"' % v
if extra_cflags:
args['extra_cflags'] = repr(extra_cflags).replace("'", '"')
if extra_ldflags:
args['extra_ldflags'] = repr(extra_ldflags).replace("'", '"')
gn_args = ' '.join('%s=%s' % (k,v) for (k,v) in sorted(args.iteritems()))
gn = skia_dir.join('bin', 'gn')
with api.context(cwd=skia_dir):
api.run(api.python,
'fetch-gn',
script=skia_dir.join('bin', 'fetch-gn'),
infra_step=True)
if 'CheckGeneratedFiles' in extra_tokens:
env['PATH'] = '%s:%%(PATH)s' % skia_dir.join('bin')
api.run(api.python,
'fetch-clang-format',
script=skia_dir.join('bin', 'fetch-clang-format'),
infra_step=True)
with api.env(env):
if ccache:
api.run(api.step, 'ccache stats-start', cmd=[ccache, '-s'])
api.run(api.step, 'gn gen',
cmd=[gn, 'gen', out_dir, '--args=' + gn_args])
api.run(api.step, 'ninja', cmd=['ninja', '-C', out_dir])
if ccache:
api.run(api.step, 'ccache stats-end', cmd=[ccache, '-s'])
def copy_build_products(api, src, dst):
util.copy_listed_files(api, src, dst, util.DEFAULT_BUILD_PRODUCTS)
extra_tokens = api.vars.extra_tokens
os = api.vars.builder_cfg.get('os', '')
if 'SwiftShader' in extra_tokens:
util.copy_listed_files(api,
src.join('swiftshader_out'),
api.vars.swarming_out_dir.join('swiftshader_out'),
util.DEFAULT_BUILD_PRODUCTS)
if os == 'Mac' and any('SAN' in t for t in extra_tokens):
# The XSAN dylibs are in
# Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib
# /clang/11.0.0/lib/darwin, where 11.0.0 could change in future versions.
xcode_clang_ver_dirs = api.file.listdir(
'find XCode Clang version',
api.vars.cache_dir.join(
'Xcode.app', 'Contents', 'Developer', 'Toolchains',
'XcodeDefault.xctoolchain', 'usr', 'lib', 'clang'),
test_data=['11.0.0'])
assert len(xcode_clang_ver_dirs) == 1
dylib_dir = xcode_clang_ver_dirs[0].join('lib', 'darwin')
dylibs = api.file.glob_paths('find xSAN dylibs', dylib_dir,
'libclang_rt.*san_osx_dynamic.dylib',
test_data=[
'libclang_rt.asan_osx_dynamic.dylib',
'libclang_rt.tsan_osx_dynamic.dylib',
'libclang_rt.ubsan_osx_dynamic.dylib',
])
for f in dylibs:
api.file.copy('copy %s' % api.path.basename(f), f, dst)