Esempio n. 1
0
def intercept_build_main():
    """ Entry point for 'intercept-build' command. """

    args = intercept()
    exit_code, current = capture(args)

    # To support incremental builds, it is desired to read elements from
    # an existing compilation database from a previous run.
    if args.append and os.path.isfile(args.cdb):
        previous = CompilationDatabase.load(args.cdb)
        entries = iter(set(itertools.chain(previous, current)))
        CompilationDatabase.save(args.cdb, entries)
    else:
        CompilationDatabase.save(args.cdb, current)

    return exit_code
Esempio n. 2
0
def intercept_build_main():
    """ Entry point for 'intercept-build' command. """

    args = intercept()
    exit_code, current = capture(args)

    # To support incremental builds, it is desired to read elements from
    # an existing compilation database from a previous run.
    if args.append and os.path.isfile(args.cdb):
        previous = CompilationDatabase.load(args.cdb)
        entries = iter(set(itertools.chain(previous, current)))
        CompilationDatabase.save(args.cdb, entries)
    else:
        CompilationDatabase.save(args.cdb, current)

    return exit_code
Esempio n. 3
0
def analyze_build():
    """ Entry point for analyze-build command. """

    args = parse_args_for_analyze_build()
    # will re-assign the report directory as new output
    with report_directory(args.output, args.keep_empty) as args.output:
        # run the analyzer against a compilation db
        compilations = CompilationDatabase.load(args.cdb)
        run_analyzer_parallel(compilations, args)
        # cover report generation and bug counting
        number_of_bugs = document(args)
        # set exit status as it was requested
        return number_of_bugs if args.status_bugs else 0
Esempio n. 4
0
def analyze_build():
    """ Entry point for analyze-build command. """

    args = analyze()
    # will re-assign the report directory as new output
    with report_directory(args.output, args.keep_empty) as args.output:
        # run the analyzer against a compilation db
        compilations = CompilationDatabase.load(args.cdb)
        run_analyzer_parallel(compilations, args)
        # cover report generation and bug counting
        number_of_bugs = document(args)
        # set exit status as it was requested
        return number_of_bugs if args.status_bugs else 0
Esempio n. 5
0
    def make_scan_build(self,
                        build_args: Tuple[str],
                        cdb_file: Optional[Union[str, io.IOBase]] = None,
                        suppress_output: bool = False,
                        sandbox: bool = False):
        from libscanbuild.compilation import Compilation, CompilationDatabase
        from libscanbuild.arguments import create_intercept_parser
        import itertools

        import subprocess
        import argparse

        if sandbox:
            import tempfile
            td = tempfile.TemporaryDirectory()
            td_path = td.name.replace("\\", "/")
            build_args = [*build_args, f'BINDIR={td_path}']

        def libscanbuild_capture(
                args: argparse.Namespace) -> Tuple[int, Iterable[Compilation]]:
            """
            Implementation of compilation database generation.

            :param args:    the parsed and validated command line arguments
            :return:        the exit status of build process.
            """
            from libscanbuild.intercept import setup_environment, run_build, exec_trace_files, parse_exec_trace, \
                compilations
            from libear import temporary_directory

            with temporary_directory(prefix='intercept-') as tmp_dir:
                # run the build command
                environment = setup_environment(args, tmp_dir)
                if os.environ.get('PROS_TOOLCHAIN'):
                    environment['PATH'] = os.path.join(os.environ.get('PROS_TOOLCHAIN'), 'bin') + os.pathsep + \
                                          environment['PATH']

                if sys.platform == 'darwin':
                    environment['PATH'] = os.path.dirname(os.path.abspath(sys.executable)) + os.pathsep + \
                                          environment['PATH']

                if not suppress_output:
                    pipe = EchoPipe()
                else:
                    pipe = subprocess.DEVNULL
                logger(__name__).debug(self.directory)
                exit_code = run_build(args.build,
                                      env=environment,
                                      stdout=pipe,
                                      stderr=pipe,
                                      cwd=self.directory)
                if not suppress_output:
                    pipe.close()
                # read the intercepted exec calls
                calls = (parse_exec_trace(file)
                         for file in exec_trace_files(tmp_dir))
                current = compilations(calls, args.cc, args.cxx)

                return exit_code, iter(set(current))

        # call make.exe if on Windows
        if os.name == 'nt' and os.environ.get('PROS_TOOLCHAIN'):
            make_cmd = os.path.join(os.environ.get('PROS_TOOLCHAIN'), 'bin',
                                    'make.exe')
        else:
            make_cmd = 'make'
        args = create_intercept_parser().parse_args([
            '--override-compiler', '--use-cc', 'arm-none-eabi-gcc',
            '--use-c++', 'arm-none-eabi-g++', make_cmd, *build_args,
            'CC=intercept-cc', 'CXX=intercept-c++'
        ])
        exit_code, entries = libscanbuild_capture(args)

        if sandbox and td:
            td.cleanup()

        any_entries, entries = itertools.tee(entries, 2)
        if not any(any_entries):
            return exit_code
        if not suppress_output:
            ui.echo('Capturing metadata for PROS Editor...')
        env = os.environ.copy()
        # Add PROS toolchain to the beginning of PATH to ensure PROS binaries are preferred
        if os.environ.get('PROS_TOOLCHAIN'):
            env['PATH'] = os.path.join(os.environ.get('PROS_TOOLCHAIN'),
                                       'bin') + os.pathsep + env['PATH']
        cc_sysroot = subprocess.run([make_cmd, 'cc-sysroot'],
                                    env=env,
                                    stdout=subprocess.PIPE,
                                    stderr=subprocess.PIPE,
                                    cwd=self.directory)
        lines = str(cc_sysroot.stderr.decode()).splitlines() + str(
            cc_sysroot.stdout.decode()).splitlines()
        lines = [l.strip() for l in lines]
        cc_sysroot_includes = []
        copy = False
        for line in lines:
            if line == '#include <...> search starts here:':
                copy = True
                continue
            if line == 'End of search list.':
                copy = False
                continue
            if copy:
                cc_sysroot_includes.append(f'-isystem{line}')
        cxx_sysroot = subprocess.run([make_cmd, 'cxx-sysroot'],
                                     env=env,
                                     stdout=subprocess.PIPE,
                                     stderr=subprocess.PIPE,
                                     cwd=self.directory)
        lines = str(cxx_sysroot.stderr.decode()).splitlines() + str(
            cxx_sysroot.stdout.decode()).splitlines()
        lines = [l.strip() for l in lines]
        cxx_sysroot_includes = []
        copy = False
        for line in lines:
            if line == '#include <...> search starts here:':
                copy = True
                continue
            if line == 'End of search list.':
                copy = False
                continue
            if copy:
                cxx_sysroot_includes.append(f'-isystem{line}')
        new_entries, entries = itertools.tee(entries, 2)
        new_sources = set([e.source for e in entries])
        if not cdb_file:
            cdb_file = os.path.join(self.directory, 'compile_commands.json')
        if isinstance(cdb_file, str) and os.path.isfile(cdb_file):
            old_entries = itertools.filterfalse(
                lambda entry: entry.source in new_sources,
                CompilationDatabase.load(cdb_file))
        else:
            old_entries = []

        extra_flags = ['-target', 'armv7ar-none-none-eabi']
        logger(__name__).debug('cc_sysroot_includes')
        logger(__name__).debug(cc_sysroot_includes)
        logger(__name__).debug('cxx_sysroot_includes')
        logger(__name__).debug(cxx_sysroot_includes)

        if sys.platform == 'win32':
            extra_flags.extend([
                "-fno-ms-extensions", "-fno-ms-compatibility",
                "-fno-delayed-template-parsing"
            ])

        def new_entry_map(entry):
            if entry.compiler == 'c':
                entry.flags = extra_flags + cc_sysroot_includes + entry.flags
            elif entry.compiler == 'c++':
                entry.flags = extra_flags + cxx_sysroot_includes + entry.flags
            return entry

        new_entries = map(new_entry_map, new_entries)

        def entry_map(entry: Compilation):
            json_entry = entry.as_db_entry()
            json_entry['arguments'][
                0] = 'clang' if entry.compiler == 'cc' else 'clang++'
            return json_entry

        entries = itertools.chain(old_entries, new_entries)
        json_entries = list(map(entry_map, entries))
        if isinstance(cdb_file, str):
            cdb_file = open(cdb_file, 'w')
        import json
        json.dump(json_entries, cdb_file, sort_keys=True, indent=4)

        return exit_code
Esempio n. 6
0
for line in lines:
    if line == '#include <...> search starts here:':
        copy = True
        continue
    if line == 'End of search list.':
        copy = False
        continue
    if copy:
        cxx_sysroot_includes.append(f'-isystem{line}')
new_entries, entries = itertools.tee(entries, 2)
new_sources = set([e.source for e in entries])
cdb_file = 'compile_commands.json'
if isinstance(cdb_file, str) and os.path.isfile(cdb_file):
    old_entries = itertools.filterfalse(
        lambda entry: entry.source in new_sources,
        CompilationDatabase.load(cdb_file))
else:
    old_entries = []

extra_flags = ['-target', 'armv6m-none-none-eabi']

if sys.platform == 'win32':
    extra_flags.extend([
        "-fno-ms-extensions", "-fno-ms-compatibility",
        "-fno-delayed-template-parsing"
    ])


def new_entry_map(entry):
    if entry.compiler == 'c':
        entry.flags = extra_flags + cc_sysroot_includes + entry.flags