Skip to content

Add CppInterOp API dispatch mechanism#730

Closed
aaronj0 wants to merge 13 commits intocompiler-research:mainfrom
aaronj0:interop-dispatch
Closed

Add CppInterOp API dispatch mechanism#730
aaronj0 wants to merge 13 commits intocompiler-research:mainfrom
aaronj0:interop-dispatch

Conversation

@aaronj0
Copy link
Copy Markdown
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

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

codecov bot commented Oct 15, 2025

Codecov Report

❌ Patch coverage is 83.33333% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 79.10%. Comparing base (2272962) to head (d7862c9).

Files with missing lines Patch % Lines
include/CppInterOp/Dispatch.h 84.00% 4 Missing ⚠️
lib/CppInterOp/Dispatch.cpp 80.00% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #730      +/-   ##
==========================================
+ Coverage   79.07%   79.10%   +0.03%     
==========================================
  Files           9       11       +2     
  Lines        3899     3929      +30     
==========================================
+ Hits         3083     3108      +25     
- Misses        816      821       +5     
Files with missing lines Coverage Δ
include/CppInterOp/CppInterOp.h 95.12% <ø> (ø)
lib/CppInterOp/CXCppInterOp.cpp 48.09% <ø> (ø)
lib/CppInterOp/CppInterOp.cpp 87.62% <ø> (ø)
lib/CppInterOp/Dispatch.cpp 80.00% <80.00%> (ø)
include/CppInterOp/Dispatch.h 84.00% <84.00%> (ø)
Files with missing lines Coverage Δ
include/CppInterOp/CppInterOp.h 95.12% <ø> (ø)
lib/CppInterOp/CXCppInterOp.cpp 48.09% <ø> (ø)
lib/CppInterOp/CppInterOp.cpp 87.62% <ø> (ø)
lib/CppInterOp/Dispatch.cpp 80.00% <80.00%> (ø)
include/CppInterOp/Dispatch.h 84.00% <84.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown
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.

github-actions[bot]

This comment was marked as outdated.

github-actions[bot]

This comment was marked as outdated.

github-actions[bot]

This comment was marked as outdated.

@aaronj0 aaronj0 force-pushed the interop-dispatch branch 2 times, most recently from 3b9e2b4 to 795db00 Compare December 15, 2025 16:12
github-actions[bot]

This comment was marked as outdated.

github-actions[bot]

This comment was marked as outdated.

github-actions[bot]

This comment was marked as outdated.

#include <vector>

#include <cstdlib>
#include <dlfcn.h>
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

needs something like:

#ifdef _WIN32
#include <io.h>
#include <Psapi.h>
#define RTLD_DEFAULT ((void *)::GetModuleHandle(NULL))
//#define dlsym(library, function_name) ::GetProcAddress((HMODULE)library, function_name)
#define dlopen(library_name, flags) ::LoadLibrary(library_name)
#define dlclose(library) ::FreeLibrary((HMODULE)library)
#endif

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The windows specific code has been added and compiled but is untested due to the absence of a shared lib build on the CI (or so it seems) The CppInterOpDispatch test executable is not built.

github-actions[bot]

This comment was marked as outdated.

@mcbarton mcbarton dismissed their stale review December 15, 2025 20:16

My requested changes have been dealt with now.

Copy link
Copy Markdown
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 150. Check the log or trigger a new build to see more.

Copy link
Copy Markdown
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 144. Check the log or trigger a new build to see more.

@aaronj0 aaronj0 marked this pull request as ready for review January 9, 2026 17:02
@aaronj0
Copy link
Copy Markdown
Collaborator Author

aaronj0 commented Jan 9, 2026

TODO:

  • Failures in the CPyCppyy build step are expected since it redefines TemplateArgInfo and 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 to be merged following this PR

  • clang-format has to be run, will do that when refactoring the PR into atomic commits (once it is ready to be merged)

  • dev docs to be added

Copy link
Copy Markdown
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 135. Check the log or trigger a new build to see more.

static const std::unordered_map<std::string_view, CppFnPtrTy>
DispatchMap = {
#define DISPATCH_API(name, type) {#name, (CppFnPtrTy) static_cast<type>(&CppImpl::name)},
CPPINTEROP_API_TABLE
Copy link
Copy Markdown
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]

        CPPINTEROP_API_TABLE
        ^
Additional context

include/CppInterOp/Dispatch.h:44: expanded from macro 'CPPINTEROP_API_TABLE'

  DISPATCH_API(CreateInterpreter, decltype(&CppImpl::CreateInterpreter))                  \
  ^

lib/CppInterOp/Dispatch.cpp:7: expanded from macro 'DISPATCH_API'

#define DISPATCH_API(name, type) {#name, (CppFnPtrTy) static_cast<type>(&CppImpl::name)},
                                         ^

#undef DISPATCH_API
};

static inline CppFnPtrTy _cppinterop_get_proc_address(const char* funcName) {
Copy link
Copy Markdown
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 '_cppinterop_get_proc_address', which is reserved in the global namespace [bugprone-reserved-identifier]

static inline CppFnPtrTy _cppinterop_get_proc_address(const char* funcName) {
                         ^

this fix will not be applied because it overlaps with another fix

#undef DISPATCH_API
};

static inline CppFnPtrTy _cppinterop_get_proc_address(const char* funcName) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: invalid case style for function '_cppinterop_get_proc_address' [readability-identifier-naming]

static inline CppFnPtrTy _cppinterop_get_proc_address(const char* funcName) {
                         ^

this fix will not be applied because it overlaps with another fix

Copy link
Copy Markdown
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 125. Check the log or trigger a new build to see more.

"test_func<<<1,1>>>();", false))
return false;
intptr_t result = Cpp::Evaluate("(bool)cudaGetLastError()");
intptr_t result = Cpp::Evaluate("(bool)cudaGetLastError()", nullptr);
Copy link
Copy Markdown
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 "intptr_t" is directly included [misc-include-cleaner]

unittests/CppInterOp/CUDATest.cpp:5:

+ #include <cstdint>

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 = {};
Copy link
Copy Markdown
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 "std::vector" is directly included [misc-include-cleaner]

unittests/CppInterOp/FunctionReflectionTest.cpp:16:

+ #include <vector>

std::vector<Cpp::TemplateArgInfo> args1 = {C.IntTy.getAsOpaquePtr()};
std::vector<Cpp::TemplateArgInfo> args2 = {
Cpp::GetVariableType(Cpp::GetNamed("a"))};
Cpp::GetVariableType(Cpp::GetNamed("a", 0))};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: use nullptr [modernize-use-nullptr]

Suggested change
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)),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: use nullptr [modernize-use-nullptr]

Suggested change
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))};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: use nullptr [modernize-use-nullptr]

Suggested change
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)),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: use nullptr [modernize-use-nullptr]

Suggested change
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))};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: use nullptr [modernize-use-nullptr]

Suggested change
Cpp::GetVariableType(Cpp::GetNamed("a", 0))};
Cpp::GetVariableType(Cpp::GetNamed("a", nullptr))};

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`
Rename CppInterOpDispatch -> CppDispatch, Address more review comments and drop `DECLARE_CPP` style macros
…atch.h

With the introduction of the CppStatic namespace we conditionally alias `Cpp` to the implementation provided by CppInterOp.h (link to clangCppInterOp.so) or CppDispatch (dlopen the dylib with RTLD_LOCAL)
This is an intentional ODR violation but remains consistent with our API model.
Gives the mechanism complete coverage. Now runs CppInterOpTests and CppInterOpDispatchTests
This patch also improves the readability of the test run log:

```
2: [ RUN      ] CppInterOpDispatchTest/InProcessJIT.Interpreter_IncludePaths
2: [       OK ] CppInterOpDispatchTest/InProcessJIT.Interpreter_IncludePaths (0 ms)
2: [ RUN      ] CppInterOpDispatchTest/InProcessJIT.Interpreter_CodeCompletion
2: [       OK ] CppInterOpDispatchTest/InProcessJIT.Interpreter_CodeCompletion (86 ms)
2: [ RUN      ] CppInterOpDispatchTest/InProcessJIT.Interpreter_ExternalInterpreter
2: [       OK ] CppInterOpDispatchTest/InProcessJIT.Interpreter_ExternalInterpreter (1123 ms)
2: [ RUN      ] CppInterOpDispatchTest/InProcessJIT.Jit_InsertOrReplaceJitSymbol
2: [       OK ] CppInterOpDispatchTest/InProcessJIT.Jit_InsertOrReplaceJitSymbol (56 ms)
2: [ RUN      ] CppInterOpDispatchTest/InProcessJIT.Jit_StreamRedirect
2: [       OK ] CppInterOpDispatchTest/InProcessJIT.Jit_StreamRedirect (0 ms)
2: [ RUN      ] CppInterOpDispatchTest/InProcessJIT.Jit_StreamRedirectJIT
2: [       OK ] CppInterOpDispatchTest/InProcessJIT.Jit_StreamRedirectJIT (154 ms)
2: [ RUN      ] CppInterOpDispatchTest/InProcessJIT.ScopeReflection_IsEnumScope
2: [       OK ] CppInterOpDispatchTest/InProcessJIT.ScopeReflection_IsEnumScope (21 ms)
2: [ RUN      ] CppInterOpDispatchTest/InProcessJIT.ScopeReflection_IsEnumConstant
```

instead of:

```
2: [ RUN      ] CppInterOpDispatchTest/InProcessJIT.InterpreterTestIncludePaths
2: [       OK ] CppInterOpDispatchTest/InProcessJIT.InterpreterTestIncludePaths (0 ms)
2: [ RUN      ] CppInterOpDispatchTest/InProcessJIT.InterpreterTestCodeCompletion
2: [       OK ] CppInterOpDispatchTest/InProcessJIT.InterpreterTestCodeCompletion (86 ms)
2: [ RUN      ] CppInterOpDispatchTest/InProcessJIT.InterpreterTestExternalInterpreter
2: [       OK ] CppInterOpDispatchTest/InProcessJIT.InterpreterTestExternalInterpreter (1123 ms)
2: [ RUN      ] CppInterOpDispatchTest/InProcessJIT.JitTestInsertOrReplaceJitSymbol
2: [       OK ] CppInterOpDispatchTest/InProcessJIT.JitTestInsertOrReplaceJitSymbol (56 ms)
2: [ RUN      ] CppInterOpDispatchTest/InProcessJIT.JitTestStreamRedirect
2: [       OK ] CppInterOpDispatchTest/InProcessJIT.JitTestStreamRedirect (0 ms)
2: [ RUN      ] CppInterOpDispatchTest/InProcessJIT.JitTestStreamRedirectJIT
2: [       OK ] CppInterOpDispatchTest/InProcessJIT.JitTestStreamRedirectJIT (154 ms)
2: [ RUN      ] CppInterOpDispatchTest/InProcessJIT.ScopeReflectionTestIsEnumScope
2: [       OK ] CppInterOpDispatchTest/InProcessJIT.ScopeReflectionTestIsEnumScope (21 ms)
2: [ RUN      ] CppInterOpDispatchTest/InProcessJIT.ScopeReflectionTestIsEnumConstant
```

We repeated the word "Test" twice and the lack of a spacer made it hard to read. Since this patch changes the TYPED_TEST line to use `CPPINTEROP_TEST_MODE` instead of `CppInterOpTest` this is a good opportunity to improve this without bloating the history
Simplify the unittest cmake logic on top of compiler-research#770
clang-format, clang-tidy suggestions
Copy link
Copy Markdown
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 117. Check the log or trigger a new build to see more.

} // end namespace CppAPIType

namespace CppInternal {
namespace Dispatch {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: nested namespaces can be concatenated [modernize-concat-nested-namespaces]

Suggested change
namespace Dispatch {
namespace CppInternal::Dispatch {

include/CppInterOp/Dispatch.h:264:

- } // namespace Dispatch
- } // namespace CppInternal
+ } // namespace CppInternal::Dispatch

static const std::unordered_map<std::string_view, CppFnPtrTy>
DispatchMap = {
#define DISPATCH_API(name, type) {#name, (CppFnPtrTy) static_cast<type>(&CppImpl::name)},
CPPINTEROP_API_TABLE
Copy link
Copy Markdown
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]

        CPPINTEROP_API_TABLE
        ^
Additional context

include/CppInterOp/Dispatch.h:48: expanded from macro 'CPPINTEROP_API_TABLE'

  DISPATCH_API(CreateInterpreter, decltype(&CppImpl::CreateInterpreter))                  \
  ^

lib/CppInterOp/Dispatch.cpp:7: expanded from macro 'DISPATCH_API'

#define DISPATCH_API(name, type) {#name, (CppFnPtrTy) static_cast<type>(&CppImpl::name)},
                                         ^

Cpp::GetVariableType(Cpp::GetNamed("a", 0))};
std::vector<Cpp::TemplateArgInfo> args2 = {
Cpp::GetVariableType(Cpp::GetNamed("a")), C.IntTy.getAsOpaquePtr()};
Cpp::GetVariableType(Cpp::GetNamed("a", 0)), C.IntTy.getAsOpaquePtr()};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: use nullptr [modernize-use-nullptr]

Suggested change
Cpp::GetVariableType(Cpp::GetNamed("a", 0)), C.IntTy.getAsOpaquePtr()};
Cpp::GetVariableType(Cpp::GetNamed("a", nullptr)), C.IntTy.getAsOpaquePtr()};

Cpp::GetVariableType(Cpp::GetNamed("a", 0)), C.IntTy.getAsOpaquePtr()};
std::vector<Cpp::TemplateArgInfo> args3 = {
Cpp::GetVariableType(Cpp::GetNamed("a")), C.DoubleTy.getAsOpaquePtr()};
Cpp::GetVariableType(Cpp::GetNamed("a", 0)), C.DoubleTy.getAsOpaquePtr()};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: use nullptr [modernize-use-nullptr]

Suggested change
Cpp::GetVariableType(Cpp::GetNamed("a", 0)), C.DoubleTy.getAsOpaquePtr()};
Cpp::GetVariableType(Cpp::GetNamed("a", nullptr)), C.DoubleTy.getAsOpaquePtr()};

Cpp::GetOperator(
Cpp::GetScopeFromType(Cpp::GetVariableType(Cpp::GetNamed("a"))),
Cpp::Operator::OP_Minus, candidates);
Cpp::GetScopeFromType(Cpp::GetVariableType(Cpp::GetNamed("a", 0))),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: use nullptr [modernize-use-nullptr]

Suggested change
Cpp::GetScopeFromType(Cpp::GetVariableType(Cpp::GetNamed("a", 0))),
Cpp::GetScopeFromType(Cpp::GetVariableType(Cpp::GetNamed("a", nullptr))),


std::vector<Cpp::TemplateArgInfo> args4 = {
Cpp::GetVariableType(Cpp::GetNamed("a"))};
Cpp::GetVariableType(Cpp::GetNamed("a", 0))};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: use nullptr [modernize-use-nullptr]

Suggested change
Cpp::GetVariableType(Cpp::GetNamed("a", 0))};
Cpp::GetVariableType(Cpp::GetNamed("a", nullptr))};

std::vector<Cpp::TemplateArgInfo> args2 = {C.IntTy.getAsOpaquePtr()};
std::vector<Cpp::TemplateArgInfo> args3 = {
Cpp::GetVariableType(Cpp::GetNamed("a"))};
Cpp::GetVariableType(Cpp::GetNamed("a", 0))};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: use nullptr [modernize-use-nullptr]

Suggested change
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("b"))};
Cpp::GetVariableType(Cpp::GetNamed("a", 0)),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: use nullptr [modernize-use-nullptr]

Suggested change
Cpp::GetVariableType(Cpp::GetNamed("a", 0)),
Cpp::GetVariableType(Cpp::GetNamed("a", nullptr)),

Cpp::GetVariableType(Cpp::GetNamed("a")),
Cpp::GetVariableType(Cpp::GetNamed("b"))};
Cpp::GetVariableType(Cpp::GetNamed("a", 0)),
Cpp::GetVariableType(Cpp::GetNamed("b", 0))};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: use nullptr [modernize-use-nullptr]

Suggested change
Cpp::GetVariableType(Cpp::GetNamed("b", 0))};
Cpp::GetVariableType(Cpp::GetNamed("b", nullptr))};

std::vector<Cpp::TemplateArgInfo> args5 = {
Cpp::GetVariableType(Cpp::GetNamed("a")),
Cpp::GetVariableType(Cpp::GetNamed("a"))};
Cpp::GetVariableType(Cpp::GetNamed("a", 0)),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: use nullptr [modernize-use-nullptr]

Suggested change
Cpp::GetVariableType(Cpp::GetNamed("a", 0)),
Cpp::GetVariableType(Cpp::GetNamed("a", nullptr)),

@aaronj0
Copy link
Copy Markdown
Collaborator Author

aaronj0 commented Jan 17, 2026

Not sure how dynamic loading works on emscripten but the following error indicates something wrong with that step for the dispatch test executable:

[ 95%] Linking CXX executable CppInterOpTestsDispatch.html
wasm-ld: error: attempted static link of dynamic object ../../lib/libclangCppInterOp.so
em++: error: '/Users/runner/work/CppInterOp/CppInterOp/emsdk/upstream/bin/wasm-ld -o CppInterOpTestsDispatch.wasm CMakeFiles/CppInterOpTestsDispatch.dir/EnumReflectionTest.cpp.o CMakeFiles/CppInterOpTestsDispatch.dir/FunctionReflectionTest.cpp.o CMakeFiles/CppInterOpTestsDispatch.dir/InterpreterTest.cpp.o CMakeFiles/CppInterOpTestsDispatch.dir/JitTest.cpp.o CMakeFiles/CppInterOpTestsDispatch.dir/ScopeReflectionTest.cpp.o CMakeFiles/CppInterOpTestsDispatch.dir/TypeReflectionTest.cpp.o CMakeFiles/CppInterOpTestsDispatch.dir/Utils.cpp.o CMakeFiles/CppInterOpTestsDispatch.dir/VariableReflectionTest.cpp.o CMakeFiles/CppInterOpTestsDispatch.dir/main.cpp.o ../googletest-prefix/src/googletest-build/lib//libgtest.a ../googletest-prefix/src/googletest-build/lib//libgmock.a ../../lib/libclangCppInterOp.so -L/Users/runner/work/CppInterOp/CppInterOp/emsdk/upstream/emscripten/cache/sysroot/lib/wasm32-emscripten -L/Users/runner/work/CppInterOp/CppInterOp/emsdk/upstream/emscripten/src/lib -lGL-getprocaddr -lal -lhtml5 -lstubs -lnoexit -lc -ldlmalloc -lcompiler_rt -lc++-noexcept -lc++abi-noexcept -lsockets -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr /var/folders/sz/cwqy23057413nkkfyjbx066h0000gn/T/tmp68oq2eqelibemscripten_js_symbols.so --strip-debug --export=_emscripten_stack_alloc --export=__wasm_call_ctors --export=emscripten_stack_get_current --export=_emscripten_stack_restore --export-if-defined=__start_em_asm --export-if-defined=__stop_em_asm --export-if-defined=__start_em_lib_deps --export-if-defined=__stop_em_lib_deps --export-if-defined=__start_em_js --export-if-defined=__stop_em_js --export-if-defined=main --export-if-defined=__main_argc_argv --export-table -z stack-size=65536 --no-growable-memory --initial-heap=16777216 --no-entry --table-base=1 --global-base=1024' failed (returned 1)
make[3]: *** [unittests/CppInterOp/CppInterOpTestsDispatch.html] Error 1
make[2]: *** [unittests/CppInterOp/CMakeFiles/CppInterOpTestsDispatch.dir/all] Error 2

Copy link
Copy Markdown
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 108. Check the log or trigger a new build to see more.

static const std::unordered_map<std::string_view, CppFnPtrTy>
DispatchMap = {
#define DISPATCH_API(name, type) {#name, (CppFnPtrTy) static_cast<type>(&CppImpl::name)},
CPPINTEROP_API_TABLE
Copy link
Copy Markdown
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]

        CPPINTEROP_API_TABLE
        ^
Additional context

include/CppInterOp/Dispatch.h:48: expanded from macro 'CPPINTEROP_API_TABLE'

  DISPATCH_API(CreateInterpreter, decltype(&CppImpl::CreateInterpreter))                  \
  ^

lib/CppInterOp/Dispatch.cpp:8: expanded from macro 'DISPATCH_API'

#define DISPATCH_API(name, type) {#name, (CppFnPtrTy) static_cast<type>(&CppImpl::name)},
                                         ^

Cpp::GetVariableType(Cpp::GetNamed("a")),
Cpp::GetVariableType(Cpp::GetNamed("a"))};
Cpp::GetVariableType(Cpp::GetNamed("a", 0)),
Cpp::GetVariableType(Cpp::GetNamed("a", 0))};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: use nullptr [modernize-use-nullptr]

Suggested change
Cpp::GetVariableType(Cpp::GetNamed("a", 0))};
Cpp::GetVariableType(Cpp::GetNamed("a", nullptr))};

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);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: use nullptr [modernize-use-nullptr]

Suggested change
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));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: use nullptr [modernize-use-nullptr]

Suggested change
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)));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: use nullptr [modernize-use-nullptr]

Suggested change
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)));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: use nullptr [modernize-use-nullptr]

Suggested change
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)));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: use nullptr [modernize-use-nullptr]

Suggested change
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);
Copy link
Copy Markdown
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]

  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);
Copy link
Copy Markdown
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 "clang::NamedDecl" is directly included [misc-include-cleaner]

  clang::NamedDecl *ClassC = (clang::NamedDecl*)Cpp::GetNamed("C", 0);
         ^

@aaronj0
Copy link
Copy Markdown
Collaborator Author

aaronj0 commented Jan 17, 2026

This PR is closed in favour of a fresh one, since the history is bloated, and the page metadata is too large for github to load on the browser consistently. We should also see cleaner clang-tidy reports

@aaronj0 aaronj0 closed this Jan 17, 2026
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.

4 participants