Logo ROOT  
Reference Guide
Loading...
Searching...
No Matches
TPluginManager.cxx
Go to the documentation of this file.
1// @(#)root/base:$Id$
2// Author: Fons Rademakers 26/1/2002
3
4/*************************************************************************
5 * Copyright (C) 1995-2002, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12/** \class TPluginManager
13\ingroup Base
14
15This class implements a plugin library manager.
16
17It keeps track of a list of plugin handlers. A plugin handler knows which plugin
18library to load to get a specific class that is used to extend the
19functionality of a specific base class and how to create an object
20of this class. For example, to extend the base class TFile to be
21able to read SQLite files one needs to load the plugin library
22libRSQLite.so which defines the TRSQLiteServer class. This loading
23should be triggered when a given URI contains a regular expression
24defined by the handler.
25
26Plugin handlers can be defined via macros in a list of plugin
27directories. With $ROOTSYS/etc/plugins the default top plugin
28directory specified in $ROOTSYS/etc/system.rootrc. Additional
29directories can be specified by adding them to the end of the list.
30Macros for identical plugin handlers in later directories will
31override previous ones (the inverse of normal search path behavior).
32The macros must have names like `<BaseClass>/PX0_<PluginClass>.C`,
33e.g. TSQLServer/P20_TMySQLServer.C, to allow easy sorting and grouping.
34If the BaseClass is in a namespace the directory must have the name
35NameSpace@@BaseClass as `:` is a reserved pathname character on some
36operating systems. Macros not beginning with 'P' and ending with ".C"
37are ignored. These macros typically look like:
38~~~ {.cpp}
39 void P10_TDCacheFile()
40 {
41 gPluginMgr->AddHandler("TFile", "^dcache", "TDCacheFile",
42 "DCache", "TDCacheFile(const char*,Option_t*)");
43 }
44~~~
45Plugin handlers can also be defined via resources in the .rootrc
46file. Although now deprecated this method still works for backward
47compatibility, e.g.:
48~~~ {.cpp}
49 Plugin.TSQLServer: ^mysql: TMySQLServer MySQL "<constructor>"
50 Plugin.TVirtualFitter: * TFitter Minuit "TFitter(Int_t)"
51~~~
52Add a `+` in front of Plugin.TSQLServer to extend a previously
53existing definition of TSQLServer, useful when there is more than
54one plugin that can extend the same base class. The "<constructor>"
55should be the constructor or a static method that generates an
56instance of the specified class. Global methods should start with
57"::" in their name, like "::CreateFitter()".
58Instead of being a shared library a plugin can also be a CINT
59script, so instead of libDialog.so one can have Dialog.C.
60The * is a placeholder in case there is no need for a URI to
61differentiate between different plugins for the same base class.
62For the default plugins see $ROOTSYS/etc/system.rootrc.
63
64Plugin handlers can also be registered at run time, e.g.:
65~~~ {.cpp}
66 gPluginMgr->AddHandler("TSQLServer", "^sqlite:",
67 "TSQLiteServer", "RSQLite",
68 "TSQLiteServer(const char*,const char*,const char*)");
69~~~
70A list of currently defined handlers can be printed using:
71~~~ {.cpp}
72 gPluginMgr->Print(); // use option="a" to see ctors
73~~~
74The use of the plugin library manager removes all textual references
75to hard-coded class and library names and the resulting dependencies
76in the base classes. The plugin manager is used to extend a.o.
77TFile etc. functionality.
78*/
79
80#include "TPluginManager.h"
81#include "TEnv.h"
82#include "TRegexp.h"
83#include "TROOT.h"
84#include "TSortedList.h"
85#include "THashList.h"
86#include "THashTable.h"
87#include "TClass.h"
88#include "TClassEdit.h"
89#include "TInterpreter.h"
90#include "TMethod.h"
91#include "TMethodArg.h"
92#include "TDataType.h"
93#include "TMethodCall.h"
94#include "TVirtualMutex.h"
95#include "TSystem.h"
96#include "TObjString.h"
97#include "TObjArray.h"
98#include "ThreadLocalStorage.h"
99
100#include <memory>
101#include <sstream>
102
103TPluginManager *gPluginMgr; // main plugin manager created in TROOT
104
105static bool &TPH__IsReadingDirs() {
106 TTHREAD_TLS(bool) readingDirs (false);
107 return readingDirs;
108}
109
110
111////////////////////////////////////////////////////////////////////////////////
112/// Create a plugin handler. Called by TPluginManager.
113
114TPluginHandler::TPluginHandler(const char *base, const char *regexp, const char *className, const char *pluginName,
115 const char *ctor, const char *origin)
116 : fBase(base),
117 fRegexp(regexp),
118 fClass(className),
119 fPlugin(pluginName),
120 fCtor(ctor),
121 fOrigin(origin),
122 fCallEnv(nullptr),
123 fMethod(nullptr),
124 fCanCall(0),
127 fLoadStatus(-1)
128{
129 TString aclicMode, arguments, io;
130 TString fname = gSystem->SplitAclicMode(fPlugin, aclicMode, arguments, io);
131 Bool_t validMacro = kFALSE;
132 if (fname.EndsWith(".C") || fname.EndsWith(".cxx") || fname.EndsWith(".cpp") ||
133 fname.EndsWith(".cc"))
134 validMacro = kTRUE;
135
136 if (validMacro && gROOT->LoadMacro(fPlugin, nullptr, kTRUE) == 0)
137 fIsMacro = kTRUE;
138
139 if (fCtor.BeginsWith("::")) {
140 fIsGlobal = kTRUE;
141 fCtor = fCtor.Strip(TString::kLeading, ':');
142 }
143}
144
145////////////////////////////////////////////////////////////////////////////////
146/// Cleanup plugin handler object.
147
152
153////////////////////////////////////////////////////////////////////////////////
154/// Check if regular expression appears in the URI, if so return kTRUE.
155/// If URI = 0 always return kTRUE.
156
157Bool_t TPluginHandler::CanHandle(const char *base, const char *uri)
158{
159 if (fBase != base)
160 return kFALSE;
161
162 if (!uri || fRegexp == "*")
163 return kTRUE;
164
165 Bool_t wildcard = kFALSE;
166 if (!fRegexp.MaybeRegexp())
167 wildcard = kTRUE;
168
169 TRegexp re(fRegexp, wildcard);
170 TString ruri = uri;
171
172 if (ruri.Index(re) != kNPOS)
173 return kTRUE;
174 return kFALSE;
175}
176
177////////////////////////////////////////////////////////////////////////////////
178/// Return true if the name of the iarg-th argument's type match `type_name`
179Bool_t TPluginHandler::CheckNameMatch(int iarg, const std::type_info& ti)
180{
181 int err = 0;
182 char* demangled_name = TClassEdit::DemangleTypeIdName(ti, err);
183 if (err) {
184 return false;
185 }
186 std::string norm_name;
187 TClassEdit::GetNormalizedName(norm_name, demangled_name);
188 free(demangled_name);
189 const TMethodArg *arg = static_cast<const TMethodArg *>(fMethod->GetListOfMethodArgs()->At(iarg));
190 return norm_name == arg->GetTypeNormalizedName();
191}
192
193////////////////////////////////////////////////////////////////////////////////
194/// Setup ctor or static method call environment.
195
197{
198 int setCanCall = -1;
199
200 // Use a exit_scope guard, to insure that fCanCall is set (to the value of
201 // result) as the last action of this function before returning.
202
203 // When the standard supports it, we should use std::exit_code
204 // See N4189 for example.
205 // auto guard = make_exit_scope( [...]() { ... } );
206 using exit_scope = std::shared_ptr<void*>;
207 exit_scope guard(nullptr,
208 [this,&setCanCall](void *) { this->fCanCall = setCanCall; } );
209
210 // check if class exists
212 if (!cl && !fIsGlobal) {
213 Error("SetupCallEnv", "class %s not found in plugin %s", fClass.Data(),
214 fPlugin.Data());
215 return;
216 }
217
218 // split method and prototype strings
219 TString method = fCtor(0, fCtor.Index("("));
220 TString proto = fCtor(fCtor.Index("(")+1, fCtor.Index(")")-fCtor.Index("(")-1);
221
222 if (fIsGlobal) {
223 cl = nullptr;
224 fMethod = gROOT->GetGlobalFunctionWithPrototype(method, proto, kFALSE);
225 } else {
226 fMethod = cl->GetMethodWithPrototype(method, proto);
227 }
228
229 if (!fMethod) {
230 if (fIsGlobal)
231 Error("SetupCallEnv", "global function %s not found", method.Data());
232 else
233 Error("SetupCallEnv", "method %s not found in class %s", method.Data(),
234 fClass.Data());
235 return;
236 }
237
238 if (!fIsGlobal && !(fMethod->Property() & kIsPublic)) {
239 Error("SetupCallEnv", "method %s is not public", method.Data());
240 return;
241 }
242
243 fCallEnv = new TMethodCall;
244 fCallEnv->Init(fMethod);
245
246 // cache argument types for fast comparison
247 fArgTupleTypeInfo.clear();
248 fArgTupleTypeInfo.resize(fMethod->GetNargs());
249
250 setCanCall = 1;
251
252 return;
253}
254
255
256////////////////////////////////////////////////////////////////////////////////
257/// Check if the plugin library for this handler exits. Returns 0
258/// when it exists and -1 in case the plugin does not exist.
259
261{
262 if (fIsMacro) {
263 if (TClass::GetClass(fClass)) return 0;
264 return gROOT->LoadMacro(fPlugin, nullptr, kTRUE);
265 } else
266 return gROOT->LoadClass(fClass, fPlugin, kTRUE);
267}
268
269////////////////////////////////////////////////////////////////////////////////
270/// Load the plugin library for this handler. Sets status to 0 on successful loading
271/// and -1 in case the library does not exist or in case of error.
273{
274 if (fIsMacro) {
276 fLoadStatus = 0;
277 else
278 fLoadStatus = gROOT->LoadMacro(fPlugin);
279 } else {
280 // first call also loads dependent libraries declared via the rootmap file
281 if (TClass::LoadClass(fClass, /* silent = */ kFALSE))
282 fLoadStatus = 0;
283 else
284 fLoadStatus = gROOT->LoadClass(fClass, fPlugin);
285 }
286}
287
288////////////////////////////////////////////////////////////////////////////////
289/// Load the plugin library for this handler. Returns 0 on successful loading
290/// and -1 in case the library does not exist or in case of error.
292{
293 // call once and cache the result to reduce lock contention
294 std::call_once(fLoadStatusFlag, &TPluginHandler::LoadPluginImpl, this);
295 return fLoadStatus;
296}
297
298////////////////////////////////////////////////////////////////////////////////
299/// Check that we can properly run ExecPlugin.
300
302{
303 if (fCtor.IsNull()) {
304 Error("ExecPlugin", "no ctor specified for this handler %s", fClass.Data());
305 return kFALSE;
306 }
307
308 if (fCanCall == 0) {
309 // Not initialized yet.
310 // SetupCallEnv is likely to require/take the interpreter lock.
311 // Grab it now to avoid dead-lock. In particular TPluginHandler::ExecPluginImpl
312 // takes the gInterpreterMutex and *then* call (indirectly) code that
313 // take the lock in fHandlers.
315
316 // Now check if another thread did not already do the work.
317 if (fCanCall == 0)
318 SetupCallEnv();
319 }
320
321 if (fCanCall == -1)
322 return kFALSE;
323
324 if (nargs < fMethod->GetNargs() - fMethod->GetNargsOpt() ||
325 nargs > fMethod->GetNargs()) {
326 Error("ExecPlugin", "nargs (%d) not consistent with expected number of arguments ([%d-%d])",
327 nargs, fMethod->GetNargs() - fMethod->GetNargsOpt(),
328 fMethod->GetNargs());
329 return kFALSE;
330 }
331
332 return kTRUE;
333}
334
335////////////////////////////////////////////////////////////////////////////////
336/// Print info about the plugin handler. If option is "a" print
337/// also the ctor's that will be used.
338
340{
341 const char *exist = "";
342 if (CheckPlugin() == -1)
343 exist = " [*]";
344
345 Printf("%-20s %-13s %-18s %s%s", fBase.Data(), fRegexp.Data(),
346 fClass.Data(), fPlugin.Data(), exist);
347 if (strchr(opt, 'a')) {
348 if (!exist[0]) {
349 TString lib = fPlugin;
350 if (!lib.BeginsWith("lib"))
351 lib = "lib" + lib;
352 char *path = gSystem->DynamicPathName(lib, kTRUE);
353 if (path) Printf(" [Lib: %s]", path);
354 delete [] path;
355 }
356 Printf(" [Ctor: %s]", fCtor.Data());
357 Printf(" [origin: %s]", fOrigin.Data());
358 }
359}
360
361
362
363////////////////////////////////////////////////////////////////////////////////
364/// Constructor
366{
367 fHandlers->UseRWLock();
368 fHandlers->SetOwner();
369}
370
371////////////////////////////////////////////////////////////////////////////////
372/// Clean up the plugin manager.
373
375{
376 delete fHandlers;
377 delete fBasesLoaded;
378}
379
380////////////////////////////////////////////////////////////////////////////////
381/// Load plugin handlers specified in config file, like:
382/// ~~~ {.cpp}
383/// Plugin.TSQLServer: ^mysql: TMySQLServer MySQL "TMySQLServer(...)"
384/// ~~~
385/// Add a `+` before `Plugin.` to allow for the extension of an already defined resource (see TEnv).
386
388{
389 if (!env) return;
390
391 TIter next(env->GetTable());
392 TEnvRec *er;
393
394 while ((er = (TEnvRec*) next())) {
395 const char *s;
396 if ((s = strstr(er->GetName(), "Plugin."))) {
397 // use s, i.e. skip possible OS and application prefix to Plugin.
398 // so that GetValue() takes properly care of returning the value
399 // for the specified OS and/or application
400 const char *val = env->GetValue(s, (const char*)nullptr);
401 if (val) {
402 Int_t cnt = 0;
403 char *v = StrDup(val);
404 s += 7;
405 while (1) {
406 TString regexp = strtok(!cnt ? v : nullptr, "; "); // this method does not need to be reentrant
407 if (regexp.IsNull()) break;
408 TString clss = strtok(nullptr, "; ");
409 if (clss.IsNull()) break;
410 TString plugin = strtok(nullptr, "; ");
411 if (plugin.IsNull()) break;
412 TString ctor = strtok(nullptr, ";\"");
413 if (!ctor.Contains("("))
414 ctor = strtok(nullptr, ";\"");
415 AddHandler(s, regexp, clss, plugin, ctor, "TEnv");
416 cnt++;
417 }
418 delete [] v;
419 }
420 }
421 }
422}
423
424////////////////////////////////////////////////////////////////////////////////
425/// Load all plugin macros from the specified path/base directory.
426
428{
429 void *dirp = gSystem->OpenDirectory(path);
430 if (dirp) {
431 if (gDebug > 0)
432 Info("LoadHandlerMacros", "%s", path);
433 TSortedList macros;
434 macros.SetOwner();
435 const char *f1;
436 while ((f1 = gSystem->GetDirEntry(dirp))) {
437 TString f = f1;
438 if (f[0] == 'P' && f.EndsWith(".C")) {
439 const char *p = gSystem->PrependPathName(path, f);
440 if (!gSystem->AccessPathName(p, kReadPermission)) {
441 macros.Add(new TObjString(p));
442 }
443 }
444 }
445 // load macros in alphabetical order
446 TIter next(&macros);
447 TObjString *s;
448 while ((s = (TObjString*)next())) {
449 if (gDebug > 1)
450 Info("LoadHandlerMacros", " plugin macro: %s", s->String().Data());
451 Longptr_t res;
452 if ((res = gROOT->Macro(s->String(), nullptr, kFALSE)) < 0) {
453 Error("LoadHandlerMacros", "pluging macro %s returned %ld",
454 s->String().Data(), res);
455 }
456 }
457 }
458 gSystem->FreeDirectory(dirp);
459}
460
461////////////////////////////////////////////////////////////////////////////////
462/// Load plugin handlers specified via macros in a list of plugin
463/// directories. The `$ROOTSYS/etc/plugins` is the default top plugin directory
464/// specified in `$ROOTSYS/etc/system.rootrc`. The macros must have names
465/// like `<BaseClass>/PX0_<PluginClass>.C`, e.g. //`TSQLServer/P20_TMySQLServer.C`,
466/// to allow easy sorting and grouping. If the BaseClass is in a namespace
467/// the directory must have the name NameSpace@@BaseClass as : is a reserved
468/// pathname character on some operating systems. Macros not beginning with
469/// 'P' and ending with ".C" are ignored. If base is specified only plugin
470/// macros for that base class are loaded. The macros typically
471/// should look like:
472/// ~~~ {.cpp}
473/// void P10_TDCacheFile()
474/// {
475/// gPluginMgr->AddHandler("TFile", "^dcache", "TDCacheFile",
476/// "DCache", "TDCacheFile(const char*,Option_t*,const char*,Int_t)");
477/// }
478/// ~~~
479/// In general these macros should not cause side effects, by changing global
480/// ROOT state via, e.g. gSystem calls, etc. However, in specific cases
481/// this might be useful, e.g. adding a library search path, adding a specific
482/// dependency, check on some OS or ROOT capability or downloading
483/// of the plugin.
484
486{
487 TString sbase = base;
488 if (sbase.Length())
489 sbase.ReplaceAll("::", "@@");
490
492
493 if (fBasesLoaded && fBasesLoaded->FindObject(sbase))
494 return;
495
497
498 // While waiting for the lock, another thread may
499 // have process the requested plugin.
500 if (fBasesLoaded && fBasesLoaded->FindObject(sbase))
501 return;
502
503 if (!fBasesLoaded) {
504 fBasesLoaded = new THashTable();
505 fBasesLoaded->SetOwner();
506 }
507 fBasesLoaded->Add(new TObjString(sbase));
508
510
511 TString plugindirs = gEnv->GetValue("Root.PluginPath", (char*)nullptr);
512 if (plugindirs.Length() == 0) {
513 plugindirs = "plugins";
514 gSystem->PrependPathName(TROOT::GetEtcDir(), plugindirs);
515 }
516#ifdef WIN32
517 TObjArray *dirs = plugindirs.Tokenize(";");
518#else
519 TObjArray *dirs = plugindirs.Tokenize(":");
520#endif
521 TString d;
522 for (Int_t i = 0; i < dirs->GetEntriesFast(); i++) {
523 d = ((TObjString*)dirs->At(i))->GetString();
524 // check if directory already scanned
525 Int_t skip = 0;
526 for (Int_t j = 0; j < i; j++) {
527 TString pd = ((TObjString*)dirs->At(j))->GetString();
528 if (pd == d) {
529 skip++;
530 break;
531 }
532 }
533 if (!skip) {
534 if (sbase != "") {
535 const char *p = gSystem->PrependPathName(d, sbase);
537 } else {
538 void *dirp = gSystem->OpenDirectory(d);
539 if (dirp) {
540 if (gDebug > 0)
541 Info("LoadHandlersFromPluginDirs", "%s", d.Data());
542 const char *f1;
543 while ((f1 = gSystem->GetDirEntry(dirp))) {
544 TString f = f1;
545 TString temp = f1;
546 const char *p1 = gSystem->PrependPathName(d, temp);
548 fBasesLoaded->Add(new TObjString(f));
549 }
550 }
551 gSystem->FreeDirectory(dirp);
552 }
553 }
554 }
556 delete dirs;
557}
558
559////////////////////////////////////////////////////////////////////////////////
560/// Add plugin handler to the list of handlers. If there is already a
561/// handler defined for the same base and regexp it will be replaced.
562
563void TPluginManager::AddHandler(const char *base, const char *regexp,
564 const char *className, const char *pluginName,
565 const char *ctor, const char *origin)
566{
567 // make sure there is no previous handler for the same case
568 RemoveHandler(base, regexp);
569
570 if (TPH__IsReadingDirs())
571 origin = gInterpreter->GetCurrentMacroName();
572
573 TPluginHandler *h = new TPluginHandler(base, regexp, className,
574 pluginName, ctor, origin);
575 fHandlers->Add(h);
576}
577
578////////////////////////////////////////////////////////////////////////////////
579/// Remove handler for the specified base class and the specified
580/// regexp. If regexp=0 remove all handlers for the specified base.
581
582void TPluginManager::RemoveHandler(const char *base, const char *regexp)
583{
584 TIter next(fHandlers);
586
587 while ((h = (TPluginHandler*) next())) {
588 if (h->fBase == base) {
589 if (!regexp || h->fRegexp == regexp) {
590 fHandlers->Remove(h);
591 delete h;
592 }
593 }
594 }
595}
596
597////////////////////////////////////////////////////////////////////////////////
598/// Returns the handler if there exists a handler for the specified URI.
599/// The uri can be 0 in which case the first matching plugin handler
600/// will be returned. Returns 0 in case handler is not found.
601
602TPluginHandler *TPluginManager::FindHandler(const char *base, const char *uri)
603{
605
606 TIter next(fHandlers);
608
609 while ((h = (TPluginHandler*) next())) {
610 if (h->CanHandle(base, uri)) {
611 if (gDebug > 0)
612 Info("FindHandler", "found plugin for %s", h->GetClass());
613 return h;
614 }
615 }
616
617 if (gDebug > 2) {
618 if (uri)
619 Info("FindHandler", "did not find plugin for class %s and uri %s", base, uri);
620 else
621 Info("FindHandler", "did not find plugin for class %s", base);
622 }
623
624 return nullptr;
625}
626
627////////////////////////////////////////////////////////////////////////////////
628/// Print list of registered plugin handlers. If option is "a" print
629/// also the ctor's that will be used.
630
632{
633 TIter next(fHandlers);
635 Int_t cnt = 0, cntmiss = 0;
636
637 Printf("=====================================================================");
638 Printf("Base Regexp Class Plugin");
639 Printf("=====================================================================");
640
641 while ((h = (TPluginHandler*) next())) {
642 cnt++;
643 h->Print(opt);
644 if (h->CheckPlugin() == -1)
645 cntmiss++;
646 }
647 Printf("=====================================================================");
648 Printf("%d plugin handlers registered", cnt);
649 Printf("[*] %d %s not available", cntmiss, cntmiss==1 ? "plugin" : "plugins");
650 Printf("=====================================================================\n");
651}
652
653////////////////////////////////////////////////////////////////////////////////
654/// Write in the specified directory the plugin macros. If plugin is specified
655/// and if it is a base class all macros for that base will be written. If it
656/// is a plugin class name, only that one macro will be written. If plugin
657/// is 0 all macros are written. Returns -1 if dir does not exist, 0 otherwise.
658
659Int_t TPluginManager::WritePluginMacros(const char *dir, const char *plugin) const
660{
661 const_cast<TPluginManager*>(this)->LoadHandlersFromPluginDirs();
662
663 TString d;
664 if (!dir || !dir[0])
665 d = ".";
666 else
667 d = dir;
668
669 if (gSystem->AccessPathName(d, kWritePermission)) {
670 Error("WritePluginMacros", "cannot write in directory %s", d.Data());
671 return -1;
672 }
673
674 TString base;
675 Int_t idx = 0;
676
677 TObjLink *lnk = fHandlers->FirstLink();
678 while (lnk) {
680 if (plugin && strcmp(plugin, h->fBase) && strcmp(plugin, h->fClass)) {
681 lnk = lnk->Next();
682 continue;
683 }
684 if (base != h->fBase) {
685 idx = 10;
686 base = h->fBase;
687 } else
688 idx += 10;
689 TString temp = h->fBase;
690 TString sdd = gSystem->PrependPathName(d, temp);
691 sdd.ReplaceAll("::", "@@");
692 if (gSystem->AccessPathName(sdd, kWritePermission)) {
693 if (gSystem->MakeDirectory(sdd) < 0) {
694 Error("WritePluginMacros", "cannot create directory %s", sdd.Data());
695 return -1;
696 }
697 }
698 TString fn;
699 fn.Form("P%03d_%s.C", idx, h->fClass.Data());
700 const char *fd = gSystem->PrependPathName(sdd, fn);
701 FILE *f = fopen(fd, "w");
702 if (f) {
703 fprintf(f, "void P%03d_%s()\n{\n", idx, h->fClass.Data());
704 fprintf(f, " gPluginMgr->AddHandler(\"%s\", \"%s\", \"%s\",\n",
705 h->fBase.Data(), h->fRegexp.Data(), h->fClass.Data());
706 fprintf(f, " \"%s\", \"%s\");\n", h->fPlugin.Data(), h->fCtor.Data());
707
708 // check for different regexps cases for the same base + class and
709 // put them all in the same macro
710 TObjLink *lnk2 = lnk->Next();
711 while (lnk2) {
712 TPluginHandler *h2 = (TPluginHandler *) lnk2->GetObject();
713 if (h->fBase != h2->fBase || h->fClass != h2->fClass)
714 break;
715
716 fprintf(f, " gPluginMgr->AddHandler(\"%s\", \"%s\", \"%s\",\n",
717 h2->fBase.Data(), h2->fRegexp.Data(), h2->fClass.Data());
718 fprintf(f, " \"%s\", \"%s\");\n", h2->fPlugin.Data(), h2->fCtor.Data());
719
720 lnk = lnk2;
721 lnk2 = lnk2->Next();
722 }
723 fprintf(f, "}\n");
724 fclose(f);
725 }
726 lnk = lnk->Next();
727 }
728 return 0;
729}
730
731////////////////////////////////////////////////////////////////////////////////
732/// Write in the specified environment config file the plugin records. If
733/// plugin is specified and if it is a base class all records for that
734/// base will be written. If it is a plugin class name, only that one
735/// record will be written. If plugin is 0 all macros are written.
736/// If envFile is 0 or "" the records are written to stdout.
737/// Returns -1 if envFile cannot be created or opened, 0 otherwise.
738
739Int_t TPluginManager::WritePluginRecords(const char *envFile, const char *plugin) const
740{
741 const_cast<TPluginManager*>(this)->LoadHandlersFromPluginDirs();
742
743 FILE *fd;
744 if (!envFile || !envFile[0])
745 fd = stdout;
746 else
747 fd = fopen(envFile, "w+");
748
749 if (!fd) {
750 Error("WritePluginRecords", "error opening file %s", envFile);
751 return -1;
752 }
753
754 TString base, base2;
755 Int_t idx = 0;
756
757 TObjLink *lnk = fHandlers->FirstLink();
758 while (lnk) {
760 if (plugin && strcmp(plugin, h->fBase) && strcmp(plugin, h->fClass)) {
761 lnk = lnk->Next();
762 continue;
763 }
764 if (base != h->fBase) {
765 idx = 1;
766 base = h->fBase;
767 base2 = base;
768 base2.ReplaceAll("::", "@@");
769 } else
770 idx += 1;
771
772 if (idx == 1)
773 fprintf(fd, "Plugin.%s: %s %s %s \"%s\"\n", base2.Data(), h->fRegexp.Data(),
774 h->fClass.Data(), h->fPlugin.Data(), h->fCtor.Data());
775 else
776 fprintf(fd, "+Plugin.%s: %s %s %s \"%s\"\n", base2.Data(), h->fRegexp.Data(),
777 h->fClass.Data(), h->fPlugin.Data(), h->fCtor.Data());
778
779 // check for different regexps cases for the same base + class and
780 // put them all in the same macro
781 TObjLink *lnk2 = lnk->Next();
782 while (lnk2) {
783 TPluginHandler *h2 = (TPluginHandler *) lnk2->GetObject();
784 if (h->fBase != h2->fBase || h->fClass != h2->fClass)
785 break;
786
787 fprintf(fd, "+Plugin.%s: %s %s %s \"%s\"\n", base2.Data(), h2->fRegexp.Data(),
788 h2->fClass.Data(), h2->fPlugin.Data(), h2->fCtor.Data());
789
790 lnk = lnk2;
791 lnk2 = lnk2->Next();
792 }
793 lnk = lnk->Next();
794 }
795
796 if (envFile && envFile[0])
797 fclose(fd);
798
799 return 0;
800}
#define d(i)
Definition RSha256.hxx:102
#define f(i)
Definition RSha256.hxx:104
#define h(i)
Definition RSha256.hxx:106
int Int_t
Signed integer 4 bytes (int).
Definition RtypesCore.h:59
long Longptr_t
Integer large enough to hold a pointer (platform-dependent).
Definition RtypesCore.h:89
bool Bool_t
Boolean (0=false, 1=true) (bool).
Definition RtypesCore.h:77
constexpr Bool_t kFALSE
Definition RtypesCore.h:108
constexpr Ssiz_t kNPOS
The equivalent of std::string::npos for the ROOT class TString.
Definition RtypesCore.h:131
constexpr Bool_t kTRUE
Definition RtypesCore.h:107
const char Option_t
Option string (const char).
Definition RtypesCore.h:80
@ kIsPublic
Definition TDictionary.h:75
if(name) objname
externTEnv * gEnv
Definition TEnv.h:170
#define gInterpreter
externTVirtualMutex * gInterpreterMutex
Double_t err
static bool & TPH__IsReadingDirs()
externTPluginManager * gPluginMgr
Int_t gDebug
Definition TROOT.cxx:777
#define gROOT
Definition TROOT.h:417
void Printf(const char *fmt,...)
Formats a string in a circular formatting buffer and prints the string.
Definition TString.cxx:2510
char * StrDup(const char *str)
Duplicate the string str.
Definition TString.cxx:2564
@ kReadPermission
Definition TSystem.h:55
@ kWritePermission
Definition TSystem.h:54
externTSystem * gSystem
Definition TSystem.h:582
#define R__LOCKGUARD(mutex)
#define R__WRITE_LOCKGUARD(mutex)
#define R__READ_LOCKGUARD(mutex)
const char * proto
Definition civetweb.c:18822
#define free
Definition civetweb.c:1578
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:84
static TClass * LoadClass(const char *requestedname, Bool_t silent)
Helper function used by TClass::GetClass().
Definition TClass.cxx:5851
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition TClass.cxx:2994
virtual void SetOwner(Bool_t enable=kTRUE)
Set whether this collection is the owner (enable==true) of its content.
Definition TEnv.h:86
const char * GetName() const override
Returns name of object.
Definition TEnv.h:109
The TEnv class reads config files, by default named .rootrc.
Definition TEnv.h:124
virtual Int_t GetValue(const char *name, Int_t dflt) const
Returns the integer value for a resource.
Definition TEnv.cxx:503
THashList * GetTable() const
Definition TEnv.h:140
THashTable implements a hash table to store TObject's.
Definition THashTable.h:35
A doubly linked list.
Definition TList.h:38
Each ROOT method (see TMethod) has a linked list of its arguments.
Definition TMethodArg.h:36
std::string GetTypeNormalizedName() const
Get the normalized name of the return type.
Method or function calling interface.
Definition TMethodCall.h:37
An array of TObjects.
Definition TObjArray.h:31
Int_t GetEntriesFast() const
Definition TObjArray.h:58
TObject * At(Int_t idx) const override
Definition TObjArray.h:170
Collectable string class.
Definition TObjString.h:28
TString & String()
Definition TObjString.h:48
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1098
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition TObject.cxx:1072
bool CheckNameMatch(int iarg, const std::type_info &ti)
Return true if the name of the iarg-th argument's type match type_name.
Int_t CheckPlugin() const
Check if the plugin library for this handler exits.
TFunction * fMethod
!ctor method or global function
AtomicInt_t fCanCall
!if 1 fCallEnv is ok, -1 fCallEnv is not ok, 0 fCallEnv not setup yet.
void Print(Option_t *opt="") const override
Print info about the plugin handler.
Bool_t CanHandle(const char *base, const char *uri)
Check if regular expression appears in the URI, if so return kTRUE.
~TPluginHandler()
Cleanup plugin handler object.
Bool_t CheckForExecPlugin(Int_t nargs)
Check that we can properly run ExecPlugin.
void SetupCallEnv()
Setup ctor or static method call environment.
void LoadPluginImpl()
Load the plugin library for this handler.
TMethodCall * fCallEnv
!ctor method call environment
std::vector< std::string > fArgTupleTypeInfo
Int_t LoadPlugin()
Load the plugin library for this handler.
std::once_flag fLoadStatusFlag
This class implements a plugin library manager.
Int_t WritePluginMacros(const char *dir, const char *plugin=nullptr) const
Write in the specified directory the plugin macros.
void AddHandler(const char *base, const char *regexp, const char *className, const char *pluginName, const char *ctor=nullptr, const char *origin=nullptr)
Add plugin handler to the list of handlers.
void Print(Option_t *opt="") const override
Print list of registered plugin handlers.
~TPluginManager()
Clean up the plugin manager.
void RemoveHandler(const char *base, const char *regexp=nullptr)
Remove handler for the specified base class and the specified regexp.
TPluginManager(const TPluginManager &)=delete
void LoadHandlersFromEnv(TEnv *env)
Load plugin handlers specified in config file, like:
Bool_t fReadingDirs
! true if we are running LoadHandlersFromPluginDirs
THashTable * fBasesLoaded
! table of base classes already checked or loaded
void LoadHandlerMacros(const char *path)
Load all plugin macros from the specified path/base directory.
Int_t WritePluginRecords(const char *envFile, const char *plugin=nullptr) const
Write in the specified environment config file the plugin records.
TPluginHandler * FindHandler(const char *base, const char *uri=nullptr)
Returns the handler if there exists a handler for the specified URI.
TPluginManager()
Constructor.
void LoadHandlersFromPluginDirs(const char *base=nullptr)
Load plugin handlers specified via macros in a list of plugin directories.
static const TString & GetEtcDir()
Get the sysconfig directory in the installation. Static utility function.
Definition TROOT.cxx:3381
Regular expression class.
Definition TRegexp.h:31
A sorted doubly linked list.
Definition TSortedList.h:28
void Add(TObject *obj) override
Add object in sorted list.
Basic string class.
Definition TString.h:138
Ssiz_t Length() const
Definition TString.h:425
Bool_t EndsWith(const char *pat, ECaseCompare cmp=kExact) const
Return true if string ends with the specified string.
Definition TString.cxx:2250
const char * Data() const
Definition TString.h:384
TString & ReplaceAll(const TString &s1, const TString &s2)
Definition TString.h:713
TObjArray * Tokenize(const TString &delim) const
This function is used to isolate sequential tokens in a TString.
Definition TString.cxx:2270
Bool_t BeginsWith(const char *s, ECaseCompare cmp=kExact) const
Definition TString.h:632
Bool_t IsNull() const
Definition TString.h:422
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition TString.cxx:2363
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition TString.h:641
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition TString.h:660
TF1 * f1
Definition legend1.C:11
externTVirtualRWMutex * gCoreMutex
char * DemangleTypeIdName(const std::type_info &ti, int &errorCode)
Demangle in a portable way the type id name.
void GetNormalizedName(std::string &norm_name, std::string_view name)
Return the normalized name.