clang_runner_test.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #include "toolchain/driver/clang_runner.h"
  5. #include <gmock/gmock.h>
  6. #include <gtest/gtest.h>
  7. #include <filesystem>
  8. #include <fstream>
  9. #include <string>
  10. #include <utility>
  11. #include "common/check.h"
  12. #include "common/ostream.h"
  13. #include "common/raw_string_ostream.h"
  14. #include "llvm/ADT/ScopeExit.h"
  15. #include "llvm/Object/Binary.h"
  16. #include "llvm/Support/FormatVariadic.h"
  17. #include "llvm/Support/Program.h"
  18. #include "llvm/TargetParser/Host.h"
  19. #include "testing/base/capture_std_streams.h"
  20. #include "testing/base/file_helpers.h"
  21. #include "testing/base/global_exe_path.h"
  22. namespace Carbon {
  23. namespace {
  24. using ::testing::HasSubstr;
  25. using ::testing::StrEq;
  26. TEST(ClangRunnerTest, Version) {
  27. RawStringOstream test_os;
  28. const auto install_paths =
  29. InstallPaths::MakeForBazelRunfiles(Testing::GetExePath());
  30. std::string target = llvm::sys::getDefaultTargetTriple();
  31. auto vfs = llvm::vfs::getRealFileSystem();
  32. ClangRunner runner(&install_paths, target, vfs, &test_os);
  33. std::string out;
  34. std::string err;
  35. EXPECT_TRUE(Testing::CallWithCapturedOutput(
  36. out, err, [&] { return runner.Run({"--version"}); }));
  37. // The arguments to Clang should be part of the verbose log.
  38. EXPECT_THAT(test_os.TakeStr(), HasSubstr("--version"));
  39. // No need to flush stderr, just check its contents.
  40. EXPECT_THAT(err, StrEq(""));
  41. // Flush and get the captured stdout to test that this command worked.
  42. // We don't care about any particular version, just that it is printed.
  43. EXPECT_THAT(out, HasSubstr("clang version"));
  44. // The target should match what we provided.
  45. EXPECT_THAT(out, HasSubstr((llvm::Twine("Target: ") + target).str()));
  46. // Clang's install should be our private LLVM install bin directory.
  47. EXPECT_THAT(out, HasSubstr(std::string("InstalledDir: ") +
  48. install_paths.llvm_install_bin().native()));
  49. }
  50. // It's hard to write a portable and reliable unittest for all the layers of the
  51. // Clang driver because they work hard to interact with the underlying
  52. // filesystem and operating system. For now, we just check that a link command
  53. // is echoed back with plausible contents.
  54. //
  55. // TODO: We should eventually strive to have a more complete setup that lets us
  56. // test more complete Clang functionality here.
  57. TEST(ClangRunnerTest, LinkCommandEcho) {
  58. // Just create some empty files to use in a synthetic link command below.
  59. std::filesystem::path foo_file = *Testing::WriteTestFile("foo.o", "");
  60. std::filesystem::path bar_file = *Testing::WriteTestFile("bar.o", "");
  61. const auto install_paths =
  62. InstallPaths::MakeForBazelRunfiles(Testing::GetExePath());
  63. RawStringOstream verbose_out;
  64. std::string target = llvm::sys::getDefaultTargetTriple();
  65. auto vfs = llvm::vfs::getRealFileSystem();
  66. ClangRunner runner(&install_paths, target, vfs, &verbose_out);
  67. std::string out;
  68. std::string err;
  69. EXPECT_TRUE(Testing::CallWithCapturedOutput(
  70. out, err,
  71. [&] {
  72. return runner.Run(
  73. {"-###", "-o", "binary", foo_file.string(), bar_file.string()});
  74. }))
  75. << "Verbose output from runner:\n"
  76. << verbose_out.TakeStr() << "\n";
  77. verbose_out.clear();
  78. // Because we use `-###' above, we should just see the command that the Clang
  79. // driver would have run in a subprocess. This will be very architecture
  80. // dependent and have lots of variety, but we expect to see both file strings
  81. // in it the command at least.
  82. EXPECT_THAT(err, HasSubstr(foo_file.string())) << err;
  83. EXPECT_THAT(err, HasSubstr(bar_file.string())) << err;
  84. // And no non-stderr output should be produced.
  85. EXPECT_THAT(out, StrEq(""));
  86. }
  87. TEST(ClangRunnerTest, DashC) {
  88. std::filesystem::path test_file =
  89. *Testing::WriteTestFile("test.cpp", "int test() { return 0; }");
  90. std::filesystem::path test_output = *Testing::WriteTestFile("test.o", "");
  91. const auto install_paths =
  92. InstallPaths::MakeForBazelRunfiles(Testing::GetExePath());
  93. RawStringOstream verbose_out;
  94. std::string target = llvm::sys::getDefaultTargetTriple();
  95. auto vfs = llvm::vfs::getRealFileSystem();
  96. ClangRunner runner(&install_paths, target, vfs, &verbose_out);
  97. std::string out;
  98. std::string err;
  99. EXPECT_TRUE(Testing::CallWithCapturedOutput(
  100. out, err,
  101. [&] {
  102. return runner.Run(
  103. {"-c", test_file.string(), "-o", test_output.string()});
  104. }))
  105. << "Verbose output from runner:\n"
  106. << verbose_out.TakeStr() << "\n";
  107. verbose_out.clear();
  108. // No output should be produced.
  109. EXPECT_THAT(out, StrEq(""));
  110. EXPECT_THAT(err, StrEq(""));
  111. }
  112. TEST(ClangRunnerTest, BuitinHeaders) {
  113. std::filesystem::path test_file = *Testing::WriteTestFile("test.c", R"cpp(
  114. #include <stdalign.h>
  115. #ifndef alignas
  116. #error included the wrong header
  117. #endif
  118. )cpp");
  119. std::filesystem::path test_output = *Testing::WriteTestFile("test.o", "");
  120. const auto install_paths =
  121. InstallPaths::MakeForBazelRunfiles(Testing::GetExePath());
  122. RawStringOstream verbose_out;
  123. std::string target = llvm::sys::getDefaultTargetTriple();
  124. auto vfs = llvm::vfs::getRealFileSystem();
  125. ClangRunner runner(&install_paths, target, vfs, &verbose_out);
  126. std::string out;
  127. std::string err;
  128. EXPECT_TRUE(Testing::CallWithCapturedOutput(
  129. out, err,
  130. [&] {
  131. return runner.Run(
  132. {"-c", test_file.string(), "-o", test_output.string()});
  133. }))
  134. << "Verbose output from runner:\n"
  135. << verbose_out.TakeStr() << "\n";
  136. verbose_out.clear();
  137. // No output should be produced.
  138. EXPECT_THAT(out, StrEq(""));
  139. EXPECT_THAT(err, StrEq(""));
  140. }
  141. TEST(ClangRunnerTest, CompileMultipleFiles) {
  142. const auto install_paths =
  143. InstallPaths::MakeForBazelRunfiles(Testing::GetExePath());
  144. // Memory leaks and other errors from running Clang can at times only manifest
  145. // with repeated compilations. Use a lambda to just do a series of compiles.
  146. auto compile = [&](llvm::StringRef filename, llvm::StringRef source) {
  147. std::string output_file = std::string(filename.split('.').first) + ".o";
  148. std::filesystem::path file = *Testing::WriteTestFile(filename, source);
  149. std::filesystem::path output = *Testing::WriteTestFile(output_file, "");
  150. RawStringOstream verbose_out;
  151. std::string target = llvm::sys::getDefaultTargetTriple();
  152. auto vfs = llvm::vfs::getRealFileSystem();
  153. ClangRunner runner(&install_paths, target, vfs, &verbose_out);
  154. std::string out;
  155. std::string err;
  156. EXPECT_TRUE(Testing::CallWithCapturedOutput(
  157. out, err,
  158. [&] {
  159. return runner.Run({"-c", file.string(), "-o", output.string()});
  160. }))
  161. << "Verbose output from runner:\n"
  162. << verbose_out.TakeStr() << "\n";
  163. verbose_out.clear();
  164. EXPECT_THAT(out, StrEq(""));
  165. EXPECT_THAT(err, StrEq(""));
  166. };
  167. compile("test1.cpp", "int test1() { return 0; }");
  168. compile("test2.cpp", "int test2() { return 0; }");
  169. compile("test3.cpp", "int test3() { return 0; }");
  170. }
  171. } // namespace
  172. } // namespace Carbon