def scan_build(): """ Entry point for scan-build command. """ args = parse_args_for_scan_build() # will re-assign the report directory as new output with report_directory( args.output, args.keep_empty, args.output_format) as args.output: # Run against a build command. there are cases, when analyzer run # is not required. But we need to set up everything for the # wrappers, because 'configure' needs to capture the CC/CXX values # for the Makefile. if args.intercept_first: # Run build command with intercept module. exit_code = capture(args) # Run the analyzer against the captured commands. if need_analyzer(args.build): govern_analyzer_runs(args) else: # Run build command and analyzer with compiler wrappers. environment = setup_environment(args) exit_code = run_build(args.build, env=environment) # 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 exit_code
def scan_build(): # type: () -> int """ Entry point for scan-build command. """ args = parse_args_for_scan_build() # will re-assign the report directory as new output with report_directory(args.output, args.keep_empty) as args.output: # run against a build command. there are cases, when analyzer run # is not required. but we need to set up everything for the # wrappers, because 'configure' needs to capture the CC/CXX values # for the Makefile. if args.intercept_first: # run build command with intercept module exit_code, compilations = capture(args) if need_analyzer(args.build): # run the analyzer against the captured commands run_analyzer_parallel(compilations, args) else: # run build command and analyzer with compiler wrappers environment = setup_environment(args) exit_code = run_build(args.build, env=environment) # 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 exit_code
def capture(args): """ Implementation of compilation database generation. :param args: the parsed and validated command line arguments :return: the exit status of build process. """ with temporary_directory(prefix='intercept-', dir=tempdir()) as tmp_dir: # run the build command environment = setup_environment(args, tmp_dir) exit_code = run_build(args.build, env=environment) # 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))
def capture(args): """ Implementation of compilation database generation. :param args: the parsed and validated command line arguments :return: the exit status of build process. """ with temporary_directory(prefix='intercept-') as tmp_dir: # run the build command environment = setup_environment(args, tmp_dir) exit_code = run_build(args.build, env=environment) # 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))
def capture(args): """ The entry point of build command interception. """ def post_processing(commands): """ To make a compilation database, it needs to filter out commands which are not compiler calls. Needs to find the source file name from the arguments. And do shell escaping on the command. To support incremental builds, it is desired to read elements from an existing compilation database from a previous run. These elements shall be merged with the new elements. """ # create entries from the current run current = itertools.chain.from_iterable( # creates a sequence of entry generators from an exec, format_entry(command) for command in commands) # read entries from previous run if 'append' in args and args.append and os.path.isfile(args.cdb): with open(args.cdb) as handle: previous = iter(json.load(handle)) else: previous = iter([]) # filter out duplicate entries from both duplicate = duplicate_check(entry_hash) return (entry for entry in itertools.chain(previous, current) if os.path.exists(entry['file']) and not duplicate(entry)) with TemporaryDirectory(prefix='intercept-', dir=tempdir()) as tmp_dir: # run the build command environment = setup_environment(args, tmp_dir) exit_code = run_build(args.build, env=environment) # read the intercepted exec calls exec_traces = itertools.chain.from_iterable( parse_exec_trace(os.path.join(tmp_dir, filename)) for filename in sorted(glob.iglob(os.path.join(tmp_dir, '*.cmd')))) # do post processing entries = post_processing(exec_traces) # dump the compilation database with open(args.cdb, 'w+') as handle: json.dump(list(entries), handle, sort_keys=True, indent=4) return exit_code
def analyze_build_main(bin_dir, from_build_command): """ Entry point for 'analyze-build' and 'scan-build'. """ parser = create_parser(from_build_command) args = parser.parse_args() validate(parser, args, from_build_command) # setup logging initialize_logging(args.verbose) logging.debug('Parsed arguments: %s', args) with report_directory(args.output, args.keep_empty) as target_dir: if not from_build_command: # run analyzer only and generate cover report run_analyzer(args, target_dir) number_of_bugs = document(args, target_dir, True) return number_of_bugs if args.status_bugs else 0 elif args.intercept_first: # run build command and capture compiler executions exit_code = capture(args, bin_dir) # next step to run the analyzer against the captured commands if need_analyzer(args.build): run_analyzer(args, target_dir) # cover report generation and bug counting number_of_bugs = document(args, target_dir, True) # remove the compilation database when it was not requested if os.path.exists(args.cdb): os.unlink(args.cdb) # set exit status as it was requested return number_of_bugs if args.status_bugs else exit_code else: return exit_code else: # run the build command with compiler wrappers which # execute the analyzer too. (interposition) environment = setup_environment(args, target_dir, bin_dir) exit_code = run_build(args.build, env=environment) # cover report generation and bug counting number_of_bugs = document(args, target_dir, False) # set exit status as it was requested return number_of_bugs if args.status_bugs else exit_code
def scan_build(): """ Entry point for scan-build command. """ args = parse_args_for_scan_build() with report_directory(args.output, args.keep_empty) as target_dir: # Run against a build command. there are cases, when analyzer run # is not required. But we need to set up everything for the # wrappers, because 'configure' needs to capture the CC/CXX values # for the Makefile. if args.intercept_first: # Run build command with intercept module. exit_code = capture(args) # Run the analyzer against the captured commands. if need_analyzer(args.build): run_analyzer(args, target_dir) else: # Run build command and analyzer with compiler wrappers. environment = setup_environment(args, target_dir) exit_code = run_build(args.build, env=environment) # Cover report generation and bug counting. number_of_bugs = document(args, target_dir, False) # Set exit status as it was requested. return number_of_bugs if args.status_bugs else exit_code