@ -21,7 +21,9 @@ let normalize (args: array string) :list ClangCommand.t =>
Logging . out " InferClang got toplevel -cc1 command@ \n " ;
Logging . out " InferClang got toplevel -cc1 command@ \n " ;
[ ClangCommand . CC1 args ]
[ ClangCommand . CC1 args ]
| NonCCCommand args = >
| NonCCCommand args = >
let clang_hashhashhash = ClangCommand . prepend_arg " -### " args | > ClangCommand . command_to_run ;
let clang_hashhashhash =
Printf . sprintf
" %s 2>&1 " ( ClangCommand . prepend_arg " -### " args | > ClangCommand . command_to_run ) ;
Logging . out " clang -### invocation: %s@ \n " clang_hashhashhash ;
Logging . out " clang -### invocation: %s@ \n " clang_hashhashhash ;
let normalized_commands = ref [] ;
let normalized_commands = ref [] ;
let one_line line = >
let one_line line = >
@ -31,12 +33,16 @@ let normalize (args: array string) :list ClangCommand.t =>
/* split by whitespace */
/* split by whitespace */
Str . split ( Str . regexp_string " \" \" " ) | > Array . of_list | >
Str . split ( Str . regexp_string " \" \" " ) | > Array . of_list | >
ClangCommand . mk ClangCommand . DoubleQuotes
ClangCommand . mk ClangCommand . DoubleQuotes
} else if (
Str . string_match ( Str . regexp " clang[^ :]*: warning: " ) line 0
) {
ClangCommand . ClangWarning line
} else {
} else {
ClangCommand . ClangError line
ClangCommand . ClangError line
} ;
} ;
let commands_or_errors =
let commands_or_errors =
/* commands generated by `clang -### ...` start with ' " / absolute / path / to / binary"' */
/* commands generated by `clang -### ...` start with ' " / absolute / path / to / binary"' */
Str . regexp " \" / \\ |clang \\ ( \\ |++ \\ ): error: " ;
Str . regexp " \" / \\ |clang [^ :]*: \\ (error \\ |warning \\ ): " ;
let consume_input i = >
let consume_input i = >
try (
try (
while true {
while true {
@ -50,7 +56,7 @@ let normalize (args: array string) :list ClangCommand.t =>
| End_of_file = > ()
| End_of_file = > ()
} ;
} ;
/* collect stdout and stderr output together (in reverse order) */
/* collect stdout and stderr output together (in reverse order) */
with_process_ full clang_hashhashhash consume_input consume_input | > ignore ;
with_process_ in clang_hashhashhash consume_input | > ignore ;
normalized_commands := IList . rev ! normalized_commands ;
normalized_commands := IList . rev ! normalized_commands ;
/* Discard assembly commands. This may make the list of commands empty, in which case we'll run
/* Discard assembly commands. This may make the list of commands empty, in which case we'll run
the original clang command . We could be smarter about this and try to execute the assembly
the original clang command . We could be smarter about this and try to execute the assembly
@ -69,18 +75,19 @@ let normalize (args: array string) :list ClangCommand.t =>
/* discard assembly commands -- see above */
/* discard assembly commands -- see above */
Logging . out " InferClang got toplevel assembly command@ \n " ;
Logging . out " InferClang got toplevel assembly command@ \n " ;
[]
[]
| ClangError _ = >
| ClangError _
| ClangWarning _ = >
/* we cannot possibly get this from the command-line... */
/* we cannot possibly get this from the command-line... */
assert false
assert false
} ;
} ;
let execute_clang_command ( clang_cmd : ClangCommand . t ) = >
let execute_clang_command ( clang_cmd : ClangCommand . t ) = > {
/* reset logging, otherwise we might print into the logs of the previous file that was compiled */
Logging . set_log_file_identifier None ;
switch clang_cmd {
switch clang_cmd {
| CC1 args = >
| CC1 args = >
/* this command compiles some code; replace the invocation of clang with our own clang and
/* this command compiles some code; replace the invocation of clang with our own clang and
plugin * /
plugin * /
/* reset logging, otherwise we might print into the logs of the previous file that was compiled */
Logging . set_log_file_identifier None ;
Logging . out " Capturing -cc1 command: %s@ \n " ( ClangCommand . command_to_run args ) ;
Logging . out " Capturing -cc1 command: %s@ \n " ( ClangCommand . command_to_run args ) ;
Capture . capture args
Capture . capture args
| ClangError error = >
| ClangError error = >
@ -88,6 +95,7 @@ let execute_clang_command (clang_cmd: ClangCommand.t) =>
` clang - # # # ` pretty much never fails , but warns of failures on stderr instead . * /
` clang - # # # ` pretty much never fails , but warns of failures on stderr instead . * /
Logging . err " %s " error ;
Logging . err " %s " error ;
exit 1
exit 1
| ClangWarning warning = > Logging . err " %s@ \n " warning
| Assembly args = >
| Assembly args = >
/* We shouldn't get any assembly command at this point */
/* We shouldn't get any assembly command at this point */
( if Config . debug_mode { failwithf } else { Logging . err } )
( if Config . debug_mode { failwithf } else { Logging . err } )
@ -96,41 +104,51 @@ let execute_clang_command (clang_cmd: ClangCommand.t) =>
/* Non-compilation (eg, linking) command. Run the command as-is. It will not get captured
/* Non-compilation (eg, linking) command. Run the command as-is. It will not get captured
further since ` clang - # # # ... ` will only output commands that invoke binaries using their
further since ` clang - # # # ... ` will only output commands that invoke binaries using their
absolute paths . * /
absolute paths . * /
Logging . out " Executing raw command: %s@ \n " ( ClangCommand . command_to_run args ) ;
let argv = ClangCommand . get_orig_argv args ;
Process . create_process_and_wait ( ClangCommand . get_argv args )
Logging . out " Executing raw command: %s@ \n " ( String . concat " " ( Array . to_list argv ) ) ;
} ;
Process . create_process_and_wait argv
}
} ;
let () = {
let () = {
let xx_suffix =
let xx_suffix =
try ( Sys . getenv " INFER_XX " ) {
if ( string_is_suffix " ++ " Sys . argv . ( 0 ) ) {
| Not_found = > " "
" ++ "
} else {
try ( Sys . getenv " INFER_XX " ) {
| Not_found = > " "
}
} ;
} ;
let args = Array . copy Sys . argv ;
let args = Array . copy Sys . argv ;
/* make sure we don't call ourselves recursively */
/* make sure we don't call ourselves recursively */
args . ( 0 ) = CFrontend_config . clang_bin xx_suffix ;
args . ( 0 ) = CFrontend_config . clang_bin xx_suffix ;
let commands = normalize args ;
let commands = normalize args ;
if ( commands = = [] ) {
/* No command to execute after -###, let's execute the original command
instead .
In particular , this can happen when
- there are only assembly commands to execute , which we skip , or
- the user tries to run ` infer - - clang - c file_that_does_not_exist . c ` . In this case , this
will fail with the appropriate error message from clang instead of silently analyzing 0
files . * /
Logging . out
" WARNING: `clang -### <args>` returned an empty set of commands to run and no error. Will run the original command directly:@ \n %s@ \n "
( String . concat " " @@ Array . to_list args ) ;
Process . create_process_and_wait args
} else {
IList . iter execute_clang_command commands
} ;
/* xcodebuild projects may require the object files to be generated by the Apple compiler, eg to
/* xcodebuild projects may require the object files to be generated by the Apple compiler, eg to
generate precompiled headers compatible with Apple's clang . * /
generate precompiled headers compatible with Apple's clang . * /
switch ( Sys . getenv " FCP_APPLE_CLANG " ) {
let should_run_original_command =
| bin = >
switch ( Sys . getenv " FCP_APPLE_CLANG " ) {
args . ( 0 ) = bin ^ xx_suffix ;
| bin = >
let bin_xx = bin ^ xx_suffix ;
Logging . out " Will run Apple clang %s " bin_xx ;
args . ( 0 ) = bin_xx ;
true
| exception Not_found = > false
} ;
IList . iter execute_clang_command commands ;
if ( commands = = [] | | should_run_original_command ) {
if ( commands = = [] ) {
/* No command to execute after -###, let's execute the original command
instead .
In particular , this can happen when
- there are only assembly commands to execute , which we skip , or
- the user tries to run ` infer - - clang - c file_that_does_not_exist . c ` . In this case , this
will fail with the appropriate error message from clang instead of silently analyzing 0
files . * /
Logging . out
" WARNING: `clang -### <args>` returned an empty set of commands to run and no error. Will run the original command directly:@ \n %s@ \n "
( String . concat " " @@ Array . to_list args )
} ;
Process . create_process_and_wait args
Process . create_process_and_wait args
| exception Not_found = > ()
}
}
} ;
} ;