blob: bc1efaa6e533f09d77965891f75f32c2540490d8 [file] [log] [blame]
#!/usr/bin/env python
#
# 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.
#
import os
import re
import string
import build_common
import make_to_ninja
import ninja_generator
import ninja_generator_runner
import open_source
import staging
import toolchain
from build_options import OPTIONS
from make_to_ninja import MakefileNinjaTranslator
_LOADER_TEXT_SECTION_START_ADDRESS = '0x20000'
_ARM_ASM_FILES = [
# TODO(crbug.com/446400): L-rebase: Choose better optimized versions
# of string functions.
# 'android/bionic/libc/arch-arm/bionic/memcmp.S',
# 'android/bionic/libc/arch-arm/bionic/memcpy.S',
'android/bionic/libc/arch-arm/generic/bionic/memset.S',
]
_I686_ASM_FILES = [
# Note: bzero internally uses memset. These should be enabled or disabled
# as a pair.
# 'android/bionic/libc/arch-x86/atom/string/sse2-memset-atom.S',
# 'android/bionic/libc/arch-x86/atom/string/sse2-bzero-atom.S',
'android/bionic/libc/arch-x86/atom/string/sse2-strchr-atom.S',
# For saving register context for waiting threads.
'android/bionic/libc/arch-x86/bionic/save_reg_context.S',
]
# The list of libc modules linked to the linker.
_LINKER_MODULES = [
'libc_aeabi', # __aeabi_memcpy etc.
'libc_bionic', # logging functions
'libc_common',
'libc_openbsd', # strcmp, strcpy, exit etc.
]
def _add_bare_metal_flags_to_make_to_ninja_vars(vars):
if ((vars.is_c_library() or vars.is_executable()) and
OPTIONS.is_bare_metal_build()):
vars.get_asmflags().append('-DBARE_METAL_BIONIC')
vars.get_cflags().append('-DBARE_METAL_BIONIC')
vars.get_cxxflags().append('-DBARE_METAL_BIONIC')
def _add_bare_metal_flags_to_ninja_generator(n):
if OPTIONS.is_bare_metal_build():
n.add_defines('BARE_METAL_BIONIC')
def _get_gen_source_dir():
return ninja_generator.NaClizeNinjaGenerator.get_gen_source_dir('bionic')
def _get_gen_source_stamp():
return ninja_generator.NaClizeNinjaGenerator.get_gen_source_stamp('bionic')
def _get_asm_source(f):
# For NaCl, we need to use naclized version of aseembly code.
if OPTIONS.is_nacl_build():
f = os.path.join(_get_gen_source_dir(), os.path.basename(f))
return f
def _remove_assembly_source(sources):
asm_sources = filter(lambda s: s.endswith('.S'), sources)
for asm in asm_sources:
sources.remove(asm)
def _get_crt_cc():
if OPTIONS.is_nacl_build():
return toolchain.get_tool(OPTIONS.target(), 'clang')
else:
return toolchain.get_tool(OPTIONS.target(), 'cc')
def _get_crt_cxx():
if OPTIONS.is_nacl_build():
return toolchain.get_tool(OPTIONS.target(), 'clangxx')
else:
return toolchain.get_tool(OPTIONS.target(), 'cxx')
def _generate_naclized_i686_asm_ninja():
if not OPTIONS.is_nacl_i686():
return
n = ninja_generator.NaClizeNinjaGenerator('bionic')
n.generate(_I686_ASM_FILES)
def _filter_libc_common_for_arm(vars, sources):
for f in _ARM_ASM_FILES:
sources.append(_get_asm_source(f))
if OPTIONS.is_bare_metal_build():
# For direct syscalls used internally.
sources.append('android/bionic/libc/arch-arm/bionic/syscall.S')
else:
# Generated assembly files are included from other assembly file.
# So, we need to make additional dependency by using a stamp file.
# Order-only dependency should be sufficient for this case
# because all dependencies should be handled properly once .d
# files are generated. However, we have a strict check for
# order-only dependencies (see NinjaGenerator._check_deps)
# so we use implicit dependencies here for now. As we do not
# update assembly code often, this will not harm our iteration
# cycle much.
# TODO(crbug.com/318433): Use order-only dependencies.
vars.get_implicit_deps().append(_get_gen_source_stamp())
def _filter_libc_common_for_i686(vars, sources):
for f in _I686_ASM_FILES:
sources.append(_get_asm_source(f))
if OPTIONS.is_nacl_i686():
# Assembly code requires cache.h.
vars.get_includes().append('android/bionic/libc/arch-x86/atom/string')
if OPTIONS.is_bare_metal_build():
# For direct syscalls used internally.
sources.append('android/bionic/libc/arch-x86/bionic/syscall.S')
else:
# See the comment in _filter_libc_common_for_arm.
# TODO(crbug.com/318433): Use order-only dependencies.
vars.get_implicit_deps().append(_get_gen_source_stamp())
# It seems newlib's memset is slightly faster than the
# assembly implementation (0.16[sec/GB] vs 0.19[sec/GB]).
sources.append('nacl-newlib/newlib/libc/string/memset.c')
sources.append('android/bionic/libc/string/bzero.c')
# TODO(crbug.com/268485): Confirm ARC can ignore non-SSSE3 x86 devices
vars.get_cflags().append('-DUSE_SSSE3=1')
def _filter_libc_common_for_x86_64(vars, sources):
sources.extend([
'android/bionic/libc/arch-nacl/bionic/nacl_read_tp.c',
# TODO(crbug.com/446400): L-rebase: Enable assembly versions.
'android/bionic/libc/string/bzero.c',
'android/bionic/libc/bionic/time64.c',
# Newlib's memset is much faster than Bionic's
# memset.c. (0.13[sec/GB] vs 0.51[sec/GB])
'nacl-newlib/newlib/libc/string/memset.c',
# As we support ARM NDKs even on NaCl x86-64, we provide legacy
# APIs.
'android/bionic/libc/bionic/legacy_32_bit_support.cpp'])
sources.append('android/bionic/libc/arch-x86_64/bionic/save_reg_context.S')
def _remove_unnecessary_defines(vars):
"""Cleans up unnecessary C/C++ defines."""
# We always use hard-float.
vars.remove_c_or_cxxflag('-DSOFTFLOAT')
# Remove debug related macros since they should be controlled by
# ./configure.
vars.remove_c_or_cxxflag('-DNDEBUG')
vars.remove_c_or_cxxflag('-UDEBUG')
def _filter_libc_common(vars):
sources = vars.get_sources()
_remove_assembly_source(sources)
# libc_common is used from both the loader and libc.so. Functions
# which are necessary for the bionic loader must be in this list.
sources.extend([
# TODO(crbug.com/243244): If possible, move arch-nacl/ files into a
# separate archive and build them with -Werror.
'android/bionic/libc/arch-nacl/bionic/__set_tls.c',
'android/bionic/libc/arch-nacl/bionic/clone.cpp',
'android/bionic/libc/arch-nacl/syscalls/__exit.cpp',
'android/bionic/libc/arch-nacl/syscalls/__getcwd.c',
'android/bionic/libc/arch-nacl/syscalls/__getdents64.c',
'android/bionic/libc/arch-nacl/syscalls/__openat.c',
'android/bionic/libc/arch-nacl/syscalls/_exit.c',
'android/bionic/libc/arch-nacl/syscalls/clock_getres.c',
'android/bionic/libc/arch-nacl/syscalls/clock_gettime.c',
'android/bionic/libc/arch-nacl/syscalls/close.c',
'android/bionic/libc/arch-nacl/syscalls/dup.c',
'android/bionic/libc/arch-nacl/syscalls/dup2.c',
'android/bionic/libc/arch-nacl/syscalls/enosys.c',
'android/bionic/libc/arch-nacl/syscalls/fdatasync.c',
'android/bionic/libc/arch-nacl/syscalls/fstat.c',
'android/bionic/libc/arch-nacl/syscalls/fsync.c',
'android/bionic/libc/arch-nacl/syscalls/futex.c',
'android/bionic/libc/arch-nacl/syscalls/getpid.c',
'android/bionic/libc/arch-nacl/syscalls/gettid.cpp',
'android/bionic/libc/arch-nacl/syscalls/gettimeofday.c',
'android/bionic/libc/arch-nacl/syscalls/getuid.c',
'android/bionic/libc/arch-nacl/syscalls/lseek.c',
'android/bionic/libc/arch-nacl/syscalls/lseek64.c',
'android/bionic/libc/arch-nacl/syscalls/lstat.c',
'android/bionic/libc/arch-nacl/syscalls/mkdir.c',
'android/bionic/libc/arch-nacl/syscalls/mmap.c',
'android/bionic/libc/arch-nacl/syscalls/mprotect.c',
'android/bionic/libc/arch-nacl/syscalls/munmap.c',
'android/bionic/libc/arch-nacl/syscalls/nacl_stat.c',
'android/bionic/libc/arch-nacl/syscalls/nacl_timespec.c',
'android/bionic/libc/arch-nacl/syscalls/nacl_timeval.c',
'android/bionic/libc/arch-nacl/syscalls/poll.c',
'android/bionic/libc/arch-nacl/syscalls/prctl.cpp',
'android/bionic/libc/arch-nacl/syscalls/read.c',
'android/bionic/libc/arch-nacl/syscalls/recvfrom.c',
'android/bionic/libc/arch-nacl/syscalls/rmdir.c',
'android/bionic/libc/arch-nacl/syscalls/sendto.c',
'android/bionic/libc/arch-nacl/syscalls/setpriority.c',
'android/bionic/libc/arch-nacl/syscalls/socketpair.c',
'android/bionic/libc/arch-nacl/syscalls/stat.c',
'android/bionic/libc/arch-nacl/syscalls/unlink.c',
'android/bionic/libc/arch-nacl/syscalls/write.c',
'android/bionic/libc/arch-nacl/syscalls/writev.c',
'android/bionic/libc/arch-nacl/tmp/raw_print.c',
# TODO(crbug.com/352917): Use assembly version on Bare Metal ARM.
'android/bionic/libc/bionic/memcmp.c',
'android/bionic/libc/bionic/memcpy.cpp',
'android/bionic/libc/bionic/property_service.c',
'android/bionic/libc/bionic/pthread_context.cpp',
'android/bionic/libc/bionic/ffs.cpp'])
if OPTIONS.is_nacl_build():
# They define SFI NaCl specific functions for dynamic code.
sources.extend([
'android/bionic/libc/arch-nacl/syscalls/nacl_dyncode_create.c',
'android/bionic/libc/arch-nacl/syscalls/nacl_dyncode_delete.c',
# TODO(crbug.com/238463): Drop this.
'android/bionic/libc/arch-nacl/syscalls/nacl_list_mappings.c'])
if OPTIONS.is_arm():
# TODO(crbug.com/352917): Use assembly version on Bare Metal ARM.
sources.extend([
'android/bionic/libc/bionic/__memcpy_chk.cpp'])
elif OPTIONS.is_x86_64():
sources.extend([
'android/bionic/libc/bionic/memmove.c'])
elif OPTIONS.is_i686():
sources.extend([
'android/bionic/libc/bionic/memchr.c',
'android/bionic/libc/bionic/memrchr.c',
'android/bionic/libc/bionic/memmove.c',
'android/bionic/libc/bionic/strnlen.c',
'android/bionic/libc/bionic/strrchr.cpp'])
if OPTIONS.is_arm():
_filter_libc_common_for_arm(vars, sources)
elif OPTIONS.is_i686():
_filter_libc_common_for_i686(vars, sources)
elif OPTIONS.is_x86_64():
_filter_libc_common_for_x86_64(vars, sources)
if OPTIONS.is_x86_64():
# ndk_cruft is only for 32 bit architectures which has ABI that we
# want to correct in the newer 64 bit architectures. However, for
# ARC, we are running ARM 32-bit NDK binaries even in x86-64, and
# we need the same binary interface.
sources.append('android/bionic/libc/bionic/ndk_cruft.cpp')
vars.get_includes().append('android/bionic/libc/arch-nacl/syscalls')
_remove_unnecessary_defines(vars)
vars.get_cflags().append('-ffunction-sections')
vars.get_cflags().append('-fdata-sections')
return True
def _filter_libc_netbsd(vars):
# This library has some random functions grabbed from
# NetBSD. Functions defined in this library includes file tree
# functions (ftw and nftw), signal printers (e.g., psignal),
# regexp functions (e.g., regcomp), nice and strxfrm.
vars.remove_c_or_cxxflag('-w')
# libc/upstream-netbsd/netbsd-compat.h defines _GNU_SOURCE for you.
vars.remove_c_or_cxxflag('-D_GNU_SOURCE')
_remove_unnecessary_defines(vars)
sources = vars.get_sources()
if OPTIONS.is_x86_64():
# LP64 does not have these symbols in upstream but we need to stay
# compatible with ARM for NDK-translation.
sources.extend([
'android/bionic/libc/upstream-netbsd/common/lib/libc/hash/sha1/sha1.c'])
return True
def _filter_libc_openbsd(vars):
# strcmp etc taken from openbsd, and exit.
vars.remove_c_or_cxxflag('-w')
vars.get_conlyflags().append('-Wno-sign-compare')
vars.get_conlyflags().append('-Wno-unused-parameter')
sources = vars.get_sources()
sources.extend([
'android/bionic/libc/upstream-openbsd/lib/libc/string/strcmp.c',
'android/bionic/libc/upstream-openbsd/lib/libc/string/strcpy.c'])
if OPTIONS.is_x86():
# TODO(crbug.com/446400): L-rebase: use assembly versions of string
# operations for NaCl x86-64.
sources.extend([
'android/bionic/libc/upstream-openbsd/lib/libc/string/stpcpy.c',
'android/bionic/libc/upstream-openbsd/lib/libc/string/stpncpy.c',
'android/bionic/libc/upstream-openbsd/lib/libc/string/strcat.c',
'android/bionic/libc/upstream-openbsd/lib/libc/string/strlen.c',
'android/bionic/libc/upstream-openbsd/lib/libc/string/strncmp.c',
'android/bionic/libc/upstream-openbsd/lib/libc/string/strncpy.c'])
if OPTIONS.is_x86_64():
# TODO(crbug.com/446400): L-rebase: use assembly versions of string
# operations instead.
sources.extend([
'android/bionic/libc/upstream-openbsd/lib/libc/string/strncat.c'])
_remove_unnecessary_defines(vars)
return True
def _filter_libc_gdtoa(vars):
# OpenBSD gdtoa libraries. Contains strtod etc.
vars.remove_c_or_cxxflag('-w')
vars.get_conlyflags().append('-Wno-sign-compare')
if OPTIONS.is_x86_64():
# TODO(crbug.com/446400): L-rebase: long double is same size as double.
vars.get_sources().remove(
'android/bionic/libc/upstream-openbsd/lib/libc/gdtoa/strtorQ.c')
_remove_unnecessary_defines(vars)
return True
def _filter_libc_bionic(vars):
sources = vars.get_sources()
_remove_assembly_source(sources)
# NaCl does not support signals.
sources.remove('android/bionic/libc/bionic/pthread_kill.cpp')
sources.remove('android/bionic/libc/bionic/pthread_sigmask.cpp')
# Bionic's mmap is a wrapper for __mmap2 (except for x86_64). Works the
# wrapper are not necessary for NaCl and it calls madvice, which NaCl
# does not support. We will simply define mmap without the wrapper.
# For x86_64, mmap is directly defined in arch-x86_64/syscalls/mmap.S, which
# is excluded by _remove_assembly_source().
if not OPTIONS.is_x86_64():
sources.remove('android/bionic/libc/bionic/mmap.cpp')
# Remove implementation of syscall wrappers that we are going to
# mark with ENOSYS.
for x in ['android/bionic/libc/bionic/NetdClientDispatch.cpp',
'android/bionic/libc/bionic/accept.cpp',
'android/bionic/libc/bionic/accept4.cpp',
'android/bionic/libc/bionic/access.cpp',
'android/bionic/libc/bionic/chmod.cpp',
'android/bionic/libc/bionic/chown.cpp',
'android/bionic/libc/bionic/connect.cpp',
'android/bionic/libc/bionic/dup2.cpp',
'android/bionic/libc/bionic/epoll_create.cpp',
'android/bionic/libc/bionic/epoll_wait.cpp',
'android/bionic/libc/bionic/ffs.cpp',
'android/bionic/libc/bionic/fork.cpp',
'android/bionic/libc/bionic/getpid.cpp',
'android/bionic/libc/bionic/gettid.cpp',
'android/bionic/libc/bionic/inotify_init.cpp',
'android/bionic/libc/bionic/lchown.cpp',
'android/bionic/libc/bionic/link.cpp',
'android/bionic/libc/bionic/lstat.cpp',
'android/bionic/libc/bionic/mknod.cpp',
'android/bionic/libc/bionic/mkdir.cpp',
'android/bionic/libc/bionic/pause.cpp',
'android/bionic/libc/bionic/pipe.cpp',
'android/bionic/libc/bionic/poll.cpp',
'android/bionic/libc/bionic/readlink.cpp',
'android/bionic/libc/bionic/rename.cpp',
'android/bionic/libc/bionic/rmdir.cpp',
'android/bionic/libc/bionic/sigaction.cpp',
'android/bionic/libc/bionic/stat.cpp',
'android/bionic/libc/bionic/sigpending.cpp',
'android/bionic/libc/bionic/sigprocmask.cpp',
'android/bionic/libc/bionic/socket.cpp',
'android/bionic/libc/bionic/symlink.cpp',
'android/bionic/libc/bionic/utimes.cpp',
'android/bionic/libc/bionic/unlink.cpp']:
sources.remove(x)
if OPTIONS.is_i686():
sources.extend([
'android/bionic/libc/arch-x86/bionic/setjmp.S'])
sources.remove('android/bionic/libc/arch-x86/bionic/__set_tls.c')
if OPTIONS.is_x86_64():
# We have our own implementation, remove arch-specific one.
sources.remove('android/bionic/libc/arch-x86_64/bionic/__set_tls.c')
sources.extend(
['android/bionic/libc/arch-x86_64/bionic/setjmp.S'])
# Include to satisfy setjmp.S.
vars.get_includes().insert(0, 'android/bionic/libc/arch-x86_64/include')
if OPTIONS.is_arm():
sources.extend(
['android/bionic/libc/arch-arm/bionic/setjmp.S'])
# Use a NaCl-specific version of getentropy.
sources.remove('android/bionic/libc/bionic/getentropy_linux.c')
sources.append('android/bionic/libc/arch-nacl/bionic/getentropy.cpp')
return True
def _filter_libc(vars):
if vars.is_static():
return False
vars.get_sources().remove('android/bionic/libc/bionic/NetdClient.cpp')
vars.get_sources().extend([
'android/bionic/libc/arch-nacl/syscalls/clock_nanosleep.c',
'android/bionic/libc/arch-nacl/syscalls/irt_syscalls.c',
'android/bionic/libc/arch-nacl/syscalls/nanosleep.c',
'android/bionic/libc/arch-nacl/syscalls/sched_yield.c',
'android/bionic/libc/arch-nacl/tmp/libc_stubs.c',
'android/bionic/libc/bionic/rindex.cpp',
'android/bionic/libc/bionic/NetdClientDispatch.cpp'
])
if OPTIONS.is_x86_64():
vars.get_includes().insert(0, 'android/bionic/libc/arch-x86_64/include')
if OPTIONS.is_bare_metal_build():
if OPTIONS.is_arm():
vars.get_sources().extend([
'android/bionic/libc/arch-arm/bionic/_setjmp.S',
'android/bionic/libc/arch-arm/bionic/sigsetjmp.S',
'android/bionic/libc/arch-nacl/syscalls/cacheflush.c'])
else:
vars.get_sources().extend([
'android/bionic/libc/arch-x86/bionic/_setjmp.S',
'android/bionic/libc/arch-x86/bionic/sigsetjmp.S',
'android/bionic/libc/arch-x86/generic/string/bcopy.S'])
if OPTIONS.enable_valgrind():
vars.get_sources().append(
'android/bionic/libc/bionic/valgrind_supplement.c')
vars.get_includes().append('android/bionic/libc/arch-nacl/syscalls')
vars.get_implicit_deps().extend([build_common.get_bionic_crtbegin_so_o(),
build_common.get_bionic_crtend_o()])
# This looks weird libc depends on libdl, but the upstream
# bionic also does the same thing. Note that libdl.so just has
# stub functions and their actual implementations are in the
# loader (see third_party/android/bionic/linker/dlfcn.c).
vars.get_shared_deps().append('libdl')
vars.get_whole_archive_deps().extend([
'libc_aeabi',
'libc_bionic',
'libc_cxa',
'libc_dns',
'libc_freebsd',
'libc_gdtoa',
'libc_malloc',
'libc_netbsd',
'libc_openbsd',
# We do not support stack protector on NaCl, but NDK may require a
# symbol in this file. So, we always link this.
'libc_stack_protector',
'libc_tzcode',
'libjemalloc'])
# Let dlmalloc not use sbrk as NaCl Bionic does not provide brk/sbrk.
vars.get_cflags().append('-DHAVE_MORECORE=0')
_remove_unnecessary_defines(vars)
if OPTIONS.is_arm():
# libc/upstream-dlmalloc/malloc.c checks "linux" to check if
# mremap is available, which we do not have. We need this fix
# only for Bare Metal ARM because NaCl toolchain does not
# define "linux" and Android undefines "linux" by default for
# x86 (android/build/core/combo/TARGET_linux-x86.mk).
vars.get_cflags().append('-Ulinux')
vars.get_generator_args()['is_system_library'] = True
if OPTIONS.is_arm():
# Set False to 'link_crtbegin' because Android.mk for libc.so
# compiles android/bionic/libc/arch-arm/bionic/crtbegin_so.c by
# default with -DCRT_LEGACY_WORKAROUND to export the __dso_handle
# symbol.
#
# __dso_handle is passed to __cxa_atexit so that libc knows which
# atexit handler belongs to which module. In general, __dso_handle
# should be a private symbol. Otherwise, a module (say A) can
# depend on __dso_handle in another module (B), and the atexit
# handler in A will not be called when the module A is unloaded.
#
# However, it seems the old version of Android had a bug and
# __dso_handle was exposed. Several NDKs depend on __dso_handle
# in libc.so. To execute such binaries directly, we need to define
# a public __dso_handle, too. This effectively means atexit
# handlers in such NDKs will never be called, as we will never
# unload libc.so. This is a known upstream issue. See
# third_party/android/bionic/ABI-bugs.txt.
#
# Note it is OK not to have crtbegin_so.o as the first object when
# we link libc.so because we are using init_array/fini_array,
# which do not require specific watchdogs, for ARM.
vars.get_generator_args()['link_crtbegin'] = False
return True
def _filter_libc_cxa(vars):
# This module is for C++ symbols (operator new(), delete)
return True
def _filter_libc_dns(vars):
return True
def _filter_libc_malloc(vars):
# This module is the glue for dlmalloc or jemalloc.
return True
def _filter_libc_malloc_debug_leak(vars):
if vars.is_static():
return False
# This module should not be included for --opt --disable-debug-code,
# and it is controlled by TARGET_BUILD_VARIANT in the Android.mk.
assert OPTIONS.is_debug_code_enabled()
vars.get_shared_deps().append('libdl')
_remove_unnecessary_defines(vars)
vars.get_generator_args()['is_system_library'] = True
return True
def _filter_libc_freebsd(vars):
sources = vars.get_sources()
if OPTIONS.is_i686():
# TODO(crbug.com/446400): L-rebase: use assembly versions of string
# operations instead.
sources.extend([
'android/bionic/libc/upstream-freebsd/lib/libc/string/wcschr.c',
'android/bionic/libc/upstream-freebsd/lib/libc/string/wcscmp.c',
'android/bionic/libc/upstream-freebsd/lib/libc/string/wcslen.c',
'android/bionic/libc/upstream-freebsd/lib/libc/string/wcsrchr.c'])
return True
def _filter_libc_tzcode(vars):
return True
def _filter_libc_stack_protector(vars):
# Used by both libc.so and runnable-ld.so.
vars.set_instances_count(2)
return True
def _filter_libc_aeabi(vars):
# For __aeabi_atexit, __aeabi_memcpy etc. for ARM.
return True
def _filter_tzdata(vars):
vars.set_prebuilt_install_to_root_dir(True)
return True
def _filter_libstdcpp(vars):
return not vars.is_static()
def _dispatch_libc_sub_filters(vars):
# Any libraries/executables except libc.so and the loader should *NEVER*
# be linked into libc_common because libc_common has global variables
# which require proper initialization (e.g. IRT function pointers in
# irt_syscalls.c).
# TODO(crbug.com/243244): Consider using -Wsystem-headers.
return {
'libc': _filter_libc,
'libc_aeabi': _filter_libc_aeabi,
'libc_bionic': _filter_libc_bionic,
'libc_common': _filter_libc_common,
'libc_cxa': _filter_libc_cxa,
'libc_dns': _filter_libc_dns,
'libc_freebsd': _filter_libc_freebsd,
'libc_malloc': _filter_libc_malloc,
'libc_malloc_debug_leak': _filter_libc_malloc_debug_leak,
'libc_netbsd': _filter_libc_netbsd,
'libc_openbsd': _filter_libc_openbsd,
'libc_gdtoa': _filter_libc_gdtoa,
'libc_stack_protector': _filter_libc_stack_protector,
'libc_tzcode': _filter_libc_tzcode,
'libstdc++': _filter_libstdcpp,
'tzdata': _filter_tzdata,
}.get(vars.get_module_name(), lambda vars: False)(vars)
def _generate_libc_ninja():
def _filter(vars, is_for_linker=False):
if (vars.is_c_library() and OPTIONS.is_nacl_build() and
not vars.is_clang_enabled()):
vars.enable_clang()
vars.enable_cxx11()
if not _dispatch_libc_sub_filters(vars):
return False
# tzdata is not a C/C++ module.
if vars.get_module_name() != 'tzdata':
vars.get_cflags().append('-W')
vars.get_cflags().append('-Werror')
_add_bare_metal_flags_to_make_to_ninja_vars(vars)
if is_for_linker:
module_name = vars.get_module_name()
if module_name not in _LINKER_MODULES:
return False
if (module_name in ('libc_bionic', 'libc_aeabi') and
OPTIONS.is_bare_metal_arm()):
# If we specify -fstack-protector, the ARM compiler emits code
# which requires relocation even for the code to be executed
# before the self relocation. As we would like to use logging
# functions in libc_bionic before the self relocation, we disable
# the stack smashing protector for libc_bionic for now.
# TODO(crbug.com/342292): Enable stack protector for the Bionic
# loader on Bare Metal ARM.
vars.get_cflags().append('-fno-stack-protector')
vars.get_cxxflags().append('-fno-stack-protector')
vars.set_module_name(module_name + '_linker')
# The loader does not need to export any symbols.
vars.get_cflags().append('-fvisibility=hidden')
vars.get_cxxflags().append('-fvisibility=hidden')
# We need to control the visibility using GCC's pragma based on
# this macro. See bionic/libc/arch-nacl/syscalls/irt_syscalls.h.
vars.get_cflags().append('-DBUILDING_LINKER')
vars.get_cxxflags().append('-DBUILDING_LINKER')
return True
MakefileNinjaTranslator('android/bionic/libc').generate(
lambda vars: _filter(vars, is_for_linker=False))
MakefileNinjaTranslator('android/bionic/libc').generate(
lambda vars: _filter(vars, is_for_linker=True))
def _generate_libm_ninja():
def _filter(vars):
if vars.is_shared():
return False
make_to_ninja.Filters.convert_to_shared_lib(vars)
_add_bare_metal_flags_to_make_to_ninja_vars(vars)
vars.get_cflags().append('-W')
vars.get_cflags().append('-Werror')
vars.get_cflags().append('-fno-builtin')
# Disable extended precision in nacl-i686. Some libm code (e.g.
# STRICT_ASSIGN macro) does not work correctly with extended precision.
# TODO(crbug.com/450887): Remove this flag once we migrate to a toolchain
# that generates SSE instructions instead of FPU ones.
if OPTIONS.is_nacl_i686():
vars.get_cflags().append('-ffloat-store')
sources = vars.get_sources()
_remove_assembly_source(sources)
if OPTIONS.is_arm():
vars.get_includes().append('android/bionic/libc/arch-arm/include')
elif OPTIONS.is_i686():
vars.get_includes().append('android/bionic/libc/arch-x86/include')
elif OPTIONS.is_x86_64():
vars.get_includes().append('android/bionic/libc/arch-x86_64/include')
# Android.mk assumes 128bit long double under amd64, but it's actually
# 64bit under NaCl x86_64. Here we exclude long double math function
# definitions. See mods/fork/bionic-long-double for details.
for x in [
'android/bionic/libm/upstream-freebsd/lib/msun/ld128/invtrig.c',
'android/bionic/libm/upstream-freebsd/lib/msun/ld128/k_cosl.c',
'android/bionic/libm/upstream-freebsd/lib/msun/ld128/k_sinl.c',
'android/bionic/libm/upstream-freebsd/lib/msun/ld128/k_tanl.c',
'android/bionic/libm/upstream-freebsd/lib/msun/ld128/s_exp2l.c',
'android/bionic/libm/upstream-freebsd/lib/msun/ld128/s_expl.c',
'android/bionic/libm/upstream-freebsd/lib/msun/ld128/s_logl.c',
'android/bionic/libm/upstream-freebsd/lib/msun/ld128/s_nanl.c',
'android/bionic/libm/upstream-freebsd/lib/msun/src/e_acosl.c',
'android/bionic/libm/upstream-freebsd/lib/msun/src/e_acoshl.c',
'android/bionic/libm/upstream-freebsd/lib/msun/src/e_asinl.c',
'android/bionic/libm/upstream-freebsd/lib/msun/src/e_atan2l.c',
'android/bionic/libm/upstream-freebsd/lib/msun/src/e_atanhl.c',
'android/bionic/libm/upstream-freebsd/lib/msun/src/e_fmodl.c',
'android/bionic/libm/upstream-freebsd/lib/msun/src/e_hypotl.c',
'android/bionic/libm/upstream-freebsd/lib/msun/src/e_remainderl.c',
'android/bionic/libm/upstream-freebsd/lib/msun/src/e_sqrtl.c',
'android/bionic/libm/upstream-freebsd/lib/msun/src/s_asinhl.c',
'android/bionic/libm/upstream-freebsd/lib/msun/src/s_atanl.c',
'android/bionic/libm/upstream-freebsd/lib/msun/src/s_cbrtl.c',
'android/bionic/libm/upstream-freebsd/lib/msun/src/s_ceill.c',
'android/bionic/libm/upstream-freebsd/lib/msun/src/s_copysignl.c',
'android/bionic/libm/upstream-freebsd/lib/msun/src/s_cosl.c',
'android/bionic/libm/upstream-freebsd/lib/msun/src/s_fabsl.c',
'android/bionic/libm/upstream-freebsd/lib/msun/src/s_floorl.c',
'android/bionic/libm/upstream-freebsd/lib/msun/src/s_fmal.c',
'android/bionic/libm/upstream-freebsd/lib/msun/src/s_fmaxl.c',
'android/bionic/libm/upstream-freebsd/lib/msun/src/s_fminl.c',
'android/bionic/libm/upstream-freebsd/lib/msun/src/s_modfl.c',
'android/bionic/libm/upstream-freebsd/lib/msun/src/s_frexpl.c',
'android/bionic/libm/upstream-freebsd/lib/msun/src/s_ilogbl.c',
'android/bionic/libm/upstream-freebsd/lib/msun/src/s_llrintl.c',
'android/bionic/libm/upstream-freebsd/lib/msun/src/s_llroundl.c',
'android/bionic/libm/upstream-freebsd/lib/msun/src/s_logbl.c',
'android/bionic/libm/upstream-freebsd/lib/msun/src/s_lrintl.c',
'android/bionic/libm/upstream-freebsd/lib/msun/src/s_lroundl.c',
'android/bionic/libm/upstream-freebsd/lib/msun/src/s_nextafterl.c',
'android/bionic/libm/upstream-freebsd/lib/msun/src/s_nexttoward.c',
'android/bionic/libm/upstream-freebsd/lib/msun/src/s_nexttowardf.c',
'android/bionic/libm/upstream-freebsd/lib/msun/src/s_remquol.c',
'android/bionic/libm/upstream-freebsd/lib/msun/src/s_rintl.c',
'android/bionic/libm/upstream-freebsd/lib/msun/src/s_roundl.c',
'android/bionic/libm/upstream-freebsd/lib/msun/src/s_scalbnl.c',
'android/bionic/libm/upstream-freebsd/lib/msun/src/s_sinl.c',
'android/bionic/libm/upstream-freebsd/lib/msun/src/s_tanl.c',
'android/bionic/libm/upstream-freebsd/lib/msun/src/s_truncl.c']:
sources.remove(x)
vars.get_generator_args()['is_system_library'] = True
vars.get_shared_deps().append('libc')
return True
MakefileNinjaTranslator('android/bionic/libm').generate(_filter)
def _generate_libdl_ninja():
def _filter(vars):
_add_bare_metal_flags_to_make_to_ninja_vars(vars)
vars.get_implicit_deps().extend([build_common.get_bionic_crtbegin_so_o(),
build_common.get_bionic_crtend_so_o()])
vars.remove_c_or_cxxflag('-w')
vars.get_cflags().append('-W')
vars.get_cflags().append('-Werror')
if vars.is_clang_enabled():
vars.get_cflags().append('-Wno-unused-parameter')
vars.get_generator_args()['is_system_library'] = True
return True
MakefileNinjaTranslator('android/bionic/libdl').generate(_filter)
# The "fundamental test" tests the features of the loader and the
# initialization process of libc. As we may want to test various kinds
# of objects with various kinds of setup, you can specify any command
# to build and test them. If you can use googletest, you should add
# tests to normal bionic_test instead (mods/android/bionic/tests).
class BionicFundamentalTest(object):
ALL_OUTPUT_BINARIES = []
@staticmethod
def get_src_dir():
return staging.as_staging('android/bionic/tests/fundamental')
@staticmethod
def get_out_dir():
return os.path.join(build_common.get_build_dir(), 'bionic_tests')
def __init__(self, test_binary_name, inputs, output, build_commands):
self._test_binary_name = test_binary_name
self._build_commands = build_commands
out = os.path.join(BionicFundamentalTest.get_out_dir(), test_binary_name)
asmflags = ninja_generator.CNinjaGenerator.get_archasmflags()
if OPTIONS.is_bare_metal_build():
asmflags += ' -DBARE_METAL_BIONIC '
cflags = (ninja_generator.CNinjaGenerator.get_gcc_includes() +
ninja_generator.CNinjaGenerator.get_archcflags())
cxxflags = ninja_generator.CNinjaGenerator.get_cxxflags()
cflags = asmflags + cflags + ' $commonflags -g -fPIC -Wall -W -Werror '
cxxflags = cflags + cxxflags
ldflags = ('-Wl,-rpath-link=' + build_common.get_load_library_path() +
' -Wl,--hash-style=sysv')
# Use -Bsymbolic to have similar configuration as other NaCl
# executables in ARC.
soflags = '-shared -Wl,-Bsymbolic'
if OPTIONS.is_arm():
# For ARM, we need to link libgcc.a into shared objects. See the comment
# in SharedObjectNinjaGenerator.
# TODO(crbug.com/283798): Build libgcc by ourselves and remove this.
soflags += ' ' + ' '.join(
ninja_generator.get_libgcc_for_bionic())
text_segment_address = (ninja_generator.ExecNinjaGenerator.
get_nacl_text_segment_address())
if OPTIONS.is_bare_metal_build():
execflags = '-pie'
ldflags += ' -fuse-ld=gold'
else:
# This is for nacl-clang. See src/build/ninja_generator.py for detail.
execflags = '-dynamic -Wl,-Ttext-segment=' + text_segment_address
self._variables = {
'cc': _get_crt_cc(),
'cxx': _get_crt_cxx(),
'name': self._test_binary_name,
'lib_dir': build_common.get_load_library_path(),
'in_dir': BionicFundamentalTest.get_src_dir(),
'out_dir': BionicFundamentalTest.get_out_dir(),
'out': out,
'crtbegin_exe': build_common.get_bionic_crtbegin_o(),
'crtbegin_so': build_common.get_bionic_crtbegin_so_o(),
'crtend_exe': build_common.get_bionic_crtend_o(),
'crtend_so': build_common.get_bionic_crtend_so_o(),
'cflags': cflags,
'cxxflags': cxxflags,
'ldflags': ldflags,
'soflags': soflags,
'execflags': execflags
}
self._inputs = map(self._expand_vars, inputs)
self._output = self._expand_vars(output)
def _expand_vars(self, s):
return string.Template(s).substitute(self._variables)
def emit(self, n):
BionicFundamentalTest.ALL_OUTPUT_BINARIES.append(self._output)
rule_name = 'build_bionic_' + self._test_binary_name
commands = []
for command in self._build_commands:
assert command
command = self._expand_vars(' '.join(command))
commands.append(command)
n.rule(rule_name, command=' && '.join(commands),
description=rule_name + ' $in')
n.build(self._output, rule_name, self._inputs,
implicit=build_common.get_bionic_objects())
if OPTIONS.is_debug_info_enabled():
n.build_stripped(self._output)
def _generate_bionic_fundamental_test_runners(n):
rule_name = 'run_bionic_fundamental_test'
script_name = os.path.join(BionicFundamentalTest.get_src_dir(),
'run_bionic_fundamental_test.py')
n.rule(rule_name,
command=script_name + ' $test_name' +
build_common.get_test_output_handler(use_crash_analyzer=True),
description=rule_name + ' $test_name')
test_out_dir = BionicFundamentalTest.get_out_dir()
tests = []
# This uses NaCl syscalls directly and is not compatible with Bare
# Metal mode.
if OPTIONS.is_nacl_build():
# If this passes, the loader is working.
tests.append(('loader_test', [], [], {}))
# (name, extra LD_LIBRARY_PATH, extra argv, extra envs)
tests.extend([
# If this passes, IRT calls are ready.
('write_test', [], [], {}),
# If this passes, stdio and malloc are ready.
('printf_test', [], [], {}),
# If this passes, arguments and environment variables are OK.
('args_test', [], ['foobar'], {}),
# If this passes, .ctors and .dtors are working.
('structors_test', [], [], {}),
# If this passes, symbols are available for subsequently loaded binaries.
('resolve_parent_sym_test', [test_out_dir], [], {}),
# If this passes, .ctors and .dtors with DT_NEEDED are working.
('so_structors_test', [test_out_dir], [], {}),
# If this passes, .ctors and .dtors with dlopen are working.
('dlopen_structors_test', [test_out_dir], [], {}),
# If this passes, dlopen fails properly when there is a missing symbol.
('dlopen_error_test', [test_out_dir], [], {})
])
for test_name, library_paths, test_argv, test_env in tests:
test_binary_basename = re.sub(r'-.*', '', test_name)
test_binary = os.path.join(test_out_dir, test_binary_basename)
runner = toolchain.get_target_runner(extra_library_paths=library_paths,
extra_envs=test_env)
qemu_arm = (' '.join(toolchain.get_qemu_arm_args())
if OPTIONS.is_arm() else '')
test_name = 'bionic_fundamental.' + test_name
variables = {
'runner': ' '.join(runner),
'in': test_binary,
'argv': ' '.join(test_argv),
'qemu_arm': qemu_arm
}
test_info = {
'variables': variables,
'command': '$qemu_arm $runner $in $argv'
}
test_path = os.path.join(test_out_dir, test_name)
n._build_test_info(test_path, 1, test_info)
test_info_path = n.get_test_info_path(test_path, 1)
result = os.path.join(test_out_dir, test_name + '.result')
test_deps = (BionicFundamentalTest.ALL_OUTPUT_BINARIES +
[script_name, test_info_path])
n.build(result, rule_name, implicit=test_deps,
variables={'test_name': test_name})
def _generate_bionic_fundamental_tests():
n = ninja_generator.NinjaGenerator('bionic_fundamental_tests')
bionic_tests = []
if OPTIONS.is_nacl_build():
# This uses NaCl syscalls directly and is not compatible with Bare
# Metal mode.
bionic_tests.append(
BionicFundamentalTest(
'loader_test', ['$in_dir/$name.c'], '$out',
[['$cc', '$cflags', '$ldflags', '$execflags', '-nostdlib',
'-L$lib_dir', '-lc'] +
ninja_generator.get_libgcc_for_bionic() +
['-ldl', '$$in', '-o', '$$out']]))
bionic_tests.extend([
BionicFundamentalTest(
'write_test', ['$in_dir/$name.c'], '$out',
[['$cc', '$cflags', '$ldflags', '$execflags', '-nostdlib',
'$crtbegin_exe', '-L$lib_dir', '-lc'] +
ninja_generator.get_libgcc_for_bionic() +
['-ldl', '$$in', '$crtend_exe', '-o', '$$out']]),
BionicFundamentalTest(
'printf_test', ['$in_dir/$name.c'], '$out',
[['$cc', '$cflags', '$ldflags', '$execflags', '-nostdlib',
'$crtbegin_exe', '-L$lib_dir', '-lc'] +
ninja_generator.get_libgcc_for_bionic() +
['-ldl', '$$in', '$crtend_exe', '-o', '$$out']]),
BionicFundamentalTest(
'args_test', ['$in_dir/$name.c'], '$out',
[['$cc', '$cflags', '$ldflags', '$execflags', '-nostdlib',
'$crtbegin_exe', '-L$lib_dir', '-lc'] +
ninja_generator.get_libgcc_for_bionic() +
['-ldl', '$$in', '$crtend_exe', '-o', '$$out']]),
BionicFundamentalTest(
'structors_test', ['$in_dir/$name.c'], '$out',
[['$cc', '$cflags', '$ldflags', '$execflags', '-nostdlib',
'$crtbegin_exe', '-L$lib_dir', '-lc'] +
ninja_generator.get_libgcc_for_bionic() +
['-ldl', '$$in', '$crtend_exe', '-o', '$$out']]),
BionicFundamentalTest(
'resolve_parent_sym_test',
['$in_dir/$name.c',
'$in_dir/${name}_first.c', '$in_dir/${name}_second.c'],
'$out',
[['$cc', '$cflags', '$ldflags', '-nostdlib',
'$crtbegin_so', '-L$lib_dir', '-lc',
'$in_dir/${name}_second.c', '$crtend_so',
'$soflags', '-o', '$out_dir/lib${name}_second.so'],
['$cc', '$cflags', '$ldflags', '-nostdlib',
'-L$out_dir', '-l${name}_second',
'$crtbegin_so', '-L$lib_dir', '-lc',
'$in_dir/${name}_first.c', '$crtend_so',
'$soflags', '-o', '$out_dir/lib${name}_first.so'],
['$cc', '$cflags', '$ldflags', '$execflags', '-nostdlib',
'-rdynamic', '-L$out_dir',
'-Wl,--rpath-link=$out_dir', '-l${name}_first',
'$crtbegin_exe', '-L$lib_dir', '-lc'] +
ninja_generator.get_libgcc_for_bionic() +
['-ldl', '$$in', '$crtend_exe', '-o', '$$out']]),
BionicFundamentalTest(
'so_structors_test',
['$in_dir/$name.c', '$in_dir/structors_test.c'],
'$out',
[['$cc', '$cflags', '-DFOR_SHARED_OBJECT',
'$ldflags', '-nostdlib',
'$crtbegin_so', '-L$lib_dir', '-lc',
'$in_dir/structors_test.c', '$crtend_so',
'$soflags', '-o', '$out_dir/libstructors_test.so'],
['$cc', '$cflags', '$ldflags', '$execflags',
'-nostdlib', '-rdynamic',
'$crtbegin_exe', '-L$lib_dir', '-lc'] +
ninja_generator.get_libgcc_for_bionic() +
['-ldl', '$in_dir/$name.c',
'-L$out_dir', '-Wl,--rpath-link=$out_dir', '-lstructors_test',
'$crtend_exe', '-o', '$$out']]),
BionicFundamentalTest(
'dlopen_structors_test', ['$in_dir/$name.c'], '$out',
[['$cc', '$cflags', '$ldflags', '$execflags', '-nostdlib',
'$crtbegin_exe', '-L$lib_dir', '-lc'] +
ninja_generator.get_libgcc_for_bionic() +
['$$in', '-ldl', '$crtend_exe', '-o', '$$out']]),
BionicFundamentalTest(
'dlopen_error_test',
['$in_dir/$name.c',
'$in_dir/use_undefined_sym.c', '$in_dir/use_use_undefined_sym.c'],
'$out',
[['$cc', '$cflags', '$ldflags', '-nostdlib',
'$crtbegin_so', '-L$lib_dir', '-lc',
'$in_dir/use_undefined_sym.c', '$crtend_so',
'$soflags', '-o', '$out_dir/libuse_undefined_sym.so'],
['$cc', '$cflags', '$ldflags', '-nostdlib',
'-L$out_dir', '-luse_undefined_sym',
'$crtbegin_so', '-L$lib_dir', '-lc',
'$in_dir/use_use_undefined_sym.c', '$crtend_so',
'$soflags', '-o', '$out_dir/libuse_use_undefined_sym.so'],
['$cc', '$cflags', '$ldflags', '$execflags', '-nostdlib',
'-rdynamic', '-L$out_dir',
'$crtbegin_exe', '-L$lib_dir', '-lc'] +
ninja_generator.get_libgcc_for_bionic() +
['-ldl', '$in_dir/$name.c', '$crtend_exe', '-o', '$$out']]),
])
for test in bionic_tests:
test.emit(n)
_generate_bionic_fundamental_test_runners(n)
def _generate_crt_bionic_ninja():
n = ninja_generator.CNinjaGenerator('bionic_crt')
_add_bare_metal_flags_to_ninja_generator(n)
# Needed to access private/__dso_handle.h from crtbegin_so.c.
n.add_include_paths('android/bionic/libc')
rule_name = 'build_bionic_crt'
opt_flags = ''
if OPTIONS.is_optimized_build():
opt_flags = ' '.join(ninja_generator.get_optimization_cflags())
n.rule(rule_name,
deps='gcc',
depfile='$out.d',
command=(_get_crt_cc() +
' $gccsystemincludes $cflags -W -Werror '
' -I' + staging.as_staging('android/bionic/libc/private') +
' -fPIC -g %s -MD -MF $out.d -c $in -o'
' $out') % opt_flags,
description=rule_name + ' $in')
# crts is a list of tuples whose first element is the source code
# and the second element is the name of the output object.
crts = [
('android/bionic/libc/arch-common/bionic/crtbegin.c', 'crtbegin.o'),
('android/bionic/libc/arch-common/bionic/crtbegin_so.c', 'crtbeginS.o'),
('android/bionic/libc/arch-common/bionic/crtend.S', 'crtend.o'),
('android/bionic/libc/arch-common/bionic/crtend_so.S', 'crtendS.o'),
]
for crt_src, crt_o in crts:
source = staging.as_staging(crt_src)
crt_o_path = os.path.join(build_common.get_load_library_path(), crt_o)
n.build(crt_o_path, rule_name, source)
if OPTIONS.is_debug_info_enabled():
n.build_stripped(crt_o_path)
def _generate_linker_script_for_runnable_ld():
# For Bare Metal mode, we do not modify linker script.
if OPTIONS.is_bare_metal_build():
return []
rule_name = 'gen_runnable_ld_lds'
n = ninja_generator.NinjaGenerator(rule_name)
cc = toolchain.get_tool(OPTIONS.target(), 'clang')
n.rule(rule_name,
command='$in %s > $out || (rm $out; exit 1)' % cc,
description=rule_name)
linker_script = os.path.join(build_common.get_build_dir(), 'runnable-ld.lds')
n.build(linker_script, rule_name, staging.as_staging(
'android/bionic/linker/arch/nacl/gen_runnable_ld_lds.py'))
return linker_script
def _add_runnable_ld_cflags(n):
# Match bionic/linker/Android.mk.
n.add_c_flags('-std=gnu11')
n.add_cxx_flags('-std=gnu++11')
if OPTIONS.is_arm():
# If we specify -fstack-protector, the ARM compiler emits code
# which requires relocation even for the code to be executed
# before the self relocation. We disable the stack smashing
# protector for the Bionic loader for now.
# TODO(crbug.com/342292): Enable stack protector for the Bionic
# loader on Bare Metal ARM.
n.add_compiler_flags('-fno-stack-protector')
n.add_compiler_flags(
'-ffunction-sections', '-fdata-sections',
# The loader does not need to export any symbols.
'-fvisibility=hidden',
'-W', '-Wno-unused', '-Wno-unused-parameter', '-Werror')
# TODO(crbug.com/243244): Consider using -Wsystem-headers.
n.add_include_paths('android/bionic/libc',
'android/bionic/libc/private',
'android/bionic/linker/arch/nacl')
if OPTIONS.is_debug_code_enabled() or OPTIONS.is_bionic_loader_logging():
n.add_defines('LINKER_DEBUG=1')
else:
n.add_defines('LINKER_DEBUG=0')
n.add_defines('ANDROID_SMP=1')
if OPTIONS.is_x86_64():
n.add_c_flags('-Wno-pointer-to-int-cast')
n.add_c_flags('-Wno-int-to-pointer-cast')
# NaCl x86-64 looks like x86 except for the ELF header which is
# x86-64, override the header path for linker to get the proper
# elf declarations.
n.add_include_paths('android/bionic/libc/arch-x86_64/include')
if build_common.use_ndk_direct_execution():
n.add_defines('USE_NDK_DIRECT_EXECUTION')
if OPTIONS.is_bionic_loader_logging():
n.add_defines('BIONIC_LOADER_LOGGING')
_add_bare_metal_flags_to_ninja_generator(n)
if OPTIONS.enable_valgrind():
n.add_defines('RUNNING_ON_VALGRIND')
def _generate_runnable_ld_ninja():
linker_script = _generate_linker_script_for_runnable_ld()
# Not surprisingly, bionic's loader is built with a special hack to
# Android's build system so we cannot use MakefileNinjaTranslator.
n = ninja_generator.ExecNinjaGenerator('runnable-ld.so',
base_path='android/bionic/linker',
install_path='/lib',
is_system_library=True,
force_compiler='clang',
enable_cxx11=True)
_add_runnable_ld_cflags(n)
for module_name in _LINKER_MODULES:
n.add_library_deps('%s_linker.a' % module_name)
sources = n.find_all_sources()
_remove_assembly_source(sources)
sources.extend(['android/bionic/libc/arch-nacl/syscalls/irt_syscalls.c',
'android/bionic/libc/bionic/__errno.cpp',
'android/bionic/libc/bionic/pthread_create.cpp',
'android/bionic/libc/bionic/pthread_internals.cpp',
'android/bionic/libc/bionic/pthread_key.cpp'])
if OPTIONS.is_bare_metal_build():
sources.append('android/bionic/linker/linker_notify.S')
# Remove SFI NaCl specific dynamic code allocation.
sources.remove('android/bionic/linker/arch/nacl/nacl_dyncode_alloc.c')
sources.remove('android/bionic/linker/arch/nacl/nacl_dyncode_map.c')
# NaCl has no signals so debugger support cannot be implemented.
sources.remove('android/bionic/linker/debugger.cpp')
# n.find_all_sources() picks up this upstream file regardless of the
# current target. For ARM, the file is obviously irrelevant. For i686
# and x86_64, we use our own begin.c.
sources.remove('android/bionic/linker/arch/x86/begin.c')
if OPTIONS.is_nacl_x86_64():
sources.append('android/bionic/linker/get_tls_for_art.S')
ldflags = n.get_ldflags()
if OPTIONS.is_nacl_build():
ldflags += (' -dynamic' +
' -Wl,-Ttext-segment=' + _LOADER_TEXT_SECTION_START_ADDRESS +
' -Wl,-T ' + linker_script)
else:
# We need to use recent linkers for __ehdr_start.
ldflags += ' -pie'
# See the comment in linker/arch/nacl/begin.c.
ldflags += ' -Wl,--defsym=__linker_base=0'
ldflags += ' -Wl,--gc-sections'
if not OPTIONS.is_debug_info_enabled():
ldflags += ' -Wl,--strip-all'
n.add_library_deps(*ninja_generator.get_libgcc_for_bionic())
n.add_library_deps('libc_stack_protector.a')
n.build_default(sources, base_path=None)
n.link(variables={'ldflags': ldflags}, implicit=linker_script)
_BIONIC_TEST_LIB_MODULES = [
'libdlext_test',
'libdlext_test_fd',
'libdlext_test_norelro',
'libdlext_test_v2',
'libtest_atexit',
'libtest_dlsym_weak_func',
'libtest_simple',
'libtest_with_dependency']
def _generate_bionic_test_lib_ninja():
# Generate necessary libraries for tests for dlopen etc.
def _filter(vars):
if not vars.get_module_name() in _BIONIC_TEST_LIB_MODULES:
return False
if not vars.is_shared():
return False
# I don't need __wrap
vars.get_generator_args()['is_system_library'] = True
vars.get_generator_args()['is_for_test'] = True
vars.get_shared_deps().extend([
'libc',
'libstlport'])
# libtest_with_dependency.so wants DT_NEEDED to libdlext_test.so whereas
# it does not require any symbol. This file is used in
# dlfcn.dlsym_with_dependencies test.
if vars.get_module_name() == 'libtest_with_dependency':
vars.get_ldflags().append('-Wl,--no-as-needed')
return True
MakefileNinjaTranslator('android/bionic/tests/libs').generate(_filter)
# libdlext_test_v2.so must be a symbolic link to libdlext_test.so.
# This file is used in dlfcn.dlopen_symlink test.
n = ninja_generator.NinjaGenerator('libdlext_test_v2')
orig_so = os.path.join(
build_common.get_load_library_path(), 'libdlext_test.so')
link_so = os.path.join(
build_common.get_load_library_path(), 'libdlext_test_v2.so')
command = 'ln -sf %s %s' % (os.path.basename(orig_so), link_so)
n.build(link_so, 'run_shell_command', implicit=orig_so,
variables={'command': command})
def _generate_bionic_tests():
if open_source.is_open_source_repo():
# bionic_test depends on some extra libs like libpagemap.a which have not
# been opensourced.
return
# To use 64bit long double instead of usual 80bit long double under BMM x86,
# we need to use gcc supporting -mlong-double-64.
# See mods/fork/bionic-long-double for more details.
compiler = 'gcc' if OPTIONS.is_bare_metal_i686() else 'clang'
n = ninja_generator.TestNinjaGenerator('bionic_test',
base_path='android/bionic/tests',
force_compiler=compiler,
enable_cxx11=True)
_add_bare_metal_flags_to_ninja_generator(n)
def relevant(f):
if f.find('/fundamental/') >= 0:
return False
if re.search(r'(_benchmark|/benchmark_main)\.cpp$', f):
return False
if f.find('/libs/') >= 0:
# libs are generated using MakefileNinjaTranslator in
# _generate_bionic_test_lib_ninja
return False
if (OPTIONS.is_nacl_i686() and
f == 'android/bionic/tests/stack_protector_test.cpp'):
# This tries to access a segment register, which NaCl validator
# does not like.
return False
return True
sources = filter(relevant, n.find_all_sources(include_tests=True))
n.build_default(sources, base_path=None)
# Set the same flag as third_party/android/bionic/tests/Android.mk.
# This is necessary for dlfcn_test.cpp as it calls dlsym for this symbol.
ldflags = '$ldflags -Wl,--export-dynamic -Wl,-u,DlSymTestFunction'
n.add_compiler_flags('-W', '-Wno-unused-parameter', '-Werror',
# Match libBionicStandardTests_c_includes in Android.mk
'-I' + staging.as_staging('android/bionic/libc'))
# Match bionic/tests/Android.mk.
n.add_cxx_flags('-std=gnu++11')
# Suppress deprecation warning in phtread_context_test.cpp.
n.add_cxx_flags('-Wno-inline-asm')
n.add_include_paths('android/system/extras/libpagemap/include')
n.add_library_deps('libpagemap.a')
n.add_compiler_flags('-fno-builtin')
if OPTIONS.is_arm():
# TODO(crbug.com/362175): qemu-arm cannot reliably emulate threading
# functions so run them in a real ARM device.
qemu_disabled_tests = ['pthread.pthread_attr_setguardsize',
'pthread.pthread_attr_setstacksize',
'pthread.pthread_create',
'pthread.pthread_detach__leak',
'pthread.pthread_getcpuclockid__no_such_thread',
'pthread.pthread_join__multijoin',
'pthread.pthread_join__no_such_thread',
'pthread.pthread_join__race',
'pthread.pthread_no_join_after_detach',
'pthread.pthread_no_op_detach_after_join',
'pthread_thread_stack.pthread_create_detached',
'pthread_thread_stack.pthread_create_join',
'pthread_thread_stack.pthread_detach',
'string.strerror_concurrent',
'string.strsignal_concurrent']
n.add_qemu_disabled_tests(*qemu_disabled_tests)
disabled_tests = [
# ARC does not support fork(), clone(), nor popen().
'DlExtRelroSharingTest.ChildWritesGoodData',
'DlExtRelroSharingTest.ChildWritesNoRelro',
'DlExtRelroSharingTest.VerifyMemorySaving',
'pthread.pthread_atfork',
'pthread.pthread_key_fork',
'sched.clone',
'sched.clone_errno',
'stdio.popen',
'stdlib.at_quick_exit',
'stdlib.quick_exit',
'stdlib.system',
'time.timer_create',
'unistd._Exit',
'unistd._exit',
# ARC does not support signals.
# TODO(nativeclient:4065): We should be able to enable them once
# NaCl adds signal IRTs.
'pthread.pthread_kill__0',
'pthread.pthread_kill__in_signal_handler',
'pthread.pthread_kill__invalid_signal',
'pthread.pthread_kill__no_such_thread',
'pthread.pthread_sigmask',
'signal.raise_invalid',
'signal.sigaction',
'signal.sigsuspend_sigpending',
'signal.sigwait',
'time.timer_create_EINVAL',
'time.timer_create_NULL',
'time.timer_create_SIGEV_SIGNAL',
'time.timer_create_multiple',
'time.timer_delete_from_timer_thread',
'time.timer_delete_multiple',
'time.timer_settime_0',
'time.timer_settime_repeats',
'unistd.alarm',
'unistd.pause',
# Needs posix_translation: file system syscalls
# TODO(crbug.com/452355): There are some symbols for which even
# posix_translation does not support. We should review them
# and add __wrap_* functions in posix_translation.
'fcntl.f_getlk64',
'fcntl.fallocate',
'fcntl.fallocate_EINVAL',
'fcntl.fcntl_smoke',
'fcntl.posix_fadvise',
'fcntl.splice',
'fcntl.tee',
'fcntl.vmsplice',
'sys_epoll.epoll_event_data',
'sys_epoll.smoke',
'sys_select.pselect_smoke',
'sys_select.select_smoke',
'sys_sendfile.sendfile',
'sys_sendfile.sendfile64',
'sys_socket.accept4_error',
'sys_socket.accept4_smoke',
'sys_socket.recvmmsg_error',
'sys_socket.recvmmsg_smoke',
'sys_socket.sendmmsg_error',
'sys_socket.sendmmsg_smoke',
'sys_stat.futimens',
'sys_stat.futimens_EBADF',
'sys_stat.mkfifo',
'sys_statvfs.fstatvfs',
'sys_statvfs.fstatvfs64',
'sys_statvfs.statvfs',
'sys_statvfs.statvfs64',
'sys_vfs.fstatfs',
'sys_vfs.fstatfs64',
'sys_vfs.statfs',
'sys_vfs.statfs64',
'unistd.fdatasync',
'unistd.fsync',
'unistd.ftruncate',
'unistd.ftruncate64',
'unistd.truncate',
'unistd.truncate64',
# ARC does not support TTY.
'stdlib.ptsname_r_ERANGE',
'stdlib.pty_smoke',
'stdlib.ttyname_r',
'stdlib.ttyname_r_ENOTTY',
'stdlib.ttyname_r_ERANGE',
'stdlib.unlockpt_ENOTTY',
# Needs posix_translation: getrlimit
'sys_resource.smoke',
# Needs posix_translation: getpid
'unistd.getpid_caching_and_clone',
'unistd.getpid_caching_and_fork',
'unistd.getpid_caching_and_pthread_create',
'unistd.syscall',
# This test uses realpath. Also, this fails even with realpath
# on SFI NaCl, because a pointer address the sandboxed process
# is looking is different from the real address.
'dlfcn.dladdr',
# Needs posix_translation: utimes
'sys_time.utimes',
'sys_time.utimes_NULL',
# Needs posix_translation: getaddrinfo and freeaddrinfo
'netdb.getaddrinfo_NULL_hints',
# Needs posix_translation: readlink in unittests does not work
# on NaCl and Bare Metal.
'stdlib.realpath',
'stdlib.realpath__ENOENT',
# ARC does not support brk/sbrk.
'unistd.brk',
'unistd.brk_ENOMEM',
'unistd.sbrk_ENOMEM',
'unistd.syscall_long',
# We do not support pthread_setname_np.
'pthread.pthread_setname_np__self',
# ARC does not support eventfd.
'eventfd.smoke',
# TODO(crbug.com/359436): Death tests are not supported.
'TEST_NAME_DeathTest.*',
'atexit.exit',
# Note: if /dev/__properties__ is not working, this test does
# nothing so this test actually passes.
'properties_DeathTest.read_only',
'pthread_DeathTest.pthread_bug_37410',
'stack_protector_DeathTest.modify_stack_protector',
'stack_unwinding_DeathTest.unwinding_through_signal_frame',
'stdlib.getenv_after_main_thread_exits',
'stdlib_DeathTest.getenv_after_main_thread_exits',
# Too slow, takes 40 seconds on -t bi on z620
# TODO(crbug.com/446400): L-rebase: Reenable if I can make it faster, or
# enable it for integration tests.
'string.*'
]
if OPTIONS.is_bare_metal_build():
# nonsfi_loader always returns zero st_dev so symlink detection in
# linker.cpp does not work well.
disabled_tests.extend([
'dlfcn.dlopen_symlink',
])
if OPTIONS.is_i686():
# TODO(crbug.com/469093): Fix this test.
disabled_tests.extend([
'stack_protector.same_guard_per_thread',
])
if OPTIONS.is_nacl_build():
disabled_tests.extend([
# android_dlopen_ext() can not work as expected due to the gapped memory
# layout of NaCl.
'DlExtTest.Reserved',
'DlExtTest.ReservedTooSmall',
'DlExtTest.ReservedHint',
# Needs posix_translation: ARC supports symlinks recently, but
# dlopen() does not care.
'dlfcn.dlopen_symlink',
# Direct syscall is not supported.
'sys_time.gettimeofday',
'time.clock_gettime'
])
if OPTIONS.enable_valgrind():
disabled_tests.extend([
# A few tests in these files fail under valgrind probably due
# to a valgrind's bug around rounding mode.
'fenv.feclearexcept_fetestexcept',
'fenv.fesetround_fegetround_FE_DOWNWARD',
'fenv.fesetround_fegetround_FE_TOWARDZERO',
'math.__fpclassifyl',
'math.__isfinitel',
'math.__isinfl',
'math.fpclassify',
'math.lrint',
'math.nearbyint',
'math.rint',
# Valgrind aborts when pvalloc or valloc is called.
'malloc.pvalloc_overflow',
'malloc.pvalloc_std',
'malloc.valloc_std',
# These test check malloc family sets errno appropriately, but
# valgrind's replace_malloc does not update errno.
'malloc.calloc_overflow',
'malloc.malloc_overflow',
'malloc.calloc_illegal',
'malloc.realloc_overflow',
# This test relies on sleep(1) and is flaky on valgrind. See
# crbug.com/410009.
'pthread.pthread_no_op_detach_after_join',
# This test cannot find the main thread's stack from
# /proc/self/maps when a process is running under valgrind.
'pthread.pthread_attr_getstack__main_thread',
# This test intentionally leaks memory. Valgrind may detect it.
'pthread.pthread_detach__leak',
# This test expects two threads are executed in
# parallel. However, valgrind's scheduler runs the one thread
# first and then runs the other.
'stdatomic.ordering',
# TODO(474636): Tolerance level is consistently too short. Even with
# successive increases it kept causing flakiness on the tree.
'time.clock_gettime',
# Valgrind injects a few LD_PRELOAD binaries.
'dl_iterate_phdr.Basic',
])
n.add_disabled_tests(*disabled_tests)
test_deps = [
os.path.join(build_common.get_load_library_path(), '%s.so' % x) for x in
_BIONIC_TEST_LIB_MODULES + ['no-elf-hash-table-library']]
test_binary = n.link(variables={'ldflags': ldflags})
n.add_disabled_tests('PthreadThreadContext*.*')
n.run(test_binary, implicit=test_deps)
# pthread_context_test should run only with a single thread. As
# other pthread tests start detached threads which can affect the
# result of this test, we use a separate TestNinjaGenerator for this
# test.
n = ninja_generator.TestNinjaGenerator('bionic_pthread_context_test')
n.add_enabled_tests('PthreadThreadContext*.*')
n.run(test_binary, implicit=test_deps)
# Build the shared object for dlfcn.dlopen_library_with_only_gnu_hash.
def _filter(vars):
if vars.get_module_name() == 'no-elf-hash-table-library':
vars.get_generator_args()['is_for_test'] = True
return True
env = {
'bionic-unit-tests-static_src_files': ''
}
MakefileNinjaTranslator('android/bionic/tests',
extra_env_vars=env).generate(_filter)
def _generate_libgcc_ninja():
# Currently, we need to generate libgcc.a only for Bare Metal mode.
if not OPTIONS.is_bare_metal_build():
return
# TODO(crbug.com/283798): Build libgcc by ourselves.
rule_name = 'generate_libgcc'
n = ninja_generator.NinjaGenerator(rule_name)
if OPTIONS.is_i686():
# We use libgcc.a in Android NDK for Bare Metal mode as it is
# compatible with Bionic.
orig_libgcc = ('ndk/toolchains/x86-4.6/prebuilt/'
'linux-x86/lib/gcc/i686-linux-android/4.6/libgcc.a')
# This libgcc has unnecessary symbols such as __CTORS__ in
# _ctors.o. We define this symbol in crtbegin.o, so we need to
# remove this object from the archive.
# Functions in generic-morestack{,-thread}.o and morestack.o are not
# needed if one is not using split stacks and it interferes with our
# process emulation code.
remove_object = ('_ctors.o generic-morestack.o generic-morestack-thread.o '
'morestack.o')
elif OPTIONS.is_arm():
orig_libgcc = (
'ndk/toolchains/arm-linux-androideabi-4.6/prebuilt/'
'linux-x86/lib/gcc/arm-linux-androideabi/4.6/armv7-a/libgcc.a')
# This object depends on some glibc specific symbols around
# stdio. As no objects in libgcc.a use _eprintf, we can simply
# remove this object.
remove_object = '_eprintf.o'
n.rule(rule_name,
command=('cp $in $out.tmp && ar d $out.tmp %s && mv $out.tmp $out' %
remove_object),
description=rule_name + ' $out')
n.build(ninja_generator.get_libgcc_for_bare_metal(), rule_name, orig_libgcc)
def _generate_libgcc_eh_ninja():
if not OPTIONS.is_nacl_build():
return
# Create indirections to expose hidden functions in libgcc_eh.a to DSOs.
# PNaCl toolchain has its compiler runtime and exception handling code
# separately in libgcc.a and libgcc_eh.a.
# Though we need to access libgcc_eh.a from DSOs for getting backtrace,
# all symbols in libgcc_eh.a are hidden symbols.
# To expose necessary symbols, we rename these hidden symbols to "__real"
# prefixed ones, and define proxy functions for them.
#
# On the native Linux, libgcc_eh.a is linked only for statically linked
# binaries, and libgcc_s.so is linked for dynamically linked binaries.
# However, PNaCl toolchain doesn't support DSOs and doesn't have libgcc_s.so
# at this time.
# TODO(crbug.com/283798): Build libgcc by ourselves.
n = ninja_generator.CNinjaGenerator('generate_libgcc')
target = OPTIONS.target()
orig_libgcc = os.path.join(toolchain.get_nacl_libgcc_dir(), 'libgcc_eh.a')
libgcc_proxy = staging.as_staging(
'android/bionic/libc/arch-nacl/bionic/libgcc_proxy.S')
libgcc_proxy_rename_list = n.get_build_path('rename_list')
gen_rename_list_rule = 'gen_rename_list'
n.rule(gen_rename_list_rule,
command=' '.join(['sed', '-n',
'\'s/^define_proxy \\(.*\\)$$/\\1 __real\\1/p\'',
'$in', '>', '$out']))
n.build(libgcc_proxy_rename_list, gen_rename_list_rule, inputs=[libgcc_proxy])
symbol_rename_rule = 'rename_symbols'
n.rule(symbol_rename_rule,
command=' '.join([toolchain.get_tool(target, 'objcopy'),
'--redefine-syms=$rename_list', '$in', '$out']))
renamed_a = n.get_build_path('renamed.a')
n.build(renamed_a, symbol_rename_rule, inputs=orig_libgcc,
implicit=[libgcc_proxy_rename_list],
variables={'rename_list': libgcc_proxy_rename_list})
append_obj_rule = 'append_obj'
n.rule(append_obj_rule,
command=' '.join(['cp', '$in', '$out', '&&',
toolchain.get_tool(target, 'ar'),
'rs', '$out', '$objs']))
objs = n.asm_with_preprocessing(libgcc_proxy)
n.build(ninja_generator.get_libgcc_eh_for_nacl(),
append_obj_rule, inputs=renamed_a, implicit=objs,
variables={'objs': ' '.join(objs)})
def generate_ninjas():
ninja_generator_runner.request_run_in_parallel(
_generate_bionic_test_lib_ninja,
_generate_naclized_i686_asm_ninja,
_generate_libc_ninja,
_generate_libm_ninja,
_generate_libdl_ninja,
_generate_runnable_ld_ninja,
_generate_crt_bionic_ninja,
_generate_libgcc_ninja,
_generate_libgcc_eh_ninja)
def generate_test_ninjas():
ninja_generator_runner.request_run_in_parallel(
_generate_bionic_fundamental_tests,
_generate_bionic_tests)