diff --git a/compiler+runtime/include/cpp/jank/jit/processor.hpp b/compiler+runtime/include/cpp/jank/jit/processor.hpp index e2e7743c..6c8d0ce9 100644 --- a/compiler+runtime/include/cpp/jank/jit/processor.hpp +++ b/compiler+runtime/include/cpp/jank/jit/processor.hpp @@ -14,17 +14,24 @@ namespace jank::runtime namespace jank::jit { + struct processor { - processor(native_integer optimization_level); + processor(util::cli::options const &opts); ~processor(); result, native_persistent_string> eval(codegen::processor &cg_prc) const; void eval_string(native_persistent_string const &s) const; - void load_object(native_persistent_string_view const &path) const; + void load_object(native_persistent_string const &path) const; + + result + load_dynamic_libs(native_vector const &libs) const; + + option find_dynamic_lib(native_persistent_string const &lib) const; std::unique_ptr interpreter; native_integer optimization_level{}; + native_vector library_dirs; }; } diff --git a/compiler+runtime/include/cpp/jank/runtime/context.hpp b/compiler+runtime/include/cpp/jank/runtime/context.hpp index 078c9244..3d474d47 100644 --- a/compiler+runtime/include/cpp/jank/runtime/context.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/context.hpp @@ -31,7 +31,6 @@ namespace jank::runtime { context(); context(util::cli::options const &opts); - context(context const &); context(context &&) = delete; ~context(); diff --git a/compiler+runtime/include/cpp/jank/util/cli.hpp b/compiler+runtime/include/cpp/jank/util/cli.hpp index 7d9eb3bc..329f53b5 100644 --- a/compiler+runtime/include/cpp/jank/util/cli.hpp +++ b/compiler+runtime/include/cpp/jank/util/cli.hpp @@ -20,6 +20,12 @@ namespace jank::util::cli native_bool profiler_enabled{}; native_transient_string profiler_file{ "jank.profile" }; native_bool gc_incremental{}; + + /* Native dependencies */ + native_vector include_dirs; + native_vector library_dirs; + native_vector define_macros; + native_vector libs; /* Compilation. */ native_transient_string compilation_path{ "classes" }; diff --git a/compiler+runtime/src/cpp/jank/jit/processor.cpp b/compiler+runtime/src/cpp/jank/jit/processor.cpp index f9aee618..1b07c1af 100644 --- a/compiler+runtime/src/cpp/jank/jit/processor.cpp +++ b/compiler+runtime/src/cpp/jank/jit/processor.cpp @@ -16,6 +16,18 @@ namespace jank::jit { + + native_persistent_string default_shared_lib_name(native_persistent_string const &lib) +#if defined(__APPLE__) + { + return fmt::format("{}.dylib", lib); + } +#elif defined(__linux__) + { + return fmt::format("lib{}.so", lib); + } +#endif + static void handle_fatal_llvm_error(void * const user_data, char const *message, native_bool const gen_crash_diag) @@ -80,9 +92,14 @@ namespace jank::jit return output_path; } - processor::processor(native_integer const optimization_level) - : optimization_level{ optimization_level } + processor::processor(util::cli::options const &opts) + : optimization_level{ opts.optimization_level } { + for(auto const &library_dir : opts.library_dirs) + { + library_dirs.emplace_back(boost::filesystem::absolute(library_dir.c_str())); + } + profile::timer timer{ "jit ctor" }; /* TODO: Pass this into each fn below so we only do this once on startup. */ auto const jank_path(util::process_location().unwrap().parent_path()); @@ -102,7 +119,7 @@ namespace jank::jit auto const include_path(jank_path / "../include"); - native_persistent_string_view O{ "-O0" }; + native_persistent_string O{ "-O0" }; switch(optimization_level) { case 0: @@ -137,7 +154,22 @@ namespace jank::jit args.emplace_back("-include-pch"); args.emplace_back(strdup(pch_path_str.c_str())); - //fmt::println("jit flags {}", args); + for(auto const &include_path : opts.include_dirs) + { + args.emplace_back(strdup(fmt::format("-I{}", include_path).c_str())); + } + + for(auto const &library_path : opts.library_dirs) + { + args.emplace_back(strdup(fmt::format("-L{}", library_path).c_str())); + } + + for(auto const &define_macro : opts.define_macros) + { + args.emplace_back(strdup(fmt::format("-D{}", define_macro).c_str())); + } + + // fmt::println("jit flags {}", args); clang::IncrementalCompilerBuilder compiler_builder; compiler_builder.SetCompilerArgs(args); @@ -148,6 +180,12 @@ namespace jank::jit compiler_instance->LoadRequestedPlugins(); interpreter = llvm::cantFail(clang::Interpreter::create(std::move(compiler_instance))); + + auto const &load_result{ load_dynamic_libs(opts.libs) }; + if(load_result.is_err()) + { + throw std::runtime_error{ load_result.expect_err().c_str() }; + } } processor::~processor() @@ -199,4 +237,59 @@ namespace jank::jit auto err(interpreter->ParseAndExecute({ s.data(), s.size() })); llvm::logAllUnhandledErrors(std::move(err), llvm::errs(), "error: "); } + + option + processor::find_dynamic_lib(native_persistent_string const &lib) const + { + auto const &default_lib_name{ default_shared_lib_name(lib) }; + for(auto const &lib_dir : library_dirs) + { + auto const default_lib_abs_path{ fmt::format("{}/{}", lib_dir.string(), default_lib_name) }; + if(boost::filesystem::exists(default_lib_abs_path.c_str())) + { + return default_lib_abs_path; + } + else + { + auto const lib_abs_path{ fmt::format("{}/{}", lib_dir.string(), lib) }; + if(boost::filesystem::exists(lib_abs_path)) + { + return lib_abs_path; + } + } + } + + return none; + } + + result + processor::load_dynamic_libs(native_vector const &libs) const + { + for(auto const &lib : libs) + { + if(boost::filesystem::path{ lib.c_str() }.is_absolute()) + { + load_object(lib); + } + else + { + auto const result{ processor::find_dynamic_lib(lib) }; + if(result.is_none()) + { + return err(fmt::format("Failed to load dynamic library `{}`", lib)); + } + else + { + load_object(result.unwrap()); + } + } + } + + return ok(); + } + + void processor::load_object(native_persistent_string const &path) const + { + llvm::cantFail(interpreter->LoadDynamicLibrary(path.data())); + } } diff --git a/compiler+runtime/src/cpp/jank/runtime/context.cpp b/compiler+runtime/src/cpp/jank/runtime/context.cpp index d53244e8..f9f31df9 100644 --- a/compiler+runtime/src/cpp/jank/runtime/context.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/context.cpp @@ -29,7 +29,7 @@ namespace jank::runtime } context::context(util::cli::options const &opts) - : jit_prc{ opts.optimization_level } + : jit_prc{ opts } , output_dir{ opts.compilation_path } , module_loader{ *this, opts.class_path } { @@ -68,57 +68,6 @@ namespace jank::runtime .expect_ok(); } - /* TODO: Remove this. */ - context::context(context const &ctx) - : jit_prc{ ctx.jit_prc.optimization_level } - , module_dependencies{ ctx.module_dependencies } - , output_dir{ ctx.output_dir } - , module_loader{ *this, ctx.module_loader.paths } - { - { - auto ns_lock(namespaces.wlock()); - for(auto const &ns : *ctx.namespaces.rlock()) - { - ns_lock->insert({ ns.first, ns.second->clone(*this) }); - } - *keywords.wlock() = *ctx.keywords.rlock(); - } - - auto &tbfs(thread_binding_frames[this]); - auto const &other_tbfs(thread_binding_frames[&ctx]); - for(auto const &v : other_tbfs) - { - thread_binding_frame frame{ obj::persistent_hash_map::empty() }; - for(auto it(v.bindings->fresh_seq()); it != nullptr; it = runtime::next_in_place(it)) - { - auto const entry(it->first()); - auto const var(expect_object(entry->data[0])); - auto const value(entry->data[1]); - auto const new_var(intern_var(var->n->name->name, var->name->name).expect_ok()); - frame.bindings = frame.bindings->assoc(new_var, value); - } - - /* We push to the back, since we're looping from the front of the other list. If we - * pushed to the front of this one, we'd reverse the order. */ - tbfs.push_back(std::move(frame)); - } - - auto const core(intern_ns(make_box("clojure.core"))); - current_ns_var = core->intern_var(make_box("clojure.core/*ns*")); - - in_ns_var = intern_var(make_box("clojure.core/in-ns")).expect_ok(); - compile_files_var - = intern_var(make_box("clojure.core/*compile-files*")).expect_ok(); - assert_var = core->intern_var(make_box("clojure.core/*assert*")); - - current_module_var - = make_box(core, make_box("*current-module*"))->set_dynamic(true); - no_recur_var - = make_box(core, make_box("*no-recur*"))->set_dynamic(true); - gensym_env_var - = make_box(core, make_box("*gensym-env*"))->set_dynamic(true); - } - context::~context() { thread_binding_frames.erase(this); diff --git a/compiler+runtime/src/cpp/jank/util/cli.cpp b/compiler+runtime/src/cpp/jank/util/cli.cpp index d627f817..80122fe5 100644 --- a/compiler+runtime/src/cpp/jank/util/cli.cpp +++ b/compiler+runtime/src/cpp/jank/util/cli.cpp @@ -27,6 +27,20 @@ namespace jank::util::cli cli.add_option("-O,--optimization", opts.optimization_level, "The optimization level to use") ->check(CLI::Range(0, 3)); + /* TODO: new category */ + cli.add_option("-I,--include-dir", + opts.include_dirs, + "Absolute or relative path to the directory for includes resolution. Accepts multiple values"); + cli.add_option("-L,--library-dir", + opts.library_dirs, + "Absolute or relative path to the directory to search dynamic libraries in. Accepts multiple values"); + cli.add_option("-D,--define-macro", + opts.define_macros, + "Defines macro value, sets to 1 if omitted. Accepts multiple values"); + cli.add_option("-l", + opts.libs, + "Library identifiers, absolute or relative paths eg. -lfoo for libfoo.so or foo.dylib. Accepts multiple values"); + /* Run subcommand. */ auto &cli_run(*cli.add_subcommand("run", "Load and run a file")); cli_run.fallthrough();