| #!/usr/bin/env fuchsia-vendored-python |
| # Copyright 2022 The Fuchsia Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import unittest |
| import sys |
| from pathlib import Path |
| from unittest import mock |
| from typing import Any, Sequence |
| |
| import cxx |
| |
| |
| def _strs(items: Sequence[Any]) -> list[str]: |
| return [str(i) for i in items] |
| |
| |
| class CxxActionTests(unittest.TestCase): |
| def test_help_unwanted(self) -> None: |
| source = Path("hello.cc") |
| output = Path("hello.o") |
| for opt in ( |
| "-h", |
| "--help", |
| "-hwasan-record-stack-history=libcall", |
| "-hello-world-is-ignored", |
| ): |
| with mock.patch.object(sys, "exit") as mock_exit: |
| c = cxx.CxxAction( |
| _strs(["clang++", opt, "-c", source, "-o", output]) |
| ) |
| preprocess, compile = c.split_preprocessing() |
| mock_exit.assert_not_called() |
| |
| def test_simple_clang_cxx(self) -> None: |
| source = Path("hello.cc") |
| ii_file = Path("hello.ii") |
| output = Path("hello.o") |
| clang = Path("clang++") |
| c = cxx.CxxAction(_strs([clang, "-c", source, "-o", output])) |
| self.assertEqual(c.output_file, output) |
| self.assertEqual( |
| c.compiler, |
| cxx.CompilerTool(tool=clang, type=cxx.Compiler.CLANG), |
| ) |
| self.assertFalse(c.save_temps) |
| self.assertTrue(c.compiler_is_clang) |
| self.assertFalse(c.compiler_is_gcc) |
| self.assertEqual(c.target, "") |
| self.assertEqual( |
| c.sources, [cxx.Source(file=source, dialect=cxx.SourceLanguage.CXX)] |
| ) |
| self.assertTrue(c.dialect_is_cxx) |
| self.assertFalse(c.dialect_is_c) |
| self.assertIsNone(c.use_ld) |
| self.assertIsNone(c.lto) |
| self.assertIsNone(c.rtlib) |
| self.assertIsNone(c.unwindlib) |
| self.assertFalse(c.static_libstdcxx) |
| self.assertEqual(c.linker_driver_flags, []) |
| self.assertIsNone(c.linker_retain_symbols_file) |
| self.assertIsNone(c.linker_version_script) |
| self.assertIsNone(c.linker_just_symbols) |
| self.assertIsNone(c.depfile) |
| self.assertIsNone(c.sysroot) |
| self.assertEqual(c.libdirs, []) |
| self.assertIsNone(c.profile_list) |
| self.assertIsNone(c.profile_generate) |
| self.assertIsNone(c.profile_instr_generate) |
| self.assertFalse(c.shared) |
| self.assertEqual(c.sanitizers, set()) |
| self.assertFalse(c.using_asan) |
| self.assertFalse(c.using_ubsan) |
| self.assertEqual(c.uninterpreted_args, _strs([clang, "-c", source])) |
| self.assertEqual(list(c.input_files()), [source]) |
| self.assertEqual(list(c.output_files()), [output]) |
| self.assertEqual(list(c.output_dirs()), []) |
| self.assertFalse(c.uses_macos_sdk) |
| self.assertIsNone(c.crash_diagnostics_dir) |
| self.assertEqual(c.preprocessed_output, ii_file) |
| preprocess, compile = c.split_preprocessing() |
| self.assertEqual( |
| preprocess, |
| _strs( |
| ["clang++", "-c", source, "-o", ii_file, "-E", "-fno-blocks"] |
| ), |
| ) |
| self.assertEqual( |
| compile, |
| _strs(["clang++", "-c", ii_file, "-o", output]), |
| ) |
| |
| def test_all_unknown_flags_ignored(self) -> None: |
| command = ["clang", "--yolo", "foobar", "-q", "-k", "-quack"] |
| c = cxx.CxxAction(command + ["-o", "required.o"]) |
| self.assertEqual(c.uninterpreted_args, command) |
| |
| def test_output_flag_not_matched(self) -> None: |
| command_pieces = ( |
| ["clang"], |
| ["-octopus"], |
| ) # not to be interpreted as "-o" |
| output = Path("required.o") |
| c = cxx.CxxAction( |
| command_pieces[0] + _strs(["-o", output]) + command_pieces[1] |
| ) |
| self.assertEqual(c.output_file, output) |
| self.assertEqual( |
| c.uninterpreted_args, command_pieces[0] + command_pieces[1] |
| ) |
| |
| def test_clang_cxx_save_temps(self) -> None: |
| source = Path("hello.cc") |
| ii_file = Path("obj/path/to/hello.cc.ii") |
| output = Path("obj/path/to/hello.cc.o") |
| c = cxx.CxxAction( |
| _strs(["clang++", "-c", source, "-o", output, "--save-temps"]) |
| ) |
| self.assertTrue(c.save_temps) |
| self.assertEqual(c.output_file, output) |
| self.assertEqual( |
| c.compiler, |
| cxx.CompilerTool(tool=Path("clang++"), type=cxx.Compiler.CLANG), |
| ) |
| self.assertTrue(c.compiler_is_clang) |
| self.assertFalse(c.compiler_is_gcc) |
| self.assertEqual(c.target, "") |
| self.assertEqual( |
| c.sources, [cxx.Source(file=source, dialect=cxx.SourceLanguage.CXX)] |
| ) |
| self.assertTrue(c.dialect_is_cxx) |
| self.assertFalse(c.dialect_is_c) |
| self.assertIsNone(c.depfile) |
| self.assertIsNone(c.sysroot) |
| self.assertIsNone(c.profile_list) |
| self.assertEqual(list(c.input_files()), [source]) |
| self.assertEqual( |
| list(c.output_files()), |
| [ |
| output, |
| # This .ii file is implicitly output by the compiler, |
| # but not the same as what we explicitly choose with ii_file. |
| Path("hello.ii"), |
| Path("hello.bc"), |
| Path("hello.s"), |
| ], |
| ) |
| self.assertEqual(list(c.output_dirs()), []) |
| self.assertFalse(c.uses_macos_sdk) |
| self.assertIsNone(c.crash_diagnostics_dir) |
| self.assertEqual(c.preprocessed_output, ii_file) |
| preprocess, compile = c.split_preprocessing() |
| self.assertEqual( |
| preprocess, |
| _strs( |
| ["clang++", "-c", source, "-o", ii_file, "-E", "-fno-blocks"] |
| ), |
| ) |
| self.assertEqual( |
| compile, |
| _strs(["clang++", "-c", ii_file, "-o", output, "--save-temps"]), |
| ) |
| |
| def test_simple_clang_c(self) -> None: |
| source = Path("hello.c") |
| i_file = Path("hello.i") |
| output = Path("hello.o") |
| c = cxx.CxxAction(_strs(["clang", "-c", source, "-o", output])) |
| self.assertEqual(c.output_file, output) |
| self.assertEqual( |
| c.compiler, |
| cxx.CompilerTool(tool=Path("clang"), type=cxx.Compiler.CLANG), |
| ) |
| self.assertTrue(c.compiler_is_clang) |
| self.assertFalse(c.compiler_is_gcc) |
| self.assertFalse(c.save_temps) |
| self.assertEqual(c.target, "") |
| self.assertEqual( |
| c.sources, [cxx.Source(file=source, dialect=cxx.SourceLanguage.C)] |
| ) |
| self.assertFalse(c.dialect_is_cxx) |
| self.assertTrue(c.dialect_is_c) |
| self.assertIsNone(c.depfile) |
| self.assertIsNone(c.sysroot) |
| self.assertIsNone(c.profile_list) |
| self.assertEqual(list(c.input_files()), [source]) |
| self.assertEqual(list(c.output_files()), [output]) |
| self.assertEqual(list(c.output_dirs()), []) |
| self.assertIsNone(c.crash_diagnostics_dir) |
| self.assertEqual(c.preprocessed_output, i_file) |
| preprocess, compile = c.split_preprocessing() |
| self.assertEqual( |
| preprocess, |
| _strs(["clang", "-c", source, "-o", i_file, "-E", "-fno-blocks"]), |
| ) |
| self.assertEqual( |
| compile, |
| _strs(["clang", "-c", i_file, "-o", output]), |
| ) |
| |
| def test_clang_c_save_temps(self) -> None: |
| source = Path("hello.c") |
| i_file = Path("obj/path/to/hello.i") |
| output = Path("obj/path/to/hello.o") |
| c = cxx.CxxAction( |
| _strs(["clang", "-c", source, "-o", output, "--save-temps"]) |
| ) |
| self.assertEqual(c.output_file, output) |
| self.assertEqual( |
| c.compiler, |
| cxx.CompilerTool(tool=Path("clang"), type=cxx.Compiler.CLANG), |
| ) |
| self.assertTrue(c.compiler_is_clang) |
| self.assertFalse(c.compiler_is_gcc) |
| self.assertTrue(c.save_temps) |
| self.assertEqual(c.target, "") |
| self.assertEqual( |
| c.sources, [cxx.Source(file=source, dialect=cxx.SourceLanguage.C)] |
| ) |
| self.assertFalse(c.dialect_is_cxx) |
| self.assertTrue(c.dialect_is_c) |
| self.assertIsNone(c.depfile) |
| self.assertIsNone(c.sysroot) |
| self.assertIsNone(c.profile_list) |
| self.assertEqual(list(c.input_files()), [source]) |
| self.assertEqual( |
| list(c.output_files()), |
| [ |
| output, |
| # This .i file is implicitly output by the compiler, |
| # but not the same as what we explicitly choose with ii_file. |
| Path("hello.i"), |
| Path("hello.bc"), |
| Path("hello.s"), |
| ], |
| ) |
| self.assertEqual(list(c.output_dirs()), []) |
| self.assertIsNone(c.crash_diagnostics_dir) |
| self.assertEqual(c.preprocessed_output, i_file) |
| preprocess, compile = c.split_preprocessing() |
| self.assertEqual( |
| preprocess, |
| _strs(["clang", "-c", source, "-o", i_file, "-E", "-fno-blocks"]), |
| ) |
| self.assertEqual( |
| compile, |
| _strs(["clang", "-c", i_file, "-o", output, "--save-temps"]), |
| ) |
| |
| def test_simple_clang_asm(self) -> None: |
| source = Path("hello.s") |
| i_file = Path("hello.i") |
| output = Path("hello.o") |
| c = cxx.CxxAction(_strs(["clang", "-c", source, "-o", output])) |
| self.assertEqual(c.output_file, output) |
| self.assertEqual( |
| c.compiler, |
| cxx.CompilerTool(tool=Path("clang"), type=cxx.Compiler.CLANG), |
| ) |
| self.assertTrue(c.compiler_is_clang) |
| self.assertFalse(c.compiler_is_gcc) |
| self.assertEqual(c.target, "") |
| self.assertEqual( |
| c.sources, [cxx.Source(file=source, dialect=cxx.SourceLanguage.ASM)] |
| ) |
| self.assertFalse(c.dialect_is_cxx) |
| self.assertFalse(c.dialect_is_c) |
| self.assertIsNone(c.crash_diagnostics_dir) |
| |
| def test_simple_clang_asm_pp(self) -> None: |
| source = Path("hello.S") |
| i_file = Path("hello.i") |
| output = Path("hello.o") |
| c = cxx.CxxAction(_strs(["clang", "-c", source, "-o", output])) |
| self.assertEqual(c.output_file, output) |
| self.assertEqual( |
| c.compiler, |
| cxx.CompilerTool(tool=Path("clang"), type=cxx.Compiler.CLANG), |
| ) |
| self.assertTrue(c.compiler_is_clang) |
| self.assertFalse(c.compiler_is_gcc) |
| self.assertEqual(c.target, "") |
| self.assertEqual( |
| c.sources, [cxx.Source(file=source, dialect=cxx.SourceLanguage.ASM)] |
| ) |
| self.assertFalse(c.dialect_is_cxx) |
| self.assertFalse(c.dialect_is_c) |
| self.assertIsNone(c.crash_diagnostics_dir) |
| |
| def test_shared(self) -> None: |
| source = Path("hello.o") |
| output = Path("hello.so") |
| c = cxx.CxxAction(_strs(["clang++", "-shared", source, "-o", output])) |
| self.assertTrue(c.shared) |
| self.assertEqual(c.linker_inputs, [source]) |
| |
| def test_flto_default(self) -> None: |
| source = Path("hello.o") |
| output = Path("hello") |
| c = cxx.CxxAction(_strs(["clang++", "-flto", source, "-o", output])) |
| self.assertEqual(c.lto, "full") |
| |
| def test_flto_full(self) -> None: |
| source = Path("hello.o") |
| output = Path("hello") |
| c = cxx.CxxAction( |
| _strs(["clang++", "-flto=full", source, "-o", output]) |
| ) |
| self.assertEqual(c.lto, "full") |
| |
| def test_flto_thin(self) -> None: |
| source = Path("hello.o") |
| output = Path("hello") |
| c = cxx.CxxAction( |
| _strs(["clang++", "-flto=thin", source, "-o", output]) |
| ) |
| self.assertEqual(c.lto, "thin") |
| |
| def test_fuse_ld(self) -> None: |
| source = Path("hello.o") |
| output = Path("hello") |
| linker = "lld" |
| c = cxx.CxxAction( |
| _strs(["clang++", f"-fuse-ld={linker}", source, "-o", output]) |
| ) |
| self.assertEqual(c.use_ld, linker) |
| self.assertEqual(c.linker_inputs, [source]) |
| self.assertEqual(c.clang_linker_executable, "ld.lld") |
| |
| def test_fuse_ld_windows(self) -> None: |
| source = Path("hello.o") |
| output = Path("hello") |
| linker = "lld" |
| c = cxx.CxxAction( |
| _strs( |
| [ |
| "clang++", |
| "--target=x64_64-windows-msvc", |
| f"-fuse-ld={linker}", |
| source, |
| "-o", |
| output, |
| ] |
| ) |
| ) |
| self.assertEqual(c.use_ld, linker) |
| self.assertEqual(c.linker_inputs, [source]) |
| self.assertEqual(c.clang_linker_executable, "lld-link") |
| |
| def test_asan(self) -> None: |
| source = Path("hello.o") |
| output = Path("hello") |
| c = cxx.CxxAction( |
| _strs(["clang++", "-fsanitize=address", source, "-o", output]) |
| ) |
| self.assertEqual(c.sanitizers, {"address"}) |
| self.assertTrue(c.using_asan) |
| self.assertFalse(c.using_ubsan) |
| self.assertEqual(c.linker_inputs, [source]) |
| |
| def test_no_sanitize(self) -> None: |
| source = Path("hello.o") |
| output = Path("hello") |
| c = cxx.CxxAction( |
| _strs( |
| [ |
| "clang++", |
| "-fsanitize=address", |
| "-fno-sanitize=address", |
| source, |
| "-o", |
| output, |
| ] |
| ) |
| ) |
| self.assertEqual(c.sanitizers, set()) |
| self.assertFalse(c.using_asan) |
| self.assertFalse(c.using_ubsan) |
| self.assertEqual(c.linker_inputs, [source]) |
| |
| def test_ubsan(self) -> None: |
| source = Path("hello.o") |
| output = Path("hello") |
| c = cxx.CxxAction( |
| _strs(["clang++", "-fsanitize=undefined", source, "-o", output]) |
| ) |
| self.assertEqual(c.sanitizers, {"undefined"}) |
| self.assertFalse(c.using_asan) |
| self.assertTrue(c.using_ubsan) |
| self.assertEqual(c.linker_inputs, [source]) |
| |
| def test_libdirs(self) -> None: |
| source = Path("hello.o") |
| output = Path("hello") |
| c = cxx.CxxAction( |
| _strs( |
| ["clang++", "-L../foo/foo", "-Lbar/bar", source, "-o", output] |
| ) |
| ) |
| self.assertEqual(c.libdirs, [Path("../foo/foo"), Path("bar/bar")]) |
| |
| def test_unwindlib_equals_arg(self) -> None: |
| source = Path("hello.o") |
| output = Path("hello") |
| c = cxx.CxxAction( |
| _strs(["clang++", "-unwindlib=libunwind", source, "-o", output]) |
| ) |
| self.assertEqual(c.unwindlib, "libunwind") |
| |
| def test_unwindlib_separate_arg(self) -> None: |
| source = Path("hello.o") |
| output = Path("hello") |
| c = cxx.CxxAction( |
| _strs(["clang++", "-unwindlib", "libunwind", source, "-o", output]) |
| ) |
| self.assertEqual(c.unwindlib, "libunwind") |
| |
| def test_not_a_prefix_for_unwindlib(self) -> None: |
| source = Path("hello.o") |
| output = Path("hello") |
| for unknown_flag in ("-u", "--u", "--un", "-un", "-uu"): |
| c = cxx.CxxAction( |
| _strs(["clang++", unknown_flag, source, "-o", output]) |
| ) |
| self.assertIsNone(c.unwindlib) |
| self.assertIn(unknown_flag, c.uninterpreted_args) |
| |
| def test_not_a_prefix_for_rtlib(self) -> None: |
| source = Path("hello.o") |
| output = Path("hello") |
| for unknown_flag in ("-r", "--r", "--rt", "-rt", "-rx"): |
| c = cxx.CxxAction( |
| _strs(["clang++", unknown_flag, source, "-o", output]) |
| ) |
| self.assertIsNone(c.rtlib) |
| self.assertIn(unknown_flag, c.uninterpreted_args) |
| |
| def test_rtlib_equals_arg(self) -> None: |
| source = Path("hello.o") |
| output = Path("hello") |
| c = cxx.CxxAction( |
| _strs(["clang++", "-rtlib=compiler-rt", source, "-o", output]) |
| ) |
| self.assertEqual(c.rtlib, "compiler-rt") |
| |
| def test_rtlib_separate_arg(self) -> None: |
| source = Path("hello.o") |
| output = Path("hello") |
| c = cxx.CxxAction( |
| _strs( |
| [ |
| "clang++", |
| "-rtlib", |
| "different-compiler-rt", |
| source, |
| "-o", |
| output, |
| ] |
| ) |
| ) |
| self.assertEqual(c.rtlib, "different-compiler-rt") |
| |
| def test_static_libstdcxx(self) -> None: |
| source = Path("hello.o") |
| output = Path("hello") |
| c = cxx.CxxAction( |
| _strs(["clang++", "-static-libstdc++", source, "-o", output]) |
| ) |
| self.assertTrue(c.static_libstdcxx) |
| |
| def test_unknown_linker_driver_flag(self) -> None: |
| source = Path("hello.o") |
| output = Path("hello") |
| flag = "--unknown-flag=foobar" |
| c = cxx.CxxAction( |
| _strs(["clang++", f"-Wl,{flag}", source, "-o", output]) |
| ) |
| self.assertEqual(c.linker_driver_flags, [flag]) |
| |
| def test_linker_mapfile_double_dash(self) -> None: |
| source = Path("hello.o") |
| output = Path("hello") |
| mapfile = Path("hello.map") |
| c = cxx.CxxAction( |
| _strs(["clang++", f"-Wl,--Map={mapfile}", source, "-o", output]) |
| ) |
| self.assertEqual(c.linker_mapfile, mapfile) |
| self.assertEqual(list(c.linker_output_files()), [output, mapfile]) |
| |
| def test_linker_mapfile_single_dash(self) -> None: |
| source = Path("hello.o") |
| output = Path("hello") |
| mapfile = Path("hello.map") |
| c = cxx.CxxAction( |
| _strs(["clang++", f"-Wl,-Map={mapfile}", source, "-o", output]) |
| ) |
| self.assertEqual(c.linker_mapfile, mapfile) |
| self.assertEqual(list(c.linker_output_files()), [output, mapfile]) |
| |
| def test_linker_depfile(self) -> None: |
| source = Path("hello.o") |
| output = Path("hello") |
| depfile = Path("hello.d") |
| c = cxx.CxxAction( |
| _strs( |
| [ |
| "clang++", |
| f"-Wl,--dependency-file={depfile}", |
| source, |
| "-o", |
| output, |
| ] |
| ) |
| ) |
| self.assertEqual(c.linker_depfile, depfile) |
| self.assertEqual(list(c.linker_output_files()), [output, depfile]) |
| |
| def test_linker_pdb_output(self) -> None: |
| source = Path("hello.o") |
| output = Path("hello.efi") |
| pdb = Path("hello.pdb") |
| c = cxx.CxxAction( |
| _strs( |
| [ |
| "clang++", |
| "--target=x86_x64-windows-msvc", |
| f"-Wl,/debug:full", |
| source, |
| "-o", |
| output, |
| ] |
| ) |
| ) |
| self.assertEqual(c.pdb, pdb) |
| self.assertEqual(list(c.linker_output_files()), [output, pdb]) |
| |
| def test_linker_retain_symbols_file(self) -> None: |
| source = Path("hello.o") |
| output = Path("hello") |
| retain_file = Path("hello.allowlist") |
| c = cxx.CxxAction( |
| _strs( |
| [ |
| "clang++", |
| f"-Wl,--retain-symbols-file={retain_file}", |
| source, |
| "-o", |
| output, |
| ] |
| ) |
| ) |
| self.assertEqual(c.linker_retain_symbols_file, retain_file) |
| self.assertEqual(list(c.linker_inputs_from_flags()), [retain_file]) |
| |
| def test_linker_version_script(self) -> None: |
| source = Path("hello.o") |
| output = Path("hello") |
| version_script = Path("hello.ld") |
| c = cxx.CxxAction( |
| _strs( |
| [ |
| "clang++", |
| f"-Wl,--version-script={version_script}", |
| source, |
| "-o", |
| output, |
| ] |
| ) |
| ) |
| self.assertEqual(c.linker_version_script, version_script) |
| self.assertEqual(list(c.linker_inputs_from_flags()), [version_script]) |
| |
| def test_linker_version_script_with_response_file(self) -> None: |
| source = Path("hello.o") |
| output = Path("hello") |
| version_script = Path("hello.ld") |
| rsp_file = Path("hello.rsp") |
| with mock.patch.object( |
| Path, "read_text", return_value=str(version_script) |
| ) as mock_read: |
| c = cxx.CxxAction( |
| _strs( |
| [ |
| "clang++", |
| f"-Wl,--version-script,@{rsp_file}", |
| source, |
| "-o", |
| output, |
| ] |
| ) |
| ) |
| self.assertEqual(c.linker_version_script, version_script) |
| self.assertEqual(list(c.linker_inputs_from_flags()), [version_script]) |
| self.assertEqual(c.linker_response_files, [rsp_file]) |
| |
| def test_linker_just_symbols(self) -> None: |
| source = Path("hello.o") |
| output = Path("hello") |
| symbols = Path("hello.elf") |
| c = cxx.CxxAction( |
| _strs( |
| [ |
| "clang++", |
| f"-Wl,--just-symbols={symbols}", |
| source, |
| "-o", |
| output, |
| ] |
| ) |
| ) |
| self.assertEqual(c.linker_just_symbols, symbols) |
| self.assertEqual(list(c.linker_inputs_from_flags()), [symbols]) |
| |
| def test_simple_gcc_cxx(self) -> None: |
| source = Path("hello.cc") |
| output = Path("hello.o") |
| ii_file = Path("hello.ii") |
| c = cxx.CxxAction(_strs(["g++", "-c", source, "-o", output])) |
| self.assertEqual(c.output_file, output) |
| self.assertEqual( |
| c.compiler, |
| cxx.CompilerTool(tool=Path("g++"), type=cxx.Compiler.GCC), |
| ) |
| self.assertFalse(c.compiler_is_clang) |
| self.assertTrue(c.compiler_is_gcc) |
| self.assertEqual(c.target, "") |
| self.assertEqual( |
| c.sources, [cxx.Source(file=source, dialect=cxx.SourceLanguage.CXX)] |
| ) |
| self.assertTrue(c.dialect_is_cxx) |
| self.assertFalse(c.dialect_is_c) |
| self.assertIsNone(c.depfile) |
| self.assertIsNone(c.crash_diagnostics_dir) |
| self.assertEqual(c.preprocessed_output, ii_file) |
| preprocess, compile = c.split_preprocessing() |
| self.assertEqual( |
| preprocess, |
| _strs(["g++", "-c", source, "-o", ii_file, "-E"]), |
| ) |
| self.assertEqual( |
| compile, |
| _strs(["g++", "-c", ii_file, "-o", output]), |
| ) |
| |
| def test_simple_gcc_c(self) -> None: |
| source = Path("hello.c") |
| i_file = Path("hello.i") |
| output = Path("hello.o") |
| c = cxx.CxxAction(_strs(["gcc", "-c", source, "-o", output])) |
| self.assertEqual(c.output_file, output) |
| self.assertEqual( |
| c.compiler, |
| cxx.CompilerTool(tool=Path("gcc"), type=cxx.Compiler.GCC), |
| ) |
| self.assertFalse(c.compiler_is_clang) |
| self.assertTrue(c.compiler_is_gcc) |
| self.assertEqual(c.target, "") |
| self.assertEqual( |
| c.sources, [cxx.Source(file=source, dialect=cxx.SourceLanguage.C)] |
| ) |
| self.assertFalse(c.dialect_is_cxx) |
| self.assertTrue(c.dialect_is_c) |
| self.assertIsNone(c.depfile) |
| self.assertIsNone(c.crash_diagnostics_dir) |
| self.assertEqual(c.preprocessed_output, i_file) |
| preprocess, compile = c.split_preprocessing() |
| self.assertEqual( |
| preprocess, |
| _strs(["gcc", "-c", source, "-o", i_file, "-E"]), |
| ) |
| self.assertEqual( |
| compile, |
| _strs(["gcc", "-c", i_file, "-o", output]), |
| ) |
| |
| def test_clang_target(self) -> None: |
| c = cxx.CxxAction( |
| [ |
| "clang++", |
| "--target=powerpc-apple-darwin8", |
| "-c", |
| "hello.cc", |
| "-o", |
| "hello.o", |
| ] |
| ) |
| self.assertEqual(c.target, "powerpc-apple-darwin8") |
| |
| def test_clang_crash_diagnostics_dir(self) -> None: |
| crash_dir = Path("/tmp/graveyard") |
| c = cxx.CxxAction( |
| [ |
| "clang++", |
| f"-fcrash-diagnostics-dir={crash_dir}", |
| "-c", |
| "hello.cc", |
| "-o", |
| "hello.o", |
| ] |
| ) |
| self.assertEqual(c.crash_diagnostics_dir, crash_dir) |
| self.assertEqual(set(c.output_dirs()), {crash_dir}) |
| |
| def test_profile_list(self) -> None: |
| source = Path("hello.cc") |
| ii_file = Path("hello.ii") |
| output = Path("hello.o") |
| profile = Path("my/online/profile.list") |
| c = cxx.CxxAction( |
| _strs( |
| [ |
| "clang++", |
| "-c", |
| source, |
| "-o", |
| output, |
| f"-fprofile-list={profile}", |
| ] |
| ) |
| ) |
| self.assertEqual(c.profile_list, profile) |
| self.assertEqual(set(c.input_files()), {source, profile}) |
| |
| def test_profile_generate(self) -> None: |
| source = Path("hello.cc") |
| ii_file = Path("hello.ii") |
| output = Path("hello.o") |
| c = cxx.CxxAction( |
| _strs( |
| [ |
| "clang++", |
| "-c", |
| source, |
| "-o", |
| output, |
| "-fprofile-generate", |
| ] |
| ) |
| ) |
| self.assertEqual(c.profile_generate, Path(".")) |
| |
| def test_profile_generate_with_dir(self) -> None: |
| source = Path("hello.cc") |
| ii_file = Path("hello.ii") |
| output = Path("hello.o") |
| pdir = Path("my/pg/dir") |
| c = cxx.CxxAction( |
| _strs( |
| [ |
| "clang++", |
| "-c", |
| source, |
| "-o", |
| output, |
| f"-fprofile-generate={pdir}", |
| ] |
| ) |
| ) |
| self.assertEqual(c.profile_generate, pdir) |
| |
| def test_profile_instr_generate(self) -> None: |
| source = Path("hello.cc") |
| ii_file = Path("hello.ii") |
| output = Path("hello.o") |
| c = cxx.CxxAction( |
| _strs( |
| [ |
| "clang++", |
| "-c", |
| source, |
| "-o", |
| output, |
| "-fprofile-instr-generate", |
| ] |
| ) |
| ) |
| self.assertEqual(c.profile_instr_generate, Path("default.profraw")) |
| |
| def test_profile_instr_generate_with_file(self) -> None: |
| source = Path("hello.cc") |
| ii_file = Path("hello.ii") |
| output = Path("hello.o") |
| pfile = Path("pg/path/to/file.profraw") |
| c = cxx.CxxAction( |
| _strs( |
| [ |
| "clang++", |
| "-c", |
| source, |
| "-o", |
| output, |
| f"-fprofile-instr-generate={pfile}", |
| ] |
| ) |
| ) |
| self.assertEqual(c.profile_instr_generate, pfile) |
| |
| def test_uses_macos_sdk(self) -> None: |
| sysroot = Path("/Library/Developer/blah") |
| c = cxx.CxxAction( |
| [ |
| "clang++", |
| f"--sysroot={sysroot}", |
| "-c", |
| "hello.cc", |
| "-o", |
| "hello.o", |
| ] |
| ) |
| self.assertEqual(c.sysroot, sysroot) |
| self.assertTrue(c.uses_macos_sdk) |
| |
| def test_split_preprocessing(self) -> None: |
| source = Path("hello.cc") |
| ii_file = Path("hello.ii") |
| output = Path("hello.o") |
| depfile = Path("hello.d") |
| c = cxx.CxxAction( |
| _strs( |
| [ |
| "clang++", |
| "-DNDEBUG", |
| "-I/opt/include", |
| "-stdlib=libc++", |
| "-M", |
| "-MF", |
| depfile, |
| "-c", |
| source, |
| "-o", |
| output, |
| ] |
| ) |
| ) |
| self.assertEqual(c.depfile, depfile) |
| preprocess, compile = c.split_preprocessing() |
| self.assertEqual( |
| preprocess, |
| _strs( |
| [ |
| "clang++", |
| "-DNDEBUG", |
| "-I/opt/include", |
| "-stdlib=libc++", |
| "-M", |
| "-MF", |
| depfile, |
| "-c", |
| source, |
| "-o", |
| ii_file, |
| "-E", |
| "-fno-blocks", |
| ] |
| ), |
| ) |
| self.assertEqual( |
| compile, |
| _strs(["clang++", "-c", ii_file, "-o", output]), |
| ) |
| |
| |
| if __name__ == "__main__": |
| unittest.main() |