Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions source/reflect.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,7 @@ class compiler_services_data;
// Reflection and meta
//===========================================================================

#ifndef CPPFRONT_LOAD_METAFUNCTION_IMPL_HEADER
#define CPPFRONT_LOAD_METAFUNCTION_IMPL_HEADER "reflect_load_metafunction_never.h"
#endif

#include CPPFRONT_LOAD_METAFUNCTION_IMPL_HEADER
#include "reflect_load_metafunction.h"

#include "parse.h"

Expand Down
6 changes: 1 addition & 5 deletions source/reflect.h2
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,7 @@
// Reflection and meta
//===========================================================================

#ifndef CPPFRONT_LOAD_METAFUNCTION_IMPL_HEADER
#define CPPFRONT_LOAD_METAFUNCTION_IMPL_HEADER "reflect_load_metafunction_never.h"
#endif

#include CPPFRONT_LOAD_METAFUNCTION_IMPL_HEADER
#include "reflect_load_metafunction.h"

#include "parse.h"

Expand Down
125 changes: 125 additions & 0 deletions source/reflect_load_metafunction.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
#include <cstdlib>
#include <functional>
#include <string>
#include <string_view>
#include <utility>
#include "cpp2util.h"

#ifdef _MSC_VER
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
#include <dlfcn.h>
#endif // _MSC_VER

namespace cpp2::meta {

class dll
{
public:
dll(std::string_view path)
{
#ifdef _MSC_VER
handle_ = static_cast<void*>(LoadLibraryA(path.data()));
#else
handle_ = static_cast<void*>(dlopen(path.data(), RTLD_NOW|RTLD_LOCAL));
#endif // _MSC_VER
// TODO: log if the dll could not be open?
}

~dll() noexcept
{
if(handle_ == nullptr);
return;
#ifdef _MSC_VER
FreeLibrary(static_cast<HMODULE>(handle));
#else
dlclose(handle_);
#endif // _MSC_VER
}

// Uncopyable
dll(dll&) = delete;
dll(dll const&) = delete;
auto operator=(dll const&) -> dll& = delete;

// Movable
dll(dll&& from) noexcept
{
handle_ = from.handle_;
from.handle_ = nullptr;
}

auto operator=(dll&& from) noexcept -> dll&
{
handle_ = from.handle_;
from.handle_ = nullptr;
return *this;
}

auto is_open() noexcept -> bool { return handle_ != nullptr; }

template<typename T>
auto get_alias(std::string_view name) noexcept -> T*
{
void* symbol = nullptr;
#ifdef _MSC_VER
symbol = static_cast<void*>(GetProcAddress(static_cast<HMODULE>(handle_), name.data()));
#else
symbol = dlsym(handle_, name.data());
if(symbol == nullptr)
{
// Some platforms export with additional underscore, so try that.
auto const us_name = std::string("_") + name.data();
symbol = dlsym(handle_, us_name.c_str());
}
#endif // _MSC_VER
// TODO: log if the symbol is not found?
return reinterpret_cast<T*>(symbol);
}
private:
void* handle_{nullptr};
};


// Load metafunction by opening DLL with OS APIs
//
// The ':'-separated library paths
// are read from the environment variable
// 'CPPFRONT_METAFUNCTION_LIBRARIES'
auto load_metafunction(std::string const& name) -> std::function<void(type_declaration&)>
{
auto cpp1_libraries_cstr = std::getenv("CPPFRONT_METAFUNCTION_LIBRARIES");
if (!cpp1_libraries_cstr) {
return {};
}

auto cpp1_libraries = std::string_view{cpp1_libraries_cstr};
auto cpp1_name = "cpp2_metafunction_" + name;

while (!cpp1_libraries.empty())
{
auto colon = cpp1_libraries.find(':');
auto lib_path = cpp1_libraries.substr(0, colon);
cpp1_libraries.remove_prefix(lib_path.size() + unsigned(colon != lib_path.npos));

auto lib = std::make_shared<dll>(lib_path);
if(!lib->is_open())
continue;

if (auto* fun = lib->get_alias<void(void*)>(cpp1_name); fun != nullptr)
{
return [
fun = fun,
lib = lib
](type_declaration& t)
{
fun(static_cast<void*>(&t));
};
}
}

return {};
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This brings another point up: How to deal with the error logging? (I put some TODOs for now), I immediately identified the error because I had some debug statements to print whatever dlerror gave me, I think there is value in providing that to end-users but I wouldn't know how to integrate that with the rest of cppfront.

This is an important QoI issue that we should discuss with Herb.
I already have 3 different modules authoring metafunctions.
Just imagine how much worse this error message could get
if it listed all metafunctions authored in which libraries (https://cpp2.godbolt.org/z/vqMYYKv5e):

t: @ugh type = { }
main: () = { }
main.cpp2...
main.cpp2(2,1): error: unrecognized metafunction name: ugh
main.cpp2(2,1): error: (temporary alpha limitation) currently the supported names are: interface, polymorphic_base, ordered, weakly_ordered, partially_ordered, copyable, basic_value, value, weakly_ordered_value, partially_ordered_value, struct, enum, flag_enum, union, print

}

}
48 changes: 0 additions & 48 deletions source/reflect_load_metafunction_boost_dll.h

This file was deleted.

26 changes: 0 additions & 26 deletions source/reflect_load_metafunction_never.h

This file was deleted.

7 changes: 4 additions & 3 deletions source/to_cpp1.h
Original file line number Diff line number Diff line change
Expand Up @@ -6448,11 +6448,12 @@ class cppfront
{
auto identifier = print_to_string(*n.identifier);
printer.print_extra(
"\nextern \"C\" constexpr auto cpp2_metafunction_"
"\nextern \"C\" void cpp2_metafunction_"
+ identifier
+ " = &"
+ "(void* t) { "
+ identifier
+ ";"
+ "(*static_cast<cpp2::meta::type_declaration*>(t));"
+ " }"
);
}
}
Expand Down