diff --git a/core/dictgen/src/rootcling_impl.cxx b/core/dictgen/src/rootcling_impl.cxx index 2df77178d3093..57a229446dd7c 100644 --- a/core/dictgen/src/rootcling_impl.cxx +++ b/core/dictgen/src/rootcling_impl.cxx @@ -3345,11 +3345,12 @@ class TRootClingCallbacks : public cling::InterpreterCallbacks { if (!curLexer) return; auto fileEntry = curLexer->getFileEntry(); if (!fileEntry) return; - auto thisFileName = fileEntry->getName(); + auto thisFileName = llvm::sys::path::filename(fileEntry->getName()).str(); auto fileNameAsString = FileName.str(); - auto isThisLinkdef = ROOT::TMetaUtils::IsLinkdefFile(thisFileName.data()); + auto isThisLinkdef = ROOT::TMetaUtils::IsLinkdefFile(thisFileName.c_str()); if (isThisLinkdef) { - auto isTheIncludedLinkdef = ROOT::TMetaUtils::IsLinkdefFile(fileNameAsString.c_str()); + auto includedFileName = llvm::sys::path::filename(FileName).str(); + auto isTheIncludedLinkdef = ROOT::TMetaUtils::IsLinkdefFile(includedFileName.c_str()); if (isTheIncludedLinkdef) { fFilesIncludedByLinkdef.clear(); isLocked = true; diff --git a/roottest/root/meta/rootcling/CMakeLists.txt b/roottest/root/meta/rootcling/CMakeLists.txt index a915789400f99..9aacc7abef034 100644 --- a/roottest/root/meta/rootcling/CMakeLists.txt +++ b/roottest/root/meta/rootcling/CMakeLists.txt @@ -30,6 +30,36 @@ ROOTTEST_ADD_TEST(includeInLinkdef COPY_TO_BUILDDIR headerForLdef.h FIXTURES_REQUIRED root-meta-roocling-includeInLinkdefDict-fixture) +# Directory names must not make ordinary headers look like LinkDef files. +ROOTTEST_GENERATE_DICTIONARY(includeDirectoryDict + includeDirectory.h + LINKDEF includeDirectoryLinkDef.h + FIXTURES_SETUP root-meta-rootcling-includeDirectoryDict-fixture) + +ROOTTEST_ADD_TEST(includeDirectory + MACRO assertIncludeDictionary.C + MACROARG "\"includeDirectoryDict\",\"RootclingDirectory::Payload\"" + FIXTURES_REQUIRED root-meta-rootcling-includeDirectoryDict-fixture) + +ROOTTEST_GENERATE_DICTIONARY(includeDirectoryFromSelectionDict + LINKDEF includeDirectoryFromSelectionLinkDef.h + FIXTURES_SETUP root-meta-rootcling-includeDirectoryFromSelectionDict-fixture) + +ROOTTEST_ADD_TEST(includeDirectoryFromSelection + MACRO assertIncludeDictionary.C + MACROARG "\"includeDirectoryFromSelectionDict\",\"RootclingDirectory::DirectPayload\"" + FIXTURES_REQUIRED root-meta-rootcling-includeDirectoryFromSelectionDict-fixture) + +ROOTTEST_GENERATE_DICTIONARY(includeNestedDict + includeNested.h + LINKDEF NestedSelection/OuterLinkDef.h + FIXTURES_SETUP root-meta-rootcling-includeNestedDict-fixture) + +ROOTTEST_ADD_TEST(includeNested + MACRO assertIncludeDictionary.C + MACROARG "\"includeNestedDict\",\"RootclingNested::Payload\"" + FIXTURES_REQUIRED root-meta-rootcling-includeNestedDict-fixture) + # ROOT-8492 ROOTTEST_ADD_TEST(selectUnion COMMAND ${ROOT_rootcling_CMD} -f NestedClassOff.Dict.cc ${CMAKE_CURRENT_SOURCE_DIR}/NestedClassOff.h ${CMAKE_CURRENT_SOURCE_DIR}/NestedClassOff.LinkDef.h diff --git a/roottest/root/meta/rootcling/LinkDefDirectory/Wrapper.h b/roottest/root/meta/rootcling/LinkDefDirectory/Wrapper.h new file mode 100644 index 0000000000000..a58cb8c81ebb8 --- /dev/null +++ b/roottest/root/meta/rootcling/LinkDefDirectory/Wrapper.h @@ -0,0 +1,6 @@ +#ifndef ROOTTEST_ROOT_META_ROOTCLING_DIRECTORY_WRAPPER_H +#define ROOTTEST_ROOT_META_ROOTCLING_DIRECTORY_WRAPPER_H + +#include "detail/Payload.h" + +#endif diff --git a/roottest/root/meta/rootcling/LinkDefDirectory/detail/Payload.h b/roottest/root/meta/rootcling/LinkDefDirectory/detail/Payload.h new file mode 100644 index 0000000000000..81d338110f4de --- /dev/null +++ b/roottest/root/meta/rootcling/LinkDefDirectory/detail/Payload.h @@ -0,0 +1,13 @@ +#ifndef ROOTTEST_ROOT_META_ROOTCLING_DIRECTORY_PAYLOAD_H +#define ROOTTEST_ROOT_META_ROOTCLING_DIRECTORY_PAYLOAD_H + +namespace RootclingDirectory { +struct Payload { + int value = 0; +}; +struct DirectPayload { + int value = 0; +}; +} // namespace RootclingDirectory + +#endif diff --git a/roottest/root/meta/rootcling/NestedSelection/After.h b/roottest/root/meta/rootcling/NestedSelection/After.h new file mode 100644 index 0000000000000..4cfb545bfd9a7 --- /dev/null +++ b/roottest/root/meta/rootcling/NestedSelection/After.h @@ -0,0 +1,5 @@ +// Parsing this selection-only header in rootcling is intentional. The guard +// detects an unwanted direct include during later dictionary C++ compilation. +#ifndef __ROOTCLING__ +#error "Headers collected after a nested LinkDef must not be emitted directly." +#endif diff --git a/roottest/root/meta/rootcling/NestedSelection/Before.h b/roottest/root/meta/rootcling/NestedSelection/Before.h new file mode 100644 index 0000000000000..bf86672086878 --- /dev/null +++ b/roottest/root/meta/rootcling/NestedSelection/Before.h @@ -0,0 +1,5 @@ +// Parsing this selection-only header in rootcling is intentional. The guard +// detects an unwanted direct include during later dictionary C++ compilation. +#ifndef __ROOTCLING__ +#error "Headers collected before a nested LinkDef must not be emitted directly." +#endif diff --git a/roottest/root/meta/rootcling/NestedSelection/InnerLinkDef.h b/roottest/root/meta/rootcling/NestedSelection/InnerLinkDef.h new file mode 100644 index 0000000000000..2062fc78f3591 --- /dev/null +++ b/roottest/root/meta/rootcling/NestedSelection/InnerLinkDef.h @@ -0,0 +1,6 @@ +#ifdef __ROOTCLING__ +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; +#pragma link C++ class RootclingNested::Payload + ; +#endif diff --git a/roottest/root/meta/rootcling/NestedSelection/OuterLinkDef.h b/roottest/root/meta/rootcling/NestedSelection/OuterLinkDef.h new file mode 100644 index 0000000000000..5890bda2539c8 --- /dev/null +++ b/roottest/root/meta/rootcling/NestedSelection/OuterLinkDef.h @@ -0,0 +1,3 @@ +#include "Before.h" +#include "InnerLinkDef.h" +#include "After.h" diff --git a/roottest/root/meta/rootcling/NestedSelection/Payload.h b/roottest/root/meta/rootcling/NestedSelection/Payload.h new file mode 100644 index 0000000000000..ccf141a6a6213 --- /dev/null +++ b/roottest/root/meta/rootcling/NestedSelection/Payload.h @@ -0,0 +1,10 @@ +#ifndef ROOTTEST_ROOT_META_ROOTCLING_NESTED_PAYLOAD_H +#define ROOTTEST_ROOT_META_ROOTCLING_NESTED_PAYLOAD_H + +namespace RootclingNested { +struct Payload { + int value = 0; +}; +} // namespace RootclingNested + +#endif diff --git a/roottest/root/meta/rootcling/assertIncludeDictionary.C b/roottest/root/meta/rootcling/assertIncludeDictionary.C new file mode 100644 index 0000000000000..20e52ad19ff53 --- /dev/null +++ b/roottest/root/meta/rootcling/assertIncludeDictionary.C @@ -0,0 +1,34 @@ +#include "TClass.h" +#include "TClassTable.h" +#include "TError.h" +#include "TSystem.h" + +#include + +int assertIncludeDictionary(const char *library, const char *className) +{ + // Each CTest invocation starts a fresh ROOT process. Do not let a dictionary + // loaded by another case hide a missing selection in the requested library. + if (TClassTable::GetDictNorm(className)) { + Error("assertIncludeDictionary", "Dictionary for %s was already registered", className); + return 1; + } + if (gSystem->Load(library) < 0) { + Error("assertIncludeDictionary", "Could not load %s", library); + return 2; + } + + // Look up the compiled registration directly, without interpreter fallback, + // header autoparsing or autoloading a different dictionary library. + auto dictionary = TClassTable::GetDictNorm(className); + if (!dictionary) { + Error("assertIncludeDictionary", "%s did not register a dictionary for %s", library, className); + return 3; + } + auto cl = dictionary(); + if (!cl || !cl->HasDictionary() || std::strcmp(cl->GetName(), className) != 0) { + Error("assertIncludeDictionary", "Invalid compiled dictionary for %s from %s", className, library); + return 4; + } + return 0; +} diff --git a/roottest/root/meta/rootcling/includeDirectory.h b/roottest/root/meta/rootcling/includeDirectory.h new file mode 100644 index 0000000000000..75d646b744524 --- /dev/null +++ b/roottest/root/meta/rootcling/includeDirectory.h @@ -0,0 +1 @@ +#include "LinkDefDirectory/Wrapper.h" diff --git a/roottest/root/meta/rootcling/includeDirectoryFromSelectionLinkDef.h b/roottest/root/meta/rootcling/includeDirectoryFromSelectionLinkDef.h new file mode 100644 index 0000000000000..8beee46f9e18d --- /dev/null +++ b/roottest/root/meta/rootcling/includeDirectoryFromSelectionLinkDef.h @@ -0,0 +1,8 @@ +#include "LinkDefDirectory/Wrapper.h" + +#ifdef __ROOTCLING__ +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; +#pragma link C++ class RootclingDirectory::DirectPayload + ; +#endif diff --git a/roottest/root/meta/rootcling/includeDirectoryLinkDef.h b/roottest/root/meta/rootcling/includeDirectoryLinkDef.h new file mode 100644 index 0000000000000..ca6a7f8a5f8f2 --- /dev/null +++ b/roottest/root/meta/rootcling/includeDirectoryLinkDef.h @@ -0,0 +1,6 @@ +#ifdef __ROOTCLING__ +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; +#pragma link C++ class RootclingDirectory::Payload + ; +#endif diff --git a/roottest/root/meta/rootcling/includeNested.h b/roottest/root/meta/rootcling/includeNested.h new file mode 100644 index 0000000000000..531916d84b50b --- /dev/null +++ b/roottest/root/meta/rootcling/includeNested.h @@ -0,0 +1 @@ +#include "NestedSelection/Payload.h"