blob: d3acad8275e72b3b8ba2d6087c805302141f74f2 [file] [log] [blame]
#!/usr/bin/python
# Copyright (c) 2013 The Native Client Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Recipes for PNaCl target libs."""
import fnmatch
import os
import sys
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
import pynacl.gsd_storage
import pynacl.platform
import command
import pnacl_commands
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
NACL_DIR = os.path.dirname(SCRIPT_DIR)
CLANG_VER = '3.7.0'
def ToolName(name):
return 'pnacl-' + name
# Return the path to a tool to build target libraries
# msys should be false if the path will be called directly rather than passed to
# an msys or cygwin tool such as sh or make.
def PnaclTool(toolname, arch='le32', msys=True):
if not msys and pynacl.platform.IsWindows():
ext = '.bat'
else:
ext = ''
if toolname in ['llvm-mc']:
# Some tools, like llvm-mc, don't need or have a special pnacl- prefix
# binary.
base = toolname
elif IsBCArch(arch):
base = ToolName(toolname)
else:
base = '-'.join([TargetArch(arch), 'nacl', toolname])
return command.path.join('%(abs_target_lib_compiler)s',
'bin', base + ext)
# PNaCl tools for newlib's environment, e.g. CC_FOR_TARGET=/path/to/pnacl-clang
TOOL_ENV_NAMES = { 'CC': 'clang', 'CXX': 'clang++', 'AR': 'ar', 'NM': 'nm',
'RANLIB': 'ranlib', 'READELF': 'readelf', 'AS': 'as' }
def TargetTools(arch):
return [ tool + '_FOR_TARGET=' + PnaclTool(name, arch=arch, msys=True)
for tool, name in TOOL_ENV_NAMES.iteritems() ]
def MakeCommand():
make_command = ['make']
if not pynacl.platform.IsWindows():
# The make that ships with msys sometimes hangs when run with -j.
# The ming32-make that comes with the compiler itself reportedly doesn't
# have this problem, but it has issues with pathnames with LLVM's build.
make_command.append('-j%(cores)s')
return make_command
# Return the component name to use for a component name with
# a host triple. GNU configuration triples contain dashes, which are converted
# to underscores so the names are legal for Google Storage.
def GSDJoin(*args):
return '_'.join([pynacl.gsd_storage.LegalizeName(arg) for arg in args])
def TripleFromArch(bias_arch):
return bias_arch + '-nacl'
def IsBiasedBCArch(arch):
return arch.endswith('_bc')
def IsBCArch(arch):
return IsBiasedBCArch(arch) or arch == 'le32'
def IsNonSFIArch(arch):
return arch.endswith('-nonsfi')
# Return the target arch recognized by the compiler (e.g. i686) from an arch
# string which might be a biased-bitcode-style arch (e.g. i686_bc)
def TargetArch(bias_arch):
if IsBiasedBCArch(bias_arch):
return bias_arch[:bias_arch.index('_bc')]
return bias_arch
def MultilibArch(bias_arch):
return 'x86_64' if bias_arch == 'i686' else bias_arch
def MultilibLibDir(bias_arch):
suffix = '32' if bias_arch == 'i686' else ''
return os.path.join(TripleFromArch(MultilibArch(bias_arch)), 'lib' + suffix)
def BiasedBitcodeTargetFlag(bias_arch):
arch = TargetArch(bias_arch)
flagmap = {
# Arch Target Extra flags.
'x86_64': ('x86_64-unknown-nacl', []),
'i686': ('i686-unknown-nacl', []),
'arm': ('armv7-unknown-nacl-gnueabihf', ['-mfloat-abi=hard']),
'mipsel': ('mipsel-unknown-nacl', []),
}
# The -emit-llvm flag is only needed for native Clang drivers since
# pnacl-clang already passes that option to every Clang invocation.
# TODO(phosek): Refactor the per-toolchain options into a separate class.
return ['--target=%s' % flagmap[arch][0], '-emit-llvm'] + flagmap[arch][1]
def TranslatorArchToBiasArch(arch):
archmap = {'x86-32': 'i686',
'x86-32-nonsfi': 'i686',
'x86-64': 'x86_64',
'arm': 'arm',
'arm-nonsfi': 'arm',
'mips32': 'mipsel'}
return archmap[arch]
def TargetLibCflags(bias_arch):
flags = '-g -O2'
if IsBCArch(bias_arch):
flags += ' -mllvm -inline-threshold=5'
else:
# Use sections for the library builds to allow better GC for the IRT.
flags += ' -ffunction-sections -fdata-sections'
if bias_arch != 'arm':
# Newlib target libs need to be build with the LLVM assembler on x86-64
# because it uses the sandbox base address-hiding form of calls, which
# we need in the IRT. On x86-32 that doesn't matter but the LLVM assembler
# sometimes generates slightly better code and it's good to be consistent.
flags += ' -integrated-as'
if IsBiasedBCArch(bias_arch):
flags += ' ' + ' '.join(BiasedBitcodeTargetFlag(bias_arch))
return flags
def NewlibIsystemCflags(bias_arch):
include_arch = MultilibArch(bias_arch)
return ' '.join([
'-isystem',
command.path.join('%(' + GSDJoin('abs_newlib', include_arch) +')s',
TripleFromArch(include_arch), 'include')])
def LibCxxCflags(bias_arch):
# HAS_THREAD_LOCAL is used by libc++abi's exception storage, the fallback is
# pthread otherwise.
return ' '.join([TargetLibCflags(bias_arch), NewlibIsystemCflags(bias_arch),
'-fexceptions', '-DHAS_THREAD_LOCAL=1',
'-D__ARM_DWARF_EH__'])
def NativeTargetFlag(bias_arch):
arch = TargetArch(bias_arch)
flagmap = {
# Arch Target Extra flags.
'x86_64': ('x86_64-linux-gnu', []),
'i686': ('i686-linux-gnu', []),
'arm': ('armv7a-linux-gnueabihf', []),
'mipsel': ('mipsel-linux-gnu', []),
}
return ['--target=%s' % flagmap[arch][0]] + flagmap[arch][1]
def NonSFITargetLibCflags(bias_arch):
flags = '-D__native_client_nonsfi__ -fPIC -nostdinc '
flags += ' '.join([
'-isystem',
command.path.join('%(abs_target_lib_compiler)s',
'lib', 'clang', CLANG_VER, 'include')])
if bias_arch == 'i686':
flags += ' -malign-double -mllvm -mtls-use-call'
flags += ' ' + ' '.join(NativeTargetFlag(bias_arch))
return flags
# Build a single object file for the target.
def BuildTargetObjectCmd(source, output, bias_arch, output_dir='%(cwd)s',
extra_flags=[]):
flags = ['-Wall', '-Werror', '-O2', '-c'] + extra_flags
if IsBiasedBCArch(bias_arch):
flags.extend(BiasedBitcodeTargetFlag(bias_arch))
flags.extend(NewlibIsystemCflags(bias_arch).split())
return command.Command(
[PnaclTool('clang', arch=bias_arch, msys=False)] + flags + [
command.path.join('%(src)s', source),
'-o', command.path.join(output_dir, output)])
# Build a single object file as native code for the translator.
def BuildTargetTranslatorCmd(sourcefile, output, arch, extra_flags=[],
source_dir='%(src)s', output_dir='%(cwd)s'):
bias_arch = TranslatorArchToBiasArch(arch)
flags = ['-Wall', '-Werror', '-O3', '-integrated-as', '-c'] + extra_flags
if IsNonSFIArch(arch):
flags.extend(NonSFITargetLibCflags(bias_arch).split())
return command.Command(
[PnaclTool('clang', arch=bias_arch, msys=False)] + flags +
# TODO(dschuff): this include breaks the input encapsulation for build
# rules.
['-I%(top_srcdir)s/..'] +
NewlibIsystemCflags('le32').split() +
[command.path.join(source_dir, sourcefile),
'-o', command.path.join(output_dir, output)])
def BuildLibgccEhCmd(sourcefile, output, arch, no_nacl_gcc):
# Return a command to compile a file from libgcc_eh (see comments in at the
# rule definition below).
flags_common = ['-DENABLE_RUNTIME_CHECKING', '-g', '-O2', '-W', '-Wall',
'-Wwrite-strings', '-Wcast-qual', '-Wstrict-prototypes',
'-Wmissing-prototypes', '-Wold-style-definition',
'-DIN_GCC', '-DCROSS_DIRECTORY_STRUCTURE', '-DIN_LIBGCC2',
'-D__GCC_FLOAT_NOT_NEEDED', '-Dinhibit_libc',
'-DHAVE_CC_TLS', '-DHIDE_EXPORTS',
'-fno-stack-protector', '-fexceptions',
'-fvisibility=hidden',
'-I.', '-I../.././gcc', '-I%(abs_gcc_src)s/gcc/libgcc',
'-I%(abs_gcc_src)s/gcc', '-I%(abs_gcc_src)s/include',
'-isystem', './include']
# For x86 we use nacl-gcc to build libgcc_eh because of some issues with
# LLVM's handling of the gcc intrinsics used in the library. See
# https://code.google.com/p/nativeclient/issues/detail?id=1933
# and http://llvm.org/bugs/show_bug.cgi?id=8541
# For ARM, LLVM does work and we use it to avoid dealing with the fact that
# arm-nacl-gcc uses different libgcc support functions than PNaCl.
if arch in ('arm', 'mips32'):
cc = PnaclTool('clang', arch=TranslatorArchToBiasArch(arch), msys=False)
flags_naclcc = []
else:
if no_nacl_gcc:
return command.WriteData('', output)
os_name = pynacl.platform.GetOS()
arch_name = pynacl.platform.GetArch()
platform_dir = '%s_%s' % (os_name, arch_name)
newlib_dir = 'nacl_x86_newlib_raw'
nnacl_dir = os.path.join(NACL_DIR, 'toolchain', platform_dir,
newlib_dir, 'bin')
gcc_binaries = {
'x86-32': 'i686-nacl-gcc',
'x86-64': 'x86_64-nacl-gcc',
}
cc = os.path.join(nnacl_dir, gcc_binaries[arch])
flags_naclcc = []
return command.Command([cc] + flags_naclcc + flags_common +
['-c',
command.path.join('%(gcc_src)s', 'gcc', sourcefile),
'-o', output])
def TargetLibsSrc(GitSyncCmds):
newlib_sys_nacl = command.path.join('%(output)s',
'newlib', 'libc', 'sys', 'nacl')
source = {
'newlib_src': {
'type': 'source',
'output_dirname': 'pnacl-newlib',
'commands': [
# Clean any headers exported from the NaCl tree before syncing.
command.CleanGitWorkingDir(
'%(output)s',
reset=False,
path=os.path.join('newlib', 'libc', 'include'))] +
GitSyncCmds('nacl-newlib') +
# Remove newlib versions of headers that will be replaced by
# headers from the NaCl tree.
[command.RemoveDirectory(command.path.join(newlib_sys_nacl,
dirname))
for dirname in ['bits', 'sys', 'machine']] + [
command.Command([
sys.executable,
command.path.join('%(top_srcdir)s', 'src', 'trusted',
'service_runtime', 'export_header.py'),
command.path.join('%(top_srcdir)s', 'src', 'trusted',
'service_runtime', 'include'),
newlib_sys_nacl],
cwd='%(abs_output)s',
)] + [
command.Copy(
os.path.join('%(top_srcdir)s', 'src', 'untrusted', 'pthread',
header),
os.path.join('%(output)s', 'newlib', 'libc', 'include',
header))
for header in ('pthread.h', 'semaphore.h')
]
},
'compiler_rt_src': {
'type': 'source',
'output_dirname': 'compiler-rt',
'commands': GitSyncCmds('compiler-rt'),
},
'gcc_src': {
'type': 'source',
'output_dirname': 'pnacl-gcc',
'commands': GitSyncCmds('gcc'),
},
}
return source
def NewlibLibcScript(arch, elfclass_x86_64='elf32'):
template = """/*
* This is a linker script that gets installed as libc.a for the
* newlib-based NaCl toolchain. It brings in the constituent
* libraries that make up what -lc means semantically.
*/
OUTPUT_FORMAT(%s)
GROUP ( libnacl.a libcrt_common.a )
"""
if arch == 'arm':
# Listing three formats instead of one makes -EL/-EB switches work
# for the endian-switchable ARM backend.
format_list = ['elf32-littlearm-nacl',
'elf32-bigarm-nacl',
'elf32-littlearm-nacl']
elif arch == 'i686':
format_list = ['elf32-i386-nacl']
elif arch == 'x86_64':
format_list = ['%s-x86-64-nacl' % elfclass_x86_64]
elif arch == 'mipsel' :
format_list = ['elf32-tradlittlemips-nacl']
else:
raise Exception('TODO(mcgrathr): OUTPUT_FORMAT for %s' % arch)
return template % ', '.join(['"' + fmt + '"' for fmt in format_list])
def NewlibDirectoryCmds(bias_arch, newlib_triple):
commands = []
def NewlibLib(name):
return os.path.join('%(output)s', newlib_triple, 'lib', name)
if not IsBCArch(bias_arch):
commands.extend([
command.Rename(NewlibLib('libc.a'), NewlibLib('libcrt_common.a')),
command.WriteData(NewlibLibcScript(bias_arch, 'elf64'),
NewlibLib('libc.a'))])
target_triple = TripleFromArch(bias_arch)
if bias_arch != 'i686':
commands.extend([
# For biased bitcode builds, we configured newlib with target=le32-nacl
# to get its pure C implementation, so rename its output dir (which
# matches the target to the output dir for the package we are building)
command.Rename(os.path.join('%(output)s', newlib_triple),
os.path.join('%(output)s', target_triple)),
# Copy nacl_random.h, used by libc++. It uses the IRT, so should
# be safe to include in the toolchain.
command.Mkdir(
os.path.join('%(output)s', target_triple, 'include', 'nacl')),
command.Copy(os.path.join('%(top_srcdir)s', 'src', 'untrusted',
'nacl', 'nacl_random.h'),
os.path.join('%(output)s', target_triple, 'include',
'nacl', 'nacl_random.h'))
])
else:
# Use multilib-style directories for i686
multilib_triple = TripleFromArch(MultilibArch(bias_arch))
commands.extend([
command.Rename(os.path.join('%(output)s', newlib_triple),
os.path.join('%(output)s', multilib_triple)),
command.RemoveDirectory(
os.path.join('%(output)s', multilib_triple, 'include')),
command.Rename(
os.path.join('%(output)s', multilib_triple, 'lib'),
os.path.join('%(output)s', multilib_triple, 'lib32')),
])
# Remove the 'share' directory from the biased builds; the data is
# duplicated exactly and takes up 2MB per package.
if bias_arch != 'le32':
commands.append(command.RemoveDirectory(os.path.join('%(output)s','share')))
return commands
def LibcxxDirectoryCmds(bias_arch):
if bias_arch != 'i686':
return []
lib_dir = os.path.join('%(output)s', MultilibLibDir(bias_arch))
return [
# Use the multlib-style lib dir and shared headers for i686
command.Mkdir(os.path.dirname(lib_dir)),
command.Rename(os.path.join('%(output)s', 'i686-nacl', 'lib'),
lib_dir),
# The only thing left in i686-nacl is the headers
command.RemoveDirectory(os.path.join('%(output)s', 'i686-nacl')),
]
def D2NLibsSupportCommands(bias_arch, clang_libdir):
def TL(lib):
return GSDJoin(lib, pynacl.platform.GetArch3264(bias_arch))
def TranslatorFile(lib, filename):
return os.path.join('%(' + TL(lib) + ')s', filename)
commands = [
# Build compiler_rt which is now also used for the PNaCl
# translator.
command.Command(MakeCommand() + [
'-C', '%(abs_compiler_rt_src)s', 'ProjObjRoot=%(cwd)s',
'VERBOSE=1',
'AR=' + PnaclTool('ar', arch=bias_arch),
'RANLIB=' + PnaclTool('ranlib', arch=bias_arch),
'CC=' + PnaclTool('clang', arch=bias_arch), 'clang_nacl',
'EXTRA_CFLAGS=' + NewlibIsystemCflags(bias_arch)]),
command.Mkdir(clang_libdir, parents=True),
command.Copy(os.path.join(
'clang_nacl',
'full-' + bias_arch.replace('i686', 'i386')
.replace('mipsel', 'mips32'),
'libcompiler_rt.a'),
os.path.join('%(output)s', clang_libdir,
'libgcc.a')),
command.Copy(
TranslatorFile('libgcc_eh', 'libgcc_eh.a'),
os.path.join('%(output)s', clang_libdir, 'libgcc_eh.a')),
BuildTargetObjectCmd('clang_direct/crtbegin.c', 'crtbeginT.o',
bias_arch, output_dir=clang_libdir),
BuildTargetObjectCmd('crtend.c', 'crtend.o',
bias_arch, output_dir=clang_libdir),
]
if bias_arch == "mipsel":
commands.extend([
BuildTargetObjectCmd('bitcode/pnaclmm.c', 'pnaclmm.o', bias_arch),
BuildTargetObjectCmd('clang_direct/nacl-tp-offset.c',
'nacl_tp_offset.o', bias_arch,
extra_flags=['-I%(top_srcdir)s/..']),
command.Command([PnaclTool('ar'), 'rc',
command.path.join(clang_libdir, 'libpnacl_legacy.a'),
command.path.join('pnaclmm.o'),
command.path.join('nacl_tp_offset.o')])
])
return commands
def TargetLibBuildType(is_canonical):
return 'build' if is_canonical else 'build_noncanonical'
def TargetLibs(bias_arch, is_canonical):
def T(component_name):
return GSDJoin(component_name, bias_arch)
target_triple = TripleFromArch(bias_arch)
newlib_triple = target_triple if not IsBCArch(bias_arch) else 'le32-nacl'
newlib_cpp_flags = ''
if IsBCArch(bias_arch):
# This avoids putting the body of memcpy in libc for bitcode
newlib_cpp_flags = ' -DPNACL_BITCODE'
elif bias_arch == 'arm':
# This ensures that nacl gets the asm version of memcpy (gcc defines this
# macro for armv7a but clang does not)
newlib_cpp_flags = ' -D__ARM_FEATURE_UNALIGNED'
clang_libdir = os.path.join(
'%(output)s', 'lib', 'clang', CLANG_VER, 'lib', target_triple)
libc_libdir = os.path.join('%(output)s', MultilibLibDir(bias_arch))
libs = {
T('newlib'): {
'type': TargetLibBuildType(is_canonical),
'dependencies': [ 'newlib_src', 'target_lib_compiler'],
'commands' : [
command.SkipForIncrementalCommand(
['sh', '%(newlib_src)s/configure'] +
TargetTools(bias_arch) +
['CFLAGS_FOR_TARGET=' +
TargetLibCflags(bias_arch) +
newlib_cpp_flags,
'--prefix=',
'--disable-newlib-supplied-syscalls',
'--disable-texinfo',
'--disable-libgloss',
'--enable-newlib-iconv',
'--enable-newlib-iconv-from-encodings=' +
'UTF-8,UTF-16LE,UCS-4LE,UTF-16,UCS-4',
'--enable-newlib-iconv-to-encodings=' +
'UTF-8,UTF-16LE,UCS-4LE,UTF-16,UCS-4',
'--enable-newlib-io-long-long',
'--enable-newlib-io-long-double',
'--enable-newlib-io-c99-formats',
'--enable-newlib-mb',
'--target=' + newlib_triple
]),
command.Command(MakeCommand()),
command.Command(['make', 'DESTDIR=%(abs_output)s', 'install']),
] + NewlibDirectoryCmds(bias_arch, newlib_triple)
},
T('libcxx'): {
'type': TargetLibBuildType(is_canonical),
'dependencies': ['libcxx_src', 'libcxxabi_src', 'llvm_src', 'gcc_src',
'target_lib_compiler', T('newlib'),
GSDJoin('newlib', MultilibArch(bias_arch)),
T('libs_support')],
'commands' :
[command.SkipForIncrementalCommand(
[pnacl_commands.PrebuiltCmake(), '-G', 'Unix Makefiles',
'-DCMAKE_C_COMPILER_WORKS=1',
'-DCMAKE_CXX_COMPILER_WORKS=1',
'-DCMAKE_INSTALL_PREFIX=',
'-DCMAKE_BUILD_TYPE=Release',
'-DCMAKE_C_COMPILER=' + PnaclTool('clang', bias_arch),
'-DCMAKE_CXX_COMPILER=' + PnaclTool('clang++', bias_arch),
'-DCMAKE_SYSTEM_NAME=nacl',
'-DCMAKE_AR=' + PnaclTool('ar', bias_arch),
'-DCMAKE_NM=' + PnaclTool('nm', bias_arch),
'-DCMAKE_RANLIB=' + PnaclTool('ranlib', bias_arch),
'-DCMAKE_LD=' + PnaclTool('illegal', bias_arch),
'-DCMAKE_AS=' + PnaclTool('as', bias_arch),
'-DCMAKE_OBJDUMP=' + PnaclTool('illegal', bias_arch),
'-DCMAKE_C_FLAGS=-std=gnu11 ' + LibCxxCflags(bias_arch),
'-DCMAKE_CXX_FLAGS=-std=gnu++11 ' + LibCxxCflags(bias_arch),
'-DLIT_EXECUTABLE=' + command.path.join(
'%(llvm_src)s', 'utils', 'lit', 'lit.py'),
# The lit flags are used by the libcxx testsuite, which is
# currenty driven by an external script.
'-DLLVM_LIT_ARGS=--verbose --param shell_prefix="' +
os.path.join(NACL_DIR,'run.py') +' -arch env --retries=1" '+
'--param exe_suffix=".pexe" --param use_system_lib=true ' +
'--param cxx_under_test="' + os.path.join(NACL_DIR,
'toolchain/linux_x86/pnacl_newlib',
'bin/pnacl-clang++') +
'" '+
'--param link_flags="-std=gnu++11 --pnacl-exceptions=sjlj"',
'-DLIBCXX_ENABLE_CXX0X=0',
'-DLIBCXX_ENABLE_SHARED=0',
'-DLIBCXX_CXX_ABI=libcxxabi',
'-DLIBCXX_LIBCXXABI_INCLUDE_PATHS=' + command.path.join(
'%(abs_libcxxabi_src)s', 'include'),
'%(libcxx_src)s']),
command.Copy(os.path.join('%(gcc_src)s', 'gcc',
'unwind-generic.h'),
os.path.join('include', 'unwind.h')),
command.Command(MakeCommand() + ['VERBOSE=1']),
command.Command([
'make',
'DESTDIR=' + os.path.join('%(abs_output)s', target_triple),
'VERBOSE=1',
'install']),
] + LibcxxDirectoryCmds(bias_arch)
},
}
if IsBCArch(bias_arch):
libs.update({
T('compiler_rt_bc'): {
'type': TargetLibBuildType(is_canonical),
'dependencies': ['compiler_rt_src', 'target_lib_compiler'],
'commands': [
command.Mkdir(clang_libdir, parents=True),
command.Command(MakeCommand() + [
'-f',
command.path.join('%(compiler_rt_src)s', 'lib', 'builtins',
'Makefile-pnacl-bitcode'),
'libgcc.a', 'CC=' + PnaclTool('clang'),
'AR=' + PnaclTool('ar')] +
['SRC_DIR=' + command.path.join('%(abs_compiler_rt_src)s',
'lib', 'builtins'),
'CFLAGS=' + ' '.join([
'-DPNACL_' + TargetArch(bias_arch).replace('-', '_')])
]),
command.Copy('libgcc.a', os.path.join(clang_libdir, 'libgcc.a')),
],
},
T('libs_support'): {
'type': TargetLibBuildType(is_canonical),
'dependencies': [ T('newlib'), 'target_lib_compiler'],
'inputs': { 'src': os.path.join(NACL_DIR,
'pnacl', 'support', 'bitcode')},
'commands': [
command.Mkdir(clang_libdir, parents=True),
command.Mkdir(libc_libdir, parents=True),
# Two versions of crt1.x exist, for different scenarios (with and
# without EH). See:
# https://code.google.com/p/nativeclient/issues/detail?id=3069
command.Copy(command.path.join('%(src)s', 'crt1.x'),
command.path.join(libc_libdir, 'crt1.x')),
command.Copy(command.path.join('%(src)s', 'crt1_for_eh.x'),
command.path.join(libc_libdir, 'crt1_for_eh.x')),
# Install crti.bc (empty _init/_fini)
BuildTargetObjectCmd('crti.c', 'crti.bc', bias_arch,
output_dir=libc_libdir),
# Install crtbegin bitcode (__cxa_finalize for C++)
BuildTargetObjectCmd('crtbegin.c', 'crtbegin.bc', bias_arch,
output_dir=clang_libdir),
# Stubs for _Unwind_* functions when libgcc_eh is not included in
# the native link).
BuildTargetObjectCmd('unwind_stubs.c', 'unwind_stubs.bc',
bias_arch, output_dir=clang_libdir),
BuildTargetObjectCmd('sjlj_eh_redirect.cc',
'sjlj_eh_redirect.bc', bias_arch,
output_dir=clang_libdir),
# libpnaclmm.a (__atomic_* library functions).
BuildTargetObjectCmd('pnaclmm.c', 'pnaclmm.bc', bias_arch),
command.Command([
PnaclTool('ar'), 'rc',
command.path.join(clang_libdir, 'libpnaclmm.a'),
'pnaclmm.bc']),
]
}
})
else:
# For now some of the D2N support libs currently come from our native
# translator libs (libgcc_eh). crti/crtn and crt1
# come from libnacl, built by scons/gyp. TODO(dschuff): Do D2N libgcc_eh.
# Translate from bias_arch's triple-style (i686) names to the translator's
# style (x86-32). We don't change the translator's naming scheme to avoid
# churning the in-browser translator.
def TL(lib):
return GSDJoin(lib, pynacl.platform.GetArch3264(bias_arch))
libs.update({
T('libs_support'): {
'type': TargetLibBuildType(is_canonical),
'dependencies': [ 'compiler_rt_src',
GSDJoin('newlib', MultilibArch(bias_arch)),
TL('libgcc_eh'),
'target_lib_compiler'],
'inputs': { 'src': os.path.join(NACL_DIR, 'pnacl', 'support'),
'tls_params': os.path.join(NACL_DIR, 'src', 'untrusted',
'nacl', 'tls_params.h')},
'commands': D2NLibsSupportCommands(bias_arch, clang_libdir),
}
})
return libs
def SubzeroRuntimeCommands(arch, out_dir):
"""Returns a list of commands to build the Subzero runtime.
When the commands are executed, temporary files are created in the current
directory, and .o files are created in the out_dir directory. If arch isn't
among a whitelist, an empty list of commands is returned.
"""
AsmSourceBase = None
# LlcArchArgs contains arguments extracted from pnacl-translate.py.
if arch == 'x86-32-linux':
Triple = 'i686-linux-gnu'
LlcArchArgs = [ '-mcpu=pentium4m']
elif arch == 'x86-32':
Triple = 'i686-none-nacl-gnu'
LlcArchArgs = [ '-mcpu=pentium4m']
elif arch == 'x86-32-nonsfi':
Triple = 'i686-linux-gnu'
LlcArchArgs = [ '-mcpu=pentium4m', '-relocation-model=pic',
'-force-tls-non-pic', '-malign-double']
AsmSourceBase = 'szrt_asm_x8632'
elif arch == 'x86-64-linux':
Triple = 'x86_64-none-linux-gnux32'
LlcArchArgs = [ '-mcpu=x86-64']
elif arch == 'x86-64':
Triple = 'x86_64-none-nacl'
LlcArchArgs = [ '-mcpu=x86-64']
elif arch == 'arm-linux':
Triple = 'arm-linux-gnu'
LlcArchArgs = [ '-mcpu=cortex-a9', '-float-abi=hard', '-mattr=+neon']
elif arch == 'arm':
Triple = 'armv7a-none-nacl'
LlcArchArgs = [ '-mcpu=cortex-a9', '-float-abi=hard', '-mattr=+neon']
elif arch == 'arm-nonsfi':
Triple = 'armv7a-none-linux-gnueabihf'
LlcArchArgs = [ '-mcpu=cortex-a9', '-float-abi=hard', '-mattr=+neon',
'-relocation-model=pic', '-force-tls-non-pic',
'-malign-double']
AsmSourceBase = 'szrt_asm_arm32'
else:
return []
LlcArchArgs.append('-mtriple=' + Triple)
return [
command.Command([
PnaclTool('clang'), '-O2',
'-c', command.path.join('%(subzero_src)s', 'runtime', 'szrt.c'),
'-o', 'szrt.tmp.bc']),
command.Command([
PnaclTool('opt'), '-pnacl-abi-simplify-preopt',
'-pnacl-abi-simplify-postopt', '-pnaclabi-allow-debug-metadata',
'szrt.tmp.bc', '-S', '-o', 'szrt.ll']),
command.Command([
PnaclTool('llc'), '-externalize', '-function-sections', '-O2',
'-filetype=obj', '-bitcode-format=llvm',
'-o', os.path.join(out_dir, 'szrt.o'),
'szrt.ll'] +
LlcArchArgs),
command.Command([
PnaclTool('llc'), '-externalize', '-function-sections', '-O2',
'-filetype=obj', '-bitcode-format=llvm',
'-o', os.path.join(out_dir, 'szrt_ll.o'),
command.path.join('%(subzero_src)s', 'runtime', 'szrt_ll.ll')] +
LlcArchArgs),
] + ([
command.Command([
PnaclTool('llvm-mc'),
'-filetype=obj',
'-triple=' + Triple,
'--defsym', 'NONSFI=1',
'-o', os.path.join(out_dir, AsmSourceBase + '.o'),
command.path.join('%(subzero_src)s', 'runtime', AsmSourceBase + '.s')])
] if IsNonSFIArch(arch) else [])
def TranslatorLibs(arch, is_canonical, no_nacl_gcc):
setjmp_arch = arch
if setjmp_arch.endswith('-nonsfi'):
setjmp_arch = setjmp_arch[:-len('-nonsfi')]
bias_arch = TranslatorArchToBiasArch(arch)
translator_lib_dir = os.path.join('translator', arch, 'lib')
arch_cmds = []
if arch == 'arm':
arch_cmds.append(
BuildTargetTranslatorCmd('aeabi_read_tp.S', 'aeabi_read_tp.o', arch))
elif arch == 'x86-32-nonsfi':
arch_cmds.extend(
[BuildTargetTranslatorCmd('entry_linux.c', 'entry_linux.o', arch),
BuildTargetTranslatorCmd('entry_linux_x86_32.S', 'entry_linux_asm.o',
arch)])
elif arch == 'arm-nonsfi':
arch_cmds.extend(
[BuildTargetTranslatorCmd('entry_linux.c', 'entry_linux.o', arch),
BuildTargetTranslatorCmd('entry_linux_arm.S', 'entry_linux_asm.o',
arch)])
if not IsNonSFIArch(arch):
def ClangLib(lib):
return GSDJoin(lib, bias_arch)
clang_deps = [ ClangLib('newlib'), ClangLib('libs_support') ]
# Extract the object files from the newlib archive into our working dir.
# libcrt_platform.a is later created by archiving all the object files
# there.
crt_objs = ['memmove', 'memcmp', 'memset', 'memcpy']
if arch == 'mips32':
crt_objs.extend(['memset-stub', 'memcpy-stub'])
libcrt_platform_string_cmds = [command.Command([
PnaclTool('ar'), 'x',
os.path.join('%(' + ClangLib('newlib') + ')s',
MultilibLibDir(bias_arch), 'libcrt_common.a'),
] + ['lib_a-%s.o' % f for f in crt_objs])]
# Copy compiler_rt from nacl-clang
clang_libdir = os.path.join(
'lib', 'clang', CLANG_VER, 'lib', TripleFromArch(bias_arch))
compiler_rt_cmds = [command.Copy(
os.path.join('%(' + ClangLib('libs_support') + ')s',
clang_libdir, 'libgcc.a'),
os.path.join('%(output)s', 'libgcc.a'))]
else:
clang_deps = []
extra_flags = NonSFITargetLibCflags(bias_arch).split()
libcrt_platform_string_cmds = [BuildTargetTranslatorCmd(
'string.c', 'string.o', arch, ['-std=c99'],
source_dir='%(newlib_subset)s')]
# Build compiler_rt with PNaCl
compiler_rt_cmds = [
command.Command(MakeCommand() + [
'-C', '%(abs_compiler_rt_src)s', 'ProjObjRoot=%(cwd)s',
'VERBOSE=1',
'CC=' + PnaclTool('clang', arch=bias_arch), 'clang_nacl',
'EXTRA_CFLAGS=' + (NewlibIsystemCflags('le32') + ' ' +
' '.join(extra_flags))]),
command.Copy(os.path.join(
'clang_nacl',
'full-' + bias_arch.replace('i686', 'i386')
.replace('mipsel', 'mips32'),
'libcompiler_rt.a'),
os.path.join('%(output)s', 'libgcc.a')),
]
libs = {
GSDJoin('libs_support_translator', arch): {
'type': TargetLibBuildType(is_canonical),
'output_subdir': translator_lib_dir,
'dependencies': [ 'newlib_src', 'compiler_rt_src', 'subzero_src',
'target_lib_compiler', 'newlib_le32'] + clang_deps,
# These libs include
# arbitrary stuff from native_client/src/{include,untrusted,trusted}
'inputs': { 'src': os.path.join(NACL_DIR, 'pnacl', 'support'),
'include': os.path.join(NACL_DIR, 'src'),
'newlib_subset': os.path.join(
NACL_DIR, 'src', 'third_party',
'pnacl_native_newlib_subset')},
'commands': SubzeroRuntimeCommands(arch, '.') + [
BuildTargetTranslatorCmd('crtbegin.c', 'crtbegin.o', arch,
output_dir='%(output)s'),
BuildTargetTranslatorCmd('crtbegin.c', 'crtbegin_for_eh.o', arch,
['-DLINKING_WITH_LIBGCC_EH'],
output_dir='%(output)s'),
BuildTargetTranslatorCmd('crtend.c', 'crtend.o', arch,
output_dir='%(output)s'),
# libcrt_platform.a
BuildTargetTranslatorCmd('pnacl_irt.c', 'pnacl_irt.o', arch),
BuildTargetTranslatorCmd('relocate.c', 'relocate.o', arch),
BuildTargetTranslatorCmd(
'setjmp_%s.S' % setjmp_arch.replace('-', '_'),
'setjmp.o', arch),
# Pull in non-errno __ieee754_fmod from newlib and rename it to
# fmod. This is to support the LLVM frem instruction.
BuildTargetTranslatorCmd(
'e_fmod.c', 'e_fmod.o', arch,
['-std=c99', '-I%(abs_newlib_src)s/newlib/libm/common/',
'-D__ieee754_fmod=fmod'],
source_dir='%(abs_newlib_src)s/newlib/libm/math'),
BuildTargetTranslatorCmd(
'ef_fmod.c', 'ef_fmod.o', arch,
['-std=c99', '-I%(abs_newlib_src)s/newlib/libm/common/',
'-D__ieee754_fmodf=fmodf'],
source_dir='%(abs_newlib_src)s/newlib/libm/math')] +
arch_cmds + libcrt_platform_string_cmds + [
command.Command(' '.join([
PnaclTool('ar'), 'rc',
command.path.join('%(output)s', 'libcrt_platform.a'),
'*.o']), shell=True),
# Dummy IRT shim
BuildTargetTranslatorCmd(
'dummy_shim_entry.c', 'dummy_shim_entry.o', arch),
command.Command([PnaclTool('ar'), 'rc',
command.path.join('%(output)s',
'libpnacl_irt_shim_dummy.a'),
'dummy_shim_entry.o']),
] + compiler_rt_cmds,
},
}
if not arch.endswith('-nonsfi'):
libs.update({
GSDJoin('libgcc_eh', arch): {
'type': TargetLibBuildType(is_canonical),
'output_subdir': translator_lib_dir,
'dependencies': [ 'gcc_src', 'target_lib_compiler'],
'inputs': { 'scripts': os.path.join(NACL_DIR, 'pnacl', 'scripts')},
'commands': [
# Instead of trying to use gcc's build system to build only
# libgcc_eh, we just build the C files and archive them manually.
command.RemoveDirectory('include'),
command.Mkdir('include'),
command.Copy(os.path.join('%(gcc_src)s', 'gcc',
'unwind-generic.h'),
os.path.join('include', 'unwind.h')),
command.Copy(os.path.join('%(scripts)s', 'libgcc-tconfig.h'),
'tconfig.h'),
command.WriteData('', 'tm.h'),
BuildLibgccEhCmd('unwind-dw2.c', 'unwind-dw2.o', arch,
no_nacl_gcc),
BuildLibgccEhCmd('unwind-dw2-fde-glibc.c',
'unwind-dw2-fde-glibc.o', arch, no_nacl_gcc),
command.Command([PnaclTool('ar'), 'rc',
command.path.join('%(output)s', 'libgcc_eh.a'),
'unwind-dw2.o', 'unwind-dw2-fde-glibc.o']),
],
},
})
return libs
def UnsandboxedRuntime(arch, is_canonical):
assert arch in ('arm-linux', 'x86-32-linux', 'x86-32-mac', 'x86-64-linux')
compiler = {
'arm-linux': 'arm-linux-gnueabihf-gcc',
'x86-32-linux': 'gcc',
'x86-32-mac': 'gcc',
# x86-64 can't use gcc because the gcc available in the bots does not
# support x32. clang is good enough for the task, and it is available in
# the bots.
'x86-64-linux': '%(abs_target_lib_compiler)s/bin/clang',
}[arch]
arch_cflags = {
'arm-linux': ['-mcpu=cortex-a9', '-D__arm_nonsfi_linux__'],
'x86-32-linux': ['-m32'],
'x86-32-mac': ['-m32'],
'x86-64-linux': ['-mx32'],
}[arch]
libs = {
GSDJoin('unsandboxed_runtime', arch): {
'type': TargetLibBuildType(is_canonical),
'output_subdir': os.path.join('translator', arch, 'lib'),
'dependencies': [ 'subzero_src', 'target_lib_compiler'],
# This lib #includes
# arbitrary stuff from native_client/src/{include,untrusted,trusted}
'inputs': { 'support': os.path.join(NACL_DIR, 'src', 'nonsfi', 'irt'),
'untrusted': os.path.join(
NACL_DIR, 'src', 'untrusted', 'irt'),
'include': os.path.join(NACL_DIR, 'src'), },
'commands': [
# The NaCl headers insist on having a platform macro such as
# NACL_LINUX defined, but src/nonsfi/irt_interfaces.c does not
# itself use any of these macros, so defining NACL_LINUX here
# even on non-Linux systems is OK.
# TODO(dschuff): this include path breaks the input encapsulation
# for build rules.
command.Command([compiler] + arch_cflags + ['-O2', '-Wall',
'-Werror', '-I%(top_srcdir)s/..',
'-DNACL_LINUX=1', '-DDEFINE_MAIN',
'-c', command.path.join('%(support)s', 'irt_interfaces.c'),
'-o', command.path.join('%(output)s', 'unsandboxed_irt.o')]),
command.Command([compiler] + arch_cflags + ['-O2', '-Wall',
'-Werror', '-I%(top_srcdir)s/..',
'-c', command.path.join('%(support)s', 'irt_random.c'),
'-o', command.path.join('%(output)s', 'irt_random.o')]),
command.Command([compiler] + arch_cflags + ['-O2', '-Wall',
'-Werror', '-I%(top_srcdir)s/..',
'-c', command.path.join('%(untrusted)s', 'irt_query_list.c'),
'-o', command.path.join('%(output)s', 'irt_query_list.o')]),
] + SubzeroRuntimeCommands(arch, '%(output)s'),
},
}
return libs
def SDKCompiler(arches):
arch_packages = ([GSDJoin('newlib', arch) for arch in arches] +
[GSDJoin('libcxx', arch) for arch in arches])
compiler = {
'sdk_compiler': {
'type': 'work',
'output_subdir': 'sdk_compiler',
'dependencies': ['target_lib_compiler'] + arch_packages,
'commands': [
command.CopyRecursive('%(' + t + ')s', '%(output)s')
for t in ['target_lib_compiler'] + arch_packages],
},
}
return compiler
def SDKLibs(arch, is_canonical, extra_flags=[]):
scons_flags = ['--verbose', 'MODE=nacl', '-j%(cores)s', 'naclsdk_validate=0',
'pnacl_newlib_dir=%(abs_sdk_compiler)s',
'DESTINATION_ROOT=%(work_dir)s']
scons_flags.extend(extra_flags)
if arch == 'le32':
scons_flags.extend(['bitcode=1', 'platform=x86-32'])
elif not IsBCArch(arch):
scons_flags.extend(['nacl_clang=1',
'platform=' + pynacl.platform.GetArch3264(arch)])
else:
raise ValueError('Should not be building SDK libs for', arch)
libs = {
GSDJoin('core_sdk_libs', arch): {
'type': TargetLibBuildType(is_canonical),
'dependencies': ['sdk_compiler', 'target_lib_compiler'],
'inputs': {
'src_untrusted': os.path.join(NACL_DIR, 'src', 'untrusted'),
'src_include': os.path.join(NACL_DIR, 'src', 'include'),
'scons.py': os.path.join(NACL_DIR, 'scons.py'),
'site_scons': os.path.join(NACL_DIR, 'site_scons'),
},
'commands': [
command.Command(
[sys.executable, '%(scons.py)s',
'includedir=' +os.path.join('%(output)s',
TripleFromArch(MultilibArch(arch)),
'include'),
'libdir=' + os.path.join('%(output)s', MultilibLibDir(arch)),
'install'] + scons_flags,
cwd=NACL_DIR),
],
}
}
return libs