Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TSystem.cxx
Go to the documentation of this file.
1 // @(#)root/base:$Id: 8944840ba34631ec28efc779647618db43c0eee5 $
2 // Author: Fons Rademakers 15/09/95
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2019, 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 TSystem
13 \ingroup Base
14 
15 Abstract base class defining a generic interface to the underlying
16 Operating System.
17 This is not an ABC in the strict sense of the (C++) word. For
18 every member function there is an implementation (often not more
19 than a call to AbstractMethod() which prints a warning saying
20 that the method should be overridden in a derived class), which
21 allows a simple partial implementation for new OS'es.
22 */
23 
24 #include <ROOT/FoundationUtils.hxx>
25 #include "Riostream.h"
26 #include "TSystem.h"
27 #include "TApplication.h"
28 #include "TException.h"
29 #include "TROOT.h"
30 #include "TClass.h"
31 #include "TClassTable.h"
32 #include "TEnv.h"
33 #include "TBrowser.h"
34 #include "TString.h"
35 #include "TOrdCollection.h"
36 #include "TObject.h"
37 #include "TInterpreter.h"
38 #include "TRegexp.h"
39 #include "TTimer.h"
40 #include "TObjString.h"
41 #include "TError.h"
42 #include "TPluginManager.h"
43 #include "TUrl.h"
44 #include "TVirtualMutex.h"
45 #include "TVersionCheck.h"
46 #include "compiledata.h"
47 #include "RConfigure.h"
48 #include "THashList.h"
49 
50 #include <sstream>
51 #include <string>
52 #include <sys/stat.h>
53 
54 #ifdef WIN32
55 #include <io.h>
56 #endif
57 
58 const char *gRootDir;
59 const char *gProgName;
60 const char *gProgPath;
61 
62 TSystem *gSystem = 0;
63 TFileHandler *gXDisplay = 0; // Display server event handler, set in TGClient
64 
65 static Int_t *gLibraryVersion = 0; // Set in TVersionCheck, used in Load()
66 static Int_t gLibraryVersionIdx = 0; // Set in TVersionCheck, used in Load()
67 static Int_t gLibraryVersionMax = 256;
68 
69 // Pin vtable
70 ProcInfo_t::~ProcInfo_t() {}
71 ClassImp(TProcessEventTimer);
72 
73 ////////////////////////////////////////////////////////////////////////////////
74 /// Create async event processor timer. Delay is in milliseconds.
75 
76 TProcessEventTimer::TProcessEventTimer(Long_t delay) : TTimer(delay, kFALSE)
77 {
78  gROOT->SetInterrupt(kFALSE);
79  TurnOn();
80 }
81 
82 ////////////////////////////////////////////////////////////////////////////////
83 /// Process events if timer did time out. Returns kTRUE if interrupt
84 /// flag is set (by hitting a key in the canvas or selecting the
85 /// Interrupt menu item in canvas or some other action).
86 
87 Bool_t TProcessEventTimer::ProcessEvents()
88 {
89  if (fTimeout) {
90  if (gSystem->ProcessEvents()) {
91  Remove();
92  return kTRUE;
93  } else {
94  Reset();
95  return kFALSE;
96  }
97  }
98  return kFALSE;
99 }
100 
101 
102 
103 ClassImp(TSystem);
104 
105 TVirtualMutex* gSystemMutex = 0;
106 
107 ////////////////////////////////////////////////////////////////////////////////
108 /// Create a new OS interface.
109 
110 TSystem::TSystem(const char *name, const char *title) : TNamed(name, title), fAclicProperties(0)
111 {
112  if (gSystem && name[0] != '-' && strcmp(name, "Generic"))
113  Error("TSystem", "only one instance of TSystem allowed");
114 
115  fOnExitList = 0;
116  fSignalHandler = 0;
117  fFileHandler = 0;
118  fStdExceptionHandler = 0;
119  fTimers = 0;
120  fCompiled = 0;
121  fHelpers = 0;
122  fInsideNotify = kFALSE;
123  fBeepDuration = 0;
124  fBeepFreq = 0;
125  fReadmask = 0;
126  fWritemask = 0;
127  fReadready = 0;
128  fWriteready = 0;
129  fSignals = 0;
130  fDone = kFALSE;
131  fAclicMode = kDefault;
132  fInControl = kFALSE;
133  fLevel = 0;
134  fMaxrfd = -1;
135  fMaxwfd = -1;
136  fNfd = 0;
137  fSigcnt = 0;
138 
139  if (!gLibraryVersion) {
140  gLibraryVersion = new Int_t [gLibraryVersionMax];
141  memset(gLibraryVersion, 0, gLibraryVersionMax*sizeof(Int_t));
142  }
143 }
144 
145 ////////////////////////////////////////////////////////////////////////////////
146 /// Delete the OS interface.
147 
148 TSystem::~TSystem()
149 {
150  if (fOnExitList) {
151  fOnExitList->Delete();
152  SafeDelete(fOnExitList);
153  }
154 
155  if (fSignalHandler) {
156  fSignalHandler->Delete();
157  SafeDelete(fSignalHandler);
158  }
159 
160  if (fFileHandler) {
161  fFileHandler->Delete();
162  SafeDelete(fFileHandler);
163  }
164 
165  if (fStdExceptionHandler) {
166  fStdExceptionHandler->Delete();
167  SafeDelete(fStdExceptionHandler);
168  }
169 
170  if (fTimers) {
171  fTimers->Delete();
172  SafeDelete(fTimers);
173  }
174 
175  if (fCompiled) {
176  fCompiled->Delete();
177  SafeDelete(fCompiled);
178  }
179 
180  if (fHelpers) {
181  fHelpers->Delete();
182  SafeDelete(fHelpers);
183  }
184 
185  if (gSystem == this)
186  gSystem = 0;
187 }
188 
189 ////////////////////////////////////////////////////////////////////////////////
190 /// Initialize the OS interface.
191 
192 Bool_t TSystem::Init()
193 {
194  fNfd = 0;
195  fMaxrfd = -1;
196  fMaxwfd = -1;
197 
198  fSigcnt = 0;
199  fLevel = 0;
200 
201  fSignalHandler = new TOrdCollection;
202  fFileHandler = new TOrdCollection;
203  fStdExceptionHandler = new TOrdCollection;
204  fTimers = new TOrdCollection;
205 
206  fBuildArch = BUILD_ARCH;
207  fBuildCompiler = COMPILER;
208  fBuildCompilerVersion = COMPILERVERS;
209  fBuildNode = BUILD_NODE;
210  fFlagsDebug = CXXDEBUG;
211  fFlagsOpt = CXXOPT;
212  fIncludePath = INCLUDEPATH;
213  fLinkedLibs = LINKEDLIBS;
214  fSoExt = SOEXT;
215  fObjExt = OBJEXT;
216  fAclicMode = kDefault;
217  fMakeSharedLib = MAKESHAREDLIB;
218  fMakeExe = MAKEEXE;
219  fCompiled = new TOrdCollection;
220 
221  if (gEnv && fBeepDuration == 0 && fBeepFreq == 0) {
222  fBeepDuration = gEnv->GetValue("Root.System.BeepDuration", 100);
223  fBeepFreq = gEnv->GetValue("Root.System.BeepFreq", 440);
224  }
225  if (!fName.CompareTo("Generic")) return kTRUE;
226  return kFALSE;
227 }
228 
229 ////////////////////////////////////////////////////////////////////////////////
230 /// Set the application name (from command line, argv[0]) and copy it in
231 /// gProgName.
232 
233 void TSystem::SetProgname(const char *name)
234 {
235  gProgName = StrDup(name);
236 }
237 
238 ////////////////////////////////////////////////////////////////////////////////
239 /// Set DISPLAY environment variable based on utmp entry. Only for UNIX.
240 
241 void TSystem::SetDisplay()
242 {
243 }
244 
245 ////////////////////////////////////////////////////////////////////////////////
246 /// Set the system error string. This string will be used by GetError().
247 /// To be used in case one does not want or can use the system error
248 /// string (e.g. because error is generated by a third party POSIX like
249 /// library that does not use standard errno).
250 
251 void TSystem::SetErrorStr(const char *errstr)
252 {
253  ResetErrno(); // so GetError() uses the fLastErrorString
254  GetLastErrorString() = errstr;
255 }
256 
257 ////////////////////////////////////////////////////////////////////////////////
258 /// Return system error string.
259 
260 const char *TSystem::GetError()
261 {
262  if (GetErrno() == 0 && !GetLastErrorString().IsNull())
263  return GetLastErrorString().Data();
264  return Form("errno: %d", GetErrno());
265 }
266 
267 ////////////////////////////////////////////////////////////////////////////////
268 /// Static function returning system error number.
269 
270 Int_t TSystem::GetErrno()
271 {
272 #ifdef _REENTRANT
273  return errno; // errno can be a macro if _REENTRANT is set
274 #else
275 #ifdef R__SOLARIS_CC50
276  return ::errno;
277 #else
278  return errno;
279 #endif
280 #endif
281 }
282 
283 ////////////////////////////////////////////////////////////////////////////////
284 /// Static function resetting system error number.
285 
286 void TSystem::ResetErrno()
287 {
288 #ifdef _REENTRANT
289  errno = 0; // errno can be a macro if _REENTRANT is set
290 #else
291 #ifdef R__SOLARIS_CC50
292  ::errno = 0;
293 #else
294  errno = 0;
295 #endif
296 #endif
297 }
298 
299 ////////////////////////////////////////////////////////////////////////////////
300 /// Objects that should be deleted on exit of the OS interface.
301 
302 void TSystem::RemoveOnExit(TObject *obj)
303 {
304  if (fOnExitList == 0)
305  fOnExitList = new TOrdCollection;
306  if (fOnExitList->FindObject(obj) == 0)
307  fOnExitList->Add(obj);
308 }
309 
310 ////////////////////////////////////////////////////////////////////////////////
311 /// Return the system's host name.
312 
313 const char *TSystem::HostName()
314 {
315  return "Local host";
316 }
317 
318 ////////////////////////////////////////////////////////////////////////////////
319 /// Hook to tell TSystem that the TApplication object has been created.
320 
321 void TSystem::NotifyApplicationCreated()
322 {
323  // Currently needed only for WinNT interface.
324 }
325 
326 ////////////////////////////////////////////////////////////////////////////////
327 /// Beep for duration milliseconds with a tone of frequency freq.
328 /// Defaults to printing the `\a` character to stdout.
329 /// If freq or duration is <0 respectively, use default value.
330 /// If setDefault is set, only set the frequency and duration as
331 /// new defaults, but don't beep.
332 /// If default freq or duration is <0, never beep (silence)
333 
334 void TSystem::Beep(Int_t freq /*=-1*/, Int_t duration /*=-1*/,
335  Bool_t setDefault /*=kFALSE*/)
336 {
337  if (setDefault) {
338  fBeepFreq = freq;
339  fBeepDuration = duration;
340  return;
341  }
342  if (fBeepDuration < 0 || fBeepFreq < 0) return; // silence
343  if (freq < 0) freq = fBeepFreq;
344  if (duration < 0) duration = fBeepDuration;
345  DoBeep(freq, duration);
346 }
347 
348 //---- EventLoop ---------------------------------------------------------------
349 
350 ////////////////////////////////////////////////////////////////////////////////
351 /// System event loop.
352 
353 void TSystem::Run()
354 {
355  fInControl = kTRUE;
356  fDone = kFALSE;
357 
358 loop_entry:
359  try {
360  RETRY {
361  while (!fDone) {
362  gApplication->StartIdleing();
363  InnerLoop();
364  gApplication->StopIdleing();
365  }
366  } ENDTRY;
367  }
368  catch (std::exception& exc) {
369  TIter next(fStdExceptionHandler);
370  TStdExceptionHandler* eh = 0;
371  while ((eh = (TStdExceptionHandler*) next())) {
372  switch (eh->Handle(exc))
373  {
374  case TStdExceptionHandler::kSEProceed:
375  break;
376  case TStdExceptionHandler::kSEHandled:
377  goto loop_entry;
378  break;
379  case TStdExceptionHandler::kSEAbort:
380  Warning("Run", "instructed to abort");
381  goto loop_end;
382  break;
383  }
384  }
385  throw;
386  }
387  catch (const char *str) {
388  printf("%s\n", str);
389  }
390  // handle every exception
391  catch (...) {
392  Warning("Run", "handle uncaugth exception, terminating");
393  }
394 
395 loop_end:
396  fInControl = kFALSE;
397 }
398 
399 ////////////////////////////////////////////////////////////////////////////////
400 /// Exit from event loop.
401 
402 void TSystem::ExitLoop()
403 {
404  fDone = kTRUE;
405 }
406 
407 ////////////////////////////////////////////////////////////////////////////////
408 /// Inner event loop.
409 
410 void TSystem::InnerLoop()
411 {
412  fLevel++;
413  DispatchOneEvent();
414  fLevel--;
415 }
416 
417 ////////////////////////////////////////////////////////////////////////////////
418 /// Process pending events (GUI, timers, sockets). Returns the result of
419 /// TROOT::IsInterrupted(). The interrupt flag (TROOT::SetInterrupt())
420 /// can be set during the handling of the events. This mechanism allows
421 /// macros running in tight calculating loops to be interrupted by some
422 /// GUI event (depending on the interval with which this method is
423 /// called). For example hitting ctrl-c in a canvas will set the
424 /// interrupt flag.
425 
426 Bool_t TSystem::ProcessEvents()
427 {
428  gROOT->SetInterrupt(kFALSE);
429 
430  if (!gROOT->TestBit(TObject::kInvalidObject))
431  DispatchOneEvent(kTRUE);
432 
433  return gROOT->IsInterrupted();
434 }
435 
436 ////////////////////////////////////////////////////////////////////////////////
437 /// Dispatch a single event.
438 
439 void TSystem::DispatchOneEvent(Bool_t)
440 {
441  AbstractMethod("DispatchOneEvent");
442 }
443 
444 ////////////////////////////////////////////////////////////////////////////////
445 /// Sleep milliSec milli seconds.
446 
447 void TSystem::Sleep(UInt_t)
448 {
449  AbstractMethod("Sleep");
450 }
451 
452 ////////////////////////////////////////////////////////////////////////////////
453 /// Select on active file descriptors (called by TMonitor).
454 
455 Int_t TSystem::Select(TList *, Long_t)
456 {
457  AbstractMethod("Select");
458  return -1;
459 }
460 ////////////////////////////////////////////////////////////////////////////////
461 /// Select on active file descriptors (called by TMonitor).
462 
463 Int_t TSystem::Select(TFileHandler *, Long_t)
464 {
465  AbstractMethod("Select");
466  return -1;
467 }
468 
469 //---- handling of system events -----------------------------------------------
470 ////////////////////////////////////////////////////////////////////////////////
471 /// Get current time in milliseconds since 0:00 Jan 1 1995.
472 
473 TTime TSystem::Now()
474 {
475  return TTime(0);
476 }
477 
478 ////////////////////////////////////////////////////////////////////////////////
479 /// Add timer to list of system timers.
480 
481 void TSystem::AddTimer(TTimer *ti)
482 {
483  if (ti && fTimers && (fTimers->FindObject(ti) == 0))
484  fTimers->Add(ti);
485 }
486 
487 ////////////////////////////////////////////////////////////////////////////////
488 /// Remove timer from list of system timers. Returns removed timer or 0
489 /// if timer was not active.
490 
491 TTimer *TSystem::RemoveTimer(TTimer *ti)
492 {
493  if (fTimers) {
494  TTimer *tr = (TTimer*) fTimers->Remove(ti);
495  return tr;
496  }
497  return 0;
498 }
499 
500 ////////////////////////////////////////////////////////////////////////////////
501 /// Time when next timer of mode (synchronous=kTRUE or
502 /// asynchronous=kFALSE) will time-out (in ms).
503 
504 Long_t TSystem::NextTimeOut(Bool_t mode)
505 {
506  if (!fTimers) return -1;
507 
508  TOrdCollectionIter it((TOrdCollection*)fTimers);
509  TTimer *t, *to = 0;
510  Long64_t tt, tnow = Now();
511  Long_t timeout = -1;
512 
513  while ((t = (TTimer *) it.Next())) {
514  if (t->IsSync() == mode) {
515  tt = (Long64_t)t->GetAbsTime() - tnow;
516  if (tt < 0) tt = 0;
517  if (timeout == -1) {
518  timeout = (Long_t)tt;
519  to = t;
520  }
521  if (tt < timeout) {
522  timeout = (Long_t)tt;
523  to = t;
524  }
525  }
526  }
527 
528  if (to && to->IsAsync() && timeout > 0) {
529  if (to->IsInterruptingSyscalls())
530  SigAlarmInterruptsSyscalls(kTRUE);
531  else
532  SigAlarmInterruptsSyscalls(kFALSE);
533  }
534 
535  return timeout;
536 }
537 
538 ////////////////////////////////////////////////////////////////////////////////
539 /// Add a signal handler to list of system signal handlers. Only adds
540 /// the handler if it is not already in the list of signal handlers.
541 
542 void TSystem::AddSignalHandler(TSignalHandler *h)
543 {
544  if (h && fSignalHandler && (fSignalHandler->FindObject(h) == 0))
545  fSignalHandler->Add(h);
546 }
547 
548 ////////////////////////////////////////////////////////////////////////////////
549 /// Remove a signal handler from list of signal handlers. Returns
550 /// the handler or 0 if the handler was not in the list of signal handlers.
551 
552 TSignalHandler *TSystem::RemoveSignalHandler(TSignalHandler *h)
553 {
554  if (fSignalHandler)
555  return (TSignalHandler *)fSignalHandler->Remove(h);
556 
557  return 0;
558 }
559 
560 ////////////////////////////////////////////////////////////////////////////////
561 /// Add a file handler to the list of system file handlers. Only adds
562 /// the handler if it is not already in the list of file handlers.
563 
564 void TSystem::AddFileHandler(TFileHandler *h)
565 {
566  if (h && fFileHandler && (fFileHandler->FindObject(h) == 0))
567  fFileHandler->Add(h);
568 }
569 
570 ////////////////////////////////////////////////////////////////////////////////
571 /// Remove a file handler from the list of file handlers. Returns
572 /// the handler or 0 if the handler was not in the list of file handlers.
573 
574 TFileHandler *TSystem::RemoveFileHandler(TFileHandler *h)
575 {
576  if (fFileHandler)
577  return (TFileHandler *)fFileHandler->Remove(h);
578 
579  return 0;
580 }
581 
582 ////////////////////////////////////////////////////////////////////////////////
583 /// If reset is true reset the signal handler for the specified signal
584 /// to the default handler, else restore previous behaviour.
585 
586 void TSystem::ResetSignal(ESignals /*sig*/, Bool_t /*reset*/)
587 {
588  AbstractMethod("ResetSignal");
589 }
590 
591 ////////////////////////////////////////////////////////////////////////////////
592 /// Reset signals handlers to previous behaviour.
593 
594 void TSystem::ResetSignals()
595 {
596  AbstractMethod("ResetSignals");
597 }
598 
599 ////////////////////////////////////////////////////////////////////////////////
600 /// If ignore is true ignore the specified signal, else restore previous
601 /// behaviour.
602 
603 void TSystem::IgnoreSignal(ESignals /*sig*/, Bool_t /*ignore*/)
604 {
605  AbstractMethod("IgnoreSignal");
606 }
607 
608 ////////////////////////////////////////////////////////////////////////////////
609 /// If ignore is true ignore the interrupt signal, else restore previous
610 /// behaviour. Typically call ignore interrupt before writing to disk.
611 
612 void TSystem::IgnoreInterrupt(Bool_t ignore)
613 {
614  IgnoreSignal(kSigInterrupt, ignore);
615 }
616 
617 ////////////////////////////////////////////////////////////////////////////////
618 /// Add an exception handler to list of system exception handlers. Only adds
619 /// the handler if it is not already in the list of exception handlers.
620 
621 void TSystem::AddStdExceptionHandler(TStdExceptionHandler *eh)
622 {
623  if (eh && fStdExceptionHandler && (fStdExceptionHandler->FindObject(eh) == 0))
624  fStdExceptionHandler->Add(eh);
625 }
626 
627 ////////////////////////////////////////////////////////////////////////////////
628 /// Remove an exception handler from list of exception handlers. Returns
629 /// the handler or 0 if the handler was not in the list of exception handlers.
630 
631 TStdExceptionHandler *TSystem::RemoveStdExceptionHandler(TStdExceptionHandler *eh)
632 {
633  if (fStdExceptionHandler)
634  return (TStdExceptionHandler *)fStdExceptionHandler->Remove(eh);
635 
636  return 0;
637 }
638 
639 ////////////////////////////////////////////////////////////////////////////////
640 /// Return the bitmap of conditions that trigger a floating point exception.
641 
642 Int_t TSystem::GetFPEMask()
643 {
644  AbstractMethod("GetFPEMask");
645  return 0;
646 }
647 
648 ////////////////////////////////////////////////////////////////////////////////
649 /// Set which conditions trigger a floating point exception.
650 /// Return the previous set of conditions.
651 
652 Int_t TSystem::SetFPEMask(Int_t)
653 {
654  AbstractMethod("SetFPEMask");
655  return 0;
656 }
657 
658 //---- Processes ---------------------------------------------------------------
659 
660 ////////////////////////////////////////////////////////////////////////////////
661 /// Execute a command.
662 
663 int TSystem::Exec(const char*)
664 {
665  AbstractMethod("Exec");
666  return -1;
667 }
668 
669 ////////////////////////////////////////////////////////////////////////////////
670 /// Open a pipe.
671 
672 FILE *TSystem::OpenPipe(const char*, const char*)
673 {
674  AbstractMethod("OpenPipe");
675  return 0;
676 }
677 
678 ////////////////////////////////////////////////////////////////////////////////
679 /// Close the pipe.
680 
681 int TSystem::ClosePipe(FILE*)
682 {
683  AbstractMethod("ClosePipe");
684  return -1;
685 }
686 
687 ////////////////////////////////////////////////////////////////////////////////
688 /// Execute command and return output in TString.
689 
690 TString TSystem::GetFromPipe(const char *command)
691 {
692  TString out;
693 
694  FILE *pipe = OpenPipe(command, "r");
695  if (!pipe) {
696  SysError("GetFromPipe", "cannot run command \"%s\"", command);
697  return out;
698  }
699 
700  TString line;
701  while (line.Gets(pipe)) {
702  if (out != "")
703  out += "\n";
704  out += line;
705  }
706 
707  Int_t r = ClosePipe(pipe);
708  if (r) {
709  Error("GetFromPipe", "command \"%s\" returned %d", command, r);
710  }
711  return out;
712 }
713 
714 ////////////////////////////////////////////////////////////////////////////////
715 /// Get process id.
716 
717 int TSystem::GetPid()
718 {
719  AbstractMethod("GetPid");
720  return -1;
721 }
722 
723 ////////////////////////////////////////////////////////////////////////////////
724 /// Exit the application.
725 
726 void TSystem::Exit(int, Bool_t)
727 {
728  AbstractMethod("Exit");
729 }
730 
731 ////////////////////////////////////////////////////////////////////////////////
732 /// Abort the application.
733 
734 void TSystem::Abort(int)
735 {
736  AbstractMethod("Abort");
737 }
738 
739 ////////////////////////////////////////////////////////////////////////////////
740 /// Print a stack trace.
741 
742 void TSystem::StackTrace()
743 {
744  AbstractMethod("StackTrace");
745 }
746 
747 
748 //---- Directories -------------------------------------------------------------
749 
750 ////////////////////////////////////////////////////////////////////////////////
751 /// Create helper TSystem to handle file and directory operations that
752 /// might be special for remote file access.
753 
754 TSystem *TSystem::FindHelper(const char *path, void *dirptr)
755 {
756  TSystem *helper = nullptr;
757  {
758  R__READ_LOCKGUARD(ROOT::gCoreMutex);
759 
760  if (!fHelpers) {
761  R__WRITE_LOCKGUARD(ROOT::gCoreMutex);
762  fHelpers = new TOrdCollection;
763  }
764 
765  if (path) {
766  if (!GetDirPtr()) {
767  TUrl url(path, kTRUE);
768  if (!strcmp(url.GetProtocol(), "file"))
769  return nullptr;
770  }
771  }
772 
773  // look for existing helpers
774  TIter next(fHelpers);
775  while ((helper = (TSystem*) next()))
776  if (helper->ConsistentWith(path, dirptr))
777  return helper;
778 
779  if (!path)
780  return nullptr;
781  }
782 
783  // create new helper
784  TRegexp re("^root.*:"); // also roots, rootk, etc
785  TString pname = path;
786  TPluginHandler *h;
787  if (pname.BeginsWith("xroot:") || pname.Index(re) != kNPOS) {
788  // (x)rootd daemon ...
789  if ((h = gROOT->GetPluginManager()->FindHandler("TSystem", path))) {
790  if (h->LoadPlugin() == -1)
791  return nullptr;
792  helper = (TSystem*) h->ExecPlugin(2, path, kFALSE);
793  }
794  } else if ((h = gROOT->GetPluginManager()->FindHandler("TSystem", path))) {
795  if (h->LoadPlugin() == -1)
796  return nullptr;
797  helper = (TSystem*) h->ExecPlugin(0);
798  }
799 
800  if (helper) {
801  R__WRITE_LOCKGUARD(ROOT::gCoreMutex);
802  fHelpers->Add(helper);
803  }
804 
805  return helper;
806 }
807 
808 ////////////////////////////////////////////////////////////////////////////////
809 /// Check consistency of this helper with the one required
810 /// by 'path' or 'dirptr'
811 
812 Bool_t TSystem::ConsistentWith(const char *path, void *dirptr)
813 {
814  Bool_t checkproto = kFALSE;
815  if (path) {
816  if (!GetDirPtr()) {
817  TUrl url(path, kTRUE);
818  if (!strncmp(url.GetProtocol(), GetName(), strlen(GetName())))
819  checkproto = kTRUE;
820  }
821  }
822 
823  Bool_t checkdir = kFALSE;
824  if (GetDirPtr() && GetDirPtr() == dirptr)
825  checkdir = kTRUE;
826 
827  return (checkproto || checkdir);
828 }
829 
830 ////////////////////////////////////////////////////////////////////////////////
831 /// Make a directory. Returns 0 in case of success and
832 /// -1 if the directory could not be created (either already exists or
833 /// illegal path name).
834 
835 int TSystem::MakeDirectory(const char*)
836 {
837  AbstractMethod("MakeDirectory");
838  return 0;
839 }
840 
841 ////////////////////////////////////////////////////////////////////////////////
842 /// Open a directory. Returns 0 if directory does not exist.
843 
844 void *TSystem::OpenDirectory(const char*)
845 {
846  AbstractMethod("OpenDirectory");
847  return 0;
848 }
849 
850 ////////////////////////////////////////////////////////////////////////////////
851 /// Free a directory.
852 
853 void TSystem::FreeDirectory(void*)
854 {
855  AbstractMethod("FreeDirectory");
856 }
857 
858 ////////////////////////////////////////////////////////////////////////////////
859 /// Get a directory entry. Returns 0 if no more entries.
860 
861 const char *TSystem::GetDirEntry(void*)
862 {
863  AbstractMethod("GetDirEntry");
864  return 0;
865 }
866 
867 ////////////////////////////////////////////////////////////////////////////////
868 /// Change directory.
869 
870 Bool_t TSystem::ChangeDirectory(const char*)
871 {
872  AbstractMethod("ChangeDirectory");
873  return kFALSE;
874 }
875 
876 ////////////////////////////////////////////////////////////////////////////////
877 /// Return working directory.
878 
879 const char *TSystem::WorkingDirectory()
880 {
881  return 0;
882 }
883 
884 //////////////////////////////////////////////////////////////////////////////
885 /// Return working directory.
886 
887 std::string TSystem::GetWorkingDirectory() const
888 {
889  return std::string();
890 }
891 
892 ////////////////////////////////////////////////////////////////////////////////
893 /// Return the user's home directory.
894 
895 const char *TSystem::HomeDirectory(const char*)
896 {
897  return 0;
898 }
899 
900 //////////////////////////////////////////////////////////////////////////////
901 /// Return the user's home directory.
902 
903 std::string TSystem::GetHomeDirectory(const char*) const
904 {
905  return std::string();
906 }
907 
908 ////////////////////////////////////////////////////////////////////////////////
909 /// Make a file system directory. Returns 0 in case of success and
910 /// -1 if the directory could not be created (either already exists or
911 /// illegal path name).
912 /// If 'recursive' is true, makes parent directories as needed.
913 
914 int TSystem::mkdir(const char *name, Bool_t recursive)
915 {
916  if (recursive) {
917  TString safeName = name; // local copy in case 'name' is output from
918  // TSystem::DirName as it uses static buffers
919  TString dirname = DirName(safeName);
920  if (!dirname.Length()) {
921  // well we should not have to make the root of the file system!
922  // (and this avoid infinite recursions!)
923  return -1;
924  }
925  if (AccessPathName(dirname, kFileExists)) {
926  int res = mkdir(dirname, kTRUE);
927  if (res) return res;
928  }
929  if (!AccessPathName(safeName, kFileExists)) {
930  return -1;
931  }
932  }
933 
934  return MakeDirectory(name);
935 }
936 
937 //---- Paths & Files -----------------------------------------------------------
938 
939 ////////////////////////////////////////////////////////////////////////////////
940 /// Base name of a file name. Base name of /user/root is root.
941 
942 const char *TSystem::BaseName(const char *name)
943 {
944  if (name) {
945  if (name[0] == '/' && name[1] == '\0')
946  return name;
947  char *cp;
948  if ((cp = (char*)strrchr(name, '/')))
949  return ++cp;
950  return name;
951  }
952  Error("BaseName", "name = 0");
953  return 0;
954 }
955 
956 ////////////////////////////////////////////////////////////////////////////////
957 /// Return true if dir is an absolute pathname.
958 
959 Bool_t TSystem::IsAbsoluteFileName(const char *dir)
960 {
961  if (dir)
962  return dir[0] == '/';
963  return kFALSE;
964 }
965 
966 ////////////////////////////////////////////////////////////////////////////////
967 /// Return true if 'name' is a file that can be found in the ROOT include
968 /// path or the current directory.
969 /// If 'name' contains any ACLiC style information (e.g. trailing +[+][g|O]),
970 /// it will be striped off 'name'.
971 /// If fullpath is != 0, the full path to the file is returned in *fullpath,
972 /// which must be deleted by the caller.
973 
974 Bool_t TSystem::IsFileInIncludePath(const char *name, char **fullpath)
975 {
976  if (!name || !name[0]) return kFALSE;
977 
978  TString aclicMode;
979  TString arguments;
980  TString io;
981  TString realname = SplitAclicMode(name, aclicMode, arguments, io);
982 
983  TString fileLocation = DirName(realname);
984 
985  TString incPath = gSystem->GetIncludePath(); // of the form -Idir1 -Idir2 -Idir3
986  incPath.Append(":").Prepend(" ");
987  incPath.ReplaceAll(" -I",":"); // of form :dir1 :dir2:dir3
988  while ( incPath.Index(" :") != -1 ) {
989  incPath.ReplaceAll(" :",":");
990  }
991  // Remove double quotes around path expressions.
992  incPath.ReplaceAll("\":", ":");
993  incPath.ReplaceAll(":\"", ":");
994 
995  incPath.Prepend(fileLocation+":.:");
996 
997  char *actual = Which(incPath,realname);
998 
999  if (!actual) {
1000  return kFALSE;
1001  } else {
1002  if (fullpath)
1003  *fullpath = actual;
1004  else
1005  delete [] actual;
1006  return kTRUE;
1007  }
1008 }
1009 
1010 ////////////////////////////////////////////////////////////////////////////////
1011 /// Return the directory name in pathname. DirName of /user/root is /user.
1012 /// In case no dirname is specified "." is returned.
1013 
1014 const char *TSystem::DirName(const char *pathname)
1015 {
1016  if (pathname && strchr(pathname, '/')) {
1017  R__LOCKGUARD2(gSystemMutex);
1018 
1019  static int len = 0;
1020  static char *buf = 0;
1021  int pathlen = strlen(pathname);
1022  if (pathlen > len) {
1023  delete [] buf;
1024  len = pathlen;
1025  buf = new char [len+1];
1026  }
1027  strcpy(buf, pathname);
1028 
1029  char *r = buf+pathlen-1;
1030  // First skip the trailing '/'
1031  while ( r>buf && *(r)=='/') { --r; }
1032  // Then find the next non slash
1033  while ( r>buf && *(r)!='/') { --r; }
1034  // Then skip duplicate slashes
1035  // Note the 'r>buf' is a strict comparison to allows '/topdir' to return '/'
1036  while ( r>buf && *(r)=='/') { --r; }
1037  // If all was cut away, we encountered a rel. path like 'subdir/'
1038  // and ended up at '.'.
1039  if (r==buf && *(r)!='/') {
1040  return ".";
1041  }
1042  // And finally terminate the string to drop off the filename
1043  *(r+1) = '\0';
1044 
1045  return buf;
1046  }
1047  return ".";
1048 }
1049 
1050 ////////////////////////////////////////////////////////////////////////////////
1051 /// Convert from a Unix pathname to a local pathname. E.g. from `/user/root` to
1052 /// `\user\root`.
1053 
1054 const char *TSystem::UnixPathName(const char *name)
1055 {
1056  return name;
1057 }
1058 
1059 ////////////////////////////////////////////////////////////////////////////////
1060 /// Concatenate a directory and a file name. User must delete returned string.
1061 
1062 char *TSystem::ConcatFileName(const char *dir, const char *name)
1063 {
1064  TString nameString(name);
1065  PrependPathName(dir, nameString);
1066  return StrDup(nameString.Data());
1067 }
1068 
1069 ////////////////////////////////////////////////////////////////////////////////
1070 /// Concatenate a directory and a file name.
1071 
1072 const char *TSystem::PrependPathName(const char *, TString&)
1073 {
1074  AbstractMethod("PrependPathName");
1075  return 0;
1076 }
1077 
1078 
1079 //---- Paths & Files -----------------------------------------------------------
1080 
1081 ////////////////////////////////////////////////////////////////////////////////
1082 /// Expand a pathname getting rid of special shell characters like ~.$, etc.
1083 /// For Unix/Win32 compatibility use $(XXX) instead of $XXX when using
1084 /// environment variables in a pathname. If compatibility is not an issue
1085 /// you can use on Unix directly $XXX. This is a protected function called
1086 /// from the OS specific system classes, like TUnixSystem and TWinNTSystem.
1087 /// Returns the expanded filename or 0 in case of error.
1088 
1089 const char *TSystem::ExpandFileName(const char *fname)
1090 {
1091  const int kBufSize = kMAXPATHLEN;
1092  TTHREAD_TLS_ARRAY(char, kBufSize, xname);
1093 
1094  Bool_t res = ExpandFileName(fname, xname, kBufSize);
1095  if (res)
1096  return nullptr;
1097  else
1098  return xname;
1099 }
1100 
1101 //////////////////////////////////////////////////////////////////////////////
1102 /// Expand a pathname getting rid of special shell characters like ~.$, etc.
1103 /// This function is analogous to ExpandFileName(const char *), except that
1104 /// it receives a TString reference of the pathname to be expanded.
1105 /// Returns kTRUE in case of error and kFALSE otherwise.
1106 
1107 Bool_t TSystem::ExpandFileName(TString &fname)
1108 {
1109  const int kBufSize = kMAXPATHLEN;
1110  char xname[kBufSize];
1111 
1112  Bool_t res = ExpandFileName(fname.Data(), xname, kBufSize);
1113  if (!res)
1114  fname = xname;
1115 
1116  return res;
1117 }
1118 
1119 ////////////////////////////////////////////////////////////////////////////
1120 /// Private method for pathname expansion.
1121 /// Returns kTRUE in case of error and kFALSE otherwise.
1122 
1123 Bool_t TSystem::ExpandFileName(const char *fname, char *xname, const int kBufSize)
1124 {
1125  int n, ier, iter, lx, ncopy;
1126  char *inp, *out, *x, *t, *buff;
1127  const char *b, *c, *e;
1128  const char *p;
1129  buff = new char[kBufSize * 4];
1130 
1131  iter = 0; xname[0] = 0; inp = buff + kBufSize; out = inp + kBufSize;
1132  inp[-1] = ' '; inp[0] = 0; out[-1] = ' ';
1133  c = fname + strspn(fname, " \t\f\r");
1134  //VP if (isalnum(c[0])) { strcpy(inp, WorkingDirectory()); strcat(inp, "/"); } // add $cwd
1135 
1136  strlcat(inp, c, kBufSize);
1137 
1138 again:
1139  iter++; c = inp; ier = 0;
1140  x = out; x[0] = 0;
1141 
1142  p = 0; e = 0;
1143  if (c[0] == '~' && c[1] == '/') { // ~/ case
1144  std::string hd = GetHomeDirectory();
1145  p = hd.c_str();
1146  e = c + 1;
1147  if (p) { // we have smth to copy
1148  strlcpy(x, p, kBufSize);
1149  x += strlen(p);
1150  c = e;
1151  } else {
1152  ++ier;
1153  ++c;
1154  }
1155  } else if (c[0] == '~' && c[1] != '/') { // ~user case
1156  n = strcspn(c+1, "/ ");
1157  assert((n+1) < kBufSize && "This should have been prevented by the truncation 'strlcat(inp, c, kBufSize)'");
1158  // There is no overlap here as the buffer is segment in 4 strings of at most kBufSize
1159  (void)strlcpy(buff, c+1, n+1); // strlcpy copy 'size-1' characters.
1160  std::string hd = GetHomeDirectory(buff);
1161  e = c+1+n;
1162  if (!hd.empty()) { // we have smth to copy
1163  p = hd.c_str();
1164  strlcpy(x, p, kBufSize);
1165  x += strlen(p);
1166  c = e;
1167  } else {
1168  x++[0] = c[0];
1169  //++ier;
1170  ++c;
1171  }
1172  }
1173 
1174  for ( ; c[0]; c++) {
1175 
1176  p = 0; e = 0;
1177 
1178  if (c[0] == '.' && c[1] == '/' && c[-1] == ' ') { // $cwd
1179  std::string wd = GetWorkingDirectory();
1180  strlcpy(buff, wd.c_str(), kBufSize);
1181  p = buff;
1182  e = c + 1;
1183  }
1184  if (p) { // we have smth to copy */
1185  strlcpy(x, p, kBufSize); x += strlen(p); c = e-1; continue;
1186  }
1187 
1188  if (c[0] != '$') { // not $, simple copy
1189  x++[0] = c[0];
1190  } else { // we have a $
1191  b = c+1;
1192  if (c[1] == '(') b++;
1193  if (c[1] == '{') b++;
1194  if (b[0] == '$')
1195  e = b+1;
1196  else
1197  for (e = b; isalnum(e[0]) || e[0] == '_'; e++) ;
1198  buff[0] = 0; strncat(buff, b, e-b);
1199  p = Getenv(buff);
1200  if (!p) { // too bad, try UPPER case
1201  for (t = buff; (t[0] = toupper(t[0])); t++) ;
1202  p = Getenv(buff);
1203  }
1204  if (!p) { // too bad, try Lower case
1205  for (t = buff; (t[0] = tolower(t[0])); t++) ;
1206  p = Getenv(buff);
1207  }
1208  if (!p && !strcmp(buff, "cwd")) { // it is $cwd
1209  std::string wd = GetWorkingDirectory();
1210  strlcpy(buff, wd.c_str(), kBufSize);
1211  p = buff;
1212  }
1213  if (!p && !strcmp(buff, "$")) { // it is $$ (replace by GetPid())
1214  snprintf(buff,kBufSize*4, "%d", GetPid());
1215  p = buff;
1216  }
1217  if (!p) { // too bad, nothing can help
1218 #ifdef WIN32
1219  // if we're on windows, we can have \\SomeMachine\C$ - don't
1220  // complain about that, if '$' is followed by nothing or a
1221  // path delimiter.
1222  if (c[1] && c[1]!='\\' && c[1]!=';' && c[1]!='/')
1223  ier++;
1224 #else
1225  ier++;
1226 #endif
1227  x++[0] = c[0];
1228  } else { // It is OK, copy result
1229  int lp = strlen(p);
1230  if (lp >= kBufSize) {
1231  // make sure lx will be >= kBufSize (see below)
1232  strlcpy(x, p, kBufSize);
1233  x += kBufSize;
1234  break;
1235  }
1236  strcpy(x,p);
1237  x += lp;
1238  c = (b==c+1) ? e-1 : e;
1239  }
1240  }
1241  }
1242 
1243  x[0] = 0; lx = x - out;
1244  if (ier && iter < 3) { strlcpy(inp, out, kBufSize); goto again; }
1245  ncopy = (lx >= kBufSize) ? kBufSize-1 : lx;
1246  xname[0] = 0; strncat(xname, out, ncopy);
1247 
1248  delete[] buff;
1249 
1250  if (ier || ncopy != lx) {
1251  ::Error("TSystem::ExpandFileName", "input: %s, output: %s", fname, xname);
1252  return kTRUE;
1253  }
1254 
1255  return kFALSE;
1256 }
1257 
1258 
1259 ////////////////////////////////////////////////////////////////////////////////
1260 /// Expand a pathname getting rid of special shell characters like ~.$, etc.
1261 /// For Unix/Win32 compatibility use $(XXX) instead of $XXX when using
1262 /// environment variables in a pathname. If compatibility is not an issue
1263 /// you can use on Unix directly $XXX.
1264 
1265 Bool_t TSystem::ExpandPathName(TString&)
1266 {
1267  return kFALSE;
1268 }
1269 
1270 ////////////////////////////////////////////////////////////////////////////////
1271 /// Expand a pathname getting rid of special shell characters like ~.$, etc.
1272 /// For Unix/Win32 compatibility use $(XXX) instead of $XXX when using
1273 /// environment variables in a pathname. If compatibility is not an issue
1274 /// you can use on Unix directly $XXX. The user must delete returned string.
1275 
1276 char *TSystem::ExpandPathName(const char *)
1277 {
1278  return 0;
1279 }
1280 
1281 ////////////////////////////////////////////////////////////////////////////////
1282 /// Returns FALSE if one can access a file using the specified access mode.
1283 /// The file name must not contain any special shell characters line ~ or $,
1284 /// in those cases first call ExpandPathName().
1285 /// Attention, bizarre convention of return value!!
1286 
1287 Bool_t TSystem::AccessPathName(const char *, EAccessMode)
1288 {
1289  return kFALSE;
1290 }
1291 
1292 ////////////////////////////////////////////////////////////////////////////////
1293 /// Returns TRUE if the url in 'path' points to the local file system.
1294 /// This is used to avoid going through the NIC card for local operations.
1295 
1296 Bool_t TSystem::IsPathLocal(const char *path)
1297 {
1298  Bool_t localPath = kTRUE;
1299 
1300  TUrl url(path);
1301  if (strlen(url.GetHost()) > 0) {
1302  // Check locality
1303  localPath = kFALSE;
1304  TInetAddress a(gSystem->GetHostByName(url.GetHost()));
1305  TInetAddress b(gSystem->GetHostByName(gSystem->HostName()));
1306  if (!strcmp(a.GetHostName(), b.GetHostName()) ||
1307  !strcmp(a.GetHostAddress(), b.GetHostAddress())) {
1308  // Host OK
1309  localPath = kTRUE;
1310  // Check the user if specified
1311  if (strlen(url.GetUser()) > 0) {
1312  UserGroup_t *u = gSystem->GetUserInfo();
1313  if (u) {
1314  if (strcmp(u->fUser, url.GetUser()))
1315  // Requested a different user
1316  localPath = kFALSE;
1317  delete u;
1318  }
1319  }
1320  }
1321  }
1322  // Done
1323  return localPath;
1324 }
1325 
1326 ////////////////////////////////////////////////////////////////////////////////
1327 /// Copy a file. If overwrite is true and file already exists the
1328 /// file will be overwritten. Returns 0 when successful, -1 in case
1329 /// of file open failure, -2 in case the file already exists and overwrite
1330 /// was false and -3 in case of error during copy.
1331 
1332 int TSystem::CopyFile(const char *, const char *, Bool_t)
1333 {
1334  AbstractMethod("CopyFile");
1335  return -1;
1336 }
1337 
1338 ////////////////////////////////////////////////////////////////////////////////
1339 /// Rename a file.
1340 
1341 int TSystem::Rename(const char *, const char *)
1342 {
1343  AbstractMethod("Rename");
1344  return -1;
1345 }
1346 
1347 ////////////////////////////////////////////////////////////////////////////////
1348 /// Create a link from file1 to file2.
1349 
1350 int TSystem::Link(const char *, const char *)
1351 {
1352  AbstractMethod("Link");
1353  return -1;
1354 }
1355 
1356 ////////////////////////////////////////////////////////////////////////////////
1357 /// Create a symbolic link from file1 to file2.
1358 
1359 int TSystem::Symlink(const char *, const char *)
1360 {
1361  AbstractMethod("Symlink");
1362  return -1;
1363 }
1364 
1365 ////////////////////////////////////////////////////////////////////////////////
1366 /// Unlink, i.e. remove, a file.
1367 ///
1368 /// If the file is currently open by the current or another process, the behavior of this function is
1369 /// implementation-defined (in particular, POSIX systems unlink the file name, while Windows does not allow the
1370 /// file to be deleted and the operation is a no-op).
1371 
1372 int TSystem::Unlink(const char *)
1373 {
1374  AbstractMethod("Unlink");
1375  return -1;
1376 }
1377 
1378 ////////////////////////////////////////////////////////////////////////////////
1379 /// Get info about a file: id, size, flags, modification time.
1380 /// - Id is (statbuf.st_dev << 24) + statbuf.st_ino
1381 /// - Size is the file size
1382 /// - Flags is file type: 0 is regular file, bit 0 set executable,
1383 /// bit 1 set directory, bit 2 set special file
1384 /// (socket, fifo, pipe, etc.)
1385 /// Modtime is modification time.
1386 /// The function returns 0 in case of success and 1 if the file could
1387 /// not be stat'ed.
1388 
1389 int TSystem::GetPathInfo(const char *path, Long_t *id, Long_t *size,
1390  Long_t *flags, Long_t *modtime)
1391 {
1392  Long64_t lsize;
1393 
1394  int res = GetPathInfo(path, id, &lsize, flags, modtime);
1395 
1396  if (res == 0 && size) {
1397  if (sizeof(Long_t) == 4 && lsize > kMaxInt) {
1398  Error("GetPathInfo", "file %s > 2 GB, use GetPathInfo() with Long64_t size", path);
1399  *size = kMaxInt;
1400  } else {
1401  *size = (Long_t)lsize;
1402  }
1403  }
1404 
1405  return res;
1406 }
1407 
1408 ////////////////////////////////////////////////////////////////////////////////
1409 /// Get info about a file: id, size, flags, modification time.
1410 /// - Id is (statbuf.st_dev << 24) + statbuf.st_ino
1411 /// - Size is the file size
1412 /// - Flags is file type: 0 is regular file, bit 0 set executable,
1413 /// bit 1 set directory, bit 2 set special file
1414 /// (socket, fifo, pipe, etc.)
1415 /// Modtime is modification time.
1416 /// The function returns 0 in case of success and 1 if the file could
1417 /// not be stat'ed.
1418 
1419 int TSystem::GetPathInfo(const char *path, Long_t *id, Long64_t *size,
1420  Long_t *flags, Long_t *modtime)
1421 {
1422  FileStat_t buf;
1423 
1424  int res = GetPathInfo(path, buf);
1425 
1426  if (res == 0) {
1427  if (id)
1428  *id = (buf.fDev << 24) + buf.fIno;
1429  if (size)
1430  *size = buf.fSize;
1431  if (modtime)
1432  *modtime = buf.fMtime;
1433  if (flags) {
1434  *flags = 0;
1435  if (buf.fMode & (kS_IXUSR|kS_IXGRP|kS_IXOTH))
1436  *flags |= 1;
1437  if (R_ISDIR(buf.fMode))
1438  *flags |= 2;
1439  if (!R_ISREG(buf.fMode) && !R_ISDIR(buf.fMode))
1440  *flags |= 4;
1441  }
1442  }
1443 
1444  return res;
1445 }
1446 
1447 ////////////////////////////////////////////////////////////////////////////////
1448 /// Get info about a file. Info is returned in the form of a FileStat_t
1449 /// structure (see TSystem.h).
1450 /// The function returns 0 in case of success and 1 if the file could
1451 /// not be stat'ed.
1452 
1453 int TSystem::GetPathInfo(const char *, FileStat_t &)
1454 {
1455  AbstractMethod("GetPathInfo(const char*, FileStat_t&)");
1456  return 1;
1457 }
1458 
1459 ////////////////////////////////////////////////////////////////////////////////
1460 /// Get info about a file system: fs type, block size, number of blocks,
1461 /// number of free blocks.
1462 
1463 int TSystem::GetFsInfo(const char *, Long_t *, Long_t *, Long_t *, Long_t *)
1464 {
1465  AbstractMethod("GetFsInfo");
1466  return 1;
1467 }
1468 
1469 ////////////////////////////////////////////////////////////////////////////////
1470 /// Return a user configured or systemwide directory to create
1471 /// temporary files in.
1472 
1473 const char *TSystem::TempDirectory() const
1474 {
1475  AbstractMethod("TempDirectory");
1476  return 0;
1477 }
1478 
1479 ////////////////////////////////////////////////////////////////////////////////
1480 /// Create a secure temporary file by appending a unique
1481 /// 6 letter string to base. The file will be created in
1482 /// a standard (system) directory or in the directory
1483 /// provided in dir. The full filename is returned in base
1484 /// and a filepointer is returned for safely writing to the file
1485 /// (this avoids certain security problems). Returns 0 in case
1486 /// of error.
1487 
1488 FILE *TSystem::TempFileName(TString &, const char *)
1489 {
1490  AbstractMethod("TempFileName");
1491  return 0;
1492 }
1493 
1494 ////////////////////////////////////////////////////////////////////////////////
1495 /// Set the file permission bits. Returns -1 in case or error, 0 otherwise.
1496 
1497 int TSystem::Chmod(const char *, UInt_t)
1498 {
1499  AbstractMethod("Chmod");
1500  return -1;
1501 }
1502 
1503 ////////////////////////////////////////////////////////////////////////////////
1504 /// Set the process file creation mode mask.
1505 
1506 int TSystem::Umask(Int_t)
1507 {
1508  AbstractMethod("Umask");
1509  return -1;
1510 }
1511 
1512 ////////////////////////////////////////////////////////////////////////////////
1513 /// Set the a files modification and access times. If actime = 0 it will be
1514 /// set to the modtime. Returns 0 on success and -1 in case of error.
1515 
1516 int TSystem::Utime(const char *, Long_t, Long_t)
1517 {
1518  AbstractMethod("Utime");
1519  return -1;
1520 }
1521 
1522 ////////////////////////////////////////////////////////////////////////////////
1523 /// Find location of file in a search path. Return value points to TString for
1524 /// compatibility with Which(const char *, const char *, EAccessMode).
1525 /// Returns 0 in case file is not found.
1526 
1527 const char *TSystem::FindFile(const char *, TString&, EAccessMode)
1528 {
1529  AbstractMethod("FindFile");
1530  return 0;
1531 }
1532 
1533 ////////////////////////////////////////////////////////////////////////////////
1534 /// Find location of file in a search path. User must delete returned string.
1535 /// Returns 0 in case file is not found.
1536 
1537 char *TSystem::Which(const char *search, const char *wfil, EAccessMode mode)
1538 {
1539  TString wfilString(wfil);
1540  FindFile(search, wfilString, mode);
1541  if (wfilString.IsNull()) return 0;
1542  return StrDup(wfilString.Data());
1543 }
1544 
1545 //---- Users & Groups ----------------------------------------------------------
1546 
1547 ////////////////////////////////////////////////////////////////////////////////
1548 /// Returns the user's id. If user = 0, returns current user's id.
1549 
1550 Int_t TSystem::GetUid(const char * /*user*/)
1551 {
1552  AbstractMethod("GetUid");
1553  return 0;
1554 }
1555 
1556 ////////////////////////////////////////////////////////////////////////////////
1557 /// Returns the effective user id. The effective id corresponds to the
1558 /// set id bit on the file being executed.
1559 
1560 Int_t TSystem::GetEffectiveUid()
1561 {
1562  AbstractMethod("GetEffectiveUid");
1563  return 0;
1564 }
1565 
1566 ////////////////////////////////////////////////////////////////////////////////
1567 /// Returns the group's id. If group = 0, returns current user's group.
1568 
1569 Int_t TSystem::GetGid(const char * /*group*/)
1570 {
1571  AbstractMethod("GetGid");
1572  return 0;
1573 }
1574 
1575 ////////////////////////////////////////////////////////////////////////////////
1576 /// Returns the effective group id. The effective group id corresponds
1577 /// to the set id bit on the file being executed.
1578 
1579 Int_t TSystem::GetEffectiveGid()
1580 {
1581  AbstractMethod("GetEffectiveGid");
1582  return 0;
1583 }
1584 
1585 ////////////////////////////////////////////////////////////////////////////////
1586 /// Returns all user info in the UserGroup_t structure. The returned
1587 /// structure must be deleted by the user. In case of error 0 is returned.
1588 
1589 UserGroup_t *TSystem::GetUserInfo(Int_t /*uid*/)
1590 {
1591  AbstractMethod("GetUserInfo");
1592  return 0;
1593 }
1594 
1595 ////////////////////////////////////////////////////////////////////////////////
1596 /// Returns all user info in the UserGroup_t structure. If user = 0, returns
1597 /// current user's id info. The returned structure must be deleted by the
1598 /// user. In case of error 0 is returned.
1599 
1600 UserGroup_t *TSystem::GetUserInfo(const char * /*user*/)
1601 {
1602  AbstractMethod("GetUserInfo");
1603  return 0;
1604 }
1605 
1606 ////////////////////////////////////////////////////////////////////////////////
1607 /// Returns all group info in the UserGroup_t structure. The only active
1608 /// fields in the UserGroup_t structure for this call are:
1609 /// - fGid and fGroup
1610 /// The returned structure must be deleted by the user. In case of
1611 /// error 0 is returned.
1612 
1613 UserGroup_t *TSystem::GetGroupInfo(Int_t /*gid*/)
1614 {
1615  AbstractMethod("GetGroupInfo");
1616  return 0;
1617 }
1618 
1619 ////////////////////////////////////////////////////////////////////////////////
1620 /// Returns all group info in the UserGroup_t structure. The only active
1621 /// fields in the UserGroup_t structure for this call are:
1622 /// - fGid and fGroup
1623 /// If group = 0, returns current user's group. The returned structure
1624 /// must be deleted by the user. In case of error 0 is returned.
1625 
1626 UserGroup_t *TSystem::GetGroupInfo(const char * /*group*/)
1627 {
1628  AbstractMethod("GetGroupInfo");
1629  return 0;
1630 }
1631 
1632 //---- environment manipulation ------------------------------------------------
1633 
1634 ////////////////////////////////////////////////////////////////////////////////
1635 /// Set environment variable.
1636 
1637 void TSystem::Setenv(const char*, const char*)
1638 {
1639  AbstractMethod("Setenv");
1640 }
1641 
1642 ////////////////////////////////////////////////////////////////////////////////
1643 /// Unset environment variable.
1644 
1645 void TSystem::Unsetenv(const char *name)
1646 {
1647  Setenv(name, "");
1648 }
1649 
1650 ////////////////////////////////////////////////////////////////////////////////
1651 /// Get environment variable.
1652 
1653 const char *TSystem::Getenv(const char*)
1654 {
1655  AbstractMethod("Getenv");
1656  return 0;
1657 }
1658 
1659 //---- System Logging ----------------------------------------------------------
1660 
1661 ////////////////////////////////////////////////////////////////////////////////
1662 /// Open connection to system log daemon. For the use of the options and
1663 /// facility see the Unix openlog man page.
1664 
1665 void TSystem::Openlog(const char *, Int_t, ELogFacility)
1666 {
1667  AbstractMethod("Openlog");
1668 }
1669 
1670 ////////////////////////////////////////////////////////////////////////////////
1671 /// Send mess to syslog daemon. Level is the logging level and mess the
1672 /// message that will be written on the log.
1673 
1674 void TSystem::Syslog(ELogLevel, const char *)
1675 {
1676  AbstractMethod("Syslog");
1677 }
1678 
1679 ////////////////////////////////////////////////////////////////////////////////
1680 /// Close connection to system log daemon.
1681 
1682 void TSystem::Closelog()
1683 {
1684  AbstractMethod("Closelog");
1685 }
1686 
1687 //---- Standard output redirection ---------------------------------------------
1688 
1689 ////////////////////////////////////////////////////////////////////////////////
1690 /// Redirect standard output (stdout, stderr) to the specified file.
1691 /// If the file argument is 0 the output is set again to stderr, stdout.
1692 /// The second argument specifies whether the output should be added to the
1693 /// file ("a", default) or the file be truncated before ("w").
1694 /// The implementations of this function save internally the current state into
1695 /// a static structure.
1696 ///
1697 /// The call can be made reentrant by specifying the opaque structure pointed
1698 /// by 'h', which is filled with the relevant information. The handle 'h'
1699 /// obtained on the first call must then be used in any subsequent call,
1700 /// included ShowOutput, to display the redirected output.
1701 /// Returns 0 on success, -1 in case of error.
1702 
1703 Int_t TSystem::RedirectOutput(const char *, const char *, RedirectHandle_t *)
1704 {
1705  AbstractMethod("RedirectOutput");
1706  return -1;
1707 }
1708 
1709 ////////////////////////////////////////////////////////////////////////////////
1710 /// Display the content associated with the redirection described by the
1711 /// opaque handle 'h'.
1712 
1713 void TSystem::ShowOutput(RedirectHandle_t *h)
1714 {
1715  // Check input ...
1716  if (!h) {
1717  Error("ShowOutput", "handle not specified");
1718  return;
1719  }
1720 
1721  // ... and file access
1722  if (gSystem->AccessPathName(h->fFile, kReadPermission)) {
1723  Error("ShowOutput", "file '%s' cannot be read", h->fFile.Data());
1724  return;
1725  }
1726 
1727  // Open the file
1728  FILE *f = 0;
1729  if (!(f = fopen(h->fFile.Data(), "r"))) {
1730  Error("ShowOutput", "file '%s' cannot be open", h->fFile.Data());
1731  return;
1732  }
1733 
1734  // Determine the number of bytes to be read from the file.
1735  off_t ltot = lseek(fileno(f), (off_t) 0, SEEK_END);
1736  Int_t begin = (h->fReadOffSet > 0 && h->fReadOffSet < ltot) ? h->fReadOffSet : 0;
1737  lseek(fileno(f), (off_t) begin, SEEK_SET);
1738  Int_t left = ltot - begin;
1739 
1740  // Now readout from file
1741  const Int_t kMAXBUF = 16384;
1742  char buf[kMAXBUF];
1743  Int_t wanted = (left > kMAXBUF-1) ? kMAXBUF-1 : left;
1744  Int_t len;
1745  do {
1746  while ((len = read(fileno(f), buf, wanted)) < 0 &&
1747  TSystem::GetErrno() == EINTR)
1748  TSystem::ResetErrno();
1749 
1750  if (len < 0) {
1751  SysError("ShowOutput", "error reading log file");
1752  break;
1753  }
1754 
1755  // Null-terminate
1756  buf[len] = 0;
1757  fprintf(stderr,"%s", buf);
1758 
1759  // Update counters
1760  left -= len;
1761  wanted = (left > kMAXBUF) ? kMAXBUF : left;
1762 
1763  } while (len > 0 && left > 0);
1764 
1765  // Do not display twice the same thing
1766  h->fReadOffSet = ltot;
1767  fclose(f);
1768 }
1769 
1770 //---- Dynamic Loading ---------------------------------------------------------
1771 
1772 ////////////////////////////////////////////////////////////////////////////////
1773 /// Add a new directory to the dynamic path.
1774 
1775 void TSystem::AddDynamicPath(const char *)
1776 {
1777  AbstractMethod("AddDynamicPath");
1778 }
1779 
1780 ////////////////////////////////////////////////////////////////////////////////
1781 /// Return the dynamic path (used to find shared libraries).
1782 
1783 const char* TSystem::GetDynamicPath()
1784 {
1785  AbstractMethod("GetDynamicPath");
1786  return 0;
1787 }
1788 
1789 ////////////////////////////////////////////////////////////////////////////////
1790 /// Set the dynamic path to a new value.
1791 /// If the value of 'path' is zero, the dynamic path is reset to its
1792 /// default value.
1793 
1794 void TSystem::SetDynamicPath(const char *)
1795 {
1796  AbstractMethod("SetDynamicPath");
1797 }
1798 
1799 
1800 ////////////////////////////////////////////////////////////////////////////////
1801 /// Figure out if left and right points to the same
1802 /// object in the file system.
1803 
1804 static bool R__MatchFilename(const char *left, const char *right)
1805 {
1806  if (left == right) return kTRUE;
1807 
1808  if (left==0 || right==0) return kFALSE;
1809 
1810  if ( (strcmp(right,left)==0) ) {
1811  return kTRUE;
1812  }
1813 
1814 #ifdef G__WIN32
1815 
1816  char leftname[_MAX_PATH];
1817  char rightname[_MAX_PATH];
1818  _fullpath( leftname, left, _MAX_PATH );
1819  _fullpath( rightname, right, _MAX_PATH );
1820  return ((stricmp(leftname, rightname)==0));
1821 #else
1822  struct stat rightBuf;
1823  struct stat leftBuf;
1824  return ( ( 0 == stat( left, & leftBuf ) )
1825  && ( 0 == stat( right, & rightBuf ) )
1826  && ( leftBuf.st_dev == rightBuf.st_dev ) // Files on same device
1827  && ( leftBuf.st_ino == rightBuf.st_ino ) // Files on same inode (but this is not unique on AFS so we need the next 2 test
1828  && ( leftBuf.st_size == rightBuf.st_size ) // Files of same size
1829  && ( leftBuf.st_mtime == rightBuf.st_mtime ) // Files modified at the same time
1830  );
1831 #endif
1832 }
1833 
1834 ////////////////////////////////////////////////////////////////////////////////
1835 /// Load a shared library. Returns 0 on successful loading, 1 in
1836 /// case lib was already loaded, -1 in case lib does not exist
1837 /// or in case of error and -2 in case of version mismatch.
1838 /// When entry is specified the loaded lib is
1839 /// searched for this entry point (return -1 when entry does not exist,
1840 /// 0 otherwise). When the system flag is kTRUE, the library is considered
1841 /// a permanent system library that should not be unloaded during the
1842 /// course of the session.
1843 
1844 int TSystem::Load(const char *module, const char *entry, Bool_t system)
1845 {
1846  // don't load libraries that have already been loaded
1847  TString libs( GetLibraries() );
1848  TString moduleBasename( BaseName(module) );
1849  TString l(moduleBasename);
1850 
1851  Ssiz_t idx = l.Last('.');
1852  if (idx != kNPOS) {
1853  l.Remove(idx+1);
1854  }
1855  for (idx = libs.Index(l); idx != kNPOS; idx = libs.Index(l,idx+1)) {
1856  // The libs contains the sub-string 'l', let's make sure it is
1857  // not just part of a larger name.
1858  if (idx == 0 || libs[idx-1] == '/' || libs[idx-1] == '\\') {
1859  Ssiz_t len = libs.Length();
1860  idx += l.Length();
1861  if (!l.EndsWith(".") && libs[idx]=='.')
1862  idx++;
1863  // Skip the soversion.
1864  while (idx < len && isdigit(libs[idx])) {
1865  ++idx;
1866  // No need to test for len here, at worse idx==len and lib[idx]=='\0'
1867  if (libs[idx] == '.') {
1868  ++idx;
1869  }
1870  }
1871  while (idx < len && libs[idx] != '.') {
1872  if (libs[idx] == ' ' || idx+1 == len) {
1873  return 1;
1874  }
1875  ++idx;
1876  }
1877  }
1878  }
1879  if (l[l.Length()-1] == '.') {
1880  l.Remove(l.Length()-1);
1881  }
1882  if (l.BeginsWith("lib")) {
1883  l.Replace(0, 3, "-l");
1884  for(idx = libs.Index(l); idx != kNPOS; idx = libs.Index(l,idx+1)) {
1885  if ((idx == 0 || libs[idx-1] == ' ') &&
1886  (libs[idx+l.Length()] == ' ' || libs[idx+l.Length()] == 0)) {
1887  return 1;
1888  }
1889  }
1890  }
1891 
1892  char *path = DynamicPathName(module);
1893 
1894  int ret = -1;
1895  if (path) {
1896  // load any dependent libraries
1897  TString deplibs = gInterpreter->GetSharedLibDeps(moduleBasename);
1898  if (deplibs.IsNull()) {
1899  TString libmapfilename;
1900  libmapfilename = path;
1901  idx = libmapfilename.Last('.');
1902  if (idx != kNPOS) {
1903  libmapfilename.Remove(idx);
1904  }
1905  libmapfilename += ".rootmap";
1906  if (gSystem->GetPathInfo(libmapfilename, 0, (Long_t*)0, 0, 0) == 0) {
1907  if (gDebug > 0) Info("Load", "loading %s", libmapfilename.Data());
1908  gInterpreter->LoadLibraryMap(libmapfilename);
1909  deplibs = gInterpreter->GetSharedLibDeps(moduleBasename);
1910  }
1911  } else {
1912  TString delim(" ");
1913  TObjArray *tokens = deplibs.Tokenize(delim);
1914  for (Int_t i = tokens->GetEntriesFast()-1; i > 0; i--) {
1915  const char *deplib = ((TObjString*)tokens->At(i))->GetName();
1916  if (strcmp(module,deplib)==0) {
1917  continue;
1918  }
1919  if (gDebug > 0)
1920  Info("Load", "loading dependent library %s for library %s",
1921  deplib, ((TObjString*)tokens->At(0))->GetName());
1922  if ((ret = Load(deplib, "", system)) < 0) {
1923  delete tokens;
1924  delete [] path;
1925  return ret;
1926  }
1927  }
1928  delete tokens;
1929  }
1930  if (!system) {
1931  // Mark the library in $ROOTSYS/lib as system.
1932  const char *dirname = DirName(path);
1933  system = R__MatchFilename(TROOT::GetLibDir(), dirname);
1934 
1935  if (!system) {
1936  system = R__MatchFilename(TROOT::GetBinDir(), dirname);
1937  }
1938  }
1939 
1940  gLibraryVersionIdx++;
1941  if (gLibraryVersionIdx == gLibraryVersionMax) {
1942  gLibraryVersionMax *= 2;
1943  gLibraryVersion = TStorage::ReAllocInt(gLibraryVersion, gLibraryVersionMax, gLibraryVersionIdx);
1944  }
1945  ret = gInterpreter->Load(path, system);
1946  if (ret < 0) ret = -1;
1947  if (gDebug > 0)
1948  Info("Load", "loaded library %s, status %d", path, ret);
1949  if (ret == 0 && gLibraryVersion[gLibraryVersionIdx]) {
1950  int v = TROOT::ConvertVersionCode2Int(gLibraryVersion[gLibraryVersionIdx]);
1951  Error("Load", "version mismatch, %s = %d, ROOT = %d",
1952  path, v, gROOT->GetVersionInt());
1953  ret = -2;
1954  gLibraryVersion[gLibraryVersionIdx] = 0;
1955  }
1956  gLibraryVersionIdx--;
1957  delete [] path;
1958  }
1959 
1960  if (!entry || !entry[0] || ret < 0) return ret;
1961 
1962  Func_t f = DynFindSymbol(module, entry);
1963  if (f) return 0;
1964  return -1;
1965 }
1966 
1967 ///////////////////////////////////////////////////////////////////////////////
1968 /// Load all libraries known to ROOT via the rootmap system.
1969 /// Returns the number of top level libraries successfully loaded.
1970 
1971 UInt_t TSystem::LoadAllLibraries()
1972 {
1973  UInt_t nlibs = 0;
1974 
1975  TEnv* mapfile = gInterpreter->GetMapfile();
1976  if (!mapfile || !mapfile->GetTable()) return 0;
1977 
1978  std::set<std::string> loadedlibs;
1979  std::set<std::string> failedlibs;
1980 
1981  TEnvRec* rec = 0;
1982  TIter iEnvRec(mapfile->GetTable());
1983  while ((rec = (TEnvRec*) iEnvRec())) {
1984  TString libs = rec->GetValue();
1985  TString lib;
1986  Ssiz_t pos = 0;
1987  while (libs.Tokenize(lib, pos)) {
1988  // check that none of the libs failed to load
1989  if (failedlibs.find(lib.Data()) != failedlibs.end()) {
1990  // don't load it or any of its dependencies
1991  libs = "";
1992  break;
1993  }
1994  }
1995  pos = 0;
1996  while (libs.Tokenize(lib, pos)) {
1997  // ignore libCore - it's already loaded
1998  if (lib.BeginsWith("libCore"))
1999  continue;
2000 
2001  if (loadedlibs.find(lib.Data()) == loadedlibs.end()) {
2002  // just load the first library - TSystem will do the rest.
2003  auto res = gSystem->Load(lib);
2004  if (res >=0) {
2005  if (res == 0) ++nlibs;
2006  loadedlibs.insert(lib.Data());
2007  } else {
2008  failedlibs.insert(lib.Data());
2009  }
2010  }
2011  }
2012  }
2013  return nlibs;
2014 }
2015 
2016 ////////////////////////////////////////////////////////////////////////////////
2017 /// Find a dynamic library called lib using the system search paths.
2018 /// Appends known extensions if needed. Returned string must be deleted
2019 /// by the user!
2020 
2021 char *TSystem::DynamicPathName(const char *lib, Bool_t quiet /*=kFALSE*/)
2022 {
2023  TString sLib(lib);
2024  if (FindDynamicLibrary(sLib, quiet))
2025  return StrDup(sLib);
2026  return 0;
2027 }
2028 
2029 ////////////////////////////////////////////////////////////////////////////////
2030 /// Find a dynamic library using the system search paths. lib will be updated
2031 /// to contain the absolute filename if found. Returns lib if found, or NULL
2032 /// if a library called lib was not found.
2033 /// This function does not open the library.
2034 
2035 const char *TSystem::FindDynamicLibrary(TString&, Bool_t)
2036 {
2037  AbstractMethod("FindDynamicLibrary");
2038  return 0;
2039 }
2040 
2041 ////////////////////////////////////////////////////////////////////////////////
2042 /// Find specific entry point in specified library. Specify "*" for lib
2043 /// to search in all libraries.
2044 
2045 Func_t TSystem::DynFindSymbol(const char * /*lib*/, const char *entry)
2046 {
2047  return (Func_t) gInterpreter->FindSym(entry);
2048 }
2049 
2050 ////////////////////////////////////////////////////////////////////////////////
2051 /// Unload a shared library.
2052 
2053 void TSystem::Unload(const char *module)
2054 {
2055  char *path;
2056  if ((path = DynamicPathName(module))) {
2057  gInterpreter->UnloadFile(path);
2058  delete [] path;
2059  }
2060 }
2061 
2062 ////////////////////////////////////////////////////////////////////////////////
2063 /// List symbols in a shared library.
2064 
2065 void TSystem::ListSymbols(const char *, const char *)
2066 {
2067  AbstractMethod("ListSymbols");
2068 }
2069 
2070 ////////////////////////////////////////////////////////////////////////////////
2071 /// List all loaded shared libraries. Regexp is a wildcard expression,
2072 /// see TRegexp::MakeWildcard.
2073 
2074 void TSystem::ListLibraries(const char *regexp)
2075 {
2076  TString libs = GetLibraries(regexp);
2077  TRegexp separator("[^ \\t\\s]+");
2078  TString s;
2079  Ssiz_t start = 0, index = 0, end = 0;
2080  int i = 0;
2081 
2082  Printf(" ");
2083  Printf("Loaded shared libraries");
2084  Printf("=======================");
2085 
2086  while ((start < libs.Length()) && (index != kNPOS)) {
2087  index = libs.Index(separator, &end, start);
2088  if (index >= 0) {
2089  s = libs(index, end);
2090  if (s.BeginsWith("-")) {
2091  if (s.BeginsWith("-l")) {
2092  Printf("%s", s.Data());
2093  i++;
2094  }
2095  } else {
2096  Printf("%s", s.Data());
2097  i++;
2098  }
2099  }
2100  start += end+1;
2101  }
2102 
2103  Printf("-----------------------");
2104  Printf("%d libraries loaded", i);
2105  Printf("=======================");
2106 }
2107 
2108 ////////////////////////////////////////////////////////////////////////////////
2109 /// Return the thread local storage for the custom last error message
2110 
2111 TString &TSystem::GetLastErrorString()
2112 {
2113  TTHREAD_TLS_DECL( TString, gLastErrorString);
2114  return gLastErrorString;
2115 }
2116 
2117 ////////////////////////////////////////////////////////////////////////////////
2118 /// Return the thread local storage for the custom last error message
2119 
2120 const TString &TSystem::GetLastErrorString() const
2121 {
2122  return const_cast<TSystem*>(this)->GetLastErrorString();
2123 }
2124 
2125 ////////////////////////////////////////////////////////////////////////////////
2126 /// Get list of shared libraries loaded at the start of the executable.
2127 /// Returns 0 in case list cannot be obtained or in case of error.
2128 
2129 const char *TSystem::GetLinkedLibraries()
2130 {
2131  return nullptr;
2132 }
2133 
2134 ////////////////////////////////////////////////////////////////////////////////
2135 /// Return a space separated list of loaded shared libraries.
2136 /// Regexp is a wildcard expression, see TRegexp::MakeWildcard.
2137 /// This list is of a format suitable for a linker, i.e it may contain
2138 /// -Lpathname and/or -lNameOfLib.
2139 /// Option can be any of:
2140 /// - S: shared libraries loaded at the start of the executable, because
2141 /// they were specified on the link line.
2142 /// - D: shared libraries dynamically loaded after the start of the program.
2143 /// For MacOS only:
2144 /// - L: list the .dylib rather than the .so (this is intended for linking)
2145 /// This options is not the default
2146 
2147 const char *TSystem::GetLibraries(const char *regexp, const char *options,
2148  Bool_t isRegexp)
2149 {
2150  fListLibs.Clear();
2151 
2152  TString libs;
2153  TString opt(options);
2154  Bool_t so2dylib = (opt.First('L') != kNPOS);
2155  if (so2dylib)
2156  opt.ReplaceAll("L", "");
2157 
2158  if (opt.IsNull() || opt.First('D') != kNPOS)
2159  libs += gInterpreter->GetSharedLibs();
2160 
2161  // Cint currently register all libraries that
2162  // are loaded and have a dictionary in them, this
2163  // includes all the libraries that are included
2164  // in the list of (hard) linked libraries.
2165 
2166  TString slinked;
2167  const char *linked;
2168  if ((linked = GetLinkedLibraries())) {
2169  if (fLinkedLibs != LINKEDLIBS) {
2170  // This is not the default value, we need to keep the custom part.
2171  TString custom = fLinkedLibs;
2172  custom.ReplaceAll(LINKEDLIBS,linked);
2173  if (custom == fLinkedLibs) {
2174  // no replacement done, let's append linked
2175  slinked.Append(linked);
2176  slinked.Append(" ");
2177  }
2178  slinked.Append(custom);
2179  } else {
2180  slinked.Append(linked);
2181  }
2182  } else {
2183  slinked.Append(fLinkedLibs);
2184  }
2185 
2186  if (opt.IsNull() || opt.First('S') != kNPOS) {
2187  // We are done, the statically linked libraries are already included.
2188  if (libs.Length() == 0) {
2189  libs = slinked;
2190  } else {
2191  // We need to add the missing linked library
2192 
2193  static TString lastLinked;
2194  static TString lastAddMissing;
2195  if ( lastLinked != slinked ) {
2196  // Recalculate only if there was a change.
2197  static TRegexp separator("[^ \\t\\s]+");
2198  lastLinked = slinked;
2199  lastAddMissing.Clear();
2200 
2201  Ssiz_t start, index, end;
2202  start = index = end = 0;
2203 
2204  while ((start < slinked.Length()) && (index != kNPOS)) {
2205  index = slinked.Index(separator,&end,start);
2206  if (index >= 0) {
2207  TString sub = slinked(index,end);
2208  if (sub[0]=='-' && sub[1]=='L') {
2209  lastAddMissing.Prepend(" ");
2210  lastAddMissing.Prepend(sub);
2211  } else {
2212  if (libs.Index(sub) == kNPOS) {
2213  lastAddMissing.Prepend(" ");
2214  lastAddMissing.Prepend(sub);
2215  }
2216  }
2217  }
2218  start += end+1;
2219  }
2220  }
2221  libs.Prepend(lastAddMissing);
2222  }
2223  } else if (libs.Length() != 0) {
2224  // Let remove the statically linked library
2225  // from the list.
2226  static TRegexp separator("[^ \\t\\s]+");
2227  Ssiz_t start, index, end;
2228  start = index = end = 0;
2229 
2230  while ((start < slinked.Length()) && (index != kNPOS)) {
2231  index = slinked.Index(separator,&end,start);
2232  if (index >= 0) {
2233  TString sub = slinked(index,end);
2234  if (sub[0]!='-' && sub[1]!='L') {
2235  libs.ReplaceAll(sub,"");
2236  }
2237  }
2238  start += end+1;
2239  }
2240  libs = libs.Strip(TString::kBoth);
2241  }
2242 
2243  // Select according to regexp
2244  if (regexp && *regexp) {
2245  static TRegexp separator("[^ \\t\\s]+");
2246  TRegexp user_re(regexp, kTRUE);
2247  TString s;
2248  Ssiz_t start, index, end;
2249  start = index = end = 0;
2250 
2251  while ((start < libs.Length()) && (index != kNPOS)) {
2252  index = libs.Index(separator,&end,start);
2253  if (index >= 0) {
2254  s = libs(index,end);
2255  if ((isRegexp && s.Index(user_re) != kNPOS) ||
2256  (!isRegexp && s.Index(regexp) != kNPOS)) {
2257  if (!fListLibs.IsNull())
2258  fListLibs.Append(" ");
2259  fListLibs.Append(s);
2260  }
2261  }
2262  start += end+1;
2263  }
2264  } else
2265  fListLibs = libs;
2266 
2267 #if defined(R__MACOSX)
2268 // We need to remove the libraries that are dynamically loaded and not linked
2269 {
2270  TString libs2 = fListLibs;
2271  TString maclibs;
2272 
2273  static TRegexp separator("[^ \\t\\s]+");
2274  static TRegexp dynload("/lib-dynload/");
2275 
2276  Ssiz_t start, index, end;
2277  start = index = end = 0;
2278 
2279  while ((start < libs2.Length()) && (index != kNPOS)) {
2280  index = libs2.Index(separator, &end, start);
2281  if (index >= 0) {
2282  TString s = libs2(index, end);
2283  if (s.Index(dynload) == kNPOS) {
2284  if (!maclibs.IsNull()) maclibs.Append(" ");
2285  maclibs.Append(s);
2286  }
2287  }
2288  start += end+1;
2289  }
2290  fListLibs = maclibs;
2291 }
2292 #endif
2293 
2294 #if defined(R__MACOSX) && !defined(MAC_OS_X_VERSION_10_5)
2295  if (so2dylib) {
2296  TString libs2 = fListLibs;
2297  TString maclibs;
2298 
2299  static TRegexp separator("[^ \\t\\s]+");
2300  static TRegexp user_so("\\.so$");
2301 
2302  Ssiz_t start, index, end;
2303  start = index = end = 0;
2304 
2305  while ((start < libs2.Length()) && (index != kNPOS)) {
2306  index = libs2.Index(separator, &end, start);
2307  if (index >= 0) {
2308  // Change .so into .dylib and remove the
2309  // path info if it is not accessible
2310  TString s = libs2(index, end);
2311  if (s.Index(user_so) != kNPOS) {
2312  s.ReplaceAll(".so",".dylib");
2313  if ( GetPathInfo( s, 0, (Long_t*)0, 0, 0 ) != 0 ) {
2314  s.Replace( 0, s.Last('/')+1, 0, 0);
2315  s.Replace( 0, s.Last('\\')+1, 0, 0);
2316  }
2317  }
2318  if (!maclibs.IsNull()) maclibs.Append(" ");
2319  maclibs.Append(s);
2320  }
2321  start += end+1;
2322  }
2323  fListLibs = maclibs;
2324  }
2325 #endif
2326 
2327  return fListLibs.Data();
2328 }
2329 
2330 //---- RPC ---------------------------------------------------------------------
2331 
2332 ////////////////////////////////////////////////////////////////////////////////
2333 /// Get Internet Protocol (IP) address of host.
2334 
2335 TInetAddress TSystem::GetHostByName(const char *)
2336 {
2337  AbstractMethod("GetHostByName");
2338  return TInetAddress();
2339 }
2340 
2341 ////////////////////////////////////////////////////////////////////////////////
2342 /// Get Internet Protocol (IP) address of remote host and port #.
2343 
2344 TInetAddress TSystem::GetPeerName(int)
2345 {
2346  AbstractMethod("GetPeerName");
2347  return TInetAddress();
2348 }
2349 
2350 ////////////////////////////////////////////////////////////////////////////////
2351 /// Get Internet Protocol (IP) address of host and port #.
2352 
2353 TInetAddress TSystem::GetSockName(int)
2354 {
2355  AbstractMethod("GetSockName");
2356  return TInetAddress();
2357 }
2358 
2359 ////////////////////////////////////////////////////////////////////////////////
2360 /// Get port # of internet service.
2361 
2362 int TSystem::GetServiceByName(const char *)
2363 {
2364  AbstractMethod("GetServiceByName");
2365  return -1;
2366 }
2367 
2368 ////////////////////////////////////////////////////////////////////////////////
2369 /// Get name of internet service.
2370 
2371 char *TSystem::GetServiceByPort(int)
2372 {
2373  AbstractMethod("GetServiceByPort");
2374  return 0;
2375 }
2376 
2377 ////////////////////////////////////////////////////////////////////////////////
2378 /// Open a connection to another host.
2379 
2380 int TSystem::OpenConnection(const char*, int, int, const char*)
2381 {
2382  AbstractMethod("OpenConnection");
2383  return -1;
2384 }
2385 
2386 ////////////////////////////////////////////////////////////////////////////////
2387 /// Announce TCP/IP service.
2388 
2389 int TSystem::AnnounceTcpService(int, Bool_t, int, int)
2390 {
2391  AbstractMethod("AnnounceTcpService");
2392  return -1;
2393 }
2394 
2395 ////////////////////////////////////////////////////////////////////////////////
2396 /// Announce UDP service.
2397 
2398 int TSystem::AnnounceUdpService(int, int)
2399 {
2400  AbstractMethod("AnnounceUdpService");
2401  return -1;
2402 }
2403 
2404 ////////////////////////////////////////////////////////////////////////////////
2405 /// Announce unix domain service.
2406 
2407 int TSystem::AnnounceUnixService(int, int)
2408 {
2409  AbstractMethod("AnnounceUnixService");
2410  return -1;
2411 }
2412 
2413 ////////////////////////////////////////////////////////////////////////////////
2414 /// Announce unix domain service.
2415 
2416 int TSystem::AnnounceUnixService(const char *, int)
2417 {
2418  AbstractMethod("AnnounceUnixService");
2419  return -1;
2420 }
2421 
2422 ////////////////////////////////////////////////////////////////////////////////
2423 /// Accept a connection.
2424 
2425 int TSystem::AcceptConnection(int)
2426 {
2427  AbstractMethod("AcceptConnection");
2428  return -1;
2429 }
2430 
2431 ////////////////////////////////////////////////////////////////////////////////
2432 /// Close socket connection.
2433 
2434 void TSystem::CloseConnection(int, Bool_t)
2435 {
2436  AbstractMethod("CloseConnection");
2437 }
2438 
2439 ////////////////////////////////////////////////////////////////////////////////
2440 /// Receive exactly length bytes into buffer. Use opt to receive out-of-band
2441 /// data or to have a peek at what is in the buffer (see TSocket).
2442 
2443 int TSystem::RecvRaw(int, void *, int, int)
2444 {
2445  AbstractMethod("RecvRaw");
2446  return -1;
2447 }
2448 
2449 ////////////////////////////////////////////////////////////////////////////////
2450 /// Send exactly length bytes from buffer. Use opt to send out-of-band
2451 /// data (see TSocket).
2452 
2453 int TSystem::SendRaw(int, const void *, int, int)
2454 {
2455  AbstractMethod("SendRaw");
2456  return -1;
2457 }
2458 
2459 ////////////////////////////////////////////////////////////////////////////////
2460 /// Receive a buffer headed by a length indicator.
2461 
2462 int TSystem::RecvBuf(int, void *, int)
2463 {
2464  AbstractMethod("RecvBuf");
2465  return -1;
2466 }
2467 
2468 ////////////////////////////////////////////////////////////////////////////////
2469 /// Send a buffer headed by a length indicator.
2470 
2471 int TSystem::SendBuf(int, const void *, int)
2472 {
2473  AbstractMethod("SendBuf");
2474  return -1;
2475 }
2476 
2477 ////////////////////////////////////////////////////////////////////////////////
2478 /// Set socket option.
2479 
2480 int TSystem::SetSockOpt(int, int, int)
2481 {
2482  AbstractMethod("SetSockOpt");
2483  return -1;
2484 }
2485 
2486 ////////////////////////////////////////////////////////////////////////////////
2487 /// Get socket option.
2488 
2489 int TSystem::GetSockOpt(int, int, int*)
2490 {
2491  AbstractMethod("GetSockOpt");
2492  return -1;
2493 }
2494 
2495 //---- System, CPU and Memory info ---------------------------------------------
2496 
2497 ////////////////////////////////////////////////////////////////////////////////
2498 /// Returns static system info, like OS type, CPU type, number of CPUs
2499 /// RAM size, etc into the SysInfo_t structure. Returns -1 in case of error,
2500 /// 0 otherwise.
2501 
2502 int TSystem::GetSysInfo(SysInfo_t *) const
2503 {
2504  AbstractMethod("GetSysInfo");
2505  return -1;
2506 }
2507 
2508 ////////////////////////////////////////////////////////////////////////////////
2509 /// Returns cpu load average and load info into the CpuInfo_t structure.
2510 /// Returns -1 in case of error, 0 otherwise. Use sampleTime to set the
2511 /// interval over which the CPU load will be measured, in ms (default 1000).
2512 
2513 int TSystem::GetCpuInfo(CpuInfo_t *, Int_t) const
2514 {
2515  AbstractMethod("GetCpuInfo");
2516  return -1;
2517 }
2518 
2519 ////////////////////////////////////////////////////////////////////////////////
2520 /// Returns ram and swap memory usage info into the MemInfo_t structure.
2521 /// Returns -1 in case of error, 0 otherwise.
2522 
2523 int TSystem::GetMemInfo(MemInfo_t *) const
2524 {
2525  AbstractMethod("GetMemInfo");
2526  return -1;
2527 }
2528 
2529 ////////////////////////////////////////////////////////////////////////////////
2530 /// Returns cpu and memory used by this process into the ProcInfo_t structure.
2531 /// Returns -1 in case of error, 0 otherwise.
2532 
2533 int TSystem::GetProcInfo(ProcInfo_t *) const
2534 {
2535  AbstractMethod("GetProcInfo");
2536  return -1;
2537 }
2538 
2539 //---- Script Compiler ---------------------------------------------------------
2540 
2541 void AssignAndDelete(TString& target, char *tobedeleted)
2542 {
2543  // Assign the char* value to the TString and then delete it.
2544 
2545  target = tobedeleted;
2546  delete [] tobedeleted;
2547 }
2548 
2549 #ifdef WIN32
2550 
2551 static TString R__Exec(const char *cmd)
2552 {
2553  // Execute a command and return the stdout in a string.
2554 
2555  FILE * f = gSystem->OpenPipe(cmd,"r");
2556  if (!f) {
2557  return "";
2558  }
2559  TString result;
2560 
2561  char x;
2562  while ((x = fgetc(f))!=EOF ) {
2563  if (x=='\n' || x=='\r') break;
2564  result += x;
2565  }
2566 
2567  fclose(f);
2568  return result;
2569 }
2570 
2571 static void R__FixLink(TString &cmd)
2572 {
2573  // Replace the call to 'link' by a full path name call based on where cl.exe is.
2574  // This prevents us from using inadvertently the link.exe provided by cygwin.
2575 
2576  // check if link is the microsoft one...
2577  TString res = R__Exec("link 2>&1");
2578  if (res.Length()) {
2579  if (res.Contains("Microsoft (R) Incremental Linker"))
2580  return;
2581  }
2582  // else check availability of cygpath...
2583  res = R__Exec("cygpath . 2>&1");
2584  if (res.Length()) {
2585  if (res != ".")
2586  return;
2587  }
2588 
2589  res = R__Exec("which cl.exe 2>&1|grep cl|sed 's,cl\\.exe$,link\\.exe,' 2>&1");
2590  if (res.Length()) {
2591  res = R__Exec(Form("cygpath -w '%s' 2>&1",res.Data()));
2592  if (res.Length()) {
2593  cmd.ReplaceAll(" link ",Form(" \"%s\" ",res.Data()));
2594  }
2595  }
2596 }
2597 #endif
2598 
2599 #if defined(__CYGWIN__)
2600 static void R__AddPath(TString &target, const TString &path) {
2601  if (path.Length() > 2 && path[1]==':') {
2602  target += TString::Format("/cygdrive/%c",path[0]) + path(2,path.Length()-2);
2603  } else {
2604  target += path;
2605  }
2606 }
2607 #else
2608 static void R__AddPath(TString &target, const TString &path) {
2609  target += path;
2610 }
2611 #endif
2612 
2613 static void R__WriteDependencyFile(const TString & build_loc, const TString &depfilename, const TString &filename, const TString &library, const TString &libname,
2614  const TString &extension, const char *version_var_prefix, const TString &includes, const TString &defines, const TString &incPath)
2615 {
2616  // Generate the dependency via standard output, not searching the
2617  // standard include directories,
2618 
2619 #ifndef WIN32
2620  const char * stderrfile = "/dev/null";
2621 #else
2622  TString stderrfile;
2623  AssignAndDelete( stderrfile, gSystem->ConcatFileName(build_loc,"stderr.tmp") );
2624 #endif
2625  TString bakdepfilename = depfilename + ".bak";
2626 
2627 #ifdef WIN32
2628  TString touch = "echo # > "; touch += "\"" + depfilename + "\"";
2629 #else
2630  TString touch = "echo > "; touch += "\"" + depfilename + "\"";
2631 #endif
2632  TString builddep = "rmkdepend";
2633  gSystem->PrependPathName(TROOT::GetBinDir(), builddep);
2634  builddep += " \"-f";
2635  builddep += depfilename;
2636  builddep += "\" -o_" + extension + "." + gSystem->GetSoExt() + " ";
2637  if (build_loc.BeginsWith(gSystem->WorkingDirectory())) {
2638  Int_t len = strlen(gSystem->WorkingDirectory());
2639  if ( build_loc.Length() > (len+1) ) {
2640  builddep += " \"-p";
2641  if (build_loc[len] == '/' || build_loc[len+1] != '\\' ) {
2642  // Since the path is now ran through TSystem::ExpandPathName the single \ is also possible.
2643  R__AddPath(builddep, build_loc.Data() + len + 1 );
2644  } else {
2645  // Case of dir\\name
2646  R__AddPath(builddep, build_loc.Data() + len + 2 );
2647  }
2648  builddep += "/\" ";
2649  }
2650  } else {
2651  builddep += " \"-p";
2652  R__AddPath(builddep, build_loc);
2653  builddep += "/\" ";
2654  }
2655  builddep += " -Y -- ";
2656  TString rootsysInclude = TROOT::GetIncludeDir();
2657  builddep += " \"-I"+rootsysInclude+"\" "; // cflags
2658  builddep += includes;
2659  builddep += defines;
2660  builddep += " -- \"";
2661  builddep += filename;
2662  builddep += "\" ";
2663  TString targetname;
2664  if (library.BeginsWith(gSystem->WorkingDirectory())) {
2665  Int_t len = strlen(gSystem->WorkingDirectory());
2666  if ( library.Length() > (len+1) ) {
2667  if (library[len] == '/' || library[len+1] != '\\' ) {
2668  targetname = library.Data() + len + 1;
2669  } else {
2670  targetname = library.Data() + len + 2;
2671  }
2672  } else {
2673  targetname = library;
2674  }
2675  } else {
2676  targetname = library;
2677  }
2678  builddep += " \"";
2679  builddep += "-t";
2680  R__AddPath(builddep, targetname);
2681  builddep += "\" > ";
2682  builddep += stderrfile;
2683  builddep += " 2>&1 ";
2684 
2685  TString adddictdep = "echo ";
2686  R__AddPath(adddictdep,targetname);
2687  adddictdep += ": ";
2688 #if defined(R__HAS_CLING_DICTVERSION)
2689  {
2690  char *clingdictversion = gSystem->Which(incPath,"clingdictversion.h");
2691  if (clingdictversion) {
2692  R__AddPath(adddictdep,clingdictversion);
2693  adddictdep += " ";
2694  delete [] clingdictversion;
2695  } else {
2696  R__AddPath(adddictdep,rootsysInclude+"/clingdictversion.h ");
2697  }
2698  }
2699 #endif
2700  {
2701  const char *dictHeaders[] = { "RVersion.h", "RConfig.h", "TClass.h",
2702  "TDictAttributeMap.h","TInterpreter.h","TROOT.h","TBuffer.h",
2703  "TMemberInspector.h","TError.h","RtypesImp.h","TIsAProxy.h",
2704  "TFileMergeInfo.h","TCollectionProxyInfo.h"};
2705 
2706  for (unsigned int h=0; h < sizeof(dictHeaders)/sizeof(dictHeaders[0]); ++h)
2707  {
2708  char *rootVersion = gSystem->Which(incPath,dictHeaders[h]);
2709  if (rootVersion) {
2710  R__AddPath(adddictdep,rootVersion);
2711  delete [] rootVersion;
2712  } else {
2713  R__AddPath(adddictdep,rootsysInclude + "/" + dictHeaders[h]);
2714  }
2715  adddictdep += " ";
2716  }
2717  }
2718  {
2719  // Add dependency on rootcling.
2720  char *rootCling = gSystem->Which(gSystem->Getenv("PATH"),"rootcling");
2721  if (rootCling) {
2722  R__AddPath(adddictdep,rootCling);
2723  adddictdep += " ";
2724  delete [] rootCling;
2725  }
2726  }
2727  adddictdep += " >> \""+depfilename+"\"";
2728 
2729  TString addversiondep( "echo ");
2730  addversiondep += libname + version_var_prefix + " \"" + ROOT_RELEASE + "\" >> \""+depfilename+"\"";
2731 
2732  if (gDebug > 4) {
2733  ::Info("ACLiC", "%s", touch.Data());
2734  ::Info("ACLiC", "%s", builddep.Data());
2735  ::Info("ACLiC", "%s", adddictdep.Data());
2736  }
2737 
2738  Int_t depbuilt = !gSystem->Exec(touch);
2739  if (depbuilt) depbuilt = !gSystem->Exec(builddep);
2740  if (depbuilt) depbuilt = !gSystem->Exec(adddictdep);
2741  if (depbuilt) depbuilt = !gSystem->Exec(addversiondep);
2742 
2743  if (!depbuilt) {
2744  ::Warning("ACLiC","Failed to generate the dependency file for %s",
2745  library.Data());
2746  } else {
2747 #ifdef WIN32
2748  gSystem->Unlink(stderrfile);
2749 #endif
2750  gSystem->Unlink(bakdepfilename);
2751  }
2752 }
2753 
2754 ////////////////////////////////////////////////////////////////////////////////
2755 /// This method compiles and loads a shared library containing
2756 /// the code from the file "filename".
2757 ///
2758 /// The return value is true (1) in case of success and false (0)
2759 /// in case of error.
2760 ///
2761 /// The possible options are:
2762 /// - k : keep the shared library after the session end.
2763 /// - f : force recompilation.
2764 /// - g : compile with debug symbol
2765 /// - O : optimized the code
2766 /// - c : compile only, do not attempt to load the library.
2767 /// - s : silence all informational output
2768 /// - v : output all information output
2769 /// - d : debug ACLiC, keep all the output files.
2770 /// - - : if buildir is set, use a flat structure (see buildir below)
2771 ///
2772 /// If library_specified is specified, CompileMacro generates the file
2773 /// "library_specified".soext where soext is the shared library extension for
2774 /// the current platform.
2775 ///
2776 /// If build_dir is specified, it is used as an alternative 'root' for the
2777 /// generation of the shared library. The library is stored in a sub-directories
2778 /// of 'build_dir' including the full pathname of the script unless a flat
2779 /// directory structure is requested ('-' option). With the '-' option the libraries
2780 /// are created directly in the directory 'build_dir'; in particular this means that
2781 /// 2 scripts with the same name in different source directory will over-write each
2782 /// other's library.
2783 /// See also TSystem::SetBuildDir.
2784 ///
2785 /// If dirmode is not zero and we need to create the target directory, the
2786 /// file mode bit will be change to 'dirmode' using chmod.
2787 ///
2788 /// If library_specified is not specified, CompileMacro generate a default name
2789 /// for library by taking the name of the file "filename" but replacing the
2790 /// dot before the extension by an underscore and by adding the shared
2791 /// library extension for the current platform.
2792 /// For example on most platform, hsimple.cxx will generate hsimple_cxx.so
2793 ///
2794 /// It uses the directive fMakeSharedLibs to create a shared library.
2795 /// If loading the shared library fails, it tries to output a list of missing
2796 /// symbols by creating an executable (on some platforms like OSF, this does
2797 /// not HAVE to be an executable) containing the script. It uses the
2798 /// directive fMakeExe to do so.
2799 /// For both directives, before passing them to TSystem::Exec, it expands the
2800 /// variables $SourceFiles, $SharedLib, $LibName, $IncludePath, $LinkedLibs,
2801 /// $DepLibs, $ExeName and $ObjectFiles. See SetMakeSharedLib() for more
2802 /// information on those variables.
2803 ///
2804 /// This method is used to implement the following feature:
2805 ///
2806 /// Synopsis:
2807 ///
2808 /// The purpose of this addition is to allow the user to use an external
2809 /// compiler to create a shared library from its C++ macro (scripts).
2810 /// Currently in order to execute a script, a user has to type at the root
2811 /// prompt
2812 /// ~~~ {.cpp}
2813 /// .X myfunc.C(arg1,arg2)
2814 /// ~~~
2815 /// We allow them to type:
2816 /// ~~~ {.cpp}
2817 /// .X myfunc.C++(arg1,arg2)
2818 /// ~~~
2819 /// or
2820 /// ~~~ {.cpp}
2821 /// .X myfunc.C+(arg1,arg2)
2822 /// ~~~
2823 /// In which case an external compiler will be called to create a shared
2824 /// library. This shared library will then be loaded and the function
2825 /// myfunc will be called with the two arguments. With '++' the shared library
2826 /// is always recompiled. With '+' the shared library is recompiled only
2827 /// if it does not exist yet or the macro file is newer than the shared
2828 /// library.
2829 ///
2830 /// Of course the + and ++ notation is supported in similar way for .x and .L.
2831 ///
2832 /// Through the function TSystem::SetMakeSharedLib(), the user will be able to
2833 /// indicate, with shell commands, how to build a shared library (a good
2834 /// default will be provided). The most common change, namely where to find
2835 /// header files, will be available through the function
2836 /// TSystem::SetIncludePath().
2837 /// A good default will be provided so that a typical user session should be at
2838 /// most:
2839 /// ~~~ {.cpp}
2840 /// root[1] gSystem->SetIncludePath("-I$ROOTSYS/include
2841 /// -I$HOME/mypackage/include");
2842 /// root[2] .x myfunc.C++(10,20);
2843 /// ~~~
2844 /// The user may sometimes try to compile a script before it has loaded all the
2845 /// needed shared libraries. In this case we want to be helpfull and output a
2846 /// list of the unresolved symbols. So if the loading of the created shared
2847 /// library fails, we will try to build a executable that contains the
2848 /// script. The linker should then output a list of missing symbols.
2849 ///
2850 /// To support this we provide a TSystem::SetMakeExe() function, that sets the
2851 /// directive telling how to create an executable. The loader will need
2852 /// to be informed of all the libraries available. The information about
2853 /// the libraries that has been loaded by .L and TSystem::Load() is accesible
2854 /// to the script compiler. However, the information about
2855 /// the libraries that have been selected at link time by the application
2856 /// builder (like the root libraries for root.exe) are not available and need
2857 /// to be explicitly listed in fLinkedLibs (either by default or by a call to
2858 /// TSystem::SetLinkedLibs()).
2859 ///
2860 /// To simplify customization we could also add to the .rootrc support for the
2861 /// variables
2862 /// ~~~ {.cpp}
2863 /// Unix.*.Root.IncludePath: -I$ROOTSYS/include
2864 /// WinNT.*.Root.IncludePath: -I%ROOTSYS%/include
2865 ///
2866 /// Unix.*.Root.LinkedLibs: -L$ROOTSYS/lib -lBase ....
2867 /// WinNT.*.Root.LinkedLibs: %ROOTSYS%/lib/*.lib msvcrt.lib ....
2868 /// ~~~
2869 /// And also support for MakeSharedLibs() and MakeExe().
2870 ///
2871 /// (the ... have to be replaced by the actual values and are here only to
2872 /// shorten this comment).
2873 
2874 int TSystem::CompileMacro(const char *filename, Option_t *opt,
2875  const char *library_specified,
2876  const char *build_dir,
2877  UInt_t dirmode)
2878 {
2879  static const char *version_var_prefix = "__ROOTBUILDVERSION=";
2880 
2881  // ======= Analyze the options
2882  Bool_t keep = kFALSE;
2883  Bool_t recompile = kFALSE;
2884  EAclicMode mode = fAclicMode;
2885  Bool_t loadLib = kTRUE;
2886  Bool_t withInfo = kTRUE;
2887  Bool_t verbose = kFALSE;
2888  Bool_t internalDebug = kFALSE;
2889  if (opt) {
2890  keep = (strchr(opt,'k')!=0);
2891  recompile = (strchr(opt,'f')!=0);
2892  if (strchr(opt,'O')!=0) {
2893  mode = kOpt;
2894  }
2895  if (strchr(opt,'g')!=0) {
2896  mode = kDebug;
2897  }
2898  if (strchr(opt,'c')!=0) {
2899  loadLib = kFALSE;
2900  }
2901  withInfo = strchr(opt, 's') == 0;
2902  verbose = strchr(opt, 'v') != 0;
2903  internalDebug = strchr(opt, 'd') != 0;
2904  }
2905  if (mode==kDefault) {
2906  TString rootbuild = ROOTBUILD;
2907  if (rootbuild.Index("debug",0,TString::kIgnoreCase)==kNPOS) {
2908  mode=kOpt;
2909  } else {
2910  mode=kDebug;
2911  }
2912  }
2913  UInt_t verboseLevel = verbose ? 7 : gDebug;
2914  Bool_t flatBuildDir = (fAclicProperties & kFlatBuildDir) || (strchr(opt,'-')!=0);
2915 
2916  // if non-zero, build_loc indicates where to build the shared library.
2917  TString build_loc = ExpandFileName(GetBuildDir());
2918  if (build_dir && strlen(build_dir)) build_loc = build_dir;
2919  if (build_loc == ".") {
2920  build_loc = WorkingDirectory();
2921  } else if (build_loc.Length() && (!IsAbsoluteFileName(build_loc)) ) {
2922  AssignAndDelete( build_loc , ConcatFileName( WorkingDirectory(), build_loc ) );
2923  }
2924 
2925  // Get the include directory list in the dir1:dir2:dir3 format
2926  // [Used for generating the .d file and to look for header files for
2927  // the linkdef file]
2928  TString incPath = GetIncludePath(); // of the form -Idir1 -Idir2 -Idir3
2929  incPath.Append(":").Prepend(" ");
2930  if (gEnv) {
2931  TString fromConfig = gEnv->GetValue("ACLiC.IncludePaths","");
2932  incPath.Append(fromConfig);
2933  }
2934  incPath.ReplaceAll(" -I",":"); // of form :dir1 :dir2:dir3
2935  auto posISysRoot = incPath.Index(" -isysroot \"");
2936  if (posISysRoot != kNPOS) {
2937  auto posISysRootEnd = incPath.Index('"', posISysRoot + 12);
2938  if (posISysRootEnd != kNPOS) {
2939  // NOTE: should probably just skip isysroot for dependency analysis.
2940  // (And will, in the future - once we rely on compiler-generated .d files.)
2941  incPath.Insert(posISysRootEnd - 1, "/usr/include/");
2942  incPath.Replace(posISysRoot, 12, ":\"");
2943  }
2944  }
2945  while ( incPath.Index(" :") != -1 ) {
2946  incPath.ReplaceAll(" :",":");
2947  }
2948  incPath.Prepend(":.:");
2949  incPath.Prepend(WorkingDirectory());
2950 
2951  // ======= Get the right file names for the dictionary and the shared library
2952  TString expFileName(filename);
2953  ExpandPathName( expFileName );
2954  expFileName = gSystem->UnixPathName(expFileName);
2955  TString library = expFileName;
2956  if (! IsAbsoluteFileName(library) )
2957  {
2958  const char *whichlibrary = Which(incPath,library);
2959  if (whichlibrary) {
2960  library = whichlibrary;
2961  delete [] whichlibrary;
2962  } else {
2963  ::Error("ACLiC","The file %s can not be found in the include path: %s",filename,incPath.Data());
2964  return kFALSE;
2965  }
2966  } else {
2967  if (gSystem->AccessPathName(library)) {
2968  ::Error("ACLiC","The file %s can not be found.",filename);
2969  return kFALSE;
2970  }
2971  }
2972  { // Remove multiple '/' characters, rootcling treats them as comments.
2973  Ssiz_t pos = 0;
2974  while ((pos = library.Index("//", 2, pos, TString::kExact)) != kNPOS) {
2975  library.Remove(pos, 1);
2976  }
2977  }
2978  library = gSystem->UnixPathName(library);
2979  TString filename_fullpath = library;
2980 
2981  TString file_dirname = DirName( filename_fullpath );
2982  // For some probably good reason, DirName on Windows returns the 'name' of
2983  // the directory, omitting the drive letter (even if there was one). In
2984  // consequence the result is not useable as a 'root directory', we need to
2985  // add the drive letter if there was one..
2986  if (library.Length()>1 && isalpha(library[0]) && library[1]==':') {
2987  file_dirname.Prepend(library(0,2));
2988  }
2989  TString file_location( file_dirname ); // Location of the script.
2990  incPath.Prepend( file_location + ":" );
2991 
2992  Ssiz_t dot_pos = library.Last('.');
2993  TString extension = library;
2994  extension.Replace( 0, dot_pos+1, 0 , 0);
2995  TString libname_noext = library;
2996  if (dot_pos>=0) libname_noext.Remove( dot_pos );
2997 
2998  // Extension of shared library is platform dependent!!
2999  library.Replace( dot_pos, library.Length()-dot_pos,
3000  TString("_") + extension + "." + fSoExt );
3001 
3002  TString libname ( BaseName( libname_noext ) );
3003  libname.Append("_").Append(extension);
3004 
3005  if (library_specified && strlen(library_specified) ) {
3006  // Use the specified name instead of the default
3007  libname = BaseName( library_specified );
3008  library = library_specified;
3009  ExpandPathName( library );
3010  if (! IsAbsoluteFileName(library) ) {
3011  AssignAndDelete( library , ConcatFileName( WorkingDirectory(), library ) );
3012  }
3013  library = TString(library) + "." + fSoExt;
3014  }
3015  library = gSystem->UnixPathName(library);
3016 
3017  TString libname_ext ( libname );
3018  libname_ext += "." + fSoExt;
3019 
3020  TString lib_dirname = DirName( library );
3021  // For some probably good reason, DirName on Windows returns the 'name' of
3022  // the directory, omitting the drive letter (even if there was one). In
3023  // consequence the result is not useable as a 'root directory', we need to
3024  // add the drive letter if there was one..
3025  if (library.Length()>1 && isalpha(library[0]) && library[1]==':') {
3026  lib_dirname.Prepend(library(0,2));
3027  }
3028  // Strip potential, somewhat redundant '/.' from the pathname ...
3029  if ( strncmp( &(lib_dirname[lib_dirname.Length()-2]), "/.", 2) == 0 ) {
3030  lib_dirname.Remove(lib_dirname.Length()-2);
3031  }
3032  if ( strncmp( &(lib_dirname[lib_dirname.Length()-2]), "\\.", 2) == 0 ) {
3033  lib_dirname.Remove(lib_dirname.Length()-2);
3034  }
3035  TString lib_location( lib_dirname );
3036  Bool_t mkdirFailed = kFALSE;
3037 
3038  if (build_loc.Length()==0) {
3039  build_loc = lib_location;
3040  } else {
3041  // Removes an existing disk specification from the names
3042  TRegexp disk_finder ("[A-z]:");
3043  Int_t pos = library.Index( disk_finder );
3044  if (pos==0) library.Remove(pos,3);
3045  pos = lib_location.Index( disk_finder );
3046  if (pos==0) lib_location.Remove(pos,3);
3047 
3048  if (flatBuildDir) {
3049  AssignAndDelete( library, ConcatFileName( build_loc, libname_ext) );
3050  } else {
3051  AssignAndDelete( library, ConcatFileName( build_loc, library) );
3052  }
3053 
3054  Bool_t canWriteBuild_loc = !gSystem->AccessPathName(build_loc,kWritePermission);
3055  TString build_loc_store( build_loc );
3056  if (!flatBuildDir) {
3057  AssignAndDelete( build_loc, ConcatFileName( build_loc, lib_location) );
3058  }
3059 
3060  if (gSystem->AccessPathName(build_loc,kFileExists)) {
3061  mkdirFailed = (0 != mkdir(build_loc, true));
3062  if (mkdirFailed && !canWriteBuild_loc) {
3063  // The mkdir failed __and__ we can not write to the target directory,
3064  // let make sure the error message will be about the target directory
3065  build_loc = build_loc_store;
3066  mkdirFailed = kFALSE;
3067  } else if (!mkdirFailed && dirmode!=0) {
3068  Chmod(build_loc,dirmode);
3069  }
3070  }
3071  }
3072  library = gSystem->UnixPathName(library);
3073 
3074  // ======= Check if the library need to loaded or compiled
3075  if (!gInterpreter->IsLibraryLoaded(library) && gInterpreter->IsLoaded(expFileName)) {
3076  // the script has already been loaded in interpreted mode
3077  // Let's warn the user and unload it.
3078 
3079  if (withInfo) {
3080  ::Info("ACLiC","script has already been loaded in interpreted mode");
3081  ::Info("ACLiC","unloading %s and compiling it", filename);
3082  }
3083 
3084  if ( gInterpreter->UnloadFile( expFileName ) != 0 ) {
3085  // We can not unload it.
3086  return kFALSE;
3087  }
3088  }
3089 
3090  // Calculate the -I lines
3091  TString includes = GetIncludePath();
3092  includes.Prepend(' ');
3093 
3094  {
3095  // I need to replace the -Isomerelativepath by -I../ (or -I..\ on NT)
3096  TRegexp rel_inc(" -I[^\"/\\$%-][^:-]+");
3097  Int_t len,pos;
3098  pos = rel_inc.Index(includes,&len);
3099  while( len != 0 ) {
3100  TString sub = includes(pos,len);
3101  sub.Remove(0,3); // Remove ' -I'
3102  AssignAndDelete( sub, ConcatFileName( WorkingDirectory(), sub ) );
3103  sub.Prepend(" -I\"");
3104  sub.Chop(); // Remove trailing space (i.e between the -Is ...
3105  sub.Append("\" ");
3106  includes.Replace(pos,len,sub);
3107  pos = rel_inc.Index(includes,&len);
3108  }
3109  }
3110  {
3111  // I need to replace the -I"somerelativepath" by -I"$cwd/ (or -I"$cwd\ on NT)
3112  TRegexp rel_inc(" -I\"[^/\\$%-][^:-]+");
3113  Int_t len,pos;
3114  pos = rel_inc.Index(includes,&len);
3115  while( len != 0 ) {
3116  TString sub = includes(pos,len);
3117  sub.Remove(0,4); // Remove ' -I"'
3118  AssignAndDelete( sub, ConcatFileName( WorkingDirectory(), sub ) );
3119  sub.Prepend(" -I\"");
3120  includes.Replace(pos,len,sub);
3121  pos = rel_inc.Index(includes,&len);
3122  }
3123  }
3124  //includes += " -I\"" + build_loc;
3125  //includes += "\" -I\"";
3126  //includes += WorkingDirectory();
3127 // if (includes[includes.Length()-1] == '\\') {
3128 // // The current directory is (most likely) the root of a windows drive and
3129 // // has a trailing \ which would espace the quote if left by itself.
3130 // includes += '\\';
3131 // }
3132 // includes += "\"";
3133  if (gEnv) {
3134  TString fromConfig = gEnv->GetValue("ACLiC.IncludePaths","");
3135  includes.Append(" ").Append(fromConfig).Append(" ");
3136  }
3137 
3138  // Extract the -D for the dependency generation.
3139  TString defines = " ";
3140  {
3141  TString cmd = GetMakeSharedLib();
3142  TRegexp rel_def("-D[^\\s\\t\\n\\r]*");
3143  Int_t len,pos;
3144  pos = rel_def.Index(cmd,&len);
3145  while( len != 0 ) {
3146  defines += cmd(pos,len);
3147  defines += " ";
3148  pos = rel_def.Index(cmd,&len,pos+1);
3149  }
3150 
3151  }
3152 
3153  TString emergency_loc;
3154  {
3155  UserGroup_t *ug = gSystem->GetUserInfo(gSystem->GetUid());
3156  if (ug) {
3157  AssignAndDelete( emergency_loc, ConcatFileName( TempDirectory(), ug->fUser ) );
3158  delete ug;
3159  } else {
3160  emergency_loc = TempDirectory();
3161  }
3162  }
3163 
3164  Bool_t canWrite = !gSystem->AccessPathName(build_loc,kWritePermission);
3165 
3166  Bool_t modified = kFALSE;
3167 
3168  // Generate the dependency filename
3169  TString depdir = build_loc;
3170  TString depfilename;
3171  AssignAndDelete( depfilename, ConcatFileName(depdir, BaseName(libname_noext)) );
3172  depfilename += "_" + extension + ".d";
3173 
3174  if ( !recompile ) {
3175 
3176  Long_t lib_time, file_time;
3177 
3178  if ((gSystem->GetPathInfo( library, 0, (Long_t*)0, 0, &lib_time ) != 0) ||
3179  (gSystem->GetPathInfo( expFileName, 0, (Long_t*)0, 0, &file_time ) == 0 &&
3180  (lib_time < file_time))) {
3181 
3182  // the library does not exist or is older than the script.
3183  recompile = kTRUE;
3184  modified = kTRUE;
3185 
3186  } else {
3187 
3188  if ( gSystem->GetPathInfo( depfilename, 0,(Long_t*) 0, 0, &file_time ) != 0 ) {
3189  if (!canWrite) {
3190  depdir = emergency_loc;
3191  AssignAndDelete( depfilename, ConcatFileName(depdir, BaseName(libname_noext)) );
3192  depfilename += "_" + extension + ".d";
3193  }
3194  R__WriteDependencyFile(build_loc, depfilename, filename_fullpath, library, libname, extension, version_var_prefix, includes, defines, incPath);
3195  }
3196  }
3197 
3198  if (!modified) {
3199 
3200  // We need to check the dependencies
3201  FILE * depfile = fopen(depfilename.Data(),"r");
3202  if (depfile==0) {
3203  // there is no accessible dependency file, let's assume the library has been
3204  // modified
3205  modified = kTRUE;
3206  recompile = kTRUE;
3207 
3208  } else {
3209 
3210  TString version_var = libname + version_var_prefix;
3211 
3212  Int_t sz = 256;
3213  char *line = new char[sz];
3214  line[0] = 0;
3215 
3216  int c;
3217  Int_t current = 0;
3218  Int_t nested = 0;
3219  Bool_t hasversion = false;
3220 
3221  while ((c = fgetc(depfile)) != EOF) {
3222  if (c=='#') {
3223  // skip comment
3224  while ((c = fgetc(depfile)) != EOF) {
3225  if (c=='\n') {
3226  break;
3227  }
3228  }
3229  continue;
3230  }
3231  if (current && line[current-1]=='=' && strncmp(version_var.Data(),line,current)==0) {
3232 
3233  // The next word will be the version number.
3234  hasversion = kTRUE;
3235  line[0] = 0;
3236  current = 0;
3237  } else if (isspace(c) && !nested) {
3238  if (current) {
3239  if (line[current-1]!=':') {
3240  // ignore target
3241  line[current] = 0;
3242 
3243  Long_t filetime;
3244  if (hasversion) {
3245  modified |= strcmp(ROOT_RELEASE,line)!=0;
3246  hasversion = kFALSE;
3247  } else if ( gSystem->GetPathInfo( line, 0, (Long_t*)0, 0, &filetime ) == 0 ) {
3248  modified |= ( lib_time <= filetime );
3249  }
3250  }
3251  }
3252  current = 0;
3253  line[0] = 0;
3254  } else {
3255  if (current==sz-1) {
3256  sz = 2*sz;
3257  char *newline = new char[sz];
3258  memcpy(newline,line, current);
3259  delete [] line;
3260  line = newline;
3261  }
3262  if (c=='"') nested = !nested;
3263  else {
3264  line[current] = c;
3265  current++;
3266  }
3267  }
3268  }
3269  delete [] line;
3270  fclose(depfile);
3271  recompile = modified;
3272 
3273  }
3274 
3275  }
3276  }
3277 
3278  if ( gInterpreter->IsLibraryLoaded(library)
3279  || strlen(GetLibraries(library,"D",kFALSE)) != 0 ) {
3280  // The library has already been built and loaded.
3281 
3282  Bool_t reload = kFALSE;
3283  TNamed *libinfo = (TNamed*)fCompiled->FindObject(library);
3284  if (libinfo) {
3285  Long_t load_time = libinfo->GetUniqueID();
3286  Long_t lib_time;
3287  if ( gSystem->GetPathInfo( library, 0, (Long_t*)0, 0, &lib_time ) == 0
3288  && (lib_time>load_time)) {
3289  reload = kTRUE;
3290  }
3291  }
3292 
3293  if ( !recompile && reload ) {
3294 
3295  if (withInfo) {
3296  ::Info("ACLiC","%s has been modified and will be reloaded",
3297  libname.Data());
3298  }
3299  if ( gInterpreter->UnloadFile( library.Data() ) != 0 ) {
3300  // The library is being used. We can not unload it.
3301  return kFALSE;
3302  }
3303  if (libinfo) {
3304  fCompiled->Remove(libinfo);
3305  delete libinfo;
3306  libinfo = 0;
3307  }
3308  TNamed *k = new TNamed(library,library);
3309  Long_t lib_time;
3310  gSystem->GetPathInfo( library, 0, (Long_t*)0, 0, &lib_time );
3311  k->SetUniqueID(lib_time);
3312  if (!keep) k->SetBit(kMustCleanup);
3313  fCompiled->Add(k);
3314 
3315  return !gSystem->Load(library);
3316  }
3317 
3318  if (withInfo) {
3319  ::Info("ACLiC","%s script has already been compiled and loaded",
3320  modified ? "modified" : "unmodified");
3321  }
3322 
3323  if ( !recompile ) {
3324  return kTRUE;
3325  } else {
3326  if (withInfo) {
3327  ::Info("ACLiC","it will be regenerated and reloaded!");
3328  }
3329  if ( gInterpreter->UnloadFile( library.Data() ) != 0 ) {
3330  // The library is being used. We can not unload it.
3331  return kFALSE;
3332  }
3333  if (libinfo) {
3334  fCompiled->Remove(libinfo);
3335  delete libinfo;
3336  libinfo = 0;
3337  }
3338  Unlink(library);
3339  }
3340 
3341  }
3342 
3343  TString libmapfilename;
3344  AssignAndDelete( libmapfilename, ConcatFileName( build_loc, libname ) );
3345  libmapfilename += ".rootmap";
3346 #if (defined(R__MACOSX) && !defined(MAC_OS_X_VERSION_10_5)) || defined(R__WIN32)
3347  Bool_t produceRootmap = kTRUE;
3348 #else
3349  Bool_t produceRootmap = kFALSE;
3350 #endif
3351  Bool_t linkDepLibraries = !produceRootmap;
3352  if (gEnv) {
3353 #if (defined(R__MACOSX) && !defined(MAC_OS_X_VERSION_10_5))
3354  Int_t linkLibs = gEnv->GetValue("ACLiC.LinkLibs",2);
3355 #elif defined(R__WIN32)
3356  Int_t linkLibs = gEnv->GetValue("ACLiC.LinkLibs",3);
3357 #else
3358  Int_t linkLibs = gEnv->GetValue("ACLiC.LinkLibs",1);
3359 #endif
3360  produceRootmap = linkLibs & 0x2;
3361  linkDepLibraries = linkLibs & 0x1;
3362  }
3363 
3364  // FIXME: Triggers clang false positive warning -Wunused-lambda-capture.
3365  /*constexpr const*/ bool useCxxModules =
3366 #ifdef R__USE_CXXMODULES
3367  true;
3368 #else
3369  false;
3370 #endif
3371 
3372  auto LoadLibrary = [useCxxModules, produceRootmap](const TString& lib) {
3373  // We have no rootmap files or modules to construct `-l` flags enabling
3374  // explicit linking. We have to resolve the dependencies by ourselves
3375  // taking the job of the dyld.
3376  // FIXME: This is a rare case where we have rootcling running with
3377  // modules disabled. Remove this code once we fully switch to modules,
3378  // or implement a special flag in rootcling which selective enables
3379  // modules for dependent libraries and does not produce a module for
3380  // the ACLiC library.
3381  if (useCxxModules && !produceRootmap) {
3382  using namespace std;
3383  string deps = gInterpreter->GetSharedLibDeps(lib, /*tryDyld*/true);
3384  istringstream iss(deps);
3385  vector<string> libs {istream_iterator<std::string>{iss}, istream_iterator<string>{}};
3386  // Skip the first element: it is a relative path to `lib`.
3387  for (auto I = libs.begin() + 1, E = libs.end(); I != E; ++I)
3388  if (gInterpreter->Load(I->c_str(), /*system*/false) < 0)
3389  return false; // failure
3390  }
3391  return !gSystem->Load(lib);
3392  };
3393 
3394  if (!recompile) {
3395  // The library already exist, let's just load it.
3396  if (loadLib) {
3397  TNamed *k = new TNamed(library,library);
3398  Long_t lib_time;
3399  gSystem->GetPathInfo( library, 0, (Long_t*)0, 0, &lib_time );
3400  k->SetUniqueID(lib_time);
3401  if (!keep) k->SetBit(kMustCleanup);
3402  fCompiled->Add(k);
3403 
3404  if (gInterpreter->GetSharedLibDeps(libname) == 0) {
3405  gInterpreter->LoadLibraryMap(libmapfilename);
3406  }
3407 
3408  return LoadLibrary(library);
3409  }
3410  else return kTRUE;
3411  }
3412 
3413  if (!canWrite && recompile) {
3414 
3415  if (mkdirFailed) {
3416  ::Warning("ACLiC","Could not create the directory: %s",
3417  build_loc.Data());
3418  } else {
3419  ::Warning("ACLiC","%s is not writable!",
3420  build_loc.Data());
3421  }
3422  if (emergency_loc == build_dir ) {
3423  ::Error("ACLiC","%s is the last resort location (i.e. temp location)",build_loc.Data());
3424  return kFALSE;
3425  }
3426  ::Warning("ACLiC","Output will be written to %s",
3427  emergency_loc.Data());
3428  return CompileMacro(expFileName, opt, library_specified, emergency_loc, dirmode);
3429  }
3430 
3431  if (withInfo) {
3432  Info("ACLiC","creating shared library %s",library.Data());
3433  }
3434 
3435  R__WriteDependencyFile(build_loc, depfilename, filename_fullpath, library, libname, extension, version_var_prefix, includes, defines, incPath);
3436 
3437  // ======= Select the dictionary name
3438  TString dict = libname + "_ACLiC_dict";
3439 
3440  // the file name end up in the file produced
3441  // by rootcling as a variable name so all character need to be valid!
3442  static const int maxforbidden = 27;
3443  static const char *forbidden_chars[maxforbidden] =
3444  { "+","-","*","/","&","%","|","^",">","<",
3445  "=","~",".","(",")","[","]","!",",","$",
3446  " ",":","'","#","@","\\","\"" };
3447  for( int ic = 0; ic < maxforbidden; ic++ ) {
3448  dict.ReplaceAll( forbidden_chars[ic],"_" );
3449  }
3450  if ( dict.Last('.')!=dict.Length()-1 ) dict.Append(".");
3451  AssignAndDelete( dict, ConcatFileName( build_loc, dict ) );
3452  TString dicth = dict;
3453  TString dictObj = dict;
3454  dict += "cxx"; //no need to keep the extension of the original file, any extension will do
3455  dicth += "h";
3456  dictObj += fObjExt;
3457 
3458  // ======= Generate a linkdef file
3459 
3460  TString linkdef;
3461  AssignAndDelete( linkdef, ConcatFileName( build_loc, libname ) );
3462  linkdef += "_ACLiC_linkdef.h";
3463  std::ofstream linkdefFile( linkdef, std::ios::out );
3464  linkdefFile << "// File Automatically generated by the ROOT Script Compiler "
3465  << std::endl;
3466  linkdefFile << std::endl;
3467  linkdefFile << "#ifdef __CINT__" << std::endl;
3468  linkdefFile << std::endl;
3469  linkdefFile << "#pragma link C++ nestedclasses;" << std::endl;
3470  linkdefFile << "#pragma link C++ nestedtypedefs;" << std::endl;
3471  linkdefFile << std::endl;
3472 
3473  // We want to look for a header file that has the same name as the macro
3474 
3475  const char * extensions[] = { ".h", ".hh", ".hpp", ".hxx", ".hPP", ".hXX" };
3476 
3477  int i;
3478  for (i = 0; i < 6; i++ ) {
3479  char * name;
3480  TString extra_linkdef = BaseName( libname_noext );
3481  extra_linkdef.Append(GetLinkdefSuffix());
3482  extra_linkdef.Append(extensions[i]);
3483  name = Which(incPath,extra_linkdef);
3484  if (name) {
3485  if (verboseLevel>4 && withInfo) {
3486  Info("ACLiC","including extra linkdef file: %s",name);
3487  }
3488  linkdefFile << "#include \"" << name << "\"" << std::endl;
3489  delete [] name;
3490  }
3491  }
3492 
3493  if (verboseLevel>5 && withInfo) {
3494  Info("ACLiC","looking for header in: %s",incPath.Data());
3495  }
3496  for (i = 0; i < 6; i++ ) {
3497  char * name;
3498  TString lookup = BaseName( libname_noext );
3499  lookup.Append(extensions[i]);
3500  name = Which(incPath,lookup);
3501  if (name) {
3502  linkdefFile << "#pragma link C++ defined_in "<<gSystem->UnixPathName(name)<<";"<< std::endl;
3503  delete [] name;
3504  }
3505  }
3506  linkdefFile << "#pragma link C++ defined_in \""<<filename_fullpath << "\";" << std::endl;
3507  linkdefFile << std::endl;
3508  linkdefFile << "#endif" << std::endl;
3509  linkdefFile.close();
3510  // ======= Generate the list of rootmap files to be looked at
3511 
3512  TString mapfile;
3513  AssignAndDelete( mapfile, ConcatFileName( build_loc, libname ) );
3514  mapfile += "_ACLiC_map";
3515  TString mapfilein = mapfile + ".in";
3516  TString mapfileout = mapfile + ".out";
3517 
3518  Bool_t needLoadMap = kFALSE;
3519  if (!useCxxModules) {
3520  if (gInterpreter->GetSharedLibDeps(libname) !=0 ) {
3521  gInterpreter->UnloadLibraryMap(libname);
3522  needLoadMap = kTRUE;
3523  }
3524  }
3525 
3526  std::ofstream mapfileStream( mapfilein, std::ios::out );
3527  {
3528  TString name = ".rootmap";
3529  TString sname = "system.rootmap";
3530  TString file;
3531  AssignAndDelete(file, ConcatFileName(TROOT::GetEtcDir(), sname) );
3532  if (gSystem->AccessPathName(file)) {
3533  // for backward compatibility check also $ROOTSYS/system<name> if
3534  // $ROOTSYS/etc/system<name> does not exist
3535  AssignAndDelete(file, ConcatFileName(TROOT::GetRootSys(), sname));
3536  if (gSystem->AccessPathName(file)) {
3537  // for backward compatibility check also $ROOTSYS/<name> if
3538  // $ROOTSYS/system<name> does not exist
3539  AssignAndDelete(file, ConcatFileName(TROOT::GetRootSys(), name));
3540  }
3541  }
3542  mapfileStream << file << std::endl;
3543  AssignAndDelete(file, ConcatFileName(gSystem->HomeDirectory(), name) );
3544  mapfileStream << file << std::endl;
3545  mapfileStream << name << std::endl;
3546  if (gInterpreter->GetRootMapFiles()) {
3547  for (i = 0; i < gInterpreter->GetRootMapFiles()->GetEntriesFast(); i++) {
3548  mapfileStream << ((TNamed*)gInterpreter->GetRootMapFiles()->At(i))->GetTitle() << std::endl;
3549  }
3550  }
3551  }
3552  mapfileStream.close();
3553 
3554  // ======= Generate the rootcling command line
3555  TString rcling = "rootcling";
3556  PrependPathName(TROOT::GetBinDir(), rcling);
3557  rcling += " -v0 \"--lib-list-prefix=";
3558  rcling += mapfile;
3559  rcling += "\" -f \"";
3560  rcling.Append(dict).Append("\" ");
3561 
3562  if (produceRootmap && !useCxxModules) {
3563  rcling += " -rml " + libname + " -rmf \"" + libmapfilename + "\" ";
3564  rcling.Append("-DR__ACLIC_ROOTMAP ");
3565  }
3566  rcling.Append(GetIncludePath()).Append(" -D__ACLIC__ ");
3567  if (gEnv) {
3568  TString fromConfig = gEnv->GetValue("ACLiC.IncludePaths","");
3569  rcling.Append(fromConfig);
3570  }
3571 
3572  // Create a modulemap
3573  // FIXME: Merge the modulemap generation from cmake and here in rootcling.
3574  if (useCxxModules && produceRootmap) {
3575  rcling += " -cxxmodule ";
3576  // TString moduleMapFileName = file_dirname + "/" + libname + ".modulemap";
3577  TString moduleName = libname + "_ACLiC_dict";
3578  if (moduleName.BeginsWith("lib"))
3579  moduleName = moduleName.Remove(0, 3);
3580  TString moduleMapName = moduleName + ".modulemap";
3581  TString moduleMapFullPath = build_loc + "/" + moduleMapName;
3582  // A modulemap may exist from previous runs, overwrite it.
3583  if (verboseLevel > 3 && !AccessPathName(moduleMapFullPath))
3584  ::Info("ACLiC", "File %s already exists!", moduleMapFullPath.Data());
3585 
3586  std::string curDir = ROOT::FoundationUtils::GetCurrentDir();
3587  std::string relative_path = ROOT::FoundationUtils::MakePathRelative(filename_fullpath.Data(), curDir);
3588  std::ofstream moduleMapFile(moduleMapFullPath, std::ios::out);
3589  moduleMapFile << "module \"" << moduleName << "\" {" << std::endl;
3590  moduleMapFile << " header \"" << relative_path << "\"" << std::endl;
3591  moduleMapFile << " export *" << std::endl;
3592  moduleMapFile << " link \"" << libname_ext << "\"" << std::endl;
3593  moduleMapFile << "}" << std::endl;
3594  moduleMapFile.close();
3595  gInterpreter->RegisterPrebuiltModulePath(build_loc.Data(), moduleMapName.Data());
3596  rcling.Append(" \"-fmodule-map-file=" + moduleMapFullPath + "\" ");
3597  }
3598 
3599  rcling.Append(" \"").Append(filename_fullpath).Append("\" ");
3600  rcling.Append("\"").Append(linkdef).Append("\"");
3601 
3602  // ======= Run rootcling
3603  if (withInfo) {
3604  if (verboseLevel>3) {
3605  ::Info("ACLiC","creating the dictionary files");
3606  if (verboseLevel>4) ::Info("ACLiC", "%s", rcling.Data());
3607  }
3608  }
3609 
3610  Int_t dictResult = gSystem->Exec(rcling);
3611  if (dictResult) {
3612  if (dictResult==139) ::Error("ACLiC","Dictionary generation failed with a core dump!");
3613  else ::Error("ACLiC","Dictionary generation failed!");
3614  }
3615 
3616  Bool_t result = !dictResult;
3617  TString depLibraries;
3618 
3619  // ======= Load the library the script might depend on
3620  if (result) {
3621  TString linkedlibs = GetLibraries("", "S");
3622  TString libtoload;
3623  TString all_libtoload;
3624  std::ifstream liblist(mapfileout);
3625 
3626  while ( liblist >> libtoload ) {
3627  // Load the needed library except for the library we are currently building!
3628  if (libtoload == "#") {
3629  // The comment terminates the list of libraries.
3630  std::string toskipcomment;
3631  std::getline(liblist,toskipcomment);
3632  break;
3633  }
3634  if (libtoload != library && libtoload != libname && libtoload != libname_ext) {
3635  if (produceRootmap) {
3636  if (loadLib || linkDepLibraries /* For GetLibraries to Work */) {
3637  result = gROOT->LoadClass("", libtoload) >= 0;
3638  if (!result) {
3639  // We failed to load one of the dependency.
3640  break;
3641  }
3642  }
3643  if (!linkedlibs.Contains(libtoload)) {
3644  all_libtoload.Append(" ").Append(libtoload);
3645  depLibraries.Append(" ");
3646  depLibraries.Append(GetLibraries(libtoload,"DSL",kFALSE));
3647  depLibraries = depLibraries.Strip(); // Remove any trailing spaces.
3648  }
3649  } else {
3650  gROOT->LoadClass("", libtoload);
3651  }
3652  }
3653  unsigned char c = liblist.peek();
3654  if (c=='\n' || c=='\r') {
3655  // Consume the character
3656  liblist.get();
3657  break;
3658  }
3659  }
3660 
3661 // depLibraries = all_libtoload;
3662 // depLibraries.ReplaceAll(" lib"," -l");
3663 // depLibraries.ReplaceAll(TString::Format(".%s",fSoExt.Data()),"");
3664  }
3665 
3666  // ======= Calculate the libraries for linking:
3667  TString linkLibraries;
3668  /*
3669  this is intentionally disabled until it can become useful
3670  if (gEnv) {
3671  linkLibraries = gEnv->GetValue("ACLiC.Libraries","");
3672  linkLibraries.Prepend(" ");
3673  }
3674  */
3675  TString linkLibrariesNoQuotes(GetLibraries("","SDL"));
3676  // We need to enclose the single paths in quotes to account for paths with spaces
3677  TString librariesWithQuotes;
3678  TString singleLibrary;
3679  Bool_t collectingSingleLibraryNameTokens = kFALSE;
3680  for (auto tokenObj : *linkLibrariesNoQuotes.Tokenize(" ")) {
3681  singleLibrary = ((TObjString*)tokenObj)->GetString();
3682  if (!AccessPathName(singleLibrary) || singleLibrary[0]=='-') {
3683  if (collectingSingleLibraryNameTokens) {
3684  librariesWithQuotes.Chop();
3685  librariesWithQuotes += "\" \"" + singleLibrary + "\"";
3686  collectingSingleLibraryNameTokens = kFALSE;
3687  } else {
3688  librariesWithQuotes += " \"" + singleLibrary + "\"";
3689  }
3690  } else {
3691  if (collectingSingleLibraryNameTokens) {
3692  librariesWithQuotes += singleLibrary + " ";
3693  } else {
3694  collectingSingleLibraryNameTokens = kTRUE;
3695  librariesWithQuotes += " \"" + singleLibrary + " ";
3696  }
3697  }
3698  }
3699 
3700 #ifdef _MSC_VER
3701  linkLibraries.Prepend(linkLibrariesNoQuotes);
3702 #else
3703  linkLibraries.Prepend(librariesWithQuotes);
3704 #endif
3705 
3706  // ======= Generate the build command lines
3707  TString cmd = fMakeSharedLib;
3708  // we do not add filename because it is already included via the dictionary(in dicth) !
3709  // dict.Append(" ").Append(filename);
3710  cmd.ReplaceAll("$SourceFiles","-D__ACLIC__ \"$SourceFiles\"");
3711  cmd.ReplaceAll("$SourceFiles",dict);
3712  cmd.ReplaceAll("$ObjectFiles","\"$ObjectFiles\"");
3713  cmd.ReplaceAll("$ObjectFiles",dictObj);
3714  cmd.ReplaceAll("$IncludePath",includes);
3715  cmd.ReplaceAll("$SharedLib","\"$SharedLib\"");
3716  cmd.ReplaceAll("$SharedLib",library);
3717  if (linkDepLibraries) {
3718  if (produceRootmap) {
3719  cmd.ReplaceAll("$DepLibs",depLibraries);
3720  } else {
3721  cmd.ReplaceAll("$DepLibs",linkLibraries);
3722  }
3723  }
3724  cmd.ReplaceAll("$LinkedLibs",linkLibraries);
3725  cmd.ReplaceAll("$LibName",libname);
3726  cmd.ReplaceAll("\"$BuildDir","$BuildDir");
3727  cmd.ReplaceAll("$BuildDir","\"$BuildDir\"");
3728  cmd.ReplaceAll("$BuildDir",build_loc);
3729  if (mode==kDebug) {
3730  cmd.ReplaceAll("$Opt",fFlagsDebug);
3731  } else {
3732  cmd.ReplaceAll("$Opt",fFlagsOpt);
3733  }
3734 #ifdef WIN32
3735  R__FixLink(cmd);
3736  cmd.ReplaceAll("-std=", "-std:");
3737 #endif
3738 
3739  TString testcmd = fMakeExe;
3740  TString fakeMain;
3741  AssignAndDelete( fakeMain, ConcatFileName( build_loc, libname ) );
3742  fakeMain += "_ACLiC_main";
3743  fakeMain += extension;
3744  std::ofstream fakeMainFile( fakeMain, std::ios::out );
3745  fakeMainFile << "// File Automatically generated by the ROOT Script Compiler "
3746  << std::endl;
3747  fakeMainFile << "int main(char*argc,char**argvv) {};" << std::endl;
3748  fakeMainFile.close();
3749  // We could append this fake main routine to the compilation line.
3750  // But in this case compiler may output the name of the dictionary file
3751  // and of the fakeMain file while it compiles it. (this would be useless
3752  // confusing output).
3753  // We could also the fake main routine to the end of the dictionary file
3754  // however compilation would fail if a main is already there
3755  // (like stress.cxx)
3756  // dict.Append(" ").Append(fakeMain);
3757  TString exec;
3758  AssignAndDelete( exec, ConcatFileName( build_loc, libname ) );
3759  exec += "_ACLiC_exec";
3760  testcmd.ReplaceAll("$SourceFiles","-D__ACLIC__ \"$SourceFiles\"");
3761  testcmd.ReplaceAll("$SourceFiles",dict);
3762  testcmd.ReplaceAll("$ObjectFiles","\"$ObjectFiles\"");
3763  testcmd.ReplaceAll("$ObjectFiles",dictObj);
3764  testcmd.ReplaceAll("$IncludePath",includes);
3765  testcmd.ReplaceAll("$ExeName",exec);
3766  testcmd.ReplaceAll("$LinkedLibs",linkLibraries);
3767  testcmd.ReplaceAll("$BuildDir",build_loc);
3768  if (mode==kDebug)
3769  testcmd.ReplaceAll("$Opt",fFlagsDebug);
3770  else
3771  testcmd.ReplaceAll("$Opt",fFlagsOpt);
3772 
3773 #ifdef WIN32
3774  R__FixLink(testcmd);
3775  testcmd.ReplaceAll("-std=", "-std:");
3776 #endif
3777 
3778  // ======= Build the library
3779  if (result) {
3780  if (verboseLevel>3 && withInfo) {
3781  ::Info("ACLiC","compiling the dictionary and script files");
3782  if (verboseLevel>4) ::Info("ACLiC", "%s", cmd.Data());
3783  }
3784  Int_t compilationResult = gSystem->Exec( cmd );
3785  if (compilationResult) {
3786  if (compilationResult==139) ::Error("ACLiC","Compilation failed with a core dump!");
3787  else ::Error("ACLiC","Compilation failed!");
3788  if (produceRootmap) {
3789  gSystem->Unlink(libmapfilename);
3790  }
3791  }
3792  result = !compilationResult;
3793  }
3794 
3795  if ( result ) {
3796 
3797  TNamed *k = new TNamed(library,library);
3798  Long_t lib_time;
3799  gSystem->GetPathInfo( library, 0, (Long_t*)0, 0, &lib_time );
3800  k->SetUniqueID(lib_time);
3801  if (!keep) k->SetBit(kMustCleanup);
3802  fCompiled->Add(k);
3803 
3804  if (needLoadMap) {
3805  gInterpreter->LoadLibraryMap(libmapfilename);
3806  }
3807  if (verboseLevel>3 && withInfo) ::Info("ACLiC","loading the shared library");
3808  if (loadLib)
3809  result = LoadLibrary(library);
3810  else
3811  result = kTRUE;
3812 
3813  if ( !result ) {
3814  if (verboseLevel>3 && withInfo) {
3815  ::Info("ACLiC","testing for missing symbols:");
3816  if (verboseLevel>4) ::Info("ACLiC", "%s", testcmd.Data());
3817  }
3818  gSystem->Exec(testcmd);
3819  gSystem->Unlink( exec );
3820  }
3821 
3822  };
3823 
3824  if (verboseLevel<=5 && !internalDebug) {
3825  gSystem->Unlink( dict );
3826  gSystem->Unlink( dicth );
3827  gSystem->Unlink( dictObj );
3828  gSystem->Unlink( linkdef );
3829  gSystem->Unlink( mapfilein );
3830  gSystem->Unlink( mapfileout );
3831  gSystem->Unlink( fakeMain );
3832  gSystem->Unlink( exec );
3833  }
3834  if (verboseLevel>6) {
3835  rcling.Prepend("echo ");
3836  cmd.Prepend("echo \" ").Append(" \" ");
3837  testcmd.Prepend("echo \" ").Append(" \" ");
3838  gSystem->Exec(rcling);
3839  gSystem->Exec( cmd );
3840  gSystem->Exec(testcmd);
3841  }
3842 
3843  return result;
3844 }
3845 
3846 ////////////////////////////////////////////////////////////////////////////////
3847 /// Return the ACLiC properties field. See EAclicProperties for details
3848 /// on the semantic of each bit.
3849 
3850 Int_t TSystem::GetAclicProperties() const
3851 {
3852  return fAclicProperties;
3853 }
3854 
3855 ////////////////////////////////////////////////////////////////////////////////
3856 /// Return the build architecture.
3857 
3858 const char *TSystem::GetBuildArch() const
3859 {
3860  return fBuildArch;
3861 }
3862 
3863 ////////////////////////////////////////////////////////////////////////////////
3864 /// Return the build compiler
3865 
3866 const char *TSystem::GetBuildCompiler() const
3867 {
3868  return fBuildCompiler;
3869 }
3870 
3871 ////////////////////////////////////////////////////////////////////////////////
3872 /// Return the build compiler version
3873 
3874 const char *TSystem::GetBuildCompilerVersion() const
3875 {
3876  return fBuildCompilerVersion;
3877 }
3878 
3879 ////////////////////////////////////////////////////////////////////////////////
3880 /// Return the build node name.
3881 
3882 const char *TSystem::GetBuildNode() const
3883 {
3884  return fBuildNode;
3885 }
3886 
3887 ////////////////////////////////////////////////////////////////////////////////
3888 /// Return the path of the build directory.
3889 
3890 const char *TSystem::GetBuildDir() const
3891 {
3892  if (fBuildDir.Length()==0) {
3893  if (!gEnv) return "";
3894  const_cast<TSystem*>(this)->fBuildDir = gEnv->GetValue("ACLiC.BuildDir","");
3895  }
3896  return fBuildDir;
3897 }
3898 
3899 ////////////////////////////////////////////////////////////////////////////////
3900 /// Return the debug flags.
3901 
3902 const char *TSystem::GetFlagsDebug() const
3903 {
3904  return fFlagsDebug;
3905 }
3906 
3907 ////////////////////////////////////////////////////////////////////////////////
3908 /// Return the optimization flags.
3909 
3910 const char *TSystem::GetFlagsOpt() const
3911 {
3912  return fFlagsOpt;
3913 }
3914 
3915 ////////////////////////////////////////////////////////////////////////////////
3916 /// AclicMode indicates whether the library should be built in
3917 /// debug mode or optimized. The values are:
3918 /// - TSystem::kDefault : compile the same as the current ROOT
3919 /// - TSystem::kDebug : compiled in debug mode
3920 /// - TSystem::kOpt : optimized the library
3921 
3922 TSystem::EAclicMode TSystem::GetAclicMode() const
3923 {
3924  return fAclicMode;
3925 }
3926 
3927 ////////////////////////////////////////////////////////////////////////////////
3928 /// Return the command line use to make a shared library.
3929 /// See TSystem::CompileMacro for more details.
3930 
3931 const char *TSystem::GetMakeSharedLib() const
3932 {
3933  return fMakeSharedLib;
3934 }
3935 
3936 ////////////////////////////////////////////////////////////////////////////////
3937 /// Return the command line use to make an executable.
3938 /// See TSystem::CompileMacro for more details.
3939 
3940 const char *TSystem::GetMakeExe() const
3941 {
3942  return fMakeExe;
3943 }
3944 
3945 ////////////////////////////////////////////////////////////////////////////////
3946 /// Get the list of include path.
3947 
3948 const char *TSystem::GetIncludePath()
3949 {
3950  fListPaths = fIncludePath;
3951 #ifndef _MSC_VER
3952  // FIXME: This is a temporary fix for the following error with ACLiC
3953  // (and this is apparently not needed anyway):
3954  // 48: input_line_12:8:38: error: use of undeclared identifier 'IC'
3955  // 48: "C:/Users/bellenot/build/debug/etc" -IC:/Users/bellenot/build/debug/etc//cling -IC:/Users/bellenot/build/debug/include"",
3956  // 48: ^
3957  // 48: Error in <ACLiC>: Dictionary generation failed!
3958  fListPaths.Append(" ").Append(gInterpreter->GetIncludePath());
3959 #endif
3960  return fListPaths;
3961 }
3962 
3963 ////////////////////////////////////////////////////////////////////////////////
3964 /// Return the list of library linked to this executable.
3965 /// See TSystem::CompileMacro for more details.
3966 
3967 const char *TSystem::GetLinkedLibs() const
3968 {
3969  return fLinkedLibs;
3970 }
3971 
3972 ////////////////////////////////////////////////////////////////////////////////
3973 /// Return the linkdef suffix chosen by the user for ACLiC.
3974 /// See TSystem::CompileMacro for more details.
3975 
3976 const char *TSystem::GetLinkdefSuffix() const
3977 {
3978  if (fLinkdefSuffix.Length()==0) {
3979  if (!gEnv) return "_linkdef";
3980  const_cast<TSystem*>(this)->fLinkdefSuffix = gEnv->GetValue("ACLiC.Linkdef","_linkdef");
3981  }
3982  return fLinkdefSuffix;
3983 }
3984 
3985 ////////////////////////////////////////////////////////////////////////////////
3986 /// Get the shared library extension.
3987 
3988 const char *TSystem::GetSoExt() const
3989 {
3990  return fSoExt;
3991 }
3992 
3993 ////////////////////////////////////////////////////////////////////////////////
3994 /// Get the object file extension.
3995 
3996 const char *TSystem::GetObjExt() const
3997 {
3998  return fObjExt;
3999 }
4000 
4001 ////////////////////////////////////////////////////////////////////////////////
4002 /// Set the location where ACLiC will create libraries and use as
4003 /// a scratch area.
4004 ///
4005 /// If isflast is flase, then the libraries are actually stored in
4006 /// sub-directories of 'build_dir' including the full pathname of the
4007 /// script. If the script is location at /full/path/name/macro.C
4008 /// the library will be located at 'build_dir+/full/path/name/macro_C.so'
4009 /// If 'isflat' is true, then no subdirectory is created and the library
4010 /// is created directly in the directory 'build_dir'. Note that in this
4011 /// mode there is a risk than 2 script of the same in different source
4012 /// directory will over-write each other.
4013 
4014 void TSystem::SetBuildDir(const char* build_dir, Bool_t isflat)
4015 {
4016  fBuildDir = build_dir;
4017  if (isflat) fAclicProperties |= (kFlatBuildDir & kBitMask);
4018  else fAclicProperties &= ~(kFlatBuildDir & kBitMask);
4019 }
4020 
4021 ////////////////////////////////////////////////////////////////////////////////
4022 /// FlagsDebug should contain the options to pass to the C++ compiler
4023 /// in order to compile the library in debug mode.
4024 
4025 void TSystem::SetFlagsDebug(const char *flags)
4026 {
4027  fFlagsDebug = flags;
4028 }
4029 
4030 ////////////////////////////////////////////////////////////////////////////////
4031 /// FlagsOpt should contain the options to pass to the C++ compiler
4032 /// in order to compile the library in optimized mode.
4033 
4034 void TSystem::SetFlagsOpt(const char *flags)
4035 {
4036  fFlagsOpt = flags;
4037 }
4038 
4039 ////////////////////////////////////////////////////////////////////////////////
4040 /// AclicMode indicates whether the library should be built in
4041 /// debug mode or optimized. The values are:
4042 /// - TSystem::kDefault : compile the same as the current ROOT
4043 /// - TSystem::kDebug : compiled in debug mode
4044 /// - TSystem::kOpt : optimized the library
4045 
4046 void TSystem::SetAclicMode(EAclicMode mode)
4047 {
4048  fAclicMode = mode;
4049 }
4050 
4051 ////////////////////////////////////////////////////////////////////////////////
4052 /// Directives has the same syntax as the argument of SetMakeSharedLib but is
4053 /// used to create an executable. This creation is used as a means to output
4054 /// a list of unresolved symbols, when loading a shared library has failed.
4055 /// The required variable is $ExeName rather than $SharedLib, e.g.:
4056 /// ~~~ {.cpp}
4057 /// gSystem->SetMakeExe(
4058 /// "g++ -Wall -fPIC $IncludePath $SourceFiles
4059 /// -o $ExeName $LinkedLibs -L/usr/X11R6/lib -lX11 -lm -ldl -rdynamic");
4060 /// ~~~
4061 
4062 void TSystem::SetMakeExe(const char *directives)
4063 {
4064  fMakeExe = directives;
4065  // NOTE: add verification that the directives has the required variables
4066 }
4067 
4068 ////////////////////////////////////////////////////////////////////////////////
4069 /// Directives should contain the description on how to compile and link a
4070 /// shared lib. This description can be any valid shell command, including
4071 /// the use of ';' to separate several instructions. However, shell specific
4072 /// construct should be avoided. In particular this description can contain
4073 /// environment variables, like $ROOTSYS (or %ROOTSYS% on windows).
4074 /// ~~~ {.cpp}
4075 /// Five special variables will be expanded before execution:
4076 /// Variable name Expands to
4077 /// ------------- ----------
4078 /// $SourceFiles Name of source files to be compiled
4079 /// $SharedLib Name of the shared library being created
4080 /// $LibName Name of shared library without extension
4081 /// $BuildDir Directory where the files will be created
4082 /// $IncludePath value of fIncludePath
4083 /// $LinkedLibs value of fLinkedLibs
4084 /// $DepLibs libraries on which this library depends on
4085 /// $ObjectFiles Name of source files to be compiler with
4086 /// their extension changed to .o or .obj
4087 /// $Opt location of the optimization/debug options
4088 /// set fFlagsDebug and fFlagsOpt
4089 /// ~~~
4090 /// e.g.:
4091 /// ~~~ {.cpp}
4092 /// gSystem->SetMakeSharedLib(
4093 /// "KCC -n32 --strict $IncludePath -K0 \$Opt $SourceFile
4094 /// --no_exceptions --signed_chars --display_error_number
4095 /// --diag_suppress 68 -o $SharedLib");
4096 ///
4097 /// gSystem->setMakeSharedLib(
4098 /// "Cxx $IncludePath -c $SourceFile;
4099 /// ld -L/usr/lib/cmplrs/cxx -rpath /usr/lib/cmplrs/cxx -expect_unresolved
4100 /// \$Opt -shared /usr/lib/cmplrs/cc/crt0.o /usr/lib/cmplrs/cxx/_main.o
4101 /// -o $SharedLib $ObjectFile -lcxxstd -lcxx -lexc -lots -lc"
4102 ///
4103 /// gSystem->SetMakeSharedLib(
4104 /// "$HOME/mygcc/bin/g++ \$Opt -Wall -fPIC $IncludePath $SourceFile
4105 /// -shared -o $SharedLib");
4106 ///
4107 /// gSystem->SetMakeSharedLib(
4108 /// "cl -DWIN32 -D_WIN32 -D_MT -D_DLL -MD /O2 /G5 /MD -DWIN32
4109 /// -D_WINDOWS $IncludePath $SourceFile
4110 /// /link -PDB:NONE /NODEFAULTLIB /INCREMENTAL:NO /RELEASE /NOLOGO
4111 /// $LinkedLibs -entry:_DllMainCRTStartup@12 -dll /out:$SharedLib")
4112 /// ~~~
4113 
4114 void TSystem::SetMakeSharedLib(const char *directives)
4115 {
4116  fMakeSharedLib = directives;
4117  // NOTE: add verification that the directives has the required variables
4118 }
4119 
4120 ////////////////////////////////////////////////////////////////////////////////
4121 /// Add includePath to the already set include path.
4122 /// Note: This interface is mostly relevant for ACLiC and it does *not* inform
4123 /// gInterpreter for this include path. If the TInterpreter needs to know about
4124 /// the include path please use \c gInterpreter->AddIncludePath.
4125 
4126 void TSystem::AddIncludePath(const char *includePath)
4127 {
4128  if (includePath) {
4129  fIncludePath += " ";
4130  fIncludePath += includePath;
4131  }
4132 }
4133 
4134 ////////////////////////////////////////////////////////////////////////////////
4135 /// Add linkedLib to already set linked libs.
4136 
4137 void TSystem::AddLinkedLibs(const char *linkedLib)
4138 {
4139  if (linkedLib) {
4140  fLinkedLibs += " ";
4141  fLinkedLibs += linkedLib;
4142  }
4143 }
4144 
4145 ////////////////////////////////////////////////////////////////////////////////
4146 /// IncludePath should contain the list of compiler flags to indicate where
4147 /// to find user defined header files. It is used to expand $IncludePath in
4148 /// the directives given to SetMakeSharedLib() and SetMakeExe(), e.g.:
4149 /// ~~~ {.cpp}
4150 /// gSystem->SetInclude("-I$ROOTSYS/include -Imydirectory/include");
4151 /// ~~~
4152 /// the default value of IncludePath on Unix is:
4153 /// ~~~ {.cpp}
4154 /// "-I$ROOTSYS/include "
4155 /// ~~~
4156 /// and on Windows:
4157 /// ~~~ {.cpp}
4158 /// "/I%ROOTSYS%/include "
4159 /// ~~~
4160 
4161 void TSystem::SetIncludePath(const char *includePath)
4162 {
4163  fIncludePath = includePath;
4164 }
4165 
4166 ////////////////////////////////////////////////////////////////////////////////
4167 /// LinkedLibs should contain the library directory and list of libraries
4168 /// needed to recreate the current executable. It is used to expand $LinkedLibs
4169 /// in the directives given to SetMakeSharedLib() and SetMakeExe()
4170 /// The default value on Unix is: `root-config --glibs`
4171 
4172 void TSystem::SetLinkedLibs(const char *linkedLibs)
4173 {
4174  fLinkedLibs = linkedLibs;
4175 }
4176 
4177 ////////////////////////////////////////////////////////////////////////////////
4178 /// The 'suffix' will be appended to the name of a script loaded by ACLiC
4179 /// and used to locate any eventual additional linkdef information that
4180 /// ACLiC should used to produce the dictionary.
4181 ///
4182 /// So by default, when doing .L MyScript.cxx, ACLiC will look
4183 /// for a file name MyScript_linkdef and having one of the .h (.hpp,
4184 /// etc.) extensions. If such a file exist, it will be added to
4185 /// the end of the linkdef file used to created the ACLiC dictionary.
4186 /// This effectively enable the full customization of the creation
4187 /// of the dictionary. It should be noted that the file is intended
4188 /// as a linkdef `fragment`, so usually you would not list the
4189 /// typical:
4190 /// ~~~ {.cpp}
4191 /// #pragma link off ....
4192 /// ~~~
4193 
4194 void TSystem::SetLinkdefSuffix(const char *suffix)
4195 {
4196  fLinkdefSuffix = suffix;
4197 }
4198 
4199 
4200 ////////////////////////////////////////////////////////////////////////////////
4201 /// Set shared library extension, should be either .so, .sl, .a, .dll, etc.
4202 
4203 void TSystem::SetSoExt(const char *SoExt)
4204 {
4205  fSoExt = SoExt;
4206 }
4207 
4208 ////////////////////////////////////////////////////////////////////////////////
4209 /// Set object files extension, should be either .o, .obj, etc.
4210 
4211 void TSystem::SetObjExt(const char *ObjExt)
4212 {
4213  fObjExt = ObjExt;
4214 }
4215 
4216 ////////////////////////////////////////////////////////////////////////////////
4217 /// This method split a filename of the form:
4218 /// ~~~ {.cpp}
4219 /// [path/]macro.C[+|++[k|f|g|O|c|s|d|v|-]][(args)].
4220 /// ~~~
4221 /// It stores the ACliC mode [+|++[options]] in 'mode',
4222 /// the arguments (including parenthesis) in arg
4223 /// and the I/O indirection in io
4224 
4225 TString TSystem::SplitAclicMode(const char* filename, TString &aclicMode,
4226  TString &arguments, TString &io) const
4227 {
4228  char *fname = Strip(filename);
4229  TString filenameCopy = fname;
4230  filenameCopy = filenameCopy.Strip();
4231 
4232  if (filenameCopy.EndsWith(";")) {
4233  filenameCopy.Remove(filenameCopy.Length() - 1);
4234  filenameCopy = filenameCopy.Strip();
4235  }
4236  if (filenameCopy.EndsWith(")")) {
4237  Ssiz_t posArgEnd = filenameCopy.Length() - 1;
4238  // There is an argument; find its start!
4239  int parenNestCount = 1;
4240  bool inString = false;
4241  Ssiz_t posArgBegin = posArgEnd - 1;
4242  for (; parenNestCount && posArgBegin >= 0; --posArgBegin) {
4243  // Escaped if the previous character is a `\` - but not if it
4244  // itself is preceded by a `\`!
4245  if (posArgBegin > 0 && filenameCopy[posArgBegin] == '\\' &&
4246  (posArgBegin == 1 || filenameCopy[posArgBegin - 1] != '\\')) {
4247  // skip escape.
4248  --posArgBegin;
4249  continue;
4250  }
4251  switch (filenameCopy[posArgBegin]) {
4252  case ')':
4253  if (!inString)
4254  ++parenNestCount;
4255  break;
4256  case '(':
4257  if (!inString)
4258  --parenNestCount;
4259  break;
4260  case '"': inString = !inString; break;
4261  }
4262  }
4263  if (parenNestCount || inString) {
4264  Error("SplitAclicMode", "Cannot parse argument in %s", filename);
4265  } else {
4266  arguments = filenameCopy(posArgBegin + 1, posArgEnd - 1);
4267  fname[posArgBegin + 1] = 0;
4268  }
4269  }
4270 
4271  // strip off I/O redirect tokens from filename
4272  {
4273  char *s2 = 0;
4274  char *s3;
4275  s2 = strstr(fname, ">>");
4276  if (!s2) s2 = strstr(fname, "2>");
4277  if (!s2) s2 = strchr(fname, '>');
4278  s3 = strchr(fname, '<');
4279  if (s2 && s3) s2 = s2<s3 ? s2 : s3;
4280  if (s3 && !s2) s2 = s3;
4281  if (s2==fname) {
4282  io = fname;
4283  aclicMode = "";
4284  arguments = "";
4285  delete []fname;
4286  return "";
4287  } else if (s2) {
4288  s2--;
4289  while (s2 && *s2 == ' ') s2--;
4290  s2++;
4291  io = s2; // ssave = *s2;
4292  *s2 = 0;
4293  } else
4294  io = "";
4295  }
4296 
4297  // remove the possible ACLiC + or ++ and g or O etc
4298  aclicMode.Clear();
4299  int len = strlen(fname);
4300  TString mode;
4301  while (len > 1) {
4302  if (strchr("kfgOcsdv-", fname[len - 1])) {
4303  mode += fname[len - 1];
4304  --len;
4305  } else {
4306  break;
4307  }
4308  }
4309  Bool_t compile = len && fname[len - 1] == '+';
4310  Bool_t remove = compile && len > 1 && fname[len - 2] == '+';
4311  if (compile) {
4312  if (mode.Length()) {
4313  fname[len] = 0;
4314  }
4315  if (remove) {
4316  fname[strlen(fname)-2] = 0;
4317  aclicMode = "++";
4318  } else {
4319  fname[strlen(fname)-1] = 0;
4320  aclicMode = "+";
4321  }
4322  if (mode.Length())
4323  aclicMode += mode;
4324  }
4325 
4326  TString resFilename = fname;
4327 
4328  delete []fname;
4329  return resFilename;
4330 }
4331 
4332 ////////////////////////////////////////////////////////////////////////////////
4333 /// Remove the shared libs produced by the CompileMacro() function.
4334 
4335 void TSystem::CleanCompiledMacros()
4336 {
4337  TIter next(fCompiled);
4338  TNamed *lib;
4339  while ((lib = (TNamed*)next())) {
4340  if (lib->TestBit(kMustCleanup)) Unlink(lib->GetTitle());
4341  }
4342 }
4343 
4344 ////////////////////////////////////////////////////////////////////////////////
4345 /// Register version of plugin library.
4346 
4347 TVersionCheck::TVersionCheck(int versionCode)
4348 {
4349  if (versionCode != TROOT::RootVersionCode() && gLibraryVersion)
4350  gLibraryVersion[gLibraryVersionIdx] = versionCode;
4351 }