-
Notifications
You must be signed in to change notification settings - Fork 446
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Plugin Support #59
Plugin Support #59
Changes from all commits
3a05f1a
47c8184
7e95669
6641d10
083fb9a
0865fd2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
/- | ||
Copyright (c) 2019 Microsoft Corporation. All rights reserved. | ||
Released under Apache 2.0 license as described in the file LICENSE. | ||
Authors: Sebastian Ullrich | ||
-/ | ||
prelude | ||
import Init.System.IO | ||
import Init.Lean.Attributes | ||
import Init.Lean.Message | ||
import Init.Lean.Syntax | ||
|
||
namespace Lean | ||
|
||
def Linter := Environment → Name → /-Syntax → -/IO MessageLog | ||
|
||
def mkLintersRef : IO (IO.Ref (Array Linter)) := | ||
IO.mkRef #[] | ||
|
||
/- Linters should be loadable as plugins, so store in a global IO ref instead of an attribute managed by the | ||
environment (which only contains `import`ed objects). -/ | ||
@[init mkLintersRef, export lean_linters_ref] | ||
constant lintersRef : IO.Ref (Array Linter) := arbitrary _ | ||
|
||
def addLinter (l : Linter) : IO Unit := do | ||
ls ← lintersRef.get; | ||
lintersRef.set (ls.push l) | ||
|
||
end Lean |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -56,6 +56,13 @@ Author: Leonardo de Moura | |
#endif | ||
#include "githash.h" // NOLINT | ||
|
||
#ifdef LEAN_WINDOWS | ||
#include <windows.h> | ||
#undef ERROR // thanks, wingdi.h | ||
#else | ||
#include <dlfcn.h> | ||
#endif | ||
|
||
#if defined(LEAN_LLVM) | ||
#include <llvm/Support/TargetSelect.h> | ||
#endif | ||
|
@@ -201,6 +208,7 @@ static void display_help(std::ostream & out) { | |
std::cout << " --threads=num -j number of threads used to process lean files\n"; | ||
std::cout << " --tstack=num -s thread stack size in Kb\n"; | ||
#endif | ||
std::cout << " --plugin=file load and initialize shared library for registering linters etc."; | ||
std::cout << " --deps just print dependencies of a Lean input\n"; | ||
#if defined(LEAN_JSON) | ||
std::cout << " --json print JSON-formatted structured error messages\n"; | ||
|
@@ -241,14 +249,15 @@ static struct option g_long_options[] = { | |
#if defined(LEAN_MULTI_THREAD) | ||
{"tstack", required_argument, 0, 's'}, | ||
#endif | ||
{"plugin", required_argument, 0, 'p'}, | ||
#ifdef LEAN_DEBUG | ||
{"debug", required_argument, 0, 'B'}, | ||
#endif | ||
{0, 0, 0, 0} | ||
}; | ||
|
||
static char const * g_opt_str = | ||
"PdD:c:C:qgvht:012j:012rM:012T:012a" | ||
"PdD:c:C:qgvht:012j:012rM:012T:012ap:" | ||
#if defined(LEAN_MULTI_THREAD) | ||
"s:012" | ||
#endif | ||
|
@@ -289,6 +298,32 @@ options set_config_option(options const & opts, char const * in) { | |
} | ||
} | ||
|
||
void load_plugin(std::string path) { | ||
void * init; | ||
// we never want to look up plugins using the system library search | ||
path = lrealpath(path); | ||
#ifdef LEAN_WINDOWS | ||
HMODULE h = LoadLibrary(path.c_str()); | ||
if (!h) { | ||
throw exception(sstream() << "error loading plugin " << path); | ||
} | ||
init = reinterpret_cast<void *>(GetProcAddress(h, "initialize_Default")); | ||
#else | ||
void *handle = dlopen(path.c_str(), RTLD_LAZY); | ||
if (!handle) { | ||
throw exception(sstream() << "error loading plugin, " << dlerror()); | ||
} | ||
init = dlsym(handle, "initialize_Default"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems every plugin must define There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, objects loaded by
As far as I could find out, this is actually the only behavior supported on Windows, so we should be fine. Btw, note that if we ever do prefix import paths with the package name as we once discussed, this would be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this try calling dlopen with RTLD_NOLOAD (if available) first, to check if the shared library is actually loaded already, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks I had missed the section describing that in the docs, needed to read further. |
||
#endif | ||
if (!init) { | ||
throw exception(sstream() << "error, plugin " << path << " does not seem to contain a module 'Default'"); | ||
} | ||
auto init_fn = reinterpret_cast<object *(*)(object *)>(init); | ||
object *r = init_fn(io_mk_world()); | ||
consume_io_result(r); | ||
// NOTE: we never unload plugins | ||
} | ||
|
||
class initializer { | ||
private: | ||
lean::initializer m_init; | ||
|
@@ -344,6 +379,10 @@ int main(int argc, char ** argv) { | |
} catch (e) { | ||
console.log(e); | ||
}); | ||
#endif | ||
#if LEAN_WINDOWS | ||
// "best practice" according to https://docs.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-seterrormode | ||
SetErrorMode(SEM_FAILCRITICALERRORS); | ||
#endif | ||
auto init_start = std::chrono::steady_clock::now(); | ||
::initializer init; | ||
|
@@ -454,6 +493,9 @@ int main(int argc, char ** argv) { | |
case 'n': | ||
new_frontend = true; | ||
break; | ||
case 'p': | ||
load_plugin(optarg); | ||
break; | ||
default: | ||
std::cerr << "Unknown command line option\n"; | ||
display_help(std::cerr); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should move this function to a different folder since we need it to implement the
import plugin <plugin-name>
command