clang_runtimes.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  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. #ifndef CARBON_TOOLCHAIN_DRIVER_CLANG_RUNTIMES_H_
  5. #define CARBON_TOOLCHAIN_DRIVER_CLANG_RUNTIMES_H_
  6. #include <filesystem>
  7. #include <mutex>
  8. #include <optional>
  9. #include <string>
  10. #include <utility>
  11. #include "common/error.h"
  12. #include "common/filesystem.h"
  13. #include "common/latch.h"
  14. #include "common/ostream.h"
  15. #include "llvm/ADT/ArrayRef.h"
  16. #include "llvm/ADT/SmallVector.h"
  17. #include "llvm/ADT/StringRef.h"
  18. #include "llvm/Object/ArchiveWriter.h"
  19. #include "llvm/Support/FormatVariadic.h"
  20. #include "llvm/Support/ThreadPool.h"
  21. #include "llvm/Support/VirtualFileSystem.h"
  22. #include "llvm/TargetParser/Triple.h"
  23. #include "toolchain/base/install_paths.h"
  24. #include "toolchain/driver/clang_runner.h"
  25. #include "toolchain/driver/runtimes_cache.h"
  26. namespace Carbon {
  27. // Common APIs and utilities factored out of all of the Clang runtimes builders.
  28. //
  29. // The Clang runtimes builders are _asynchronous_ builders at their core, and so
  30. // their primary API is to construct the builder (kicking off work across
  31. // threads) and then `Wait` for it to finish.
  32. class ClangRuntimesBuilderBase {
  33. public:
  34. // Waits until the runtimes are finished being built and then return either
  35. // any error encountered or the path of the built runtimes.
  36. //
  37. // If a path is returned, it will be the same as `Runtimes::Builder::Commit`
  38. // would return.
  39. auto Wait() && -> ErrorOr<std::filesystem::path> {
  40. tasks_.wait();
  41. return std::move(result_);
  42. }
  43. protected:
  44. class ArchiveBuilder;
  45. // Initializes the common state of a runtimes builder.
  46. //
  47. // Both the `clang` runner and the `threads` need to outlive this object.
  48. ClangRuntimesBuilderBase(ClangRunner* clang,
  49. llvm::ThreadPoolInterface* threads,
  50. llvm::Triple target_triple)
  51. : clang_(clang),
  52. vlog_stream_(clang_->vlog_stream_),
  53. tasks_(*threads),
  54. target_triple_(std::move(target_triple)),
  55. target_flag_(llvm::formatv("--target={0}", target_triple_.str())),
  56. result_(Error("Did not finish building the runtime!")) {}
  57. auto installation() -> const InstallPaths& { return *clang_->installation_; }
  58. // We use protected members as this base is just factoring out common
  59. // implementation details of other runners.
  60. //
  61. // NOLINTBEGIN(misc-non-private-member-variables-in-classes)
  62. ClangRunner* clang_;
  63. llvm::raw_ostream* vlog_stream_;
  64. // This task group will be used both to launch asynchronous work and to wait
  65. // for all of the work for a particular build to complete.
  66. llvm::ThreadPoolTaskGroup tasks_;
  67. llvm::Triple target_triple_;
  68. std::string target_flag_;
  69. ErrorOr<std::filesystem::path> result_;
  70. // If runtimes already exist, we may never need a builder for them. But if we
  71. // do need to build the runtimes, store the `Runtimes::Builder` here.
  72. std::optional<Runtimes::Builder> runtimes_builder_;
  73. // When building runtimes, this latch synchronizes all the steps required
  74. // to build the runtimes into the above builder's staging directory. Once
  75. // satisfied, it is typically used to schedule committing the runtimes as the
  76. // last task.
  77. Latch step_counter_;
  78. // NOLINTEND(misc-non-private-member-variables-in-classes)
  79. };
  80. // Helper class that factors out the logic to build an archive as part of a set
  81. // of Clang runtimes.
  82. //
  83. // Runtimes can consist of one or more archives, and potentially other
  84. // artifacts, but because archives are very common we factor out logic to build
  85. // them here.
  86. class ClangRuntimesBuilderBase::ArchiveBuilder {
  87. public:
  88. // Initialize an archive builder.
  89. //
  90. // - The `builder` must outlive this object.
  91. // - `archive_path` is the _relative_ path of the archive file within the
  92. // built
  93. // runtimes directory.
  94. // - `src_files` is a list of the _absolute_ file paths to build into the
  95. // archive.
  96. // - `cflags` are the compile flags that should be used for all the compiles
  97. // in this archive.
  98. ArchiveBuilder(ClangRuntimesBuilderBase* builder,
  99. std::filesystem::path archive_path,
  100. std::filesystem::path srcs_root,
  101. llvm::SmallVector<llvm::StringRef> src_files,
  102. llvm::SmallVector<llvm::StringRef> cflags)
  103. : builder_(builder),
  104. vlog_stream_(builder_->vlog_stream_),
  105. archive_path_(std::move(archive_path)),
  106. srcs_root_(std::move(srcs_root)),
  107. src_files_(std::move(src_files)),
  108. cflags_(std::move(cflags)) {}
  109. // Start building the archive, with a latch handle to signal its completion.
  110. //
  111. // This will launch asynchronous tasks on the `builder_->tasks` task group to
  112. // first compile all the members of the archive, and once compiled to put them
  113. // into the archive file. Only when this last step is complete will the
  114. // provided handle be destroyed, signaling this step of any concurrent build
  115. // is done.
  116. //
  117. // This must only be called once per instance.
  118. auto Setup(Latch::Handle latch_handle) -> void;
  119. // Accessor for the result of building the archive.
  120. //
  121. // This will return an error if accessed prior to `Start`-ing the archive's
  122. // build.
  123. //
  124. // Once `Start` has been called, this must not be called until the
  125. // `latch_handle` provided to `Start` is destroyed as doing so will race with
  126. // producing the result.
  127. auto result() -> ErrorOr<Success>& { return result_; }
  128. private:
  129. // Helper for finishing the build of the archive.
  130. //
  131. // Must only be called once all members have been compiled, and returns the
  132. // result of forming the archive file from those members.
  133. auto Finish() -> ErrorOr<Success>;
  134. // Given a specific `src_path` relative to our `srcs_path`, create any
  135. // necessary directories relative to the build's runtimes root to allow the
  136. // object file for this source file to be written there.
  137. //
  138. // Returns any errors encountered creating the necessary directories.
  139. //
  140. // Uses a cache to avoid redundant directory creations, and stores a list of
  141. // all the directories created so they can be removed at the end of the build.
  142. //
  143. // This method is thread-safe, and designed to be called concurrently from
  144. // each source file's compilation.
  145. auto CreateObjDir(const std::filesystem::path& src_path) -> ErrorOr<Success>;
  146. // Compiles the `src_file` and read the resulting object as a new archive
  147. // member.
  148. //
  149. // The argument should be one of the elements of `src_files_`. The compile is
  150. // performed using the `builder_->clang_` runner and the provided `cflags_`.
  151. //
  152. // Any errors encountered are returned.
  153. auto CompileMember(llvm::StringRef src_file)
  154. -> ErrorOr<llvm::NewArchiveMember>;
  155. ClangRuntimesBuilderBase* builder_;
  156. llvm::raw_ostream* vlog_stream_;
  157. std::filesystem::path archive_path_;
  158. std::filesystem::path srcs_root_;
  159. llvm::SmallVector<llvm::StringRef> src_files_;
  160. llvm::SmallVector<llvm::StringRef> cflags_;
  161. // A latch used to synchronize building the archive once all members have been
  162. // compiled.
  163. Latch compilation_latch_;
  164. // Storage for either the archive members or the error encountered while
  165. // compiling them.
  166. llvm::SmallVector<ErrorOr<llvm::NewArchiveMember>> objs_;
  167. // A mutex and vector used to maintain a thread-safe cache of directories
  168. // created to hold object files when compiling.
  169. std::mutex obj_dirs_mu_;
  170. llvm::SmallVector<std::filesystem::path> obj_dirs_;
  171. // Storage for the final result of building the requested archive.
  172. ErrorOr<Success> result_ = Error("No archive built!");
  173. };
  174. template <Runtimes::Component Component>
  175. concept IsClangArchiveRuntimes = requires {
  176. requires(Component == Runtimes::LibUnwind || Component == Runtimes::Libcxx);
  177. };
  178. // A class template to build runtimes consisting of a single archive.
  179. //
  180. // The template argument comes from the `Runtimes::Component` enum, but is only
  181. // intended for Clang-runtimes that consist of a single archive. We use a
  182. // requires to enforce that the components used are exactly one of those
  183. // supported so we can also move instantiation into the `.cpp` file.
  184. template <Runtimes::Component Component>
  185. requires IsClangArchiveRuntimes<Component>
  186. class ClangArchiveRuntimesBuilder : public ClangRuntimesBuilderBase {
  187. public:
  188. // Constructing this class will attempt to build the `Component` archive into
  189. // `runtimes`.
  190. //
  191. // If an existing build is found, it will immediately be available.
  192. // Otherwise, constructing this class will schedule asynchronous work on
  193. // `threads` to build the archive on-demand using `clang`.
  194. //
  195. // Once constructed, callers may call `Wait` (from the base class) to wait
  196. // until the asynchronous work is complete and the runtimes are available. If
  197. // they were already available, the call to `Wait` will not block.
  198. ClangArchiveRuntimesBuilder(ClangRunner* clang,
  199. llvm::ThreadPoolInterface* threads,
  200. llvm::Triple target_triple, Runtimes* runtimes);
  201. private:
  202. // Helpers to compute the list of source files and compile flags for a
  203. // particular archive. The implementations of these are expected to be
  204. // specialized for each different `Component`.
  205. auto CollectSrcFiles() -> llvm::SmallVector<llvm::StringRef>;
  206. auto CollectCflags() -> llvm::SmallVector<llvm::StringRef>;
  207. // Helper to encapsulate the initial, but still asynchronous setup work.
  208. auto Setup() -> void;
  209. // Helper to encapsulate the final asynchronous step in building the resource
  210. // directory.
  211. auto Finish() -> void;
  212. // The relative archive path within the runtimes' build directory.
  213. std::filesystem::path archive_path_;
  214. // The (absolute) include paths used during the compilation of the source
  215. // files.
  216. llvm::SmallVector<std::filesystem::path> include_paths_;
  217. // The archive builder if it is necessary to build the archive.
  218. std::optional<ArchiveBuilder> archive_;
  219. };
  220. extern template class ClangArchiveRuntimesBuilder<Runtimes::LibUnwind>;
  221. extern template class ClangArchiveRuntimesBuilder<Runtimes::Libcxx>;
  222. using LibunwindBuilder = ClangArchiveRuntimesBuilder<Runtimes::LibUnwind>;
  223. using LibcxxBuilder = ClangArchiveRuntimesBuilder<Runtimes::Libcxx>;
  224. // Builds the target-specific resource directory for Clang.
  225. //
  226. // There is a resource directory installed along side the Clang binary that
  227. // contains all the target independent files such as headers. However, for
  228. // target-specific files like the runtimes that are part of the resource
  229. // directory, we build those on demand as runtimes.
  230. //
  231. class ClangResourceDirBuilder : public ClangRuntimesBuilderBase {
  232. public:
  233. // Constructing this class will attempt to build the Clang resource directory
  234. // into `runtimes`.
  235. //
  236. // If an existing build is found, it will immediately be available.
  237. // Otherwise, constructing this class will schedule asynchronous work on
  238. // `threads` to build them on-demand using `clang`.
  239. //
  240. // Once constructed, callers may call `Wait` (from the base class) to wait
  241. // until the asynchronous work is complete and the runtimes are available. If
  242. // they were already available, the call to `Wait` will not block.
  243. ClangResourceDirBuilder(ClangRunner* clang,
  244. llvm::ThreadPoolInterface* threads,
  245. llvm::Triple target_triple, Runtimes* runtimes);
  246. private:
  247. friend class ClangResourceDirBuilderTestPeer;
  248. static auto GetDarwinOsSuffix(llvm::Triple target_triple) -> llvm::StringRef;
  249. // Helper method to encapsulate the logic of configuring the list of source
  250. // files to use in the `builtins` archive within these runtimes on a
  251. // particular target.
  252. auto CollectBuiltinsSrcFiles() -> llvm::SmallVector<llvm::StringRef>;
  253. // Helper to encapsulate the initial, but still asynchronous setup work.
  254. auto Setup() -> void;
  255. // Helper to encapsulate the final asynchronous step in building the resource
  256. // directory.
  257. auto Finish() -> void;
  258. // Helper to compile a single file of the CRT runtimes.
  259. auto BuildCrtFile(llvm::StringRef src_file) -> ErrorOr<Success>;
  260. // The `lib` path and subdirectory of the being-built runtimes.
  261. std::filesystem::path lib_path_;
  262. Filesystem::Dir lib_dir_;
  263. // The results of compiling the CRT `begin` and `end` files.
  264. ErrorOr<Success> crt_begin_result_;
  265. ErrorOr<Success> crt_end_result_;
  266. // The include paths used during the compilation of the builtins.
  267. llvm::SmallVector<std::filesystem::path> include_paths_;
  268. // The archive builder for the builtins archive in the resource directory.
  269. std::optional<ArchiveBuilder> archive_;
  270. };
  271. } // namespace Carbon
  272. #endif // CARBON_TOOLCHAIN_DRIVER_CLANG_RUNTIMES_H_