Skip to content

Conversation

@aaronj0
Copy link
Collaborator

@aaronj0 aaronj0 commented Oct 15, 2025

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.so with RTLD_LOCAL

To be rebased after the thread-safety PR is reverted

@aaronj0 aaronj0 marked this pull request as draft October 15, 2025 12:23
@codecov
Copy link

codecov bot commented Oct 15, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 79.91%. Comparing base (2ec0b9a) to head (460f493).

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #730      +/-   ##
==========================================
+ Coverage   79.83%   79.91%   +0.07%     
==========================================
  Files           9       10       +1     
  Lines        3963     3978      +15     
==========================================
+ Hits         3164     3179      +15     
  Misses        799      799              
Files with missing lines Coverage Δ
lib/CppInterOp/CppInterOpDispatch.cpp 100.00% <100.00%> (ø)
Files with missing lines Coverage Δ
lib/CppInterOp/CppInterOpDispatch.cpp 100.00% <100.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

clang-tidy made some suggestions

There were too many comments to post at once. Showing the first 10 out of 269. Check the log or trigger a new build to see more.

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

clang-tidy made some suggestions

There were too many comments to post at once. Showing the first 10 out of 259. Check the log or trigger a new build to see more.


#include <CppInterOp/CppInterOp.h>

using __CPP_FUNC = void (*)();
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: declaration uses identifier '__CPP_FUNC', which is a reserved identifier [bugprone-reserved-identifier]

Suggested change
using __CPP_FUNC = void (*)();
using CPP_FUNC = void (*)();

include/CppInterOp/CppInterOpDispatch.h:24:

-   __CPP_FUNC address;
+   CPP_FUNC address;


#include <unordered_map>

static const FunctionEntry api_function_table[] = {
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: do not declare C-style arrays, use std::array<> instead [cppcoreguidelines-avoid-c-arrays]

static const FunctionEntry api_function_table[] = {
             ^

#include <unordered_map>

static const FunctionEntry api_function_table[] = {
{"GetInterpreter", (__CPP_FUNC)Cpp::GetInterpreter},
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]

    {"GetInterpreter", (__CPP_FUNC)Cpp::GetInterpreter},
                       ^

#include <unordered_map>

static const FunctionEntry api_function_table[] = {
{"GetInterpreter", (__CPP_FUNC)Cpp::GetInterpreter},
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: no header providing "Cpp::GetInterpreter" is directly included [misc-include-cleaner]

lib/CppInterOp/CppInterOpDispatch.cpp:10:

- #include <CppInterOp/CppInterOpDispatch.h>
+ #include <CppInterOp/CppInterOp.h>
+ #include <CppInterOp/CppInterOpDispatch.h>


static const FunctionEntry api_function_table[] = {
{"GetInterpreter", (__CPP_FUNC)Cpp::GetInterpreter},
{"CreateInterpreter", (__CPP_FUNC)Cpp::CreateInterpreter},
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]

    {"CreateInterpreter", (__CPP_FUNC)Cpp::CreateInterpreter},
                          ^


static const FunctionEntry api_function_table[] = {
{"GetInterpreter", (__CPP_FUNC)Cpp::GetInterpreter},
{"CreateInterpreter", (__CPP_FUNC)Cpp::CreateInterpreter},
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: no header providing "Cpp::CreateInterpreter" is directly included [misc-include-cleaner]

    {"CreateInterpreter", (__CPP_FUNC)Cpp::CreateInterpreter},
                                           ^

static const FunctionEntry api_function_table[] = {
{"GetInterpreter", (__CPP_FUNC)Cpp::GetInterpreter},
{"CreateInterpreter", (__CPP_FUNC)Cpp::CreateInterpreter},
{"Process", (__CPP_FUNC)Cpp::Process},
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]

    {"Process", (__CPP_FUNC)Cpp::Process},
                ^

static const FunctionEntry api_function_table[] = {
{"GetInterpreter", (__CPP_FUNC)Cpp::GetInterpreter},
{"CreateInterpreter", (__CPP_FUNC)Cpp::CreateInterpreter},
{"Process", (__CPP_FUNC)Cpp::Process},
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: no header providing "Cpp::Process" is directly included [misc-include-cleaner]

    {"Process", (__CPP_FUNC)Cpp::Process},
                                 ^

{"GetInterpreter", (__CPP_FUNC)Cpp::GetInterpreter},
{"CreateInterpreter", (__CPP_FUNC)Cpp::CreateInterpreter},
{"Process", (__CPP_FUNC)Cpp::Process},
{"GetResourceDir", (__CPP_FUNC)Cpp::GetResourceDir},
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]

    {"GetResourceDir", (__CPP_FUNC)Cpp::GetResourceDir},
                       ^

{"GetInterpreter", (__CPP_FUNC)Cpp::GetInterpreter},
{"CreateInterpreter", (__CPP_FUNC)Cpp::CreateInterpreter},
{"Process", (__CPP_FUNC)Cpp::Process},
{"GetResourceDir", (__CPP_FUNC)Cpp::GetResourceDir},
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: no header providing "Cpp::GetResourceDir" is directly included [misc-include-cleaner]

    {"GetResourceDir", (__CPP_FUNC)Cpp::GetResourceDir},
                                        ^

else()
add_test(NAME cppinterop-${name} COMMAND ${name})
endif()
if(WIN32)
Copy link
Collaborator

Choose a reason for hiding this comment

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

You have have an entire commit for this format change to cmake, but I have no idea what it has to do with adding a CppInterOp API for a dispatch mechanism. Please revert this change and put it a separate PR if you think this change needs to be made

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

As this is a draft, I have included commits that will move into a seperate PR

"LLVM_BINARY_DIR=\"${LLVM_BINARY_DIR}\""
)
set_source_files_properties(DispatchAPITest.cpp PROPERTIES COMPILE_DEFINITIONS
"CPPINTEROP_LIB_DIR=\"${CMAKE_BINARY_DIR}/lib/libclangCppInterOp.so\""
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm assuming your going to make this test file inclusion dependent on whether CppInterOp was built as a shared or static library?

"LLVM_BINARY_DIR=\"${LLVM_BINARY_DIR}\""
)
set_source_files_properties(DispatchAPITest.cpp PROPERTIES COMPILE_DEFINITIONS
"CPPINTEROP_LIB_DIR=\"${CMAKE_BINARY_DIR}/lib/libclangCppInterOp.so\""
Copy link
Collaborator

Choose a reason for hiding this comment

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

The library will only have a .so extension on Linux and Emscripten. The extension will need to be ${CMAKE_SHARED_LIBRARY_SUFFIX}

// a consistent way. This is used as our dispatched API list, along with the
// name-address pair table
#define FOR_EACH_CPP_FUNCTION(DO) \
DO(CreateInterpreter) \
Copy link
Contributor

Choose a reason for hiding this comment

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

This can take a pair <CreateInterpreter, Type> and in this case you can write the using clauses automatically. We can also use clang-tablegen to generate these for every function in the namespace Cpp.

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

clang-tidy made some suggestions

There were too many comments to post at once. Showing the first 10 out of 249. Check the log or trigger a new build to see more.

{"CreateInterpreter", (__CPP_FUNC)Cpp::CreateInterpreter},
{"Process", (__CPP_FUNC)Cpp::Process},
{"GetResourceDir", (__CPP_FUNC)Cpp::GetResourceDir},
{"AddIncludePath", (__CPP_FUNC)Cpp::AddIncludePath},
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]

    {"AddIncludePath", (__CPP_FUNC)Cpp::AddIncludePath},
                       ^

{"CreateInterpreter", (__CPP_FUNC)Cpp::CreateInterpreter},
{"Process", (__CPP_FUNC)Cpp::Process},
{"GetResourceDir", (__CPP_FUNC)Cpp::GetResourceDir},
{"AddIncludePath", (__CPP_FUNC)Cpp::AddIncludePath},
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: no header providing "Cpp::AddIncludePath" is directly included [misc-include-cleaner]

    {"AddIncludePath", (__CPP_FUNC)Cpp::AddIncludePath},
                                        ^

{"Process", (__CPP_FUNC)Cpp::Process},
{"GetResourceDir", (__CPP_FUNC)Cpp::GetResourceDir},
{"AddIncludePath", (__CPP_FUNC)Cpp::AddIncludePath},
{"LoadLibrary", (__CPP_FUNC)Cpp::LoadLibrary},
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]

    {"LoadLibrary", (__CPP_FUNC)Cpp::LoadLibrary},
                    ^

{"Process", (__CPP_FUNC)Cpp::Process},
{"GetResourceDir", (__CPP_FUNC)Cpp::GetResourceDir},
{"AddIncludePath", (__CPP_FUNC)Cpp::AddIncludePath},
{"LoadLibrary", (__CPP_FUNC)Cpp::LoadLibrary},
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: no header providing "Cpp::LoadLibrary" is directly included [misc-include-cleaner]

    {"LoadLibrary", (__CPP_FUNC)Cpp::LoadLibrary},
                                     ^

{"GetResourceDir", (__CPP_FUNC)Cpp::GetResourceDir},
{"AddIncludePath", (__CPP_FUNC)Cpp::AddIncludePath},
{"LoadLibrary", (__CPP_FUNC)Cpp::LoadLibrary},
{"Declare", (__CPP_FUNC)Cpp::Declare},
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]

    {"Declare", (__CPP_FUNC)Cpp::Declare},
                ^

{"GetResourceDir", (__CPP_FUNC)Cpp::GetResourceDir},
{"AddIncludePath", (__CPP_FUNC)Cpp::AddIncludePath},
{"LoadLibrary", (__CPP_FUNC)Cpp::LoadLibrary},
{"Declare", (__CPP_FUNC)Cpp::Declare},
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: no header providing "Cpp::Declare" is directly included [misc-include-cleaner]

    {"Declare", (__CPP_FUNC)Cpp::Declare},
                                 ^

{"AddIncludePath", (__CPP_FUNC)Cpp::AddIncludePath},
{"LoadLibrary", (__CPP_FUNC)Cpp::LoadLibrary},
{"Declare", (__CPP_FUNC)Cpp::Declare},
{"DeleteInterpreter", (__CPP_FUNC)Cpp::DeleteInterpreter},
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]

    {"DeleteInterpreter", (__CPP_FUNC)Cpp::DeleteInterpreter},
                          ^

{"AddIncludePath", (__CPP_FUNC)Cpp::AddIncludePath},
{"LoadLibrary", (__CPP_FUNC)Cpp::LoadLibrary},
{"Declare", (__CPP_FUNC)Cpp::Declare},
{"DeleteInterpreter", (__CPP_FUNC)Cpp::DeleteInterpreter},
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: no header providing "Cpp::DeleteInterpreter" is directly included [misc-include-cleaner]

    {"DeleteInterpreter", (__CPP_FUNC)Cpp::DeleteInterpreter},
                                           ^

{"LoadLibrary", (__CPP_FUNC)Cpp::LoadLibrary},
{"Declare", (__CPP_FUNC)Cpp::Declare},
{"DeleteInterpreter", (__CPP_FUNC)Cpp::DeleteInterpreter},
{"IsNamespace", (__CPP_FUNC)Cpp::IsNamespace},
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]

    {"IsNamespace", (__CPP_FUNC)Cpp::IsNamespace},
                    ^

{"LoadLibrary", (__CPP_FUNC)Cpp::LoadLibrary},
{"Declare", (__CPP_FUNC)Cpp::Declare},
{"DeleteInterpreter", (__CPP_FUNC)Cpp::DeleteInterpreter},
{"IsNamespace", (__CPP_FUNC)Cpp::IsNamespace},
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: no header providing "Cpp::IsNamespace" is directly included [misc-include-cleaner]

    {"IsNamespace", (__CPP_FUNC)Cpp::IsNamespace},
                                     ^

This defines the mechanism which enables dispatching of the CppInterOp API without linking to it, preventing any LLVM or Clang symbols from being leaked into the client application. Can be used to deploy CppInterOp in an environment where dynamic linking is not favourable and the only option is dlopen'ing `libClangCppInterOp.so` with `RTLD_LOCAL`
to be followed up with a section in docs
Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

clang-tidy made some suggestions

There were too many comments to post at once. Showing the first 10 out of 126. Check the log or trigger a new build to see more.

{"Declare", (__CPP_FUNC)Cpp::Declare},
{"DeleteInterpreter", (__CPP_FUNC)Cpp::DeleteInterpreter},
{"IsNamespace", (__CPP_FUNC)Cpp::IsNamespace},
{"ObjToString", (__CPP_FUNC)Cpp::ObjToString},
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]

    {"ObjToString", (__CPP_FUNC)Cpp::ObjToString},
                    ^

{"DeleteInterpreter", (__CPP_FUNC)Cpp::DeleteInterpreter},
{"IsNamespace", (__CPP_FUNC)Cpp::IsNamespace},
{"ObjToString", (__CPP_FUNC)Cpp::ObjToString},
{"GetQualifiedCompleteName", (__CPP_FUNC)Cpp::GetQualifiedCompleteName},
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]

    {"GetQualifiedCompleteName", (__CPP_FUNC)Cpp::GetQualifiedCompleteName},
                                 ^

{"IsNamespace", (__CPP_FUNC)Cpp::IsNamespace},
{"ObjToString", (__CPP_FUNC)Cpp::ObjToString},
{"GetQualifiedCompleteName", (__CPP_FUNC)Cpp::GetQualifiedCompleteName},
{"IsLValueReferenceType", (__CPP_FUNC)Cpp::IsLValueReferenceType},
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]

    {"IsLValueReferenceType", (__CPP_FUNC)Cpp::IsLValueReferenceType},
                              ^

{"ObjToString", (__CPP_FUNC)Cpp::ObjToString},
{"GetQualifiedCompleteName", (__CPP_FUNC)Cpp::GetQualifiedCompleteName},
{"IsLValueReferenceType", (__CPP_FUNC)Cpp::IsLValueReferenceType},
{"GetNonReferenceType", (__CPP_FUNC)Cpp::GetNonReferenceType},
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]

    {"GetNonReferenceType", (__CPP_FUNC)Cpp::GetNonReferenceType},
                            ^

{"GetQualifiedCompleteName", (__CPP_FUNC)Cpp::GetQualifiedCompleteName},
{"IsLValueReferenceType", (__CPP_FUNC)Cpp::IsLValueReferenceType},
{"GetNonReferenceType", (__CPP_FUNC)Cpp::GetNonReferenceType},
{"IsEnumType", (__CPP_FUNC)Cpp::IsEnumType},
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]

    {"IsEnumType", (__CPP_FUNC)Cpp::IsEnumType},
                   ^

{"IsLValueReferenceType", (__CPP_FUNC)Cpp::IsLValueReferenceType},
{"GetNonReferenceType", (__CPP_FUNC)Cpp::GetNonReferenceType},
{"IsEnumType", (__CPP_FUNC)Cpp::IsEnumType},
{"GetIntegerTypeFromEnumType", (__CPP_FUNC)Cpp::GetIntegerTypeFromEnumType},
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]

    {"GetIntegerTypeFromEnumType", (__CPP_FUNC)Cpp::GetIntegerTypeFromEnumType},
                                   ^

{"GetNonReferenceType", (__CPP_FUNC)Cpp::GetNonReferenceType},
{"IsEnumType", (__CPP_FUNC)Cpp::IsEnumType},
{"GetIntegerTypeFromEnumType", (__CPP_FUNC)Cpp::GetIntegerTypeFromEnumType},
{"GetReferencedType", (__CPP_FUNC)Cpp::GetReferencedType},
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]

    {"GetReferencedType", (__CPP_FUNC)Cpp::GetReferencedType},
                          ^

{"IsEnumType", (__CPP_FUNC)Cpp::IsEnumType},
{"GetIntegerTypeFromEnumType", (__CPP_FUNC)Cpp::GetIntegerTypeFromEnumType},
{"GetReferencedType", (__CPP_FUNC)Cpp::GetReferencedType},
{"IsPointerType", (__CPP_FUNC)Cpp::IsPointerType},
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]

    {"IsPointerType", (__CPP_FUNC)Cpp::IsPointerType},
                      ^

{"GetIntegerTypeFromEnumType", (__CPP_FUNC)Cpp::GetIntegerTypeFromEnumType},
{"GetReferencedType", (__CPP_FUNC)Cpp::GetReferencedType},
{"IsPointerType", (__CPP_FUNC)Cpp::IsPointerType},
{"GetPointeeType", (__CPP_FUNC)Cpp::GetPointeeType},
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]

    {"GetPointeeType", (__CPP_FUNC)Cpp::GetPointeeType},
                       ^

{"GetReferencedType", (__CPP_FUNC)Cpp::GetReferencedType},
{"IsPointerType", (__CPP_FUNC)Cpp::IsPointerType},
{"GetPointeeType", (__CPP_FUNC)Cpp::GetPointeeType},
{"GetPointerType", (__CPP_FUNC)Cpp::GetPointerType},
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]

    {"GetPointerType", (__CPP_FUNC)Cpp::GetPointerType},
                       ^

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants