You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
160 lines
6.6 KiB
160 lines
6.6 KiB
(*
|
|
* Copyright (c) 2016 - present Facebook, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under the BSD style license found in the
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
*)
|
|
|
|
open! Utils
|
|
|
|
module CLOpt = CommandLineOption
|
|
module F = Format
|
|
|
|
let capture_text =
|
|
if Config.analyzer = Config.Linters then "linting"
|
|
else "translating"
|
|
|
|
(** Read the files to compile from the changed files index. *)
|
|
let should_capture_file_from_index () =
|
|
match SourceFile.changed_files_set with
|
|
| None ->
|
|
(match Config.changed_files_index with
|
|
| Some index ->
|
|
Process.print_error_and_exit "Error reading the changed files index %s.\n%!" index
|
|
| None -> function _ -> true)
|
|
| Some files_set ->
|
|
function source_file -> SourceFile.Set.mem source_file files_set
|
|
|
|
(** The buck targets are assumed to start with //, aliases are not supported. *)
|
|
let check_args_for_targets args =
|
|
if not (IList.exists (String.is_prefix ~prefix:"//") args) then
|
|
let args_s = String.concat ~sep:" " args in
|
|
Process.print_error_and_exit
|
|
"Error reading buck command %s. Please, pass buck targets, aliases are not allowed.\n%!"
|
|
args_s
|
|
|
|
let add_flavor_to_targets args =
|
|
let flavor =
|
|
match Config.use_compilation_database with
|
|
| Some `Deps -> "#uber-compilation-database"
|
|
| Some `NoDeps -> "#compilation-database"
|
|
| _ -> assert false (* cannot happen *) in
|
|
let process_arg arg =
|
|
(* Targets are assumed to start with //, aliases are not allowed *)
|
|
if String.is_prefix ~prefix:"//" arg then arg ^ flavor
|
|
else arg in
|
|
IList.map process_arg args
|
|
|
|
let create_files_stack compilation_database should_capture_file =
|
|
let stack = Stack.create () in
|
|
let add_to_stack file _ = if should_capture_file file then
|
|
Stack.push file stack in
|
|
CompilationDatabase.iter compilation_database add_to_stack;
|
|
stack
|
|
|
|
let swap_command cmd =
|
|
let plusplus = "++" in
|
|
let clang = "clang" in
|
|
let clangplusplus = "clang++" in
|
|
if String.is_suffix ~suffix:plusplus cmd then
|
|
Config.wrappers_dir // clangplusplus
|
|
else
|
|
Config.wrappers_dir // clang
|
|
|
|
let run_compilation_file compilation_database file =
|
|
try
|
|
let compilation_data = CompilationDatabase.find compilation_database file in
|
|
let wrapper_cmd = swap_command compilation_data.command in
|
|
let arg_file =
|
|
ClangQuotes.mk_arg_file
|
|
"cdb_clang_args_" ClangQuotes.EscapedNoQuotes [compilation_data.args] in
|
|
let args = ["@" ^ arg_file] in
|
|
let env =
|
|
let env0 = Unix.environment () in
|
|
let found = ref false in
|
|
Array.iteri (fun i key_val ->
|
|
match String.rsplit2 key_val ~on:'=' with
|
|
| Some (var, args) when String.equal var CLOpt.args_env_var ->
|
|
found := true ;
|
|
env0.(i) <-
|
|
F.sprintf "%s=%s%c--fcp-syntax-only" CLOpt.args_env_var args CLOpt.env_var_sep
|
|
| _ ->
|
|
()
|
|
) env0 ;
|
|
if !found then
|
|
env0
|
|
else
|
|
Array.append env0 [|CLOpt.args_env_var ^ "=--fcp-syntax-only"|] in
|
|
(Some compilation_data.dir, wrapper_cmd, args, env)
|
|
with Not_found ->
|
|
Process.print_error_and_exit "Failed to find compilation data for %a \n%!"
|
|
SourceFile.pp file
|
|
|
|
let run_compilation_database compilation_database should_capture_file =
|
|
let number_of_files = CompilationDatabase.get_size compilation_database in
|
|
Logging.out "Starting %s %d files \n%!" capture_text number_of_files;
|
|
Logging.stdout "Starting %s %d files \n%!" capture_text number_of_files;
|
|
let jobs_stack = create_files_stack compilation_database should_capture_file in
|
|
let capture_text_upper = String.capitalize capture_text in
|
|
let job_to_string =
|
|
fun file -> Format.asprintf "%s %a" capture_text_upper SourceFile.pp file in
|
|
Process.run_jobs_in_parallel jobs_stack (run_compilation_file compilation_database) job_to_string
|
|
|
|
(** Computes the compilation database files. *)
|
|
let get_compilation_database_files_buck () =
|
|
let cmd = IList.rev_append Config.rest (IList.rev Config.buck_build_args) in
|
|
match cmd with
|
|
| buck :: build :: args ->
|
|
(check_args_for_targets args;
|
|
let args_with_flavor = add_flavor_to_targets args in
|
|
let args = build :: "--config" :: "*//cxx.pch_enabled=false" :: args_with_flavor in
|
|
Process.create_process_and_wait ~prog:buck ~args;
|
|
let buck_targets_list = buck :: "targets" :: "--show-output" :: args_with_flavor in
|
|
let buck_targets = String.concat ~sep:" " buck_targets_list in
|
|
try
|
|
match fst @@ Utils.with_process_in buck_targets Std.input_list with
|
|
| [] -> Logging.stdout "There are no files to process, exiting."; exit 0
|
|
| lines ->
|
|
Logging.out "Reading compilation database from:@\n%s@\n" (String.concat ~sep:"\n" lines);
|
|
let scan_output compilation_database_files chan =
|
|
Scanf.sscanf chan "%s %s"
|
|
(fun target file -> StringMap.add target file compilation_database_files) in
|
|
(* Map from targets to json output *)
|
|
let compilation_database_files = IList.fold_left scan_output StringMap.empty lines in
|
|
IList.map (snd) (StringMap.bindings compilation_database_files)
|
|
with Unix.Unix_error (err, _, _) ->
|
|
Process.print_error_and_exit
|
|
"Cannot execute %s\n%!"
|
|
(buck_targets ^ " " ^ (Unix.error_message err)))
|
|
| _ ->
|
|
let cmd = String.concat ~sep:" " cmd in
|
|
Process.print_error_and_exit "Incorrect buck command: %s. Please use buck build <targets>" cmd
|
|
|
|
(** Compute the compilation database files. *)
|
|
let get_compilation_database_files_xcodebuild () =
|
|
let prog_args = IList.rev Config.rest in
|
|
let temp_dir = Config.results_dir // "clang" in
|
|
create_dir temp_dir;
|
|
let tmp_file = Filename.temp_file ~in_dir:temp_dir "cdb" ".json" in
|
|
let xcodebuild_prog, xcodebuild_args =
|
|
match prog_args with
|
|
| prog :: args -> (prog, args)
|
|
| [] -> failwith("Build command cannot be empty") in
|
|
let xcpretty_prog = "xcpretty" in
|
|
let xcpretty_args = ["--report"; "json-compilation-database"; "--output"; tmp_file] in
|
|
let producer_status, consumer_status =
|
|
Process.pipeline
|
|
~producer_prog:xcodebuild_prog ~producer_args:xcodebuild_args
|
|
~consumer_prog:xcpretty_prog ~consumer_args:xcpretty_args in
|
|
match producer_status, consumer_status with
|
|
| Ok (), Ok () -> [tmp_file]
|
|
| _ ->
|
|
Logging.stderr "There was an error executing the build command";
|
|
exit 1
|
|
|
|
|
|
let capture_files_in_database compilation_database =
|
|
run_compilation_database compilation_database (should_capture_file_from_index ())
|