From bdf954f3095ef4c85402b47af99ec22e87f2a024 Mon Sep 17 00:00:00 2001 From: Juan Miguel Carceller Date: Thu, 8 Oct 2026 07:52:29 +0200 Subject: [PATCH] [cppjit] Declare code through TCling::Declare [ROOT-patch] Cpp::Declare keeps class autoloading and autoparsing on, so including a header whose dictionary is autoloaded from its rootmap can parse it twice. Use gInterpreter.Declare in cppdef, include and c_include, as cppyy did. --- python/cppjit/__init__.py | 17 +++++++------ test/CMakeLists.txt | 1 + test/test_root_declare.py | 52 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 8 deletions(-) create mode 100644 test/test_root_declare.py diff --git a/python/cppjit/__init__.py b/python/cppjit/__init__.py index 3d0282af..8b8f3a8d 100644 --- a/python/cppjit/__init__.py +++ b/python/cppjit/__init__.py @@ -241,8 +241,10 @@ def _interpreter_lock(): def cppdef(src, verbose=True): """Declare C++ source to Cling.""" with _stderr_capture() as err, _interpreter_lock(): - errcode = gbl.Cpp.Declare(src, not verbose) - if not errcode == 0 or err.err: + ok = gbl.gInterpreter.Declare(src) + if not verbose: + err.err = "" + if not ok or err.err: if "warning" in err.err.lower() and "error" not in err.err.lower(): warnings.warn(err.err, SyntaxWarning) return True @@ -326,8 +328,8 @@ def load_library(name): def include(header): """Load (and JIT) header file
into Cling.""" with _stderr_capture() as err, _interpreter_lock(): - errcode = gbl.Cpp.Declare('#include "%s"' % header, False) - if not errcode == 0: + ok = gbl.gInterpreter.Declare('#include "%s"' % header) + if not ok: raise ImportError('Failed to load header file "%s"%s' % (header, err.err)) return True @@ -335,14 +337,13 @@ def include(header): def c_include(header): """Load (and JIT) header file
into Cling.""" with _stderr_capture() as err, _interpreter_lock(): - errcode = gbl.Cpp.Declare( + ok = gbl.gInterpreter.Declare( """extern "C" { #include "%s" }""" - % header, - False, + % header ) - if not errcode == 0: + if not ok: raise ImportError('Failed to load header file "%s"%s' % (header, err.err)) return True diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 482c2abb..b0ea1e2b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -124,4 +124,5 @@ CPPJIT_ADD_PYTEST(test_eigen) CPPJIT_ADD_PYTEST(test_leakcheck) CPPJIT_ADD_PYTEST(test_numba) CPPJIT_ADD_PYTEST(test_regression) +CPPJIT_ADD_PYTEST(test_root_declare) CPPJIT_ADD_PYTEST(test_root_interpreter_lock) diff --git a/test/test_root_declare.py b/test/test_root_declare.py new file mode 100644 index 00000000..7a843385 --- /dev/null +++ b/test/test_root_declare.py @@ -0,0 +1,52 @@ +import os +import subprocess + +from pytest import mark +from support import IS_WINDOWS + + +class TestROOTDECLARE: + @mark.skipif(IS_WINDOWS, reason="builds a dictionary with rootcling") + def test01_include_header_of_autoloaded_dictionary(self, tmp_path): + """include a #pragma once header whose dictionary its rootmap autoloads""" + + import cppjit + + name = "pragma_once_dict" + header, linkdef = name + ".h", name + "LinkDef.h" + rootmap, lib = name + ".rootmap", "lib%s.so" % name + (tmp_path / header).write_text( + "#pragma once\n" + "namespace %s { struct Thing { int value() const { return 42; } }; }\n" + % name + ) + (tmp_path / linkdef).write_text( + "#ifdef __CLING__\n#pragma link C++ class %s::Thing+;\n#endif\n" % name + ) + + bindir = cppjit.gbl.TROOT.GetBinDir().Data() + rootcling = os.path.join(bindir, "rootcling") + root_config = os.path.join(bindir, "root-config") + subprocess.check_call( + [rootcling, "-f", "dict.cxx", "-rmf", rootmap, "-rml", lib] + + ["-I" + str(tmp_path), header, linkdef], + cwd=tmp_path, + ) + cxx = subprocess.check_output([root_config, "--cxx"], text=True).split() + flags = subprocess.check_output( + [root_config, "--cflags", "--libs"], text=True + ).split() + subprocess.check_call( + cxx + + ["-shared", "-fPIC", "-o", lib, "dict.cxx", "-I" + str(tmp_path)] + + flags, + cwd=tmp_path, + ) + + cppjit.add_include_path(str(tmp_path)) + cppjit.add_library_path(str(tmp_path)) + cppjit.gbl.gInterpreter.LoadLibraryMap(str(tmp_path / rootmap)) + + cppjit.include(header) + + assert cppjit.gbl.pragma_once_dict.Thing().value() == 42