blob: c3a95017987ae0e45713cb0654c0815830267cdf [file] [log] [blame]
# Copyright 2014 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.
"""Build miscellaneous open sourced components.
All rules in this file must be appropriate for open sourcing. Please avoid
adding rules to this file unless they are rules for the overall project
or for third party directories that can be open sourced.
"""
import os
from src.build import analyze_diffs
from src.build import build_common
from src.build import lint_source
from src.build import ninja_generator
from src.build import ninja_generator_runner
from src.build import open_source
from src.build import staging
from src.build import toolchain
from src.build.build_options import OPTIONS
_ANDROID_SYSTEM_IMAGE_DIR = ('ndk/platforms/android-%d' %
toolchain.get_android_api_level())
def _generate_gtest_ninja(name, instances=0, enable_libcxx=False, host=False):
n = ninja_generator.ArchiveNinjaGenerator(
name, base_path='android/external/chromium_org/testing/gtest/src',
instances=instances,
force_compiler='clang',
enable_cxx11=True,
enable_libcxx=enable_libcxx,
host=host)
n.add_include_paths(staging.as_staging(
'android/external/chromium_org/testing/gtest'))
# To avoid "private field 'pretty_' is not used" on clang.
n.add_compiler_flags('-Wno-unused-private-field')
n.build_default(['gtest-all.cc']).archive()
def _generate_gmock_ninja(name, enable_libcxx=False):
n = ninja_generator.ArchiveNinjaGenerator(
name, base_path='testing/gmock/src',
instances=0, # Not used by shared objects
force_compiler='clang',
enable_cxx11=True,
enable_libcxx=enable_libcxx)
n.add_include_paths(staging.as_staging('testing/gmock'),
staging.as_staging('testing/gmock/include'))
n.build_default(['gmock-all.cc']).archive()
def _generate_test_framework_ninjas():
# Build two versions of libgtest and libgmock that are built and linked with
# STLport or libc++. It is used to build tests that depends on each library.
_generate_gtest_ninja('libgtest', enable_libcxx=False)
if not OPTIONS.run_tests():
gtest_libcxx_instances = 0
else:
# libart-gtest.so, libarttest.so, and libnativebridgetest.so uses
# libgtest_libc++.a. But when --disable-debug-code is specified,
# libart-gtest.so is not built.
if OPTIONS.is_debug_code_enabled():
gtest_libcxx_instances = 3
else:
gtest_libcxx_instances = 2
_generate_gtest_ninja('libgtest_libc++',
instances=gtest_libcxx_instances, enable_libcxx=True)
# libartd.so for host uses libgtest_host.a. Although it is built with
# libc++, it is not named libgtest_libc++_host.a by Android.mk.
if OPTIONS.is_debug_code_enabled():
_generate_gtest_ninja('libgtest_host', host=True, enable_libcxx=True)
_generate_gmock_ninja('libgmock', enable_libcxx=False)
_generate_gmock_ninja('libgmock_libc++', enable_libcxx=True)
def _generate_breakpad_ninja():
allowed_dirs = ['common', 'linux', 'dwarf']
n = ninja_generator.ArchiveNinjaGenerator(
'libbreakpad_common',
base_path='breakpad/src/common',
host=True)
n.add_include_paths('breakpad/src')
# 19 files in breakpad includes "third_party/lss/linux_syscall_support.h".
# We use -idirafter instead of the normal -I. third_party/.. is the top
# directory of ARC and developers may put some files whose name
# conflicts with standard headers. For example, if one puts "new" at the
# top of ARC source tree, ARC will not build if we use -I here.
n.add_compiler_flags('-idirafter', 'third_party/..')
n.add_cxx_flags('-frtti') # Breakpad uses RTTI.
n.add_defines('HAVE_A_OUT_H')
all_sources = n.find_all_sources()
all_sources = [s for s in all_sources if not s.endswith('test.cc')]
all_sources = [
s for s in all_sources
if not os.path.basename(os.path.dirname(s)) not in allowed_dirs]
n.build_default(all_sources, base_path=None).archive()
for tool, directory_name, cc in [
['symupload', 'symupload', 'sym_upload.cc'],
['dump_syms', 'dump_syms', 'dump_syms.cc'],
['minidump-2-core-x86-64', 'md2core', 'minidump-2-core.cc']]:
n = ninja_generator.ExecNinjaGenerator(
tool, host=True,
base_path='breakpad/src/tools/linux/' + directory_name)
n.add_include_paths('breakpad/src')
# Workaround for third_party/lss/linux_syscall_support.h
n.add_compiler_flags('-idirafter', 'third_party/..')
n.add_library_deps('libbreakpad_common.a')
n.build_default([cc]).link()
def _generate_lint_test_ninjas():
n = ninja_generator.NinjaGenerator('analyze_diffs_test')
script = 'src/build/analyze_diffs.py'
n.rule('analyze_diffs_test_fail',
command=('if %s --under_test $in > $output_path 2>&1; then '
' echo "Expected failure, but there was none"; exit 1; '
'else '
' if ! diff $output_path $in.fail > $out; then '
' echo "Differences from expected errors:"; '
' cat $out; '
' rm -f $out; '
' echo "To update: cp $output_path $in.fail"; '
' exit 1; '
' fi; '
'fi' % script),
description='analyze_diffs_test_fail $in')
n.rule('analyze_diffs_test_success',
command=('if ! %s --under_test $in > $output_path 2>&1; then '
' echo "Unexpected failure"; cat $output_path; exit 1; '
'elif [ -s $output_path ]; then '
' echo "Succeeded but had unexpected output:"; '
' cat $output_path; '
' exit 1; '
'else '
' touch $out; '
'fi' % script),
description='analyze_diffs_test_success $in')
all_mods = build_common.find_all_files([staging.TESTS_MODS_PATH],
include_tests=True)
out_dir = os.path.join(build_common.get_target_common_dir(),
'analyze_diff_tests')
for f in all_mods:
no_ext = os.path.splitext(f)[0]
no_ext_relative = os.path.relpath(no_ext, staging.TESTS_MODS_PATH)
out_path = os.path.join(out_dir, no_ext_relative)
output_path = out_path + '.output'
results_path = out_path + '.results'
variables = {'output_path': output_path}
rule = None
if f.endswith('.fail'):
rule = 'analyze_diffs_test_fail'
elif f.endswith('.success'):
rule = 'analyze_diffs_test_success'
if rule is not None:
n.build(results_path, rule, no_ext, variables=variables,
implicit=[script], use_staging=False)
def _generate_checkdeps_ninjas():
if open_source.is_open_source_repo():
# Do not run checkdeps on the open source repo since some directories
# checked are not included there.
return
n = ninja_generator.NinjaGenerator('checkdeps', target_groups=['lint'])
checkdeps_script = staging.as_staging(
'native_client/tools/checkdeps/checkdeps.py')
n.rule('checkdeps',
command=('%s -v --root=$root $in_dir > $out.tmp 2>&1 '
'&& mv $out.tmp $out '
'|| (cat $out.tmp; rm $out.tmp; exit 1)' % checkdeps_script),
description='checkdeps $in_dir')
# Detect bad #include lines in src/.
# TODO(crbug.com/323786): Check #include lines in mods/ too.
src_dir = os.path.join(build_common.get_arc_root(), 'src')
src_deps = os.path.join(src_dir, 'DEPS')
for d in ['common', 'ndk_translation', 'posix_translation']:
# TODO(crbug.com/323786): Check other directories in src/ too.
implicit = build_common.find_all_files(
os.path.join(src_dir, d),
suffixes=['h', 'c', 'cc', 'cpp', 'java', 'DEPS'],
include_tests=True, use_staging=False)
implicit.extend([checkdeps_script, src_deps])
out = os.path.join(build_common.OUT_DIR, 'checkdeps_%s.txt' % d)
n.build(out, 'checkdeps', [],
variables={'root': src_dir, 'in_dir': d},
implicit=implicit)
def _generate_lint_ninjas():
n = ninja_generator.NinjaGenerator('lint', target_groups=['lint'])
lint_script = 'src/build/lint_source.py'
analyze_diffs_script = 'src/build/analyze_diffs.py'
ignore = 'src/build/lint_ignore.txt'
implicit_base = [analyze_diffs_script, lint_script, ignore]
n.rule('lint', command=('%s -i %s -o $out $in' % (lint_script, ignore)),
description='lint $out')
n.rule('lint_merge', command='%s --merge -o $out @$out.rsp' % lint_script,
rspfile='$out.rsp',
rspfile_content='$in_newline',
description='lint --merge $out')
files = lint_source.get_all_files_to_check()
results = []
for f in files:
with ninja_generator.open_dependency(f, 'r',
ignore_dependency=True) as source_file:
tracking_path = analyze_diffs.compute_tracking_path(None, f, source_file)
implicit = implicit_base[:]
if tracking_path:
implicit.append(tracking_path)
out = os.path.join(build_common.OUT_DIR, 'lint', f + '.result')
n.build(out, 'lint', f, implicit=implicit, use_staging=False)
results.append(out)
out = os.path.join(build_common.OUT_DIR, 'lint_results.txt')
n.build(out, 'lint_merge', results, implicit=implicit_base, use_staging=False)
def _generate_disallowed_symbols_ninja():
n = ninja_generator.NinjaGenerator('disallowed_symbols')
out_path = os.path.join(build_common.get_build_dir(),
'gen_symbols', 'disallowed_symbols.defined')
n.build([out_path], 'copy_symbols_file', 'src/build/disallowed_symbols.txt',
implicit='src/build/symbol_tool.py')
def generate_binaries_depending_ninjas(_):
if (not OPTIONS.is_bare_metal_i686() or
not OPTIONS.is_optimized_build() or
# None of the targets analyzed are currently built in the open source
# repository.
open_source.is_open_source_repo() or
# Run the checker only when --disable-debug-code is specified. Locations
# of static initializers differ depending on the debug-code option.
OPTIONS.is_debug_code_enabled() or
# The checker only works with debug symbols.
not OPTIONS.is_debug_info_enabled()):
# The static analysis tool's output varies between debug and non-debug
# builds, so we pick non-debug as the default.
return
n = ninja_generator.NinjaGenerator('analyze_static_initializers')
script = staging.as_staging(
'android/external/chromium_org/tools/linux/dump-static-initializers.py')
n.rule('analyze_static_initializers',
command=('python src/build/run_python %s -d $in | head --lines=-1 | '
'egrep -ve \'^# .*\.cpp \' |'
'sed -e \'s/ T\.[0-9]*/ T.XXXXX/\' |'
'diff -u $expect - && touch $out' %
script),
description='analyze_static_initializers $in')
libraries = build_common.CHECKED_LIBRARIES
libraries_fullpath = [
os.path.join(build_common.get_load_library_path(), lib)
for lib in libraries]
for library in zip(libraries, libraries_fullpath):
# You can manually update the text files by running
# src/build/update_static_initializer_expectations.py.
expect = 'src/build/dump-static-initializers-%s-expected.txt' % library[0]
result_path = os.path.join(build_common.get_build_dir(),
'dump_static_initializers',
'dump_static_initializers.%s.result' %
library[0])
n.build(result_path, 'analyze_static_initializers', library[1],
variables={'out': result_path, 'expect': expect},
# Add |libraries_fullpath| to implicit= not to run the analyzer
# script until all libraries in |libraries_fullpath| become ready.
# This makes it easy to use
# update_static_initializer_expectations.py especially when you
# remove global variables from two or more libraries at the same
# time.
implicit=[script, expect] + libraries_fullpath)
def _generate_check_symbols_ninja():
# If we do not use NDK direct execution, the compatibility is less
# important.
if not build_common.use_ndk_direct_execution():
return
n = ninja_generator.NinjaGenerator('check_symbols')
script = staging.as_staging('src/build/check_symbols.py')
rule_name = 'check_symbols'
n.rule(rule_name,
command=('src/build/run_python %s $android_lib $in %s' % (
script, build_common.get_test_output_handler())),
description=(rule_name + ' $in'))
if OPTIONS.is_arm():
arch_subdir = 'arch-arm'
else:
arch_subdir = 'arch-x86'
lib_dir = os.path.join(_ANDROID_SYSTEM_IMAGE_DIR, arch_subdir, 'usr/lib')
for so_file in build_common.find_all_files(lib_dir, suffixes='.so'):
lib_name = os.path.basename(so_file)
if lib_name not in ['libc.so', 'libdl.so', 'libm.so']:
# For now, we only check Bionic.
# TODO(crbug.com/408548): Extend this for other libraries.
continue
result_path = os.path.join(build_common.get_build_dir(),
'check_symbols',
'check_symbols.%s.result' % lib_name)
n.build(result_path, rule_name,
build_common.get_build_path_for_library(lib_name),
variables={'android_lib': staging.as_staging(so_file)},
implicit=[script, staging.as_staging(so_file)])
def generate_ninjas():
ninja_generator_runner.request_run_in_parallel(
_generate_breakpad_ninja,
_generate_check_symbols_ninja,
_generate_checkdeps_ninjas,
_generate_disallowed_symbols_ninja,
_generate_lint_ninjas,
_generate_test_framework_ninjas)
def generate_test_ninjas():
if not open_source.is_open_source_repo():
# expected_driver_times_test.py and run_integration_tests_test.py have extra
# implicit dependencies, so generate the ninja for them separately.
test_list_paths = [build_common.get_all_integration_test_lists_path(),
build_common.get_all_unittest_info_path()]
implicit_map = dict.fromkeys(
['src/build/cts/expected_driver_times_test.py',
'src/build/run_integration_tests_test.py'],
test_list_paths)
ninja_generator.generate_python_test_ninjas_for_path(
'src/build',
implicit_map=implicit_map,
exclude='perf_test.py')
ninja_generator_runner.request_run_in_parallel(
_generate_lint_test_ninjas)