diff --git a/infer/lib/python/inferlib/capture/make.py b/infer/lib/python/inferlib/capture/make.py index a64edb022..8178a7b53 100644 --- a/infer/lib/python/inferlib/capture/make.py +++ b/infer/lib/python/inferlib/capture/make.py @@ -26,7 +26,7 @@ infer -- clang -c srcfile.m infer -- gcc -c srcfile.c''' ALIASED_COMMANDS = ['clang', 'clang++', 'cc', 'gcc', 'g++'] -BUILD_COMMANDS = ['configure', 'make', 'waf'] +BUILD_COMMANDS = ['cmake', 'configure', 'make', 'waf'] SUPPORTED_COMMANDS = ALIASED_COMMANDS + BUILD_COMMANDS def gen_instance(*args): diff --git a/infer/tests/build_systems/build_integration_tests.py b/infer/tests/build_systems/build_integration_tests.py index 3ec94f43f..5fef4162f 100755 --- a/infer/tests/build_systems/build_integration_tests.py +++ b/infer/tests/build_systems/build_integration_tests.py @@ -95,19 +95,25 @@ def save_report(reports, filename): separators=(',', ': '), sort_keys=True) -def run_analysis(root, clean_cmd, build_cmd, analyzer, env=None, n=1): +def run_analysis(root, clean_cmds, build_cmds, analyzer, env=None): + if not os.path.exists(root): + os.makedirs(root) os.chdir(root) - subprocess.check_call(clean_cmd, env=env) - - temp_out_dir = tempfile.mkdtemp(suffix='_out', prefix='infer_') - infer_cmd = ['infer', '-a', analyzer, '-o', temp_out_dir, '--'] + build_cmd - - with tempfile.TemporaryFile( - mode='w', - suffix='.out', - prefix='analysis_') as analysis_output: - for i in xrange(n): + for clean_cmd in clean_cmds: + subprocess.check_call(clean_cmd, env=env) + + for build_cmd in build_cmds: + temp_out_dir = tempfile.mkdtemp(suffix='_out', prefix='infer_') + infer_cmd = (['infer', '-a', analyzer, '-o', temp_out_dir, '--'] + + build_cmd) + # Only record the output of the last build command. We record + # all of them but each command overwrites the output of the + # previous one. + with tempfile.TemporaryFile( + mode='w', + suffix='.out', + prefix='analysis_') as analysis_output: subprocess.check_call(infer_cmd, stdout=analysis_output, env=env) json_path = os.path.join(temp_out_dir, REPORT_JSON) @@ -193,8 +199,8 @@ class BuildIntegrationTest(unittest.TestCase): root = os.path.join(SCRIPT_DIR, os.pardir) errors = run_analysis( root, - ['ant', 'clean'], - ['ant', 'compile'], + [['ant', 'clean']], + [['ant', 'compile']], INFER_EXECUTABLE) original = os.path.join(EXPECTED_OUTPUTS_DIR, 'ant_report.json') do_test(errors, original) @@ -214,8 +220,8 @@ class BuildIntegrationTest(unittest.TestCase): ) errors = run_analysis( root, - ['true'], - ['gradle', 'build'], + [], + [['gradle', 'build']], INFER_EXECUTABLE, env=env) original = os.path.join(EXPECTED_OUTPUTS_DIR, 'gradle_report.json') @@ -230,8 +236,8 @@ class BuildIntegrationTest(unittest.TestCase): print('\nRunning Buck integration test') errors = run_analysis( ROOT_DIR, - ['buck', 'clean'], - ['buck', 'build', 'infer'], + [['buck', 'clean']], + [['buck', 'build', 'infer']], INFER_EXECUTABLE) original = os.path.join(EXPECTED_OUTPUTS_DIR, 'buck_report.json') do_test(errors, original) @@ -245,8 +251,8 @@ class BuildIntegrationTest(unittest.TestCase): root = os.path.join(CODETOANALYZE_DIR, 'make') errors = run_analysis( root, - ['make', 'clean'], - ['make', 'all'], + [['make', 'clean']], + [['make', 'all']], INFER_EXECUTABLE) original = os.path.join(EXPECTED_OUTPUTS_DIR, 'make_report.json') do_test(errors, original) @@ -264,11 +270,11 @@ class BuildIntegrationTest(unittest.TestCase): # running the analysis twice errors = run_analysis( root, - ['true'], - ['clang', '-c', 'utf8_in_function_names.c'], + [], + [['clang', '-c', 'utf8_in_function_names.c'], + ['clang', '-c', 'utf8_in_function_names.c']], INFER_EXECUTABLE, - env=env, - n=2) + env=env) original = os.path.join(EXPECTED_OUTPUTS_DIR, 'locale_report.json') do_test(errors, original) @@ -281,12 +287,30 @@ class BuildIntegrationTest(unittest.TestCase): root = os.path.join(CODETOANALYZE_DIR, 'make') errors = run_analysis( root, - ['make', 'clean'], - ['./waf', 'build'], + [['make', 'clean']], + [['./waf', 'build']], INFER_EXECUTABLE) original = os.path.join(EXPECTED_OUTPUTS_DIR, 'waf_report.json') do_test(errors, original) + def test_cmake_integration(self): + if not ('cmake' in to_test and + is_tool_available(['cmake', '--version'])): + print('\nSkipping cmake integration test') + return + + print('\nRunning cmake integration test') + root = os.path.join(CODETOANALYZE_DIR, 'cmake', 'build') + errors = run_analysis( + root, + [], + [['cmake', '..'], ['make', 'clean', 'all']], + INFER_EXECUTABLE) + # remove build/ directory + shutil.rmtree(root) + original = os.path.join(EXPECTED_OUTPUTS_DIR, 'cmake_report.json') + do_test(errors, original) + if __name__ == '__main__': # hackish capturing of the arguments after '--' diff --git a/infer/tests/build_systems/codetoanalyze/cmake/CMakeLists.txt b/infer/tests/build_systems/codetoanalyze/cmake/CMakeLists.txt new file mode 100644 index 000000000..4aa597cdc --- /dev/null +++ b/infer/tests/build_systems/codetoanalyze/cmake/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required (VERSION 2.8.11) +project (HELLO) +add_library (Hello hello.c) diff --git a/infer/tests/build_systems/codetoanalyze/cmake/hello.c b/infer/tests/build_systems/codetoanalyze/cmake/hello.c new file mode 120000 index 000000000..b336897bc --- /dev/null +++ b/infer/tests/build_systems/codetoanalyze/cmake/hello.c @@ -0,0 +1 @@ +../../../../../examples/hello.c \ No newline at end of file diff --git a/infer/tests/build_systems/expected_outputs/cmake_report.json b/infer/tests/build_systems/expected_outputs/cmake_report.json new file mode 100644 index 000000000..b29ee489e --- /dev/null +++ b/infer/tests/build_systems/expected_outputs/cmake_report.json @@ -0,0 +1,7 @@ +[ + { + "bug_type": "NULL_DEREFERENCE", + "file": "/home/jul/infer/infer/tests/build_systems/codetoanalyze/cmake/hello.c", + "procedure": "test" + } +] \ No newline at end of file