GRSISort "v4.0.0.5"
An extension of the ROOT analysis Framework
Loading...
Searching...
No Matches
TDataFrameLibrary.cxx
Go to the documentation of this file.
1#include "TDataFrameLibrary.h"
2#include "RVersion.h"
3#if ROOT_VERSION_CODE >= ROOT_VERSION(6, 14, 0)
4
5#define dlsym __bull__
6#include <dlfcn.h>
7#undef dlsym
8
9#include <sstream>
10#include <cstdlib>
11#include <sys/stat.h>
12
13#include "TGRSIOptions.h"
14#include "TGRSIUtilities.h"
15#include "TGRSIFrame.h"
16
17// redeclare dlsym to be a function returning a function pointer instead of void *
18extern "C" void* (*dlsym(void* handle, const char* symbol))();
19
21{
22 if(fHandle != nullptr) {
23 dlclose(fHandle);
24 }
25}
26
28{
29 if(fHandle != nullptr) {
30 std::cout << "Already loaded handle " << fHandle << std::endl;
31 return;
32 }
33
34 std::string libraryPath = TGRSIOptions::Get()->DataFrameLibrary();
35 if(libraryPath.empty()) {
36 std::ostringstream str;
37 str << DRED << "No data frame library provided! Please provided the location of the data frame library on the command line." << RESET_COLOR;
38 throw std::runtime_error(str.str());
39 }
40
41 // check if the provided file ends in .cxx (which means we should compile it into a library) otherwise we just try to load it
42 // if there is no dot in the path or the dot is before a slash in the path we just try to load this weirdly named library
43 size_t dot = libraryPath.find_last_of('.');
44 size_t slash = libraryPath.find_last_of('/');
45 if(dot != std::string::npos && (dot > slash || slash == std::string::npos) && libraryPath.substr(dot) == ".cxx") {
46 // let's get the full path first (or maybe move this into the function?)
47 Compile(libraryPath, dot, slash);
48 // replace the .cxx extension with .so
49 libraryPath.replace(dot, std::string::npos, ".so");
50 }
51
52 if(!FileExists(libraryPath.c_str())) {
53 std::ostringstream str;
54 str << DRED << "Library '" << libraryPath << "' does not exist or we do not have permissions to access it!" << RESET_COLOR;
55 throw std::runtime_error(str.str());
56 }
57
58 fHandle = dlopen(libraryPath.c_str(), RTLD_LAZY);
59 if(fHandle == nullptr) {
60 std::ostringstream str;
61 str << DRED << "Failed to open data frame library '" << libraryPath << "': " << dlerror() << "!" << RESET_COLOR;
62 std::cout << "dlerror: '" << dlerror() << "'" << std::endl;
63 throw std::runtime_error(str.str());
64 }
65 // try and get constructor and destructor functions from opened library
66#pragma GCC diagnostic push
67#pragma GCC diagnostic ignored "-Wcast-function-type"
68 fCreateHelper = reinterpret_cast<TGRSIHelper* (*)(TList*)>(dlsym(fHandle, "CreateHelper"));
69 fDestroyHelper = reinterpret_cast<void (*)(TGRSIHelper*)>(dlsym(fHandle, "DestroyHelper"));
70#pragma GCC diagnostic pop
71
72 if(fCreateHelper == nullptr || fDestroyHelper == nullptr) {
73 std::ostringstream str;
74 str << DRED << "Failed to find CreateHelper, and/or DestroyHelper functions in library '" << libraryPath << "'!" << RESET_COLOR;
75 throw std::runtime_error(str.str());
76 }
77 std::cout << "\tUsing library " << libraryPath << std::endl;
78}
79
80void TDataFrameLibrary::Compile(std::string& path, const size_t& dot, const size_t& slash)
81{
82 /// \brief
83 /// Try and compile the provided .cxx file into a shared object library using the provided
84 /// path, position of the last dot, and the position of the last slash.
85 /// \details
86 /// The name of the parser library used is determined from it's path and used to add
87 /// `grsiconfig --<parser library name>-cflags` to the compile command.
88 /// Other flags used are "-c -fPIC -g", `root-config --cflags --glibs`, and the directory
89 /// the path points to as include directory.
90 /// \param[in] path path of the .cxx file
91 /// \param[in] dot position of the last dot (guaranteed to be after the last slash!)
92 /// \param[in] slash position of the last slash (can be std::string::npos)
93
94 // first we create the paths for the header file, and shared library
95 // we know dot != npos and either dot > slash or slash = npos
96 std::string sourceFile = path;
97 std::string headerFile = path.replace(dot, std::string::npos, ".hh");
98 std::string sharedLibrary = path.replace(dot, std::string::npos, ".so");
99 // first we get the stats of the file's involved (.cxx, .hh, .so, and the libTGRSIFrame.so)
100 struct stat sourceStat{};
101 if(stat(sourceFile.c_str(), &sourceStat) != 0) {
102 std::ostringstream str;
103 str << "Unable to access stat of source file " << sourceFile << std::endl;
104 throw std::runtime_error(str.str());
105 }
106 struct stat headerStat{};
107 if(stat(headerFile.c_str(), &headerStat) != 0) {
108 std::ostringstream str;
109 str << "Unable to access stat of header file " << headerFile << std::endl;
110 throw std::runtime_error(str.str());
111 }
112 struct stat frameLibStat{};
113 // get path of libTGRSIFrame via
114 Dl_info info;
115 if(dladdr(reinterpret_cast<void*>(DummyFunctionToLocateTGRSIFrameLibrary), &info) == 0) {
116 std::ostringstream str;
117 str << "Unable to find location of DummyFunctionToLocateTGRSIFrameLibrary" << std::endl;
118 throw std::runtime_error(str.str());
119 }
120 if(stat(info.dli_fname, &frameLibStat) != 0) {
121 std::ostringstream str;
122 str << "Unable to access stat of " << info.dli_fname << std::endl;
123 throw std::runtime_error(str.str());
124 }
125 struct stat sharedLibStat{};
126 if(stat(sharedLibrary.c_str(), &sharedLibStat) == 0 &&
127 sharedLibStat.st_atime > sourceStat.st_atime &&
128 sharedLibStat.st_atime > headerStat.st_atime &&
129 sharedLibStat.st_atime > frameLibStat.st_atime) {
130 std::cout << DCYAN << "shared library " << sharedLibrary << " exists and is newer than " << sourceFile << ", " << headerFile << ", and $GRSISYS/lib/libTGRSIFrame.so" << RESET_COLOR << std::endl;
131 return;
132 }
133 // get include path
134 std::string includePath = ".";
135 if(slash != std::string::npos) {
136 includePath = path.substr(0, slash);
137 }
138 std::cout << DCYAN << "---------- starting compilation of user code ----------" << RESET_COLOR << std::endl;
139 std::string parserLibraryPath = TGRSIOptions::Get()->ParserLibrary();
140 // this should look something like $GRSISYS/<library name>/lib/lib<library name>.so
141 // so we can simply take everything between "last '/' + 3" and "last '.'" to be the name?
142 std::string parserLibraryName = parserLibraryPath.substr(parserLibraryPath.find_last_of('/') + 4, parserLibraryPath.find_last_of('.') - parserLibraryPath.find_last_of('/') - 4);
143 std::string objectFile = path.replace(dot, std::string::npos, ".o");
144 std::ostringstream command;
145 command << "g++ -c -fPIC -g $(grsi-config --cflags --" << parserLibraryName << "-cflags) $(root-config --cflags) -I" << includePath;
146#ifdef OS_DARWIN
147 command << " -I/opt/local/include ";
148#endif
149 command << " -o " << objectFile << " " << sourceFile;
150 if(std::system(command.str().c_str()) != 0) {
151 std::ostringstream str;
152 str << "Unable to compile source file " << sourceFile << " using " << DBLUE << "'" << command.str() << "'" << RESET_COLOR << std::endl;
153 throw std::runtime_error(str.str());
154 }
155 std::cout << DCYAN << "---------- starting linking user code -----------------" << RESET_COLOR << std::endl;
156 std::ostringstream().swap(command); // create new (empty) stringstream and swap it with command this resets the underlying string and all error flags
157 command << "g++ -fPIC -g -shared $(grsi-config --libs --" << parserLibraryName << "-libs) $(root-config --glibs) -o " << sharedLibrary << " " << objectFile;
158 if(std::system(command.str().c_str()) != 0) {
159 std::ostringstream str;
160 str << "Unable to link shared object library " << sharedLibrary << " using " << DBLUE << "'" << command.str() << "'" << RESET_COLOR << std::endl;
161 throw std::runtime_error(str.str());
162 }
163 std::cout << DCYAN << "---------- done compiling user code -------------------" << RESET_COLOR << std::endl;
164}
165#endif
#define DRED
Definition Globals.h:18
#define DBLUE
Definition Globals.h:15
#define DCYAN
Definition Globals.h:21
#define RESET_COLOR
Definition Globals.h:5
#define dlsym
void DummyFunctionToLocateTGRSIFrameLibrary()
bool FileExists(const char *filename)
static void Compile(std::string &path, const size_t &dot, const size_t &slash)
void * fHandle
handle for shared object library
TGRSIHelper *(* fCreateHelper)(TList *)
void Load()
if necessary loads shared object library and sets/initializes all other functions
void(* fDestroyHelper)(TGRSIHelper *)
static TGRSIOptions * Get(int argc=0, char **argv=nullptr)
Do not use!
const std::string & DataFrameLibrary() const
void ParserLibrary(std::string &library)