Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. # -*- coding: utf-8 -*-
  2. # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  3. # See https://llvm.org/LICENSE.txt for license information.
  4. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  5. """ This module compiles the intercept library. """
  6.  
  7. import sys
  8. import os
  9. import os.path
  10. import re
  11. import tempfile
  12. import shutil
  13. import contextlib
  14. import logging
  15.  
  16. __all__ = ['build_libear']
  17.  
  18.  
  19. def build_libear(compiler, dst_dir):
  20.     """ Returns the full path to the 'libear' library. """
  21.  
  22.     try:
  23.         src_dir = os.path.dirname(os.path.realpath(__file__))
  24.         toolset = make_toolset(src_dir)
  25.         toolset.set_compiler(compiler)
  26.         toolset.set_language_standard('c99')
  27.         toolset.add_definitions(['-D_GNU_SOURCE'])
  28.  
  29.         configure = do_configure(toolset)
  30.         configure.check_function_exists('execve', 'HAVE_EXECVE')
  31.         configure.check_function_exists('execv', 'HAVE_EXECV')
  32.         configure.check_function_exists('execvpe', 'HAVE_EXECVPE')
  33.         configure.check_function_exists('execvp', 'HAVE_EXECVP')
  34.         configure.check_function_exists('execvP', 'HAVE_EXECVP2')
  35.         configure.check_function_exists('exect', 'HAVE_EXECT')
  36.         configure.check_function_exists('execl', 'HAVE_EXECL')
  37.         configure.check_function_exists('execlp', 'HAVE_EXECLP')
  38.         configure.check_function_exists('execle', 'HAVE_EXECLE')
  39.         configure.check_function_exists('posix_spawn', 'HAVE_POSIX_SPAWN')
  40.         configure.check_function_exists('posix_spawnp', 'HAVE_POSIX_SPAWNP')
  41.         configure.check_symbol_exists('_NSGetEnviron', 'crt_externs.h',
  42.                                       'HAVE_NSGETENVIRON')
  43.         configure.write_by_template(
  44.             os.path.join(src_dir, 'config.h.in'),
  45.             os.path.join(dst_dir, 'config.h'))
  46.  
  47.         target = create_shared_library('ear', toolset)
  48.         target.add_include(dst_dir)
  49.         target.add_sources('ear.c')
  50.         target.link_against(toolset.dl_libraries())
  51.         target.link_against(['pthread'])
  52.         target.build_release(dst_dir)
  53.  
  54.         return os.path.join(dst_dir, target.name)
  55.  
  56.     except Exception:
  57.         logging.info("Could not build interception library.", exc_info=True)
  58.         return None
  59.  
  60.  
  61. def execute(cmd, *args, **kwargs):
  62.     """ Make subprocess execution silent. """
  63.  
  64.     import subprocess
  65.     kwargs.update({'stdout': subprocess.PIPE, 'stderr': subprocess.STDOUT})
  66.     return subprocess.check_call(cmd, *args, **kwargs)
  67.  
  68.  
  69. @contextlib.contextmanager
  70. def TemporaryDirectory(**kwargs):
  71.     name = tempfile.mkdtemp(**kwargs)
  72.     try:
  73.         yield name
  74.     finally:
  75.         shutil.rmtree(name)
  76.  
  77.  
  78. class Toolset(object):
  79.     """ Abstract class to represent different toolset. """
  80.  
  81.     def __init__(self, src_dir):
  82.         self.src_dir = src_dir
  83.         self.compiler = None
  84.         self.c_flags = []
  85.  
  86.     def set_compiler(self, compiler):
  87.         """ part of public interface """
  88.         self.compiler = compiler
  89.  
  90.     def set_language_standard(self, standard):
  91.         """ part of public interface """
  92.         self.c_flags.append('-std=' + standard)
  93.  
  94.     def add_definitions(self, defines):
  95.         """ part of public interface """
  96.         self.c_flags.extend(defines)
  97.  
  98.     def dl_libraries(self):
  99.         raise NotImplementedError()
  100.  
  101.     def shared_library_name(self, name):
  102.         raise NotImplementedError()
  103.  
  104.     def shared_library_c_flags(self, release):
  105.         extra = ['-DNDEBUG', '-O3'] if release else []
  106.         return extra + ['-fPIC'] + self.c_flags
  107.  
  108.     def shared_library_ld_flags(self, release, name):
  109.         raise NotImplementedError()
  110.  
  111.  
  112. class DarwinToolset(Toolset):
  113.     def __init__(self, src_dir):
  114.         Toolset.__init__(self, src_dir)
  115.  
  116.     def dl_libraries(self):
  117.         return []
  118.  
  119.     def shared_library_name(self, name):
  120.         return 'lib' + name + '.dylib'
  121.  
  122.     def shared_library_ld_flags(self, release, name):
  123.         extra = ['-dead_strip'] if release else []
  124.         return extra + ['-dynamiclib', '-install_name', '@rpath/' + name]
  125.  
  126.  
  127. class UnixToolset(Toolset):
  128.     def __init__(self, src_dir):
  129.         Toolset.__init__(self, src_dir)
  130.  
  131.     def dl_libraries(self):
  132.         return []
  133.  
  134.     def shared_library_name(self, name):
  135.         return 'lib' + name + '.so'
  136.  
  137.     def shared_library_ld_flags(self, release, name):
  138.         extra = [] if release else []
  139.         return extra + ['-shared', '-Wl,-soname,' + name]
  140.  
  141.  
  142. class LinuxToolset(UnixToolset):
  143.     def __init__(self, src_dir):
  144.         UnixToolset.__init__(self, src_dir)
  145.  
  146.     def dl_libraries(self):
  147.         return ['dl']
  148.  
  149.  
  150. def make_toolset(src_dir):
  151.     platform = sys.platform
  152.     if platform in {'win32', 'cygwin'}:
  153.         raise RuntimeError('not implemented on this platform')
  154.     elif platform == 'darwin':
  155.         return DarwinToolset(src_dir)
  156.     elif platform in {'linux', 'linux2'}:
  157.         return LinuxToolset(src_dir)
  158.     else:
  159.         return UnixToolset(src_dir)
  160.  
  161.  
  162. class Configure(object):
  163.     def __init__(self, toolset):
  164.         self.ctx = toolset
  165.         self.results = {'APPLE': sys.platform == 'darwin'}
  166.  
  167.     def _try_to_compile_and_link(self, source):
  168.         try:
  169.             with TemporaryDirectory() as work_dir:
  170.                 src_file = 'check.c'
  171.                 with open(os.path.join(work_dir, src_file), 'w') as handle:
  172.                     handle.write(source)
  173.  
  174.                 execute([self.ctx.compiler, src_file] + self.ctx.c_flags,
  175.                         cwd=work_dir)
  176.                 return True
  177.         except Exception:
  178.             return False
  179.  
  180.     def check_function_exists(self, function, name):
  181.         template = "int FUNCTION(); int main() { return FUNCTION(); }"
  182.         source = template.replace("FUNCTION", function)
  183.  
  184.         logging.debug('Checking function %s', function)
  185.         found = self._try_to_compile_and_link(source)
  186.         logging.debug('Checking function %s -- %s', function,
  187.                       'found' if found else 'not found')
  188.         self.results.update({name: found})
  189.  
  190.     def check_symbol_exists(self, symbol, include, name):
  191.         template = """#include <INCLUDE>
  192.                      int main() { return ((int*)(&SYMBOL))[0]; }"""
  193.         source = template.replace('INCLUDE', include).replace("SYMBOL", symbol)
  194.  
  195.         logging.debug('Checking symbol %s', symbol)
  196.         found = self._try_to_compile_and_link(source)
  197.         logging.debug('Checking symbol %s -- %s', symbol,
  198.                       'found' if found else 'not found')
  199.         self.results.update({name: found})
  200.  
  201.     def write_by_template(self, template, output):
  202.         def transform(line, definitions):
  203.  
  204.             pattern = re.compile(r'^#cmakedefine\s+(\S+)')
  205.             m = pattern.match(line)
  206.             if m:
  207.                 key = m.group(1)
  208.                 if key not in definitions or not definitions[key]:
  209.                     return '/* #undef {0} */{1}'.format(key, os.linesep)
  210.                 else:
  211.                     return '#define {0}{1}'.format(key, os.linesep)
  212.             return line
  213.  
  214.         with open(template, 'r') as src_handle:
  215.             logging.debug('Writing config to %s', output)
  216.             with open(output, 'w') as dst_handle:
  217.                 for line in src_handle:
  218.                     dst_handle.write(transform(line, self.results))
  219.  
  220.  
  221. def do_configure(toolset):
  222.     return Configure(toolset)
  223.  
  224.  
  225. class SharedLibrary(object):
  226.     def __init__(self, name, toolset):
  227.         self.name = toolset.shared_library_name(name)
  228.         self.ctx = toolset
  229.         self.inc = []
  230.         self.src = []
  231.         self.lib = []
  232.  
  233.     def add_include(self, directory):
  234.         self.inc.extend(['-I', directory])
  235.  
  236.     def add_sources(self, source):
  237.         self.src.append(source)
  238.  
  239.     def link_against(self, libraries):
  240.         self.lib.extend(['-l' + lib for lib in libraries])
  241.  
  242.     def build_release(self, directory):
  243.         for src in self.src:
  244.             logging.debug('Compiling %s', src)
  245.             execute(
  246.                 [self.ctx.compiler, '-c', os.path.join(self.ctx.src_dir, src),
  247.                  '-o', src + '.o'] + self.inc +
  248.                 self.ctx.shared_library_c_flags(True),
  249.                 cwd=directory)
  250.         logging.debug('Linking %s', self.name)
  251.         execute(
  252.             [self.ctx.compiler] + [src + '.o' for src in self.src] +
  253.             ['-o', self.name] + self.lib +
  254.             self.ctx.shared_library_ld_flags(True, self.name),
  255.             cwd=directory)
  256.  
  257.  
  258. def create_shared_library(name, toolset):
  259.     return SharedLibrary(name, toolset)
  260.