Regex usage in TSystem::ListLibraries()

Dear all,
I am afraid that my problem has a simple solution, but I failed to find it. After loading some libraries with:

gSystem->Load("myLib.so");

I want to check the actual location of the loaded libraries; I am trying to accomplish this by using TSystem::ListLibraries(const char *regex = “”), but with partial success. I.e., if I use:

gSystem->ListLibraries();

I obtain a complete list of all the loaded libraries. If I replace “” with any kind of regular expression, the result is always empty. For example:

gSystem->ListLibraries(".*")

returns 0 matches, while I naively expected its output to be the same as in the first line. I see this behavior even when I do not load any library, and start root with the -n option (to skip the rootlogon.C file). Would it be possible to point me to some successful examples of using the regex parameter? Thanks for any suggestions! Best,

Alberto


ROOT Version: 6.26/08
Platform: x86_64
Compiler: gcc 11.3.0 (probably)


I agree with you. The regular expression does not seem to work as it should.

I investigated a bit further, and it seems that the “/” characters in the libraries’ names (path names) make the RexExp inoperant. I will see how to fix that and propose a PR. Thanks to have seen it.

Hello,

thank you very much for looking into this, and the extremely prompt feedback! Best,

Alberto

1 Like

The following script shows the issue. The string s1 contains a / and Index with a regulars expression * does not work whereas with s2, which has no /, it is fine:

void regexptest() {
   TRegexp re("*", kTRUE);

   TString s1 = "lib/libRIO.so";
   printf("s1: %s %d\n", s1.Data(), s1.Index(re));

   TString s2 = "lib-libRIO.so";
   printf("s2: %s %d\n", s2.Data(), s2.Index(re));
}

gives:

root [2] .x regexptest.C
s1: lib/libRIO.so -1
s2: lib-libRIO.so 0

-1 means “no match”, and 0 means “match”.

TRegexp re(".*", kFALSE);

TRegexp::MakeWildcard

TSystem::ListLibraries

@abelloni The name of the parameter is misleading. It’s not a “regexp” but a “wildcard expression” (with special treatment of “/”).

Thanks @Wile_E_Coyote . That helps. I will check further this track. In the current implementation TSystem::ListLibraries calls:

      TRegexp user_re(regexp, kTRUE);

With that, it does not work:

% root
   ------------------------------------------------------------------
  | Welcome to ROOT 6.27/01                        https://root.cern |
  | (c) 1995-2022, The ROOT Team; conception: R. Brun, F. Rademakers |
  | Built for macosx64 on Nov 24 2022, 06:43:42                      |
  | From heads/master@v6-25-02-2828-g33beda7d0d                      |
  | With Apple clang version 14.0.0 (clang-1400.0.29.202)            |
  | Try '.help'/'.?', '.demo', '.license', '.credits', '.quit'/'.q'  |
   ------------------------------------------------------------------

root [0] gSystem->ListLibraries();
 
Loaded shared libraries
=======================
/Users/couet/git/couet-root-bin/lib/libRint.so
/Users/couet/git/couet-root-bin/lib/libCore.so
/Users/couet/git/couet-root-bin/lib/libRIO.so
/Users/couet/git/couet-root-bin/lib/libThread.so
/Users/couet/git/couet-root-bin/lib/libtbb.dylib
/Users/couet/git/couet-root-bin/lib/libCling.so
/Users/couet/git/couet-root-bin/lib/libMathCore.so
/Users/couet/git/couet-root-bin/lib/libImt.so
/Users/couet/git/couet-root-bin/lib/libMultiProc.so
/Users/couet/git/couet-root-bin/lib/libNet.so
-----------------------
10 libraries loaded
=======================


root [1] gSystem->ListLibraries("*");
 
Loaded shared libraries
=======================
-----------------------
0 libraries loaded
=======================


root [2] gSystem->ListLibraries(".*");
 
Loaded shared libraries
=======================
-----------------------
0 libraries loaded
=======================


root [3] gSystem->ListLibraries(".*RIO.*");
 
Loaded shared libraries
=======================
-----------------------
0 libraries loaded
=======================
root [4] 

I will try with kFALSE.

@Wile_E_Coyote , yes but how to list only RIO lib only in that case?

@couet Please note that the TSystem::ListLibraries method description explicitly says that it expects a “wildcard expression”, not a “regexp”. That’s how it always was. Don’t make changes that will break “backward compatibility”.

I don’t really know how to force ROOT “wildcard expression” to treat “/” as a regular character. Maybe the original author of this code knows it.

I would use TSystem::GetLibraries, with an empty “regexp” parameter, and then parse the returned character string myself (with a regular “regexp”, not a “wildcard expression”).

Changing the flag to kFALSE in GetLibraries make ListLibrarie mush easier to use.

root [2] gSystem->ListLibraries(".*");
 
Loaded shared libraries
=======================
/Users/couet/git/couet-root-bin/lib/libRint.so
/Users/couet/git/couet-root-bin/lib/libCore.so
/Users/couet/git/couet-root-bin/lib/libRIO.so
/Users/couet/git/couet-root-bin/lib/libThread.so
/Users/couet/git/couet-root-bin/lib/libtbb.dylib
/Users/couet/git/couet-root-bin/lib/libCling.so
/Users/couet/git/couet-root-bin/lib/libMathCore.so
/Users/couet/git/couet-root-bin/lib/libImt.so
/Users/couet/git/couet-root-bin/lib/libMultiProc.so
/Users/couet/git/couet-root-bin/lib/libNet.so
-----------------------
10 libraries loaded
=======================
root [3] gSystem->ListLibraries(".*RIO.*");
 
Loaded shared libraries
=======================
/Users/couet/git/couet-root-bin/lib/libRIO.so
-----------------------
1 libraries loaded
=======================
root [4] 

But I won’t do that change …

//
// Usage example:
// root -l -q 'ListLibraries.cxx(".*libCore\\..*")'
//
#include "TString.h"
#include "TRegexp.h"
#include "TSystem.h"
#include <iostream>
void ListLibraries(const char *regexp = ".*", Bool_t wildcard = kFALSE) {
  if (!gSystem) return; // just a precaution
  if (!(regexp && regexp[0])) regexp = (wildcard ? "*" : ".*");
  TRegexp pat(regexp, wildcard);
  TString libs(gSystem->GetLibraries());
  TString tok;
  Ssiz_t from = 0, ext;
  while (libs.Tokenize(tok, from, " ")) {
    if ((tok.Index(pat, &ext) != 0) || (ext != tok.Length())) continue;
    std::cout << tok << "\n";
  }
}

@couet How about something that is “backward compatible”:

void TSystem::ListLibraries(const char *regexp = "", Bool_t wildcard = kTRUE)
{
   // ...
   TString libs = GetLibraries(regexp, wildcard);
   // ...
}

Yes I was thinking of it.

I made a PR.

This PR allows the following:

root [0] gSystem->ListLibraries("Core")
 
Loaded shared libraries
=======================
-----------------------
0 libraries loaded
=======================


root [1] gSystem->ListLibraries("Core",kFALSE)
 
Loaded shared libraries
=======================
/Users/couet/git/couet-root-bin/lib/libCore.so
/Users/couet/git/couet-root-bin/lib/libMathCore.so
-----------------------
2 libraries loaded
=======================

@couet This output is terribly wrong. The regexp "Core" should return nothing (there is no library with the full file name “Core”. Only a regexp like ".*Core.*" should return both libraries.

@Wile_E_Coyote

That’s exactly the problem the regular expression like ".*Core.*" does not work as a regular expression as it is a wildcard (cf my previous post) and it returns nothing. (bug ?) … now gSystem->ListLibraries("Core") returns nothing either (as before).

But, with the PR, when you put the flag to kFALSE then regexp is considered as a string and you get the two libraries. The PR does not change anything compared to the current behavior. Seems to me it is buggy but you said we should not change it and you proposed a quite complex workaround.

Now I added the possibility to change the flag. So we can tell the method to not consider regexp as a wildcard. The logic is already encoded in GetLibraries, this flag only allows us to trigger it. By doing that (see the new help) you can display the two “Core”.

So, maybe stop calling this parameter “regexp”, because it’s misleading. Change its name to “substring”. Then, when the “wildcard = true” (the default now), it will be treated as a ROOT “wildcard expression”, and when “wildcard = false”, it will be treated as an ordinary “substring” (i.e., it’s never a “regular expression”).

I think the core of the problem now is that the TSystem::GetLibraries method names its parameter “regexp”, but it’s never a “regular expression” (again, it’s either treated as a ROOT “wildcard expression” or as an ordinary “substring”).

Well, maybe the original author of the ROOT “wildcard expression” source code knows how to force it to treat “/” as a regular character.

See my “ListLibraries.cxx” macro. It really takes a “regular expression” as a parameter.

Dear all,

let me thank you for your interest in finding a solution! From a user’s standpoint, it would be great if the name of the parameter were updated, to clarify what, by default, the parameter represents, and have the possibility (e.g., via an additional flag, as you both suggested) to pass a real regular expression. That would make the command very powerful and flexible. I believe I did try both ".*" (reg exp) and "*" (a wildcard expression?), and in both cases the command returned 0 libraries found, hence my original message. Thank you very much again for your suggestions, and proposals for a fix! Best,
Alberto

Hi Alberto,
I will update the PR today.
Cheers,
Olivier

Just remember that, also with the new PR, you will NOT get the “regular expression” functionality.