1 // Copyright 2020 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef TOOLS_GN_RUST_PROJECT_WRITER_HELPERS_H_ 6 #define TOOLS_GN_RUST_PROJECT_WRITER_HELPERS_H_ 7 8 #include <fstream> 9 #include <optional> 10 #include <sstream> 11 #include <string> 12 #include <string_view> 13 #include <tuple> 14 #include <unordered_map> 15 #include <vector> 16 17 #include "base/containers/flat_map.h" 18 #include "build_settings.h" 19 #include "gn/source_file.h" 20 #include "gn/target.h" 21 22 // These are internal types and helper functions for RustProjectWriter that have 23 // been extracted for easier testability. 24 25 // Crate Index in the generated file 26 using CrateIndex = size_t; 27 28 using ConfigList = std::vector<std::string>; 29 using Dependency = std::pair<CrateIndex, std::string>; 30 using DependencyList = std::vector<Dependency>; 31 32 // This class represents a crate to be serialized out as part of the 33 // rust-project.json file. This is used to separate the generating 34 // of the data that needs to be in the file, from the file itself. 35 class Crate { 36 public: Crate(SourceFile root,std::optional<OutputFile> gen_dir,CrateIndex index,std::string label,std::string edition)37 Crate(SourceFile root, 38 std::optional<OutputFile> gen_dir, 39 CrateIndex index, 40 std::string label, 41 std::string edition) 42 : root_(root), 43 gen_dir_(gen_dir), 44 index_(index), 45 label_(label), 46 edition_(edition) {} 47 48 ~Crate() = default; 49 50 // Add a config item to the crate. AddConfigItem(std::string cfg_item)51 void AddConfigItem(std::string cfg_item) { configs_.push_back(cfg_item); } 52 53 // Add a key-value environment variable pair used when building this crate. AddRustenv(std::string key,std::string value)54 void AddRustenv(std::string key, std::string value) { 55 rustenv_.emplace(key, value); 56 } 57 58 // Add another crate as a dependency of this one. AddDependency(CrateIndex index,std::string name)59 void AddDependency(CrateIndex index, std::string name) { 60 deps_.push_back(std::make_pair(index, name)); 61 } 62 63 // Set the compiler arguments used to invoke the compilation of this crate SetCompilerArgs(std::vector<std::string> args)64 void SetCompilerArgs(std::vector<std::string> args) { compiler_args_ = args; } 65 66 // Set the compiler target ("e.g. x86_64-linux-kernel") SetCompilerTarget(std::string target)67 void SetCompilerTarget(std::string target) { compiler_target_ = target; } 68 69 // Set that this is a proc macro with the path to the output .so/dylib/dll SetIsProcMacro(OutputFile proc_macro_dynamic_library)70 void SetIsProcMacro(OutputFile proc_macro_dynamic_library) { 71 proc_macro_dynamic_library_ = proc_macro_dynamic_library; 72 } 73 74 // Returns the root file for the crate. root()75 SourceFile& root() { return root_; } 76 77 // Returns the root file for the crate. gen_dir()78 std::optional<OutputFile>& gen_dir() { return gen_dir_; } 79 80 // Returns the crate index. index()81 CrateIndex index() { return index_; }; 82 83 // Returns the displayable crate label. label()84 const std::string& label() { return label_; } 85 86 // Returns the Rust Edition this crate uses. edition()87 const std::string& edition() { return edition_; } 88 89 // Return the set of config items for this crate. configs()90 ConfigList& configs() { return configs_; } 91 92 // Return the set of dependencies for this crate. dependencies()93 DependencyList& dependencies() { return deps_; } 94 95 // Return the compiler arguments used to invoke the compilation of this crate CompilerArgs()96 const std::vector<std::string>& CompilerArgs() { return compiler_args_; } 97 98 // Return the compiler target "triple" from the compiler args CompilerTarget()99 const std::optional<std::string>& CompilerTarget() { 100 return compiler_target_; 101 } 102 103 // Returns whether this crate builds a proc macro .so proc_macro_path()104 const std::optional<OutputFile>& proc_macro_path() { 105 return proc_macro_dynamic_library_; 106 } 107 108 // Returns environment variables applied to this, which may be necessary 109 // for correct functioning of environment variables rustenv()110 const base::flat_map<std::string, std::string>& rustenv() { return rustenv_; } 111 112 private: 113 SourceFile root_; 114 std::optional<OutputFile> gen_dir_; 115 CrateIndex index_; 116 std::string label_; 117 std::string edition_; 118 ConfigList configs_; 119 DependencyList deps_; 120 std::optional<std::string> compiler_target_; 121 std::vector<std::string> compiler_args_; 122 std::optional<OutputFile> proc_macro_dynamic_library_; 123 base::flat_map<std::string, std::string> rustenv_; 124 }; 125 126 using CrateList = std::vector<Crate>; 127 128 // Mapping of a sysroot crate (path) to it's index in the crates list. 129 using SysrootCrateIndexMap = std::unordered_map<std::string_view, CrateIndex>; 130 131 // Mapping of a sysroot (path) to the mapping of each of the sysroot crates to 132 // their index in the crates list. 133 using SysrootIndexMap = 134 std::unordered_map<std::string_view, SysrootCrateIndexMap>; 135 136 // Add all of the crates for a sysroot (path) to the rust_project ostream. 137 // Add the given sysroot to the project, if it hasn't already been added. 138 void AddSysroot(const BuildSettings* build_settings, 139 std::string_view sysroot, 140 SysrootIndexMap& sysroot_lookup, 141 CrateList& crate_list); 142 143 // Write the entire rust-project.json file contents into the given stream, based 144 // on the the given crates list. 145 void WriteCrates(const BuildSettings* build_settings, 146 CrateList& crate_list, 147 std::ostream& rust_project); 148 149 // Assemble the compiler arguments for the given GN Target. 150 std::vector<std::string> ExtractCompilerArgs(const Target* target); 151 152 // Find the value of an argument that's passed to the compiler as two 153 // consecutive strings in the list of arguments: ["arg", "value"] 154 std::optional<std::string> FindArgValue(const char* arg, 155 const std::vector<std::string>& args); 156 157 // Find the first argument that matches the prefix, returning the value after 158 // the prefix. e.g. ˝--arg=value", is returned as "value" if the prefix 159 // "--arg=" is used. 160 std::optional<std::string> FindArgValueAfterPrefix( 161 const std::string& prefix, 162 const std::vector<std::string>& args); 163 164 // Find all arguments that match the given prefix, returning the value after 165 // the prefix for each one. e.g. "--cfg=value" is returned as "value" if the 166 // prefix "--cfg=" is used. 167 std::vector<std::string> FindAllArgValuesAfterPrefix( 168 const std::string& prefix, 169 const std::vector<std::string>& args); 170 171 172 #endif // TOOLS_GN_RUST_PROJECT_WRITER_HELPERS_H_ 173