Spicy
driver.h
1 // Copyright (c) 2020-2021 by the Zeek Project. See LICENSE for details.
2 // p
3 
4 #pragma once
5 
6 #include <fstream>
7 #include <iostream>
8 #include <memory>
9 #include <set>
10 #include <string>
11 #include <string_view>
12 #include <unordered_map>
13 #include <utility>
14 #include <vector>
15 
16 #include <hilti/rt/filesystem.h>
17 
18 #include <hilti/base/logger.h>
19 #include <hilti/base/result.h>
20 #include <hilti/base/timing.h>
21 #include <hilti/compiler/context.h>
22 #include <hilti/compiler/unit.h>
23 
24 namespace hilti {
25 
26 class JIT;
27 struct Options;
28 
29 namespace driver {
30 
32 enum class Dependencies {
33  None,
34  All,
35  Code
36 };
37 
43 struct Options {
44  bool include_linker = false;
45  bool output_hilti = false;
46  bool output_prototypes = false;
47  bool output_cxx = false;
48  std::string output_cxx_prefix;
49  bool output_linker = false;
50  Dependencies output_dependencies = Dependencies::None;
51  bool execute_code = false;
52  bool show_backtraces = false;
53  bool abort_on_exceptions = false;
54  bool keep_tmps = false;
55  bool skip_dependencies = false;
56  bool report_resource_usage = false;
57  bool report_times = false;
58  bool dump_code = false;
59  bool global_optimizations = true;
60  std::vector<hilti::rt::filesystem::path>
62  hilti::rt::filesystem::path output_path;
63  std::unique_ptr<Logger>
66  Options() { logger = std::make_unique<Logger>(); }
67 };
68 
69 } // namespace driver
70 
83 class Driver {
84 public:
89  explicit Driver(std::string name);
90 
98  Driver(std::string name, const hilti::rt::filesystem::path& argv0);
99 
100  virtual ~Driver();
101 
102  Driver() = delete;
103  Driver(const Driver&) = delete;
104  Driver(Driver&&) noexcept = delete;
105  Driver& operator=(const Driver&) = delete;
106  Driver& operator=(Driver&&) noexcept = delete;
107 
118  Result<Nothing> parseOptions(int argc, char** argv);
119 
131  Result<Nothing> addInput(const std::shared_ptr<Unit>& u);
132 
145  Result<Nothing> addInput(const hilti::rt::filesystem::path& path);
146 
148  bool hasInputs() const {
149  return ! (_pending_units.empty() && _processed_units.empty() && _processed_paths.empty() &&
150  _libraries.empty() && _external_cxxs.empty());
151  }
152 
154  const auto& driverOptions() const { return _driver_options; }
155 
157  const auto& hiltiOptions() const { return _compiler_options; }
158 
164  void setDriverOptions(driver::Options options);
165 
171  void setCompilerOptions(hilti::Options options);
172 
179  Result<Nothing> initialize();
180 
188  Result<Nothing> compile();
189 
194  const auto& context() const { return _ctx; }
195 
197  const auto& options() const { return _ctx->options(); }
198 
208  Result<Nothing> initRuntime();
209 
216  Result<Nothing> executeMain();
217 
224  Result<Nothing> finishRuntime();
225 
234  Result<Nothing> run();
235 
236 protected:
241  void usage();
242 
248  Result<Nothing> compileUnits();
249 
257  Result<Nothing> codegenUnits();
258 
264  Result<Nothing> linkUnits();
265 
271  Result<Nothing> outputUnits();
272 
278  Result<Nothing> jitUnits();
279 
288  result::Error error(std::string_view msg, const hilti::rt::filesystem::path& p = "");
289 
298  result::Error augmentError(const result::Error& err, const hilti::rt::filesystem::path& p = "");
299 
308  Result<std::ofstream> openOutput(const hilti::rt::filesystem::path& p, bool binary = false, bool append = false);
309 
317  Result<Nothing> openInput(std::ifstream& in, const hilti::rt::filesystem::path& p);
318 
326  Result<Nothing> writeOutput(std::ifstream& in, const hilti::rt::filesystem::path& p);
327 
334  Result<std::stringstream> readInput(const hilti::rt::filesystem::path& p);
335 
344  Result<hilti::rt::filesystem::path> writeToTemp(std::ifstream& in, const std::string& name_hint,
345  const std::string& extension = "tmp");
346 
348  void dumpUnit(const Unit& unit);
349 
355  void printHiltiException(const hilti::rt::Exception& e);
356 
361  virtual std::string hookAddCommandLineOptions() { return ""; }
362 
364  virtual bool hookProcessCommandLineOption(int opt, const char* optarg) { return false; }
365 
370  virtual std::string hookAugmentUsage() { return ""; }
371 
376  virtual void hookAddInput(std::shared_ptr<Unit> unit) {} // NOLINT(performance-unnecessary-value-param)
377 
382  virtual void hookAddInput(const hilti::rt::filesystem::path& path) {}
383 
389  virtual void hookNewASTPreCompilation(std::shared_ptr<Unit> unit) {} // NOLINT(performance-unnecessary-value-param)
390 
396  virtual void hookNewASTPostCompilation(std::shared_ptr<Unit> unit) {} // NOLINT(performance-unnecessary-value-param)
397 
409  virtual Result<Nothing> hookCompilationFinished(const Plugin& plugin) { return Nothing(); }
410 
415  virtual void hookInitRuntime() {}
416 
421  virtual void hookFinishRuntime() {}
422 
423 private:
424  // Tracking the state of the compilation pipeline to catch out of order
425  // operation.
426  enum Stage { UNINITIALIZED, INITIALIZED, COMPILED, CODEGENED, LINKED, JITTED } _stage = UNINITIALIZED;
427 
428  // Backend for adding a new unit.
429  void _addUnit(const std::shared_ptr<Unit>& unit);
430 
431  // Run a specific plugini's AST passes on all units with the corresponding extension.
432  Result<Nothing> _resolveUnitsWithPlugin(const Plugin& plugin, std::vector<std::shared_ptr<Unit>> units, int& round);
433 
434  // Runs a specific plugin's transform step on a given set of units.
435  Result<Nothing> _transformUnitsWithPlugin(const Plugin& plugin, const std::vector<std::shared_ptr<Unit>>& units);
436 
437  // Run all plugins on current units, iterating until finished.
438  Result<Nothing> _resolveUnits();
439 
440  // Turns all HILTI units into C++.
441  Result<Nothing> _codegenUnits();
442 
443  // Performs global transformations on the generated code.
444  Result<Nothing> _optimizeUnits();
445 
446  // Sends a debug dump of a unit's AST to the global logger.
447  void _dumpAST(const std::shared_ptr<Unit>& unit, const logging::DebugStream& stream, const Plugin& plugin,
448  const std::string& prefix, int round);
449 
450  // Sends a debug dump of a unit's AST to the global logger.
451  void _dumpAST(const std::shared_ptr<Unit>& unit, const logging::DebugStream& stream, const std::string& prefix);
452 
453  // Sends a debug dump of a unit's AST to an output stream.
454  void _dumpAST(const std::shared_ptr<Unit>& unit, std::ostream& stream, const Plugin& plugin,
455  const std::string& prefix, int round);
456 
457  // Records a reduced debug dump of a unit's AST limited to just declarations.
458  void _dumpDeclarations(const std::shared_ptr<Unit>& unit, const Plugin& plugin);
459 
460  // Records a debug dump of a unit's AST to disk.
461  void _saveIterationAST(const std::shared_ptr<Unit>& unit, const Plugin& plugin, const std::string& prefix,
462  int round);
463 
464  // Records a debug dump of a unit's AST to disk.
465  void _saveIterationAST(const std::shared_ptr<Unit>& unit, const Plugin& plugin, const std::string& prefix,
466  const std::string& tag);
467 
474  static Result<void*> _symbol(const std::string& symbol);
475 
476  std::string _name;
477  driver::Options _driver_options;
478  hilti::Options _compiler_options;
479 
480  std::vector<std::shared_ptr<Unit>> _pending_units;
481  std::set<ID> _processed_units;
482  std::set<hilti::rt::filesystem::path> _processed_paths;
483 
484  std::shared_ptr<Context> _ctx; // driver's compiler context
485  std::unique_ptr<hilti::JIT> _jit; // driver's JIT instance
486  std::shared_ptr<const hilti::rt::Library> _library; // Compiled code
487 
488  std::vector<CxxCode> _generated_cxxs;
489  std::unordered_map<std::string, Library> _libraries;
490  std::vector<hilti::rt::filesystem::path> _external_cxxs;
491  std::vector<linker::MetaData> _mds;
492  std::vector<std::shared_ptr<Unit>> _hlts;
493 
494  bool _runtime_initialized = false; // true once initRuntime() has succeeded
495  std::set<std::string> _tmp_files; // all tmp files created, so that we can clean them up.
496 };
497 
498 } // namespace hilti
virtual void hookAddInput(const hilti::rt::filesystem::path &path)
Definition: driver.h:382
std::unique_ptr< Logger > logger
Definition: driver.h:64
virtual bool hookProcessCommandLineOption(int opt, const char *optarg)
Definition: driver.h:364
Definition: result.h:18
Definition: context.h:33
const auto & driverOptions() const
Definition: driver.h:154
virtual std::string hookAugmentUsage()
Definition: driver.h:370
const auto & context() const
Definition: driver.h:194
virtual void hookInitRuntime()
Definition: driver.h:415
bool hasInputs() const
Definition: driver.h:148
Definition: plugin.h:52
virtual void hookNewASTPreCompilation(std::shared_ptr< Unit > unit)
Definition: driver.h:389
virtual Result< Nothing > hookCompilationFinished(const Plugin &plugin)
Definition: driver.h:409
virtual void hookFinishRuntime()
Definition: driver.h:421
virtual void hookAddInput(std::shared_ptr< Unit > unit)
Definition: driver.h:376
hilti::rt::filesystem::path output_path
Definition: driver.h:62
Definition: driver.h:83
virtual std::string hookAddCommandLineOptions()
Definition: driver.h:361
Definition: unit.h:49
const auto & options() const
Definition: driver.h:197
const auto & hiltiOptions() const
Definition: driver.h:157
Definition: exception.h:22
Definition: result.h:57
std::string output_cxx_prefix
Definition: driver.h:48
Definition: result.h:67
Definition: driver.h:43
virtual void hookNewASTPostCompilation(std::shared_ptr< Unit > unit)
Definition: driver.h:396
std::vector< hilti::rt::filesystem::path > inputs
Definition: driver.h:61
Definition: logger.h:28