llvm_symlinks_test.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. #!/usr/bin/env python3
  2. """Checks various LLVM tool symlinks behave as expected."""
  3. __copyright__ = """
  4. Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  5. Exceptions. See /LICENSE for license information.
  6. SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  7. """
  8. from pathlib import Path
  9. import subprocess
  10. import os
  11. import platform
  12. import sys
  13. import unittest
  14. from bazel_tools.tools.python.runfiles import runfiles
  15. class LLVMSymlinksTest(unittest.TestCase):
  16. def setUp(self) -> None:
  17. # The install root is adjacent to the test script
  18. self.install_root = Path(sys.argv[0]).parent
  19. self.tmpdir = Path(os.environ["TEST_TMPDIR"])
  20. self.test_o_file = self.tmpdir / "test.o"
  21. self.test_o_file.touch()
  22. self.runfiles = runfiles.Create()
  23. self.prebuilt_runtimes = self.runfiles.Rlocation(
  24. "carbon/toolchain/install/runtimes"
  25. )
  26. def get_link_cmd(self, clang: Path) -> list[str | Path]:
  27. return [
  28. clang,
  29. # Verbose printing to help with debugging.
  30. "-v",
  31. # Pass a parameter to the underlying Carbon busybox using `-Xcarbon`
  32. # to switch it to use the prebuilt runtimes rather than building
  33. # runtimes on demand.
  34. f"-Xcarbon=--prebuilt-runtimes={self.prebuilt_runtimes}",
  35. # Print out the link command rather than running it.
  36. "-###",
  37. # Give the link command an output.
  38. "-o",
  39. self.tmpdir / "test",
  40. # A test input file. This won't be read though.
  41. self.test_o_file,
  42. ]
  43. def unsupported(self, stderr: str) -> None:
  44. self.fail(f"Unsupported platform '{platform.uname()}':\n{stderr}")
  45. # Note that we can't test `clang` vs. `clang++` portably. The only commands
  46. # with useful differences are _link_ commands, and those need to build
  47. # runtime libraries on demand, which requires the host to be able to compile
  48. # and link for the target. Instead, we test linking with the default target
  49. # (the host), as that is the one that should reliably work if we're
  50. # developing Carbon, and encode all the different platform results in the
  51. # test expectations.
  52. def test_clang(self) -> None:
  53. bin = self.install_root / "llvm/bin/clang"
  54. # Most errors are caught by ensuring the command succeeds.
  55. run = subprocess.run(
  56. self.get_link_cmd(bin), check=True, capture_output=True, text=True
  57. )
  58. # Also ensure that it correctly didn't imply a C++ link.
  59. self.assertNotRegex(run.stderr, r'"-lc\+\+"')
  60. self.assertNotRegex(run.stderr, r'"-lstdc\+\+"')
  61. # Note that we can't test `clang` vs. `clang++` portably. See the comment on
  62. # `test_clang` for details.
  63. def test_clangplusplus(self) -> None:
  64. bin = self.install_root / "llvm/bin/clang++"
  65. run = subprocess.run(
  66. self.get_link_cmd(bin), check=True, capture_output=True, text=True
  67. )
  68. # Ensure that this binary _does_ imply a C++ link. Also ensure it uses
  69. # `libc++`, as we default our Clang to use that on all platforms.
  70. self.assertRegex(run.stderr, r'"-lc\+\+"')
  71. def test_clang_cl(self) -> None:
  72. bin = self.install_root / "llvm/bin/clang-cl"
  73. run = subprocess.run(
  74. # Use the `cl.exe`-specific help flag to test the mode.
  75. [bin, "/?"],
  76. check=True,
  77. capture_output=True,
  78. text=True,
  79. )
  80. # This should print the help string, including `cl.exe` specifics.
  81. self.assertRegex(run.stdout, r"CL.EXE COMPATIBILITY OPTIONS:")
  82. def test_clang_cpp(self) -> None:
  83. # Note that this is a test of the C-preprocessor mode, not C++ mode.
  84. # Create a test file that we'll preprocess.
  85. text_file = self.tmpdir / "test.txt"
  86. with open(text_file, "w") as f:
  87. f.write("TEST\n")
  88. # Run the preprocessor using a CPP-specific command line reading from
  89. # the test file and writing to stdout. We define a macro that we'll
  90. # check is expanded.
  91. bin = self.install_root / "llvm/bin/clang-cpp"
  92. try:
  93. run = subprocess.run(
  94. [bin, "-D", "TEST=SUCCESS", text_file, "-"],
  95. check=True,
  96. capture_output=True,
  97. text=True,
  98. )
  99. except subprocess.CalledProcessError as err:
  100. print(err.stderr, file=sys.stderr)
  101. raise
  102. self.assertEqual(run.stderr, "")
  103. self.assertRegex(run.stdout, r"(^|\n)SUCCESS\n")
  104. if __name__ == "__main__":
  105. unittest.main()