Skip to content

Commit 3ad9392

Browse files
committed
[Python] Continue clingwrapper synchronization
Continue clingwrapper synchronization with upstream.
1 parent efad335 commit 3ad9392

File tree

3 files changed

+109
-90
lines changed

3 files changed

+109
-90
lines changed

bindings/pyroot/cppyy/cppyy-backend/clingwrapper/src/clingwrapper.cxx

Lines changed: 68 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,24 @@
5252
#include <cstring>
5353
#include <typeinfo>
5454

55+
#if defined(__arm64__)
56+
#include <exception>
57+
#include <setjmp.h>
58+
#define CLING_CATCH_UNCAUGHT_ \
59+
ARMUncaughtException guard; \
60+
if (setjmp(gExcJumBuf) == 0) {
61+
#define _CLING_CATCH_UNCAUGHT \
62+
} else { \
63+
if (!std::getenv("CPPYY_UNCAUGHT_QUIET")) \
64+
std::cerr << "Warning: uncaught exception in JIT is rethrown; resources may leak" \
65+
<< " (suppress with \"CPPYY_UNCAUGHT_QUIET=1\")" << std::endl;\
66+
std::rethrow_exception(std::current_exception()); \
67+
}
68+
#else
69+
#define CLING_CATCH_UNCAUGHT_
70+
#define _CLING_CATCH_UNCAUGHT
71+
#endif
72+
5573
// temp
5674
#include <iostream>
5775
typedef CPyCppyy::Parameter Parameter;
@@ -75,6 +93,7 @@ static const ClassRefs_t::size_type STD_HANDLE = GLOBAL_HANDLE + 1;
7593

7694
typedef std::map<std::string, ClassRefs_t::size_type> Name2ClassRefIndex_t;
7795
static Name2ClassRefIndex_t g_name2classrefidx;
96+
7897
static std::map<std::string, std::string> resolved_enum_types;
7998

8099
namespace {
@@ -245,7 +264,7 @@ class ApplicationStarter {
245264
public:
246265
ApplicationStarter() {
247266
// initialize ROOT early to guarantee proper order of shutdown later on (gROOT is a
248-
// macro that resolves to the ROOT::GetROOT() function call)
267+
// macro that resolves to the ::CppyyLegacy::GetROOT() function call)
249268
(void)gROOT;
250269

251270
// setup dummy holders for global and std namespaces
@@ -262,6 +281,13 @@ class ApplicationStarter {
262281
g_globalvars.push_back(nullptr);
263282
g_globalidx[nullptr] = 0;
264283

284+
// fill out the builtins
285+
std::set<std::string> bi{g_builtins};
286+
for (const auto& name : bi) {
287+
for (const char* a : {"*", "&", "*&", "[]", "*[]"})
288+
g_builtins.insert(name+a);
289+
}
290+
265291
// disable fast path if requested
266292
if (std::getenv("CPPYY_DISABLE_FASTPATH")) gEnableFastPath = false;
267293

@@ -324,25 +350,23 @@ class ApplicationStarter {
324350
gInterpreter->Declare("namespace __cppyy_internal { struct Sep; }");
325351

326352
// retrieve all initial (ROOT) C++ names in the global scope to allow filtering later
327-
if (!std::getenv("CPPYY_NO_ROOT_FILTER")) {
328-
gROOT->GetListOfGlobals(true); // force initialize
329-
gROOT->GetListOfGlobalFunctions(true); // id.
330-
std::set<std::string> initial;
331-
Cppyy::GetAllCppNames(GLOBAL_HANDLE, initial);
332-
gInitialNames = initial;
353+
gROOT->GetListOfGlobals(true); // force initialize
354+
gROOT->GetListOfGlobalFunctions(true); // id.
355+
std::set<std::string> initial;
356+
Cppyy::GetAllCppNames(GLOBAL_HANDLE, initial);
357+
gInitialNames = initial;
333358

334359
#ifndef WIN32
335-
gRootSOs.insert("libCore.so ");
336-
gRootSOs.insert("libRIO.so ");
337-
gRootSOs.insert("libThread.so ");
338-
gRootSOs.insert("libMathCore.so ");
360+
gRootSOs.insert("libCore.so ");
361+
gRootSOs.insert("libRIO.so ");
362+
gRootSOs.insert("libThread.so ");
363+
gRootSOs.insert("libMathCore.so ");
339364
#else
340-
gRootSOs.insert("libCore.dll ");
341-
gRootSOs.insert("libRIO.dll ");
342-
gRootSOs.insert("libThread.dll ");
343-
gRootSOs.insert("libMathCore.dll ");
365+
gRootSOs.insert("libCore.dll ");
366+
gRootSOs.insert("libRIO.dll ");
367+
gRootSOs.insert("libThread.dll ");
368+
gRootSOs.insert("libMathCore.dll ");
344369
#endif
345-
}
346370

347371
// start off with a reasonable size placeholder for wrappers
348372
gWrapperHolder.reserve(1024);
@@ -467,10 +491,10 @@ std::string Cppyy::ResolveName(const std::string& cppitem_name)
467491
if (tclean.compare(0, 9, "std::byte") == 0)
468492
return tclean;
469493

470-
471494
// check data types list (accept only builtins as typedefs will
472495
// otherwise not be resolved)
473496
if (IsBuiltin(tclean)) return tclean;
497+
474498
// special case for enums
475499
if (IsEnum(cppitem_name))
476500
return ResolveEnum(cppitem_name);
@@ -699,15 +723,17 @@ Cppyy::TCppType_t Cppyy::GetActualClass(TCppType_t klass, TCppObject_t obj)
699723
// if the raw name is the empty string (no guarantees that this is so as truly, the
700724
// address is corrupt, but it is common to be empty), then there is no accessible RTTI
701725
// and getting the unmangled name will crash ...
702-
if (!raw)
726+
727+
// a common case are the i/o stream objects b/c these are pulled in from libCling
728+
if (!raw || (strstr(cr->GetName(), "std::basic_") && strstr(cr->GetName(), "stream")) || raw[0] == '\0')
703729
return klass;
704730
} catch (std::bad_typeid) {
705731
return klass; // can't risk passing to ROOT/meta as it may do RTTI
706732
}
707733
#endif
708734

709735
TClass* clActual = cr->GetActualClass((void*)obj);
710-
// The additional check using TClass::GetClassInfo is to prevent returning classes of which the Interpreter has no info
736+
// The additional check using TClass::GetClassInfo is to prevent returning classes of which the Interpreter has no info (see https://github.com/root-project/root/pull/16177)
711737
if (clActual && clActual != cr.GetClass() && clActual->GetClassInfo()) {
712738
auto itt = g_name2classrefidx.find(clActual->GetName());
713739
if (itt != g_name2classrefidx.end())
@@ -733,7 +759,6 @@ size_t Cppyy::SizeOf(const std::string& type_name)
733759
return SizeOf(GetScope(type_name));
734760
}
735761

736-
737762
bool Cppyy::IsBuiltin(const std::string& type_name)
738763
{
739764
if (g_builtins.find(type_name) != g_builtins.end())
@@ -756,7 +781,7 @@ bool Cppyy::IsComplete(const std::string& type_name)
756781

757782
int oldEIL = gErrorIgnoreLevel;
758783
gErrorIgnoreLevel = 3000;
759-
TClass* klass = TClass::GetClass(TClassEdit::ShortType(type_name.c_str(), 1).c_str());
784+
TClass* klass = TClass::GetClass(type_name.c_str());
760785
if (klass && klass->GetClassInfo()) // works for normal case w/ dict
761786
b = gInterpreter->ClassInfo_IsLoaded(klass->GetClassInfo());
762787
else { // special case for forward declared classes
@@ -802,11 +827,11 @@ void Cppyy::Destruct(TCppType_t type, TCppObject_t instance)
802827
else {
803828
auto ib = sHasOperatorDelete.find(type);
804829
if (ib == sHasOperatorDelete.end()) {
805-
TFunction *f = (TFunction *)cr->GetMethodAllAny("operator delete");
806-
sHasOperatorDelete[type] = (bool)(f && (f->Property() & kIsPublic));
807-
ib = sHasOperatorDelete.find(type);
830+
TFunction *f = (TFunction *)cr->GetMethodAllAny("operator delete");
831+
sHasOperatorDelete[type] = (bool)(f && (f->Property() & kIsPublic));
832+
ib = sHasOperatorDelete.find(type);
808833
}
809-
ib->second ? cr->Destructor((void *)instance) : ::operator delete((void *)instance);
834+
ib->second ? cr->Destructor((void*)instance) : ::operator delete((void*)instance);
810835
}
811836
}
812837
}
@@ -869,7 +894,8 @@ bool copy_args(Parameter* args, size_t nargs, void** vargs)
869894
}
870895

871896
static inline
872-
void release_args(Parameter* args, size_t nargs) {
897+
void release_args(Parameter* args, size_t nargs)
898+
{
873899
for (size_t i = 0; i < nargs; ++i) {
874900
if (args[i].fTypeCode == 'X')
875901
free(args[i].fValue.fVoidp);
@@ -1106,15 +1132,19 @@ bool Cppyy::IsAbstract(TCppType_t klass)
11061132
bool Cppyy::IsEnum(const std::string& type_name)
11071133
{
11081134
if (type_name.empty()) return false;
1135+
1136+
if (type_name.rfind("enum ", 0) == 0)
1137+
return true; // by definition (C-style)
1138+
11091139
std::string tn_short = TClassEdit::ShortType(type_name.c_str(), 1);
11101140
if (tn_short.empty()) return false;
11111141
return gInterpreter->ClassInfo_IsEnum(tn_short.c_str());
11121142
}
11131143

1114-
bool Cppyy::IsAggregate(TCppType_t klass)
1144+
bool Cppyy::IsAggregate(TCppType_t type)
11151145
{
1116-
// Test if this type is an aggregate type
1117-
TClassRef& cr = type_from_handle(klass);
1146+
// Test if this type is a "plain old data" type
1147+
TClassRef& cr = type_from_handle(type);
11181148
if (cr.GetClass())
11191149
return cr->ClassProperty() & kClassIsAggregate;
11201150
return false;
@@ -1183,7 +1213,7 @@ static inline
11831213
void cond_add(Cppyy::TCppScope_t scope, const std::string& ns_scope,
11841214
std::set<std::string>& cppnames, const char* name, bool nofilter = false)
11851215
{
1186-
if (!name || name[0] == '_' || strstr(name, ".h") != 0 || strncmp(name, "operator", 8) == 0)
1216+
if (!name || strstr(name, ".h") != 0)
11871217
return;
11881218

11891219
if (scope == GLOBAL_HANDLE) {
@@ -1252,23 +1282,21 @@ void Cppyy::GetAllCppNames(TCppScope_t scope, std::set<std::string>& cppnames)
12521282

12531283
// add functions
12541284
coll = (scope == GLOBAL_HANDLE) ?
1255-
gROOT->GetListOfGlobalFunctions() : cr->GetListOfMethods();
1285+
gROOT->GetListOfGlobalFunctions(true) : cr->GetListOfMethods(true);
12561286
{
12571287
TIter itr{coll};
12581288
TFunction* obj = nullptr;
12591289
while ((obj = (TFunction*)itr.Next())) {
12601290
const char* nm = obj->GetName();
12611291
// skip templated functions, adding only the un-instantiated ones
1262-
if (nm && nm[0] != '_' && strstr(nm, "<") == 0 && strncmp(nm, "operator", 8) != 0) {
1263-
if (gInitialNames.find(nm) == gInitialNames.end())
1264-
cppnames.insert(nm);
1265-
}
1292+
if (nm && gInitialNames.find(nm) == gInitialNames.end())
1293+
cppnames.insert(nm);
12661294
}
12671295
}
12681296

12691297
// add uninstantiated templates
12701298
coll = (scope == GLOBAL_HANDLE) ?
1271-
gROOT->GetListOfFunctionTemplates() : cr->GetListOfFunctionTemplates();
1299+
gROOT->GetListOfFunctionTemplates() : cr->GetListOfFunctionTemplates(true);
12721300
FILL_COLL(TFunctionTemplate, kIsPrivate | kIsProtected)
12731301

12741302
// add (global) data members
@@ -1350,7 +1378,7 @@ std::string Cppyy::GetScopedFinalName(TCppType_t klass)
13501378
return std::string("std::")+cr->GetName();
13511379
return cr->GetName();
13521380
}
1353-
return "";
1381+
return "<unknown>";
13541382
}
13551383

13561384
bool Cppyy::HasVirtualDestructor(TCppType_t klass)
@@ -1512,10 +1540,8 @@ bool Cppyy::GetSmartPtrInfo(
15121540
TClassRef& cr = type_from_handle(GetScope(tname));
15131541
if (cr.GetClass()) {
15141542
TFunction* func = cr->GetMethod("operator->", "");
1515-
if (!func) {
1516-
gInterpreter->UpdateListOfMethods(cr.GetClass());
1543+
if (!func)
15171544
func = cr->GetMethod("operator->", "");
1518-
}
15191545
if (func) {
15201546
if (deref) *deref = (TCppMethod_t)new_CallWrapper(func);
15211547
if (raw) *raw = GetScope(TClassEdit::ShortType(
@@ -2483,3 +2509,5 @@ long long Cppyy::GetEnumDataValue(TCppEnum_t etype, TCppIndex_t idata)
24832509
TEnumConstant* ecst = (TEnumConstant*)((TEnum*)etype)->GetConstants()->At((int)idata);
24842510
return (long long)ecst->GetValue();
24852511
}
2512+
2513+

bindings/pyroot/cppyy/patches/cppyy-Enable-testsuite.patch

Lines changed: 0 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,3 @@
1-
From 7eafbaa8ad7a17ac9fe860982bd168c5d3c05589 Mon Sep 17 00:00:00 2001
2-
From: Aaron Jomy <[email protected]>
3-
Date: Thu, 27 Mar 2025 11:31:02 +0100
4-
Subject: [PATCH 1/2] [cppyy] Drop genreflex in favour of rootcling for test
5-
dictionaries
6-
7-
This patch modifies upstream cppyy's test suite to use rootcling for
8-
dictionary generation, and also marks all tests that regress or crash
9-
on ROOT. This heavily simplifies the MakeFile, which will be dropped
10-
subsequently in favour of CMake that adds this to ROOTs ctest executable.
11-
---
12-
bindings/pyroot/cppyy/cppyy/test/Makefile | 14 ++++++++------
13-
1 file changed, 8 insertions(+), 6 deletions(-)
14-
15-
diff --git a/bindings/pyroot/cppyy/cppyy/test/Makefile b/bindings/pyroot/cppyy/cppyy/test/Makefile
16-
index 0d13d38c22..c40442fab0 100644
17-
--- a/bindings/pyroot/cppyy/cppyy/test/Makefile
18-
+++ b/bindings/pyroot/cppyy/cppyy/test/Makefile
19-
@@ -16,20 +16,22 @@ dicts = advancedcppDict.so \
20-
21-
all : $(dicts)
22-
23-
-genreflex_flags := $(shell genreflex --cppflags)
24-
-cppflags=$(shell cling-config --cppflags) $(genreflex_flags) -O3 -fPIC -I$(shell python -c 'import sysconfig as sc; print(sc.get_config_var("INCLUDEPY"))') -Wno-register
25-
-
26-
+cppflags=$(shell root-config --cflags) -O3 -fPIC -I$(shell python -c 'import sysconfig as sc; print(sc.get_config_var("INCLUDEPY"))') -Wno-register
27-
PLATFORM := $(shell uname -s)
28-
ifeq ($(PLATFORM),Darwin)
29-
cppflags+=-dynamiclib -undefined dynamic_lookup -Wno-delete-non-virtual-dtor
30-
endif
31-
32-
+# For these tests, the rootcling invocation looks like the following:
33-
+# rootcling advancedcpp_rflx.cpp --rmf advancedcppDict.rootmap --rml advancedCppDict.so advancedcpp.h advancedcpp.xml
34-
+%_rflx.cpp: %.h %.xml
35-
+ rootcling $@ --rmf $*Dict.rootmap --rml $*Dict.so $^
36-
+
37-
+# Compiling the test dictionaries to shared libs:
38-
+# g++ $(cppflags) -shared -o advancedcppDict.so advancedcpp_rflx.cpp advancedcpp.cxx
39-
%Dict.so: %_rflx.cpp %.cxx
40-
$(CXX) $(cppflags) -shared -o $@ $^
41-
42-
-%_rflx.cpp: %.h %.xml
43-
- genreflex $< --selection=$*.xml --rootmap=$*Dict.rootmap --rootmap-lib=$*Dict.so
44-
-
45-
.PHONY: test clean
46-
47-
test:
48-
--
49-
2.43.0
50-
511
From 23d7c1353eb0bdd88f0e83a3c7a6c8b177e98700 Mon Sep 17 00:00:00 2001
522
From: Aaron Jomy <[email protected]>
533
Date: Thu, 27 Mar 2025 11:32:57 +0100

bindings/pyroot/cppyy/sync-upstream

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,22 @@
44

55
# We will keep our own CMakeLists.txt files
66

7+
mv cppyy-backend/CMakeLists.txt cppyy-backend_CMakeLists.txt
78
mv CPyCppyy/CMakeLists.txt CPyCppyy_CMakeLists.txt
89
mv cppyy/CMakeLists.txt cppyy_CMakeLists.txt
910
mv cppyy/test/CMakeLists.txt cppyy_test_CMakeLists.txt
1011

1112
rm -rf CPyCppyy
1213
rm -rf cppyy
14+
rm -rf cppyy-backend
1315

1416
# If we want to clone specific branches:
1517
# git clone --depth 1 --branch CPyCppyy-1.13.0 https://github.com/wlav/CPyCppyy.git
1618
# git clone --depth 1 --branch cppyy-3.5.0 https://github.com/wlav/cppyy.git
1719

1820
git clone https://github.com/wlav/CPyCppyy.git
1921
git clone https://github.com/wlav/cppyy.git
22+
git clone https://github.com/wlav/cppyy-backend.git
2023

2124
rebase_topic () {
2225
git rebase sync $1 && git branch -D sync && git checkout -b sync
@@ -51,16 +54,54 @@ git checkout -b sync
5154

5255
rebase_topic guitargeek/concurrency_tests_gil
5356

57+
rm test/Makefile
58+
59+
cd ../
60+
61+
cd cppyy-backend/
62+
63+
git reset --hard 8928218a6c95dcd02627a402ee4ed09cb138db17
64+
65+
git remote rename origin wlav
66+
67+
git remote add guitargeek https://github.com/guitargeek/cppyy-backend.git
68+
git fetch guitargeek
69+
70+
git checkout -b sync
71+
72+
rebase_topic guitargeek/root_patches # https://github.com/wlav/cppyy-backend/pull/37
73+
74+
sed '/C-linkage wrappers/,$d' clingwrapper/src/clingwrapper.cxx > clingwrapper/src/clingwrapper.cxx.no_c_api
75+
76+
mv clingwrapper/src/clingwrapper.cxx.no_c_api clingwrapper/src/clingwrapper.cxx
77+
78+
rm -rf .circleci/
79+
rm -rf .github/
80+
rm .gitignore
81+
rm README.rst
82+
rm circleci.py
83+
rm -rf cling/
84+
rm clingwrapper/MANIFEST.in
85+
rm clingwrapper/README.rst
86+
rm clingwrapper/pyproject.toml
87+
rm clingwrapper/setup.cfg
88+
rm clingwrapper/setup.py
89+
rm clingwrapper/src/capi.h
90+
rm clingwrapper/src/clingwrapper.h
91+
rm clingwrapper/src/cppyy.h
92+
5493
cd ../
5594

5695
rm -rf CPyCppyy/.git
5796
rm -rf cppyy/.git
97+
rm -rf cppyy-backend/.git
5898

5999
# Move back CMakeLists.txt files
60100

61101
mv CPyCppyy_CMakeLists.txt CPyCppyy/CMakeLists.txt
62102
mv cppyy_CMakeLists.txt cppyy/CMakeLists.txt
63103
mv cppyy_test_CMakeLists.txt cppyy/test/CMakeLists.txt
104+
mv cppyy-backend_CMakeLists.txt cppyy-backend/CMakeLists.txt
64105

65106
# Apply patches (they were created with git format-patch -1 HEAD)
66107
# Alternatively, one can also use "git am" to create individual commits

0 commit comments

Comments
 (0)