CERN ROOT: генерировать стример для внешней структуры "C" в пространстве имен - PullRequest
1 голос
/ 10 октября 2019

Предположим, что в файле "MyStruct.h" объявлено struct MyStruct.

// file MyStruct.h
#ifndef MY_STRUCT_H
#define MY_STRUCT_H
/*****************************************************/
#if defined(__cplusplus)
namespace SomeNameSpace
{
   extern "C"
   {
#endif
typedef struct Inner {       
    char ch[2];
} Inner;       
#if defined(__cplusplus)
   } /* extern "C" */
} /* namespace */
#endif
/*****************************************************/
struct MyStruct { SomeNameSpace::Inner inner; };

//using namespace SomeNameSpace;
//struct MyStruct { Inner inner; };
/*****************************************************/
#endif

Как можно написать такую ​​структуру, как ветвь ROOT TTree? Обратите внимание, я не могу удалить обертку

#if defined(__cplusplus)
namespace SomeNameSpace
{
   extern "C"
   {

, поскольку она определена во внешнем заголовке библиотеки.

ROOT выдает мне следующую ошибку:

root [0] gROOT->LoadMacro("MyStruct.h+")
Info in <TUnixSystem::ACLiC>: creating shared library .../MyStruct_h.so
Error in <CloseStreamerInfoROOTFile>: Cannot find class Inner.
Error in <ACLiC>: Dictionary generation failed!
(int) -1

Всеработает, если я удаляю namespace, т.е. работает следующий код:

// file MyStruct.h
#ifndef MY_STRUCT_H
#define MY_STRUCT_H
/*****************************************************/
#if defined(__cplusplus)
   extern "C"
   {
#endif
typedef struct Inner {       
    char ch[2];
} Inner;       
#if defined(__cplusplus)
   } /* extern "C" */
#endif
/*****************************************************/
struct MyStruct { Inner inner; };
/*****************************************************/
#endif

т.е. ROOT дает:

root [0] gROOT->LoadMacro("MyStruct.h+")
Info in <TUnixSystem::ACLiC>: creating shared library .../MyStruct_h.so
(int) 0
root [1] MyStruct x;
root [2] TFile f("temp.root", "recreate");
root [3] TTree t("t","");
root [4] t.Branch("x", &x); // no errors :-)

Может быть, что-то можно сделать с файлом MyStruct_Linkdef.h:

// rootcling -f MyStructDict.cxx -c MyStruct.h MyStruct_Linkdef.h
// g++ -shared -o libMyStruct.so `root-config --ldflags` ${CXXFLAGS} -I${ROOTSYS}/include -std=c++17 -fPIC MyStructDict.cxx

//#ifdef __CINT__

#pragma link off all functions;
#pragma link off all globals;
#pragma link off all classes;

#pragma link C++ nestedclass;
#pragma link C++ nestedtypedef;
#pragma link C++ namespace SomeNameSpace;
//#pragma link C++ class MyStruct;
//#pragma link C++ class SomeNameSpace::MyStruct;
//#pragma link C++ defined_in "MyStruct.h";

//#endif

Большое спасибо за помощь!

1 Ответ

0 голосов
/ 11 октября 2019

Вот решение проблемы:

#ifndef MY_STRUCT_H
#define MY_STRUCT_H
/*****************************************************/
#if defined(__cplusplus)
namespace SomeNameSpace
{
   extern "C"
   {
#endif
typedef struct Inner {
    char ch[2];
} Inner;
#if defined(__cplusplus)
   } /* extern "C" */
} /* namespace */
#endif
/*****************************************************/
using Inner = SomeNameSpace::Inner;
struct MyStruct { Inner inner; };
/*****************************************************/
#endif
...