Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@
*.app

# Directories
build
install
build*
install*

# CLion files
.idea
Expand Down
11 changes: 8 additions & 3 deletions unittests/CppInterOp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,12 @@ add_cppinterop_unittest(TracingTests
TracingTests.cpp
Utils.cpp
)
# CPPINTEROP_SRC_DIR: source checkout (the coverage test reads .cpp sources).
# CPPINTEROP_BIN_DIR: default artifacts prefix; the CPPINTEROP_BIN_DIR
# environment variable overrides it at runtime (see TestPaths.h).
target_compile_definitions(TracingTests PRIVATE
"CPPINTEROP_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}/../../\""
"CPPINTEROP_BINARY_DIR=\"${CMAKE_CURRENT_BINARY_DIR}/../../\""
"CPPINTEROP_SRC_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}/../../\""
"CPPINTEROP_BIN_DIR=\"${CMAKE_BINARY_DIR}\""

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.

I believe that change breaks ROOT. @aaronj0, can you review?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

These defines are PRIVATE to the TracingTests target (test-internal only) — they're not exported to the install tree and can't reach ROOT. I also checked: neither ROOT's own CMake files nor its bundled CppInterOp use CPPINTEROP_DIR or CPPINTEROP_BINARY_DIR as CMake variables. So this rename shouldn't affect ROOT at all.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

CMAKE_BINARY_DIR will evaluate to the build directory of the current project (ROOT), in which CppInterOp is built as a subproject (which is why that was changed to ${CMAKE_CURRENT_SOURCE_DIR}/../../) . That will be problematic, since that is not where the CppInterOp binary lives in that build tree.

I can test the patch with my ongoing CppInterOp upgrade (root-project/root#22728) and figure out what works for both usecases

)
# GCC 12 and (less often) 13/14 emit a -Wmaybe-uninitialized false positive
# inside libstdc++'s <regex> headers when the std::function subobject of
Expand Down Expand Up @@ -182,8 +185,10 @@ if(NOT EMSCRIPTEN AND BUILD_SHARED_LIBS)
${CMAKE_CURRENT_BINARY_DIR} ${GTEST_INCLUDE_DIR})
target_link_libraries(DispatchTests PRIVATE ${gtest_libs} ${link_pthreads_lib})
# Deliberately no target_link_libraries(... clangCppInterOp).
# Default artifacts prefix; the CPPINTEROP_BIN_DIR environment variable
# overrides it at runtime (see TestPaths.h).
target_compile_definitions(DispatchTests PRIVATE
CPPINTEROP_LIB_PATH="${CMAKE_BINARY_DIR}/lib/libclangCppInterOp${CMAKE_SHARED_LIBRARY_SUFFIX}"
CPPINTEROP_BIN_DIR="${CMAKE_BINARY_DIR}"
)
set_output_directory(DispatchTests
BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/bin/$<CONFIG>/
Expand Down
18 changes: 16 additions & 2 deletions unittests/CppInterOp/DispatchInit.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
// Storage definitions and initialization for dispatch function pointers.
// Linked only by DispatchTests — not by the normal test suite.

#include "TestPaths.h"
#include "CppInterOp/Dispatch.h"

#include <cstdlib>
#include <iostream>

// Define storage for all raw dispatch function pointers.
using namespace Cpp;
#define CPPINTEROP_API_FUNC(DN, CN, Ret, DeclArgs, CallArgs, RawTypes) \
Expand All @@ -12,8 +16,18 @@ using namespace Cpp;
namespace {
struct DispatchInitializer {
DispatchInitializer() {
if (!Cpp::LoadDispatchAPI(CPPINTEROP_LIB_PATH)) {
std::abort();
std::string libPath = TestUtils::GetCppInterOpLibPath();

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::string" is directly included [misc-include-cleaner]

unittests/CppInterOp/DispatchInit.cpp:9:

+ #include <string>

if (libPath.empty()) {
std::cerr << "DispatchTests: cannot locate libclangCppInterOp: set the "
"CPPINTEROP_BIN_DIR environment variable to the CppInterOp "
"artifacts prefix (the directory containing lib/ and "
"include/).\n";
std::exit(EXIT_FAILURE);
}
if (!Cpp::LoadDispatchAPI(libPath.c_str())) {
std::cerr << "DispatchTests: failed to load dispatch API from '"
<< libPath << "'.\n";
std::exit(EXIT_FAILURE);
}
}
};
Expand Down
15 changes: 11 additions & 4 deletions unittests/CppInterOp/DispatchSmokeTest.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include "TestPaths.h"
#include "CppInterOp/Dispatch.h"

#include "gtest/gtest.h"
Expand Down Expand Up @@ -186,8 +187,11 @@ TEST(DispatchSmokeTest, CAPI_ScalarFunctions) {
Cpp::CreateInterpreter({});
Cpp::Declare("namespace DispCAPI { class Cls {}; int var = 1; }");

DlHandle lib(CPPINTEROP_LIB_PATH);
ASSERT_TRUE(lib) << "Failed to dlopen " << CPPINTEROP_LIB_PATH;
std::string libPath = TestUtils::GetCppInterOpLibPath();
ASSERT_FALSE(libPath.empty())
<< "Set CPPINTEROP_BIN_DIR to the CppInterOp artifacts prefix";
DlHandle lib(libPath.c_str());
ASSERT_TRUE(lib) << "Failed to dlopen " << libPath;

using IsClassFn = bool (*)(void*);
using GetNameFn = char* (*)(void*);
Expand Down Expand Up @@ -215,8 +219,11 @@ TEST(DispatchSmokeTest, CAPI_CollectionFunctions) {
Cpp::CreateInterpreter({});
Cpp::Declare("enum DispCAPIEnum { DA, DB, DC };");

DlHandle lib(CPPINTEROP_LIB_PATH);
ASSERT_TRUE(lib) << "Failed to dlopen " << CPPINTEROP_LIB_PATH;
std::string libPath = TestUtils::GetCppInterOpLibPath();
ASSERT_FALSE(libPath.empty())
<< "Set CPPINTEROP_BIN_DIR to the CppInterOp artifacts prefix";
DlHandle lib(libPath.c_str());
ASSERT_TRUE(lib) << "Failed to dlopen " << libPath;

using GetNamedFn = void* (*)(const char*, void*);
using GetEnumConstantsFn = Cpp::CppInterOpArray (*)(void*);
Expand Down
9 changes: 7 additions & 2 deletions unittests/CppInterOp/DispatchTest.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "CppInterOp/Dispatch.h"
#include "TestPaths.h"

#include "gtest/gtest.h"

Expand Down Expand Up @@ -39,18 +40,22 @@ TEST(DispatchTest, DlGetProcAddress_Unimplemented) {
}

TEST(DispatchTest, LoadUnloadCycle) {
std::string libPath = TestUtils::GetCppInterOpLibPath();
ASSERT_FALSE(libPath.empty())
<< "Set CPPINTEROP_BIN_DIR to the CppInterOp artifacts prefix";

Cpp::UnloadDispatchAPI(); // make sure we're not loaded already...
EXPECT_FALSE(Cpp::LoadDispatchAPI("some/random/invalid/directory.so"));

Cpp::UnloadDispatchAPI(); // should reset for next load to be successful
EXPECT_TRUE(Cpp::LoadDispatchAPI(CPPINTEROP_LIB_PATH));
EXPECT_TRUE(Cpp::LoadDispatchAPI(libPath.c_str()));

Cpp::UnloadDispatchAPI(); // should reset for next load to fail
EXPECT_FALSE(Cpp::LoadDispatchAPI("some/other/random/invalid/directory.so"));

// NOTE: minimize side-effects: reload assuming the static set is still
// and other test may depend on this being loaded
EXPECT_TRUE(Cpp::LoadDispatchAPI(CPPINTEROP_LIB_PATH));
EXPECT_TRUE(Cpp::LoadDispatchAPI(libPath.c_str()));
}

// NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast)
40 changes: 40 additions & 0 deletions unittests/CppInterOp/TestPaths.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#ifndef CPPINTEROP_UNITTESTS_LIBCPPINTEROP_TESTPATHS_H
#define CPPINTEROP_UNITTESTS_LIBCPPINTEROP_TESTPATHS_H

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: header guard does not follow preferred style [llvm-header-guard]

Suggested change
#define CPPINTEROP_UNITTESTS_LIBCPPINTEROP_TESTPATHS_H
#ifndef GITHUB_WORKSPACE_UNITTESTS_CPPINTEROP_TESTPATHS_H
#define GITHUB_WORKSPACE_UNITTESTS_CPPINTEROP_TESTPATHS_H

unittests/CppInterOp/TestPaths.h:39:

- #endif // CPPINTEROP_UNITTESTS_LIBCPPINTEROP_TESTPATHS_H
+ #endif // GITHUB_WORKSPACE_UNITTESTS_CPPINTEROP_TESTPATHS_H

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think these need to be ignored, right? Maybe there is a clang-tidy config update so this doesn't get flagged @vgvassilev?

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.

Yes!


#include <cstdlib>
#include <string>

namespace TestUtils {

/// CppInterOp artifacts prefix (a directory containing lib/ and include/).
/// The CPPINTEROP_BIN_DIR environment variable overrides the compile-time
/// default so relocated test binaries can find the library. Empty if
/// neither is available.
inline std::string GetCppInterOpDirPath() {
if (const char* env = std::getenv("CPPINTEROP_BIN_DIR"))
return env;
#ifdef CPPINTEROP_BIN_DIR
return CPPINTEROP_BIN_DIR;
#else
return {};
#endif
}

/// Full path to libclangCppInterOp under the artifacts prefix; empty if the
/// prefix is unknown.
inline std::string GetCppInterOpLibPath() {
std::string dir = GetCppInterOpDirPath();
if (dir.empty())
return {};
#if defined(_WIN32)
return dir + "/lib/libclangCppInterOp.dll";
#elif defined(__APPLE__)
return dir + "/lib/libclangCppInterOp.dylib";
#else
return dir + "/lib/libclangCppInterOp.so";
#endif
}

} // end namespace TestUtils

#endif // CPPINTEROP_UNITTESTS_LIBCPPINTEROP_TESTPATHS_H
24 changes: 14 additions & 10 deletions unittests/CppInterOp/TracingTests.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "../../lib/CppInterOp/Tracing.h"

#include "TestPaths.h"

#include "clang/Basic/Version.h"

#include "CppInterOp/CppInterOp.h"
Expand Down Expand Up @@ -1191,9 +1193,9 @@ TEST_F(TracingTest, ReproducerCompilesViaInterpreter) {

// Create a fresh interpreter and #include the reproducer file as-is.
Cpp::CreateInterpreter({});
Cpp::AddIncludePath(CPPINTEROP_DIR "/include");
// Generated .inc files live under the build tree.
Cpp::AddIncludePath(CPPINTEROP_BINARY_DIR "/include");
Cpp::AddIncludePath(CPPINTEROP_SRC_DIR "/include");
// Generated .inc files live under the artifacts prefix.
Cpp::AddIncludePath((TestUtils::GetCppInterOpDirPath() + "/include").c_str());

std::string includeDirective = "#include \"" + Path + "\"";
EXPECT_EQ(Cpp::Process(includeDirective.c_str()), 0)
Expand Down Expand Up @@ -1389,7 +1391,7 @@ static std::string ReadFileToString(const std::string& path) {
return {std::istreambuf_iterator<char>(ifs),
std::istreambuf_iterator<char>()};
}
// This test reads source files from the build tree via CPPINTEROP_DIR.
// This test reads source files from the checkout via CPPINTEROP_SRC_DIR.
TEST_F(TracingTest, StartStopTracingWritesToFile) {
// StartTracing begins recording; StopTracing writes the file.
std::string Path = CppInterOp::Tracing::StartTracing(/*WriteOnStdErr=*/false);
Expand Down Expand Up @@ -1543,13 +1545,15 @@ TEST(TracingCoverageTest, AllPublicAPIsAreTraced) {
// 1. Parse the header and generated declarations to extract all
// CPPINTEROP_API function names.
std::string Header =
ReadFileToString(CPPINTEROP_DIR "/include/CppInterOp/CppInterOp.h");
ReadFileToString(CPPINTEROP_SRC_DIR "/include/CppInterOp/CppInterOp.h");
ASSERT_FALSE(Header.empty()) << "Could not read CppInterOp.h";
// Function declarations are generated into CppInterOpDecl.inc.
std::string DeclInc = ReadFileToString(
CPPINTEROP_BINARY_DIR "/include/CppInterOp/CppInterOpDecl.inc");
// Function declarations are generated into CppInterOpDecl.inc, which
// lives under the artifacts prefix.
std::string DeclInc =
ReadFileToString(TestUtils::GetCppInterOpDirPath() +
"/include/CppInterOp/CppInterOpDecl.inc");
if (DeclInc.empty())
DeclInc = ReadFileToString(CPPINTEROP_DIR
DeclInc = ReadFileToString(CPPINTEROP_SRC_DIR
"/include/CppInterOp/CppInterOpDecl.inc");
Header += DeclInc;

Expand Down Expand Up @@ -1578,7 +1582,7 @@ TEST(TracingCoverageTest, AllPublicAPIsAreTraced) {
// 2. For each API name, find its definition in the implementation and
// verify INTEROP_TRACE appears shortly after the opening brace.
std::string Impl =
ReadFileToString(CPPINTEROP_DIR "/lib/CppInterOp/CppInterOp.cpp");
ReadFileToString(CPPINTEROP_SRC_DIR "/lib/CppInterOp/CppInterOp.cpp");
ASSERT_FALSE(Impl.empty()) << "Could not read CppInterOp.cpp";

std::vector<std::string> Missing;
Expand Down
Loading