How to call ROOT from c code?

Hi I am trying to call root from C. Is this possible? I have read How to mix C and c++ but somehow I can not make it work.

As a minimal example consider the following cmake project:

main.c

int main(int argc, char** argv){

	TFile* file = CreateRootFile();

	return 0;
}

create _rootfile.cpp

#include "TFile.h"

extern "C" TFile* CreateRootFile();

TFile* CreateRootFile(){

	TFile* file = TFile::Open("testfile.root", "RECREATE");
	return file;
}

CMakesLists.txt

project(testproject CXX C)
cmake_minimum_required(VERSION 3.0)

find_package(ROOT REQUIRED COMPONENTS RIO)
message(STATUS "ROOT ${ROOT_VERSION} found at ${ROOT_BINDIR}")

add_executable(testproject ./src/main.c ./src/create_rootfile.cpp)
target_link_libraries(testproject ROOT::RIO)

I get the error:

error: unknown type name ‘TFile’

which makes sense to me. But I also understand that I cannot include ROOT header files in my c code since they are written for c++, is that right? Because trying to include the TFile header in my c code then gives me the error that the header is not found.

What is the right way to do this?

You might need a header file with:

struct TFile;
extern "C" TFile* CreateRootFile();`

Added the header file to my build and included it in the main.c file.
It still does not work. Tried to fiddle around with the suggested header without any success.

With your suggestion I get the following errors:

...../test/include/RootHeader.h:5:8: error: expected identifier or '('
extern "C" TFile* CreateRootFile();
       ^
...../test/src/main.c:5:2: error: must use 'struct' tag to refer to type 'TFile'
        TFile* file = CreateRootFile();
        ^
        struct
....../src/main.c:5:16: error: implicit declaration of function 'CreateRootFile' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
        TFile* file = CreateRootFile();
                      ^
......./test/src/main.c:5:9: warning: incompatible integer to pointer conversion initializing 'struct TFile *' with an expression of type 'int' [-Wint-conversion]
        TFile* file = CreateRootFile();

In the “main”, you probably need: struct TFile *file = CreateRootFile();

Try it with (in both source code files #include "RootHeader.h"):

/* RootHeader.h */
#ifndef _RootHeader_h_
#define _RootHeader_h_
#ifdef __cplusplus
#include "TFile.h"
extern "C" {
#endif
struct TFile *CreateRootFile();
#ifdef __cplusplus
}
#endif
#endif

One could maybe “simplify” it so that one can use “TFile *file = CreateRootFile();” in the “main”:

/* RootHeader.h */
#ifndef _RootHeader_h_
#define _RootHeader_h_
#ifdef __cplusplus
#include "TFile.h"
extern "C" {
#endif
typedef struct TFile TFile;
TFile *CreateRootFile();
#ifdef __cplusplus
}
#endif
#endif

Hey thanks that seems to work. But I run into the next problem. Assume i want to add a tree to my file:

In my create_rootfile.cpp:

TTree* CreateTree(){
TTree *tree = new TTree("tree","data");

return tree;
}

In the RootHeader i add:

typedef struct TTree TTree;
TTree *CreateTree(); 

And in my main.c I try to do:

TFile* file = CreateRootFile();
TTree* tree = CreateTree();
tree->Write();

The code compiles but trying to run it I get the error:

error: dereferencing pointer to incomplete type ‘TTree’ {aka ‘struct TTree’}
 1741 |  tree->Write(file);

Well, “tree->Write();” directly tries to call a C++ class method. I don’t think this can work in C code.

Ok that makes sense. What would be a workaround?
Defining another method in the cpp file taking the file and tree as input arguments? Would something like this work?

Make your “main” a C++ program. Use C++ everywhere possible and call C routines only where needed.

Unfortunately this is not possible. I try to modify open source software which comes with a waveform digitizing ADC which is completely written in C and quite complex.It comes with methods to store the data to ascii or binary files but I’d like to store it directly in a rootfile. I mean, another way I can think of is simply using the built in methods to store the data and then write another program which reads the ouput files and creates the rootfile. But that sounds quite cumbersome.

It is much easier to link a C++ “main” program against C libraries than the opposite (i.e., calling C functions from C++ is usually pretty straightforward).

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.