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 // Write the entire rust-project.json file contents into the given stream, based
129 // on the the given crates list.
130 void WriteCrates(const BuildSettings* build_settings,
131                  CrateList& crate_list,
132                  std::optional<std::string>& sysroot,
133                  std::ostream& rust_project);
134 
135 // Assemble the compiler arguments for the given GN Target.
136 std::vector<std::string> ExtractCompilerArgs(const Target* target);
137 
138 // Find the value of an argument that's passed to the compiler as two
139 // consecutive strings in the list of arguments:  ["arg", "value"]
140 std::optional<std::string> FindArgValue(const char* arg,
141                                         const std::vector<std::string>& args);
142 
143 // Find the first argument that matches the prefix, returning the value after
144 // the prefix.  e.g. ˝--arg=value", is returned as "value" if the prefix
145 // "--arg=" is used.
146 std::optional<std::string> FindArgValueAfterPrefix(
147     const std::string& prefix,
148     const std::vector<std::string>& args);
149 
150 // Find all arguments that match the given prefix, returning the value after
151 // the prefix for each one.  e.g. "--cfg=value" is returned as "value" if the
152 // prefix "--cfg=" is used.
153 std::vector<std::string> FindAllArgValuesAfterPrefix(
154     const std::string& prefix,
155     const std::vector<std::string>& args);
156 
157 #endif  // TOOLS_GN_RUST_PROJECT_WRITER_HELPERS_H_
158