`#include` causes macro executation failure


ROOT Version: 6.40.04
Platform: linuxarm64
Compiler: gcc (GCC) 16.2.1


Hello Experts,
I ran into a weird error:

Processing examples/convention_test.C...
In file included from libpueoEvent dictionary payload:15:
./src/pueo/RawHeader.h:17:33: error: no type named 'pol_t' in namespace 'pueo::pol'
  int isInPhiMask(int phi, pol::pol_t p=pol::kVertical) const{
                           ~~~~~^
./src/pueo/RawHeader.h:17:46: error: no member named 'kVertical' in namespace 'pueo::pol'
  int isInPhiMask(int phi, pol::pol_t p=pol::kVertical) const{
                                        ~~~~~^
./src/pueo/RawHeader.h:18:42: error: no member named 'fromChar' in namespace 'pueo::pol'
    std::cout << "pol is " << pueo::pol::fromChar(p);

This is the entire test macro:

// file: test_convention.C
#include "pueo/Conventions.h" // It appears that having this include causes macro execution failure
#include <iostream>
void convention_test(){
  std::cout << "Hello, World!\n";
}

I’ve tried a few workarounds:

  • I could comment out the #include and the macro would run fine.
  • I could change #include pueo/Conventions.h to #include pueo/RawHeader.h and the macro would run fine
  • I could execute the above commands line-by-line in the ROOT REPL and everything works
  • Compiled into a C++ executable with proper linkage, the above would of course still work.
  • Via PyROOT (with gSystem->Load) it also works.
  • I could remove the installed rootmap (not desirable, because I found in another ROOT Forum Post that rootmap is needed – without it, another library of ours complains about missing definition)
  • Lastly, I could “fix” my linkdef by commenting out the last two lines, as shown below:
// LinkDef.h
#ifdef __ROOTCLING__
#pragma link off all globals;
#pragma link off all classes;

#pragma link C++ namespace     pueo;
#pragma link C++ namespace     pueo::pol;

// #pragma link C++ enum          pueo::pol::pol_t;
// #pragma link C++ function      pueo::pol::fromChar;
#endif

My question is this: have we messed up the LinkDef.h? I thought it should be fine to have enums and functions in the linkdef according to the ROOT documentation?

Below, I am listing the remaining the files involved:

#ifndef PUEO_CONVENTIONS_H
#define PUEO_CONVENTIONS_H
namespace  pueo
{
namespace pol {
  enum pol_t {
    kHorizontal = 0,
    kVertical   = 1,
    kNotAPol
  };

  inline pol_t fromChar(char p) { return p == 'H' ? kHorizontal : p == 'V' ? kVertical : kNotAPol; }
}
}
#endif //PUEO_CONVENTIONS_H
#ifndef PUEO_RAW_HEADER_H
#define PUEO_RAW_HEADER_H

#include "pueo/Conventions.h"
#include "Rtypes.h"
#include <iostream>

namespace pueo
{
class RawHeader
{
public:

  uint32_t run = 0; ///< Run number
  uint32_t eventNumber = 0;

  int isInPhiMask(int phi, pol::pol_t p=pol::kVertical) const{
    std::cout << "pol is " << pueo::pol::fromChar(p);
    return phi;
  }

  ClassDefNV(RawHeader,4);
};
}

#endif

The following is our CmakeLists.txt. I’ve made sure to install rootmap alongside the dictionary in our LD_LIBRARY_PATH.

cmake_minimum_required(VERSION 3.23.0)
project(pueoEvent VERSION 1.0.0)
add_library(${PROJECT_NAME} SHARED)
include(GNUInstallDirs)

set(HEADER_FILES
  src/pueo/Conventions.h
  src/pueo/RawHeader.h
)
target_sources(${PROJECT_NAME} PRIVATE
  src/Conventions.cc
  src/RawHeader.cc
)

find_package(ROOT REQUIRED COMPONENTS TreePlayer Physics)

target_sources(${PROJECT_NAME} PUBLIC
  FILE_SET HEADERS
  BASE_DIRS src
  FILES ${HEADER_FILES}
)

target_link_libraries(${PROJECT_NAME} 
  PUBLIC ROOT::TreePlayer ROOT::Physics
)

# CERN ROOT dictionary generation
set(DICTNAME G__${PROJECT_NAME})
root_generate_dictionary(${DICTNAME} ${HEADER_FILES} MODULE ${PROJECT_NAME} LINKDEF LinkDef.h)

install(
  TARGETS ${PROJECT_NAME}
  EXPORT ${PROJECT_NAME}Targets 
  FILE_SET HEADERS DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
  LIBRARY DESTINATION lib
)

install(
  FILES 
    "${CMAKE_CURRENT_BINARY_DIR}/lib${PROJECT_NAME}_rdict.pcm"
    "${CMAKE_CURRENT_BINARY_DIR}/lib${PROJECT_NAME}.rootmap"
  DESTINATION lib
)