mirror of
https://github.com/Gericom/teak-llvm.git
synced 2025-06-20 03:55:48 -04:00

to reflect the new license. We understand that people may be surprised that we're moving the header entirely to discuss the new license. We checked this carefully with the Foundation's lawyer and we believe this is the correct approach. Essentially, all code in the project is now made available by the LLVM project under our new license, so you will see that the license headers include that license only. Some of our contributors have contributed code under our old license, and accordingly, we have retained a copy of our old license notice in the top-level files in each project and repository. llvm-svn: 351636
260 lines
8.3 KiB
Python
260 lines
8.3 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
# See https://llvm.org/LICENSE.txt for license information.
|
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
""" This module compiles the intercept library. """
|
|
|
|
import sys
|
|
import os
|
|
import os.path
|
|
import re
|
|
import tempfile
|
|
import shutil
|
|
import contextlib
|
|
import logging
|
|
|
|
__all__ = ['build_libear']
|
|
|
|
|
|
def build_libear(compiler, dst_dir):
|
|
""" Returns the full path to the 'libear' library. """
|
|
|
|
try:
|
|
src_dir = os.path.dirname(os.path.realpath(__file__))
|
|
toolset = make_toolset(src_dir)
|
|
toolset.set_compiler(compiler)
|
|
toolset.set_language_standard('c99')
|
|
toolset.add_definitions(['-D_GNU_SOURCE'])
|
|
|
|
configure = do_configure(toolset)
|
|
configure.check_function_exists('execve', 'HAVE_EXECVE')
|
|
configure.check_function_exists('execv', 'HAVE_EXECV')
|
|
configure.check_function_exists('execvpe', 'HAVE_EXECVPE')
|
|
configure.check_function_exists('execvp', 'HAVE_EXECVP')
|
|
configure.check_function_exists('execvP', 'HAVE_EXECVP2')
|
|
configure.check_function_exists('exect', 'HAVE_EXECT')
|
|
configure.check_function_exists('execl', 'HAVE_EXECL')
|
|
configure.check_function_exists('execlp', 'HAVE_EXECLP')
|
|
configure.check_function_exists('execle', 'HAVE_EXECLE')
|
|
configure.check_function_exists('posix_spawn', 'HAVE_POSIX_SPAWN')
|
|
configure.check_function_exists('posix_spawnp', 'HAVE_POSIX_SPAWNP')
|
|
configure.check_symbol_exists('_NSGetEnviron', 'crt_externs.h',
|
|
'HAVE_NSGETENVIRON')
|
|
configure.write_by_template(
|
|
os.path.join(src_dir, 'config.h.in'),
|
|
os.path.join(dst_dir, 'config.h'))
|
|
|
|
target = create_shared_library('ear', toolset)
|
|
target.add_include(dst_dir)
|
|
target.add_sources('ear.c')
|
|
target.link_against(toolset.dl_libraries())
|
|
target.link_against(['pthread'])
|
|
target.build_release(dst_dir)
|
|
|
|
return os.path.join(dst_dir, target.name)
|
|
|
|
except Exception:
|
|
logging.info("Could not build interception library.", exc_info=True)
|
|
return None
|
|
|
|
|
|
def execute(cmd, *args, **kwargs):
|
|
""" Make subprocess execution silent. """
|
|
|
|
import subprocess
|
|
kwargs.update({'stdout': subprocess.PIPE, 'stderr': subprocess.STDOUT})
|
|
return subprocess.check_call(cmd, *args, **kwargs)
|
|
|
|
|
|
@contextlib.contextmanager
|
|
def TemporaryDirectory(**kwargs):
|
|
name = tempfile.mkdtemp(**kwargs)
|
|
try:
|
|
yield name
|
|
finally:
|
|
shutil.rmtree(name)
|
|
|
|
|
|
class Toolset(object):
|
|
""" Abstract class to represent different toolset. """
|
|
|
|
def __init__(self, src_dir):
|
|
self.src_dir = src_dir
|
|
self.compiler = None
|
|
self.c_flags = []
|
|
|
|
def set_compiler(self, compiler):
|
|
""" part of public interface """
|
|
self.compiler = compiler
|
|
|
|
def set_language_standard(self, standard):
|
|
""" part of public interface """
|
|
self.c_flags.append('-std=' + standard)
|
|
|
|
def add_definitions(self, defines):
|
|
""" part of public interface """
|
|
self.c_flags.extend(defines)
|
|
|
|
def dl_libraries(self):
|
|
raise NotImplementedError()
|
|
|
|
def shared_library_name(self, name):
|
|
raise NotImplementedError()
|
|
|
|
def shared_library_c_flags(self, release):
|
|
extra = ['-DNDEBUG', '-O3'] if release else []
|
|
return extra + ['-fPIC'] + self.c_flags
|
|
|
|
def shared_library_ld_flags(self, release, name):
|
|
raise NotImplementedError()
|
|
|
|
|
|
class DarwinToolset(Toolset):
|
|
def __init__(self, src_dir):
|
|
Toolset.__init__(self, src_dir)
|
|
|
|
def dl_libraries(self):
|
|
return []
|
|
|
|
def shared_library_name(self, name):
|
|
return 'lib' + name + '.dylib'
|
|
|
|
def shared_library_ld_flags(self, release, name):
|
|
extra = ['-dead_strip'] if release else []
|
|
return extra + ['-dynamiclib', '-install_name', '@rpath/' + name]
|
|
|
|
|
|
class UnixToolset(Toolset):
|
|
def __init__(self, src_dir):
|
|
Toolset.__init__(self, src_dir)
|
|
|
|
def dl_libraries(self):
|
|
return []
|
|
|
|
def shared_library_name(self, name):
|
|
return 'lib' + name + '.so'
|
|
|
|
def shared_library_ld_flags(self, release, name):
|
|
extra = [] if release else []
|
|
return extra + ['-shared', '-Wl,-soname,' + name]
|
|
|
|
|
|
class LinuxToolset(UnixToolset):
|
|
def __init__(self, src_dir):
|
|
UnixToolset.__init__(self, src_dir)
|
|
|
|
def dl_libraries(self):
|
|
return ['dl']
|
|
|
|
|
|
def make_toolset(src_dir):
|
|
platform = sys.platform
|
|
if platform in {'win32', 'cygwin'}:
|
|
raise RuntimeError('not implemented on this platform')
|
|
elif platform == 'darwin':
|
|
return DarwinToolset(src_dir)
|
|
elif platform in {'linux', 'linux2'}:
|
|
return LinuxToolset(src_dir)
|
|
else:
|
|
return UnixToolset(src_dir)
|
|
|
|
|
|
class Configure(object):
|
|
def __init__(self, toolset):
|
|
self.ctx = toolset
|
|
self.results = {'APPLE': sys.platform == 'darwin'}
|
|
|
|
def _try_to_compile_and_link(self, source):
|
|
try:
|
|
with TemporaryDirectory() as work_dir:
|
|
src_file = 'check.c'
|
|
with open(os.path.join(work_dir, src_file), 'w') as handle:
|
|
handle.write(source)
|
|
|
|
execute([self.ctx.compiler, src_file] + self.ctx.c_flags,
|
|
cwd=work_dir)
|
|
return True
|
|
except Exception:
|
|
return False
|
|
|
|
def check_function_exists(self, function, name):
|
|
template = "int FUNCTION(); int main() { return FUNCTION(); }"
|
|
source = template.replace("FUNCTION", function)
|
|
|
|
logging.debug('Checking function %s', function)
|
|
found = self._try_to_compile_and_link(source)
|
|
logging.debug('Checking function %s -- %s', function,
|
|
'found' if found else 'not found')
|
|
self.results.update({name: found})
|
|
|
|
def check_symbol_exists(self, symbol, include, name):
|
|
template = """#include <INCLUDE>
|
|
int main() { return ((int*)(&SYMBOL))[0]; }"""
|
|
source = template.replace('INCLUDE', include).replace("SYMBOL", symbol)
|
|
|
|
logging.debug('Checking symbol %s', symbol)
|
|
found = self._try_to_compile_and_link(source)
|
|
logging.debug('Checking symbol %s -- %s', symbol,
|
|
'found' if found else 'not found')
|
|
self.results.update({name: found})
|
|
|
|
def write_by_template(self, template, output):
|
|
def transform(line, definitions):
|
|
|
|
pattern = re.compile(r'^#cmakedefine\s+(\S+)')
|
|
m = pattern.match(line)
|
|
if m:
|
|
key = m.group(1)
|
|
if key not in definitions or not definitions[key]:
|
|
return '/* #undef {0} */{1}'.format(key, os.linesep)
|
|
else:
|
|
return '#define {0}{1}'.format(key, os.linesep)
|
|
return line
|
|
|
|
with open(template, 'r') as src_handle:
|
|
logging.debug('Writing config to %s', output)
|
|
with open(output, 'w') as dst_handle:
|
|
for line in src_handle:
|
|
dst_handle.write(transform(line, self.results))
|
|
|
|
|
|
def do_configure(toolset):
|
|
return Configure(toolset)
|
|
|
|
|
|
class SharedLibrary(object):
|
|
def __init__(self, name, toolset):
|
|
self.name = toolset.shared_library_name(name)
|
|
self.ctx = toolset
|
|
self.inc = []
|
|
self.src = []
|
|
self.lib = []
|
|
|
|
def add_include(self, directory):
|
|
self.inc.extend(['-I', directory])
|
|
|
|
def add_sources(self, source):
|
|
self.src.append(source)
|
|
|
|
def link_against(self, libraries):
|
|
self.lib.extend(['-l' + lib for lib in libraries])
|
|
|
|
def build_release(self, directory):
|
|
for src in self.src:
|
|
logging.debug('Compiling %s', src)
|
|
execute(
|
|
[self.ctx.compiler, '-c', os.path.join(self.ctx.src_dir, src),
|
|
'-o', src + '.o'] + self.inc +
|
|
self.ctx.shared_library_c_flags(True),
|
|
cwd=directory)
|
|
logging.debug('Linking %s', self.name)
|
|
execute(
|
|
[self.ctx.compiler] + [src + '.o' for src in self.src] +
|
|
['-o', self.name] + self.lib +
|
|
self.ctx.shared_library_ld_flags(True, self.name),
|
|
cwd=directory)
|
|
|
|
|
|
def create_shared_library(name, toolset):
|
|
return SharedLibrary(name, toolset)
|