Add CppInterOp API Dispatch mechanism #780
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #780 +/- ##
==========================================
+ Coverage 79.30% 79.32% +0.02%
==========================================
Files 9 11 +2
Lines 3933 3966 +33
==========================================
+ Hits 3119 3146 +27
- Misses 814 820 +6
🚀 New features to boost your workflow:
|
| TYPED_TEST(CppInterOpTest, FunctionReflectionTestGetClassMethods) { | ||
| // Reusable empty template args vector. In the dispatch mode, passing an empty initializer list {} | ||
| // does not work since the compiler cannot deduce the type for a function pointer | ||
| std::vector<Cpp::TemplateArgInfo> empty_templ_args = {}; |
There was a problem hiding this comment.
warning: variable 'empty_templ_args' can be made static or moved into an anonymous namespace to enforce internal linkage [misc-use-internal-linkage]
| std::vector<Cpp::TemplateArgInfo> empty_templ_args = {}; | |
| static std::vector<Cpp::TemplateArgInfo> empty_templ_args = {}; |
| std::vector<Cpp::TemplateArgInfo> args1 = {C.IntTy.getAsOpaquePtr()}; | ||
| std::vector<Cpp::TemplateArgInfo> args2 = { | ||
| Cpp::GetVariableType(Cpp::GetNamed("a"))}; | ||
| Cpp::GetVariableType(Cpp::GetNamed("a", 0))}; |
There was a problem hiding this comment.
warning: use nullptr [modernize-use-nullptr]
| Cpp::GetVariableType(Cpp::GetNamed("a", 0))}; | |
| Cpp::GetVariableType(Cpp::GetNamed("a", nullptr))}; |
| std::vector<Cpp::TemplateArgInfo> args4 = { | ||
| Cpp::GetVariableType(Cpp::GetNamed("a")), | ||
| Cpp::GetVariableType(Cpp::GetNamed("a"))}; | ||
| Cpp::GetVariableType(Cpp::GetNamed("a", 0)), |
There was a problem hiding this comment.
warning: use nullptr [modernize-use-nullptr]
| Cpp::GetVariableType(Cpp::GetNamed("a", 0)), | |
| Cpp::GetVariableType(Cpp::GetNamed("a", nullptr)), |
| Cpp::GetVariableType(Cpp::GetNamed("a")), | ||
| Cpp::GetVariableType(Cpp::GetNamed("a"))}; | ||
| Cpp::GetVariableType(Cpp::GetNamed("a", 0)), | ||
| Cpp::GetVariableType(Cpp::GetNamed("a", 0))}; |
There was a problem hiding this comment.
warning: use nullptr [modernize-use-nullptr]
| Cpp::GetVariableType(Cpp::GetNamed("a", 0))}; | |
| Cpp::GetVariableType(Cpp::GetNamed("a", nullptr))}; |
| std::vector<Cpp::TemplateArgInfo> args1 = { | ||
| Cpp::GetVariableType(Cpp::GetNamed("a")), | ||
| Cpp::GetVariableType(Cpp::GetNamed("a"))}; | ||
| Cpp::GetVariableType(Cpp::GetNamed("a", 0)), |
There was a problem hiding this comment.
warning: use nullptr [modernize-use-nullptr]
| Cpp::GetVariableType(Cpp::GetNamed("a", 0)), | |
| Cpp::GetVariableType(Cpp::GetNamed("a", nullptr)), |
lib/CppInterOp/Dispatch.cpp
Outdated
|
|
||
| CppFnPtrTy CppGetProcAddress(const char* funcName) { | ||
| auto it = DispatchMap.find(funcName); | ||
| if (it == DispatchMap.end()) |
There was a problem hiding this comment.
If this code is reachable we should provide some diagnostic message and a test.
unittests/CppInterOp/CUDATest.cpp
Outdated
|
|
||
| Cpp::CreateInterpreter({}, {"--cuda"}); | ||
| bool success = !Cpp::Declare("#include <cuda.h>"); | ||
| bool success = !Cpp::Declare("#include <cuda.h>", false); |
There was a problem hiding this comment.
Spell out the default argument names in /**/
b6db417 to
7fa58c8
Compare
| auto S = clang_getDefaultConstructor(make_scope(Decls[0], I)); | ||
| void* object_c = nullptr; | ||
| clang_invoke(S, &object_c, nullptr, 0, nullptr); | ||
| clang_invoke(S, &object_c, nullptr, 0, 0); |
There was a problem hiding this comment.
warning: multilevel pointer conversion from 'void **' to 'void *', please use explicit cast [bugprone-multi-level-implicit-pointer-conversion]
clang_invoke(S, &object_c, nullptr, 0, 0);
^| auto S = clang_getDefaultConstructor(make_scope(Decls[0], I)); | ||
| void* object_c = nullptr; | ||
| clang_invoke(S, &object_c, nullptr, 0, nullptr); | ||
| clang_invoke(S, &object_c, nullptr, 0, 0); |
There was a problem hiding this comment.
warning: use nullptr [modernize-use-nullptr]
| clang_invoke(S, &object_c, nullptr, 0, 0); | |
| clang_invoke(S, &object_c, nullptr, 0, nullptr); |
| EXPECT_TRUE(FCI1.getKind() == Cpp::JitCall::kGenericCall); | ||
| Cpp::JitCall FCI2 = | ||
| Cpp::MakeFunctionCallable(Cpp::GetNamed("f2")); | ||
| Cpp::MakeFunctionCallable(Cpp::GetNamed("f2", 0)); |
There was a problem hiding this comment.
warning: use nullptr [modernize-use-nullptr]
| Cpp::MakeFunctionCallable(Cpp::GetNamed("f2", 0)); | |
| Cpp::MakeFunctionCallable(Cpp::GetNamed("f2", nullptr)); |
| EXPECT_TRUE(FCI2.getKind() == Cpp::JitCall::kGenericCall); | ||
| Cpp::JitCall FCI3 = | ||
| Cpp::MakeFunctionCallable(Cpp::GetNamed("f3", Cpp::GetNamed("NS"))); | ||
| Cpp::MakeFunctionCallable(Cpp::GetNamed("f3", Cpp::GetNamed("NS", 0))); |
There was a problem hiding this comment.
warning: use nullptr [modernize-use-nullptr]
| Cpp::MakeFunctionCallable(Cpp::GetNamed("f3", Cpp::GetNamed("NS", 0))); | |
| Cpp::MakeFunctionCallable(Cpp::GetNamed("f3", Cpp::GetNamed("NS", nullptr))); |
| EXPECT_TRUE(FCI3.getKind() == Cpp::JitCall::kGenericCall); | ||
| Cpp::JitCall FCI4 = | ||
| Cpp::MakeFunctionCallable(Cpp::GetNamed("f4", Cpp::GetNamed("NS"))); | ||
| Cpp::MakeFunctionCallable(Cpp::GetNamed("f4", Cpp::GetNamed("NS", 0))); |
There was a problem hiding this comment.
warning: use nullptr [modernize-use-nullptr]
| Cpp::MakeFunctionCallable(Cpp::GetNamed("f4", Cpp::GetNamed("NS", 0))); | |
| Cpp::MakeFunctionCallable(Cpp::GetNamed("f4", Cpp::GetNamed("NS", nullptr))); |
|
|
||
| Cpp::JitCall FCI5 = | ||
| Cpp::MakeFunctionCallable(Cpp::GetNamed("f5", Cpp::GetNamed("NS"))); | ||
| Cpp::MakeFunctionCallable(Cpp::GetNamed("f5", Cpp::GetNamed("NS", 0))); |
There was a problem hiding this comment.
warning: use nullptr [modernize-use-nullptr]
| Cpp::MakeFunctionCallable(Cpp::GetNamed("f5", Cpp::GetNamed("NS", 0))); | |
| Cpp::MakeFunctionCallable(Cpp::GetNamed("f5", Cpp::GetNamed("NS", nullptr))); |
| )"); | ||
|
|
||
| clang::NamedDecl *ClassC = (clang::NamedDecl*)Cpp::GetNamed("C"); | ||
| clang::NamedDecl *ClassC = (clang::NamedDecl*)Cpp::GetNamed("C", 0); |
There was a problem hiding this comment.
warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]
clang::NamedDecl *ClassC = (clang::NamedDecl*)Cpp::GetNamed("C", 0);
^| )"); | ||
|
|
||
| clang::NamedDecl *ClassC = (clang::NamedDecl*)Cpp::GetNamed("C"); | ||
| clang::NamedDecl *ClassC = (clang::NamedDecl*)Cpp::GetNamed("C", 0); |
There was a problem hiding this comment.
warning: no header providing "clang::NamedDecl" is directly included [misc-include-cleaner]
clang::NamedDecl *ClassC = (clang::NamedDecl*)Cpp::GetNamed("C", 0);
^| )"); | ||
|
|
||
| clang::NamedDecl *ClassC = (clang::NamedDecl*)Cpp::GetNamed("C"); | ||
| clang::NamedDecl *ClassC = (clang::NamedDecl*)Cpp::GetNamed("C", 0); |
There was a problem hiding this comment.
warning: use nullptr [modernize-use-nullptr]
| clang::NamedDecl *ClassC = (clang::NamedDecl*)Cpp::GetNamed("C", 0); | |
| clang::NamedDecl *ClassC = (clang::NamedDecl*)Cpp::GetNamed("C", nullptr); |
| )"); | ||
|
|
||
| Cpp::TCppScope_t set_5 = Cpp::GetNamed("set_5"); | ||
| Cpp::TCppScope_t set_5 = Cpp::GetNamed("set_5", 0); |
There was a problem hiding this comment.
warning: use nullptr [modernize-use-nullptr]
| Cpp::TCppScope_t set_5 = Cpp::GetNamed("set_5", 0); | |
| Cpp::TCppScope_t set_5 = Cpp::GetNamed("set_5", nullptr); |
1584a54 to
161da95
Compare
|
|
||
| Cpp::TCppScope_t TypedefToPrivateClass = | ||
| Cpp::GetNamed("TypedefToPrivateClass"); | ||
| Cpp::GetNamed("TypedefToPrivateClass", 0); |
There was a problem hiding this comment.
warning: use nullptr [modernize-use-nullptr]
| Cpp::GetNamed("TypedefToPrivateClass", 0); | |
| Cpp::GetNamed("TypedefToPrivateClass", nullptr); |
| }; | ||
| )"); | ||
| Cpp::TCppScope_t TOperator = Cpp::GetNamed("TOperator"); | ||
| Cpp::TCppScope_t TOperator = Cpp::GetNamed("TOperator", 0); |
There was a problem hiding this comment.
warning: use nullptr [modernize-use-nullptr]
| Cpp::TCppScope_t TOperator = Cpp::GetNamed("TOperator", 0); | |
| Cpp::TCppScope_t TOperator = Cpp::GetNamed("TOperator", nullptr); |
|
|
||
| Cpp::TCppType_t K1 = Cpp::GetTypeFromScope(Cpp::GetNamed("K1")); | ||
| Cpp::TCppType_t K2 = Cpp::GetTypeFromScope(Cpp::GetNamed("K2")); | ||
| Cpp::TCppType_t K1 = Cpp::GetTypeFromScope(Cpp::GetNamed("K1", 0)); |
There was a problem hiding this comment.
warning: use nullptr [modernize-use-nullptr]
| Cpp::TCppType_t K1 = Cpp::GetTypeFromScope(Cpp::GetNamed("K1", 0)); | |
| Cpp::TCppType_t K1 = Cpp::GetTypeFromScope(Cpp::GetNamed("K1", nullptr)); |
| Cpp::TCppType_t K1 = Cpp::GetTypeFromScope(Cpp::GetNamed("K1")); | ||
| Cpp::TCppType_t K2 = Cpp::GetTypeFromScope(Cpp::GetNamed("K2")); | ||
| Cpp::TCppType_t K1 = Cpp::GetTypeFromScope(Cpp::GetNamed("K1", 0)); | ||
| Cpp::TCppType_t K2 = Cpp::GetTypeFromScope(Cpp::GetNamed("K2", 0)); |
There was a problem hiding this comment.
warning: use nullptr [modernize-use-nullptr]
| Cpp::TCppType_t K2 = Cpp::GetTypeFromScope(Cpp::GetNamed("K2", 0)); | |
| Cpp::TCppType_t K2 = Cpp::GetTypeFromScope(Cpp::GetNamed("K2", nullptr)); |
| operators.clear(); | ||
| Cpp::GetOperator(Cpp::GetScope("N2", Cpp::GetScope("N1")), Cpp::OP_Plus, | ||
| operators); | ||
| Cpp::GetOperator(Cpp::GetScope("N2", Cpp::GetScope("N1", 0)), Cpp::Operator::OP_Plus, |
There was a problem hiding this comment.
warning: use nullptr [modernize-use-nullptr]
| Cpp::GetOperator(Cpp::GetScope("N2", Cpp::GetScope("N1", 0)), Cpp::Operator::OP_Plus, | |
| Cpp::GetOperator(Cpp::GetScope("N2", Cpp::GetScope("N1", nullptr)), Cpp::Operator::OP_Plus, |
|
|
||
| std::vector<Cpp::TCppFunction_t> unresolved_candidate_methods; | ||
| Cpp::GetClassTemplatedMethods("get", Cpp::GetScope("my_std"), | ||
| Cpp::GetClassTemplatedMethods("get", Cpp::GetScope("my_std", 0), |
There was a problem hiding this comment.
warning: use nullptr [modernize-use-nullptr]
| Cpp::GetClassTemplatedMethods("get", Cpp::GetScope("my_std", 0), | |
| Cpp::GetClassTemplatedMethods("get", Cpp::GetScope("my_std", nullptr), |
| Cpp::GetClassTemplatedMethods("get", Cpp::GetScope("my_std", 0), | ||
| unresolved_candidate_methods); | ||
| Cpp::TCppType_t p = Cpp::GetTypeFromScope(Cpp::GetNamed("p")); | ||
| Cpp::TCppType_t p = Cpp::GetTypeFromScope(Cpp::GetNamed("p", 0)); |
There was a problem hiding this comment.
warning: use nullptr [modernize-use-nullptr]
| Cpp::TCppType_t p = Cpp::GetTypeFromScope(Cpp::GetNamed("p", 0)); | |
| Cpp::TCppType_t p = Cpp::GetTypeFromScope(Cpp::GetNamed("p", nullptr)); |
| unresolved_candidate_methods, {}, | ||
| {Cpp::GetVariableType(Cpp::GetNamed("tuple_one")), | ||
| Cpp::GetVariableType(Cpp::GetNamed("tuple_two"))}); | ||
| {Cpp::GetVariableType(Cpp::GetNamed("tuple_one", 0)), |
There was a problem hiding this comment.
warning: use nullptr [modernize-use-nullptr]
| {Cpp::GetVariableType(Cpp::GetNamed("tuple_one", 0)), | |
| {Cpp::GetVariableType(Cpp::GetNamed("tuple_one", nullptr)), |
| {Cpp::GetVariableType(Cpp::GetNamed("tuple_one")), | ||
| Cpp::GetVariableType(Cpp::GetNamed("tuple_two"))}); | ||
| {Cpp::GetVariableType(Cpp::GetNamed("tuple_one", 0)), | ||
| Cpp::GetVariableType(Cpp::GetNamed("tuple_two", 0))}); |
There was a problem hiding this comment.
warning: use nullptr [modernize-use-nullptr]
| Cpp::GetVariableType(Cpp::GetNamed("tuple_two", 0))}); | |
| Cpp::GetVariableType(Cpp::GetNamed("tuple_two", nullptr))}); |
|
|
||
| Cpp::TCppScope_t bar = | ||
| Cpp::GetNamed("bar", Cpp::GetScope("EnumFunctionSameName")); | ||
| Cpp::GetNamed("bar", Cpp::GetScope("EnumFunctionSameName", 0)); |
There was a problem hiding this comment.
warning: use nullptr [modernize-use-nullptr]
| Cpp::GetNamed("bar", Cpp::GetScope("EnumFunctionSameName", 0)); | |
| Cpp::GetNamed("bar", Cpp::GetScope("EnumFunctionSameName", nullptr)); |
161da95 to
b131bff
Compare
671e59b to
faea19b
Compare
include/CppInterOp/Dispatch.h
Outdated
|
|
||
| // Sanity check to verify that critical (and consequently all) functions are loaded | ||
| if (!GetInterpreter || !CreateInterpreter) { | ||
| std::cerr << "[CppInterOp] Failed to load critical functions\n"; |
There was a problem hiding this comment.
| std::cerr << "[CppInterOp] Failed to load critical functions\n"; | |
| std::cerr << "[CppInterOp Dispatch] Failed to load critical functions\n"; |
|
|
||
| Interp->declare(code); | ||
| Cpp::TCppScope_t ns_N1 = Cpp::GetNamed("N1"); | ||
| Cpp::TCppScope_t ns_N1 = Cpp::GetNamed("N1", 0); |
There was a problem hiding this comment.
| Cpp::TCppScope_t ns_N1 = Cpp::GetNamed("N1", 0); | |
| Cpp::TCppScope_t ns_N1 = Cpp::GetNamed("N1", DFLT_0); |
| EXPECT_EQ(get_base_class_name(Decls[10], 0), "<unnamed>"); | ||
|
|
||
| auto *VD = Cpp::GetNamed("var"); | ||
| auto *VD = Cpp::GetNamed("var", 0); |
There was a problem hiding this comment.
| auto *VD = Cpp::GetNamed("var", 0); | |
| auto *VD = Cpp::GetNamed("var", DFLT_0); |
| EXPECT_EQ(Cpp::GetCompleteName(TC1_A_Decl), "TC1<A>"); | ||
|
|
||
| auto* VD1 = Cpp::GetNamed("var1"); | ||
| auto* VD1 = Cpp::GetNamed("var1", 0); |
There was a problem hiding this comment.
| auto* VD1 = Cpp::GetNamed("var1", 0); | |
| auto* VD1 = Cpp::GetNamed("var1", DFLT_0); |
| std::vector<Cpp::TemplateArgInfo> args1 = {C.IntTy.getAsOpaquePtr()}; | ||
| auto Instance1 = Cpp::InstantiateTemplate(Decls[0], args1.data(), | ||
| /*type_size*/ args1.size()); | ||
| /*type_size*/ args1.size(), false); |
There was a problem hiding this comment.
| /*type_size*/ args1.size(), false); | |
| /*type_size*/ args1.size() DFLT_FALSE); |
| std::vector<Cpp::TemplateArgInfo> args1 = {C.IntTy.getAsOpaquePtr()}; | ||
| auto Instance1 = Cpp::InstantiateTemplate(Decls[0], args1.data(), | ||
| /*type_size*/ args1.size()); | ||
| /*type_size*/ args1.size(), false); |
There was a problem hiding this comment.
| /*type_size*/ args1.size(), false); | |
| /*type_size*/ args1.size() DFLT_FALSE); |
|
|
||
| auto Instance2 = Cpp::InstantiateTemplate(Decls[1], nullptr, | ||
| /*type_size*/ 0); | ||
| /*type_size*/ 0, false); |
There was a problem hiding this comment.
| /*type_size*/ 0, false); | |
| /*type_size*/ 0 DFLT_FALSE); |
| std::vector<Cpp::TemplateArgInfo> args3 = {C.IntTy.getAsOpaquePtr()}; | ||
| auto Instance3 = Cpp::InstantiateTemplate(Decls[2], args3.data(), | ||
| /*type_size*/ args3.size()); | ||
| /*type_size*/ args3.size(), false); |
There was a problem hiding this comment.
| /*type_size*/ args3.size(), false); | |
| /*type_size*/ args3.size() DFLT_FALSE); |
| auto *v1 = Cpp::GetNamed("v1", 0); | ||
| auto *v2 = Cpp::GetNamed("v2", 0); | ||
| auto *v3 = Cpp::GetNamed("v3", 0); |
There was a problem hiding this comment.
| auto *v1 = Cpp::GetNamed("v1", 0); | |
| auto *v2 = Cpp::GetNamed("v2", 0); | |
| auto *v3 = Cpp::GetNamed("v3", 0); | |
| auto *v1 = Cpp::GetNamed("v1", DFLT_0); | |
| auto *v2 = Cpp::GetNamed("v2", DFLT_0); | |
| auto *v3 = Cpp::GetNamed("v3", DFLT_0); |
f1a7de9 to
c223566
Compare
| )"); | ||
|
|
||
| clang::NamedDecl *ClassC = (clang::NamedDecl*)Cpp::GetNamed("C"); | ||
| clang::NamedDecl* ClassC = (clang::NamedDecl*)Cpp::GetNamed("C" DFLT_NULLPTR); |
There was a problem hiding this comment.
warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]
clang::NamedDecl* ClassC = (clang::NamedDecl*)Cpp::GetNamed("C" DFLT_NULLPTR);
^| )"); | ||
|
|
||
| clang::NamedDecl *ClassC = (clang::NamedDecl*)Cpp::GetNamed("C"); | ||
| clang::NamedDecl* ClassC = (clang::NamedDecl*)Cpp::GetNamed("C" DFLT_NULLPTR); |
There was a problem hiding this comment.
warning: no header providing "clang::NamedDecl" is directly included [misc-include-cleaner]
clang::NamedDecl* ClassC = (clang::NamedDecl*)Cpp::GetNamed("C" DFLT_NULLPTR);
^|
|
||
| std::string mangled_add_int; | ||
| std::string mangled_add_double; | ||
| compat::maybeMangleDeclName(Add_int, mangled_add_int); |
There was a problem hiding this comment.
warning: no header providing "compat::maybeMangleDeclName" is directly included [misc-include-cleaner]
unittests/CppInterOp/DispatchTest.cpp:6:
- #include "gtest/gtest.h"
+ #include "/github/workspace/lib/CppInterOp/Compatibility.h"
+ #include "gtest/gtest.h"a72727d to
c0d72f7
Compare
|
|
||
| std::string mangled_add_int; | ||
| std::string mangled_add_double; | ||
| compat::maybeMangleDeclName(Add_int, mangled_add_int); |
There was a problem hiding this comment.
warning: no header providing "compat::maybeMangleDeclName" is directly included [misc-include-cleaner]
unittests/CppInterOp/DispatchTest.cpp:7:
- #include "gtest/gtest.h"
+ #include "/github/workspace/lib/CppInterOp/Compatibility.h"
+ #include "gtest/gtest.h"| DispatchInitializer& operator=(DispatchInitializer&&) noexcept = default; | ||
| }; | ||
| // FIXME: Make this threadsafe by moving it as a function static. | ||
| DispatchInitializer g_dispatch_init; |
There was a problem hiding this comment.
warning: variable 'g_dispatch_init' is non-const and globally accessible, consider making it const [cppcoreguidelines-avoid-non-const-global-variables]
DispatchInitializer g_dispatch_init;
^Defines the mechanism which enables dispatching of the CppInterOp API
without linking, preventing any LLVM or Clang symbols from being leaked
into the client application. This is achieved using a symbol-address table
and an address lookup through a C symbol allowing clients to dlopen
CppInterOp with RTLD_LOCAL, and automatically assign the API during runtime.
This alternate approach is particularly useful in scenarios where CppInterOp is loaded dynamically alongside other tools/libraries/packages that also
rely on LLVM. With cppyy, importing tools like `numba` or `pygame` that come bundled with a statically linked copy of LLVM,
leads to symbol interposition and crashes. The dispatch mechanism solves this by solely relying on a C interface, which returns a pointer to the address of a requested function, which can be cast to the appropriate API type and
invoked as needed. An example can be found in `unittests/CppInterOp/DispatchTest.cpp`. For a user, this system is completely automated via the `Dispatch.h` header file, which maintains a symbol-address map for a fast look-up through a C symbol (`CppGetProcAddress`) which is fetched via `dlsym`. The provided macro system then handles all the declarations on the client end
with the inclusion of the header:
```cpp
```
At this point, the expansions already provide the same API surface as the standard CppInterOp library, except that the declarations require to be added to a translation unit for the client application.
This can be done by adding the following preprocessor directive in one of the source files:
```cpp
CPPINTEROP_API_TABLE
```
This creates the necessary function pointers in the `Cpp` namespace, which can then be used as normal CppInterOp API functions.
To load the API, invoke:
```cpp
Cpp::LoadDispatchAPI("path/to/libclangCppInterOp.so");
```
Now your application can use the CppInterOp API via the `Cpp::` namespace, with all functions being dispatched through the function pointers.
This is a one-to-one replacement for linking and using <CppInterOp/CppInterOp.h> directly, with a few drawbacks:
- This system currently does not support overloaded public API
- The function pointers are not initialized until `LoadDispatchAPI` is called, which means that any attempt to use the API before loading will result in a null pointer dereference.
- You lose the ability to assume default arguments in API calls, which must now be provided explicitly since we rely on function pointers.
9e1cb56 to
1e5775a
Compare
…te CppInterOpTestsDispatch The unittests now dynamically change behaviours from a standard library usage of CppInterOp to utilising the dispatch mechanism based on the the presence of the `ENABLE_DISPATCH_TESTS` flag
1e5775a to
dd612b1
Compare
(fresh PR on top of #730, see #730 (comment))
This PR defines the mechanism which enables dispatching CppInterOp's API without linking to it, preventing any LLVM or Clang symbols from being leaked into the client application.
This allows us to run cppyy without linking to CppInterOp motivated by the use case in ROOT. Can be used to deploy CppInterOp in an environment where dynamic linking is not favourable and the only option is dlopen'ing
libClangCppInterOp.sowithRTLD_LOCALTODO:
Failures in the CPyCppyy build step are expected since it redefines
TemplateArgInfoand expects the symbols to match the ones in cppyy-backend, which is no longer the case. Corresponding PR: Adapt Cpp::TemplateArgInfo to match cppyy-backend's CPyCppyy#148 and Migrate to CppInterOp Dispatch, no longer link/load shared lib in Python cppyy-backend#177 to be merged following this PRclang-format has to be run over all changes, will do that once the PR has been refactored into atomic commits (once approved and ready to be merged)
dev docs to be added explaining how a client would use this system