MimIR
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
driver.cpp
Go to the documentation of this file.
1#include "mim/driver.h"
2
3#include <iostream>
4#include <sstream>
5#include <stdexcept>
6
7#include "mim/plugin.h"
8
9#include "mim/util/dl.h"
10#include "mim/util/sys.h"
11
12namespace mim {
13
14std::pair<const fs::path*, bool> Driver::Imports::add(fs::path path, Sym sym, ast::Tok::Tag tag) {
15 if (!fs::exists(path)) {
16 driver_.WLOG("import path '{}' does not exist", path.string());
17 return {nullptr, false};
18 }
19
20 const fs::path* imported_path = nullptr;
21 bool fresh = true;
22 for (const auto& parsed_path : parsed_paths_) {
23 if (fs::equivalent(parsed_path, path)) {
24 imported_path = &parsed_path;
25 fresh = false;
26 break;
27 }
28 }
29
30 if (!imported_path) {
31 parsed_paths_.emplace_back(std::move(path));
32 imported_path = &parsed_paths_.back();
33 }
34
35 bool seen_entry = false;
36 for (const auto& entry : entries_) {
37 if (entry.sym == sym && entry.tag == tag && fs::equivalent(entry.path, *imported_path)) {
38 seen_entry = true;
39 break;
40 }
41 }
42
43 if (!seen_entry) entries_.emplace_back(Entry{*imported_path, sym, tag});
44 return {imported_path, fresh};
45}
46
47Driver::Driver(std::string name)
48 : version_(MIM_VERSION)
49 , log_(flags_)
50 , world_(this, sym(name))
51 , imports_(*this) {
52 // prepend empty path
53 search_paths_.emplace_front(fs::path{});
54
55 // paths from env
56 if (auto env_path = std::getenv("MIM_PLUGIN_PATH")) {
57 std::stringstream env_path_stream{env_path};
58 std::string sub_path;
59 while (std::getline(env_path_stream, sub_path, ':'))
60 add_search_path(sub_path);
61 }
62
63 // add <path/to/libmim>/mim
64 if (auto path = sys::path_to_libmim()) add_search_path(path->parent_path() / "mim");
65
66 // add install path if different from above
67 if (auto install_path = fs::path{MIM_INSTALL_PREFIX} / MIM_LIBDIR / "mim"; fs::exists(install_path)) {
68 if (search_paths().size() < 2 || !fs::equivalent(install_path, search_paths().back()))
69 add_search_path(std::move(install_path));
70 }
71
72 // all other user paths are placed just behind the first path (the empty path)
73 insert_ = ++search_paths_.begin();
74}
75
76void Driver::load(Sym name) {
77 ILOG("💾 loading plugin: '{}'", name);
78
79 if (is_loaded(name)) {
80 WLOG("mim/plugin '{}' already loaded", name);
81 return;
82 }
83
84 auto handle = Plugin::Handle{nullptr, dl::close};
85 if (auto path = fs::path{name.view()}; path.is_absolute() && fs::is_regular_file(path))
86 handle.reset(dl::open(name.c_str()));
87 if (!handle) {
88 for (const auto& path : search_paths()) {
89 auto full_path = path / std::format("libmim_{}.{}", name, dl::extension);
90 std::error_code ignore;
91 if (bool reg_file = fs::is_regular_file(full_path, ignore); reg_file && !ignore) {
92 auto path_str = full_path.string();
93 if (handle.reset(dl::open(path_str.c_str())); handle) break;
94 }
95 if (handle) break;
96 }
97 }
98
99 if (!handle) error("cannot open plugin '{}'", name);
100
101 if (auto get_info = reinterpret_cast<decltype(&mim_get_plugin)>(dl::get(handle.get(), "mim_get_plugin"))) {
102 auto plugin = get_info();
103 if (version() != plugin.version) {
104 std::ostringstream oss;
105 std::print(oss, "plugin {} has version {} while MimIR has version {}", plugin.name, plugin.version,
106 version());
107 if (flags().force_load)
108 std::cerr << "warning: " << oss.str() << '\n';
109 else
110 throw std::logic_error(oss.str());
111 }
112 assert_emplace(plugins_, name, std::move(handle));
113 // clang-format off
114 if (auto reg = plugin.register_normalizers) reg(normalizers_);
115 if (auto reg = plugin.register_stages) reg(stages_);
116 // clang-format on
117 } else {
118 error("mim/plugin has no 'mim_get_plugin()'");
119 }
120}
121
122void* Driver::get_fun_ptr(Sym plugin, const char* name) {
123 if (auto handle = lookup(plugins_, plugin)) return dl::get(handle->get(), name);
124 return nullptr;
125}
126
127} // namespace mim
std::pair< const fs::path *, bool > add(fs::path, Sym, ast::Tok::Tag)
Remembers an import or plugin directive and reports whether the resolved file is new.
Definition driver.cpp:14
void load(Sym name)
Definition driver.cpp:76
void add_search_path(fs::path path)
Definition driver.h:50
const Version & version() const
MimIR Version.
Definition driver.h:38
bool is_loaded(Sym sym) const
Definition driver.h:103
void * get_fun_ptr(Sym plugin, const char *name)
Definition driver.cpp:122
Flags & flags()
Definition driver.h:34
const auto & search_paths() const
Definition driver.h:49
#define MIM_LIBDIR
Definition config.h:13
#define MIM_INSTALL_PREFIX
Definition config.h:12
#define ILOG(...)
Definition log.h:90
#define WLOG(...)
Definition log.h:89
void * get(void *handle, const char *symbol_name)
Definition dl.cpp:32
void close(void *handle)
Definition dl.cpp:51
void * open(const char *filename)
Definition dl.cpp:13
static constexpr auto extension
Definition dl.h:8
std::optional< fs::path > path_to_libmim()
Yields std::nullopt if an error occurred.
Definition sys.cpp:52
Definition ast.h:14
auto assert_emplace(C &container, Args &&... args)
Invokes emplace on container, asserts that insertion actually happened, and returns the iterator.
Definition util.h:117
auto lookup(const C &container, const K &key)
Yields pointer to element (or the element itself if it is already a pointer), if found and nullptr ot...
Definition util.h:99
mim::Plugin mim_get_plugin()
void error(std::format_string< Args... > fmt, Args &&... args)
Wraps std::format to throw T with a formatted message.
Definition dbg.h:17
#define MIM_VERSION
Definition plugin.h:54
std::unique_ptr< void, void(*)(void *)> Handle
Definition plugin.h:60