Unable to re-run same script twice in cling

I posted this issue in the cling GitHub, but since I’m new to cling I’m not sure if it’s genuinely a bug—or just a misunderstanding of how cling works/is used. The GitHub issue is issue 428 in root-project/cling/issues/ But since I’m a new forum user I can’t add a link to this issue directly, and have re-described it below.

In short: as a warm-up, I wrote a little C++ script in cling. Executing it once works exactly as expected (amazing!) but running it a second time yields all sorts of errors, telling me that basic things (such as the constructor for a std::vector) are no longer defined. This happens even if I unload the script with “.U” before the second invocation. I’ve also had this same problem when trying to use cling with other libraries beyond libstdc++, which is making it hard to use cling in the way I had hoped.

In more detail:

Here’s an example that does not involve data structures from any library, and works fine: I can run this script many times, and even change the constant values between invocations. Suppose in particular that we define the file test1.cpp:

int test1() {
   int a = 9;
   int b = 12;
   int sum = a+b;

   return sum;
}

Running .x test1.cpp twice from within cling produces the expected result—the script runs twice, producing the same output each time:

[cling]$ .x test1.cpp
(int) 21
[cling]$ .x test1.cpp
(int) 21

Next, consider an example that uses a std::vector. First, in order to use this data structure, I create a file test2.h:

#pragma cling add_library_path("/usr/lib/")
#pragma cling load( "libstdc++.dylib" )

#include <vector>

I also create a script test2.cpp:

int test2() {
   std::vector<int> x( 10 );

   for( int i = 0; i < 10; i++ )
      x[i] = 1;

   int sum = 0;
   for( int i = 0; i < 10; i++ )
      sum += x[i];

   return sum;
}

I now run cling -l test2.h, followed by two invocations of the script test2.cpp. (I also tried running .U test.cpp in between the two invocations, which yields the same behavior.) The first invocation returns the expected result (10), but on the second invocation cling complains that the definition of the default constructor is now missing. Here is the output:

[cling]$ .x test2.cpp
(int) 10
[cling]$ .x test2.cpp
In file included from input_line_3:1:
In file included from ./test2.h:4:
/usr/local/opt/llvm/bin/../include/c++/v1/vector:362:5: error: constructor for 'std::__1::__vector_base<int, std::__1::allocator<int> >' must explicitly initialize the base class
      '__vector_base_common<true>' which does not have a default constructor
    __vector_base()
    ^
/usr/local/opt/llvm/bin/../include/c++/v1/vector:515:14: note: in instantiation of member function 'std::__1::__vector_base<int, std::__1::allocator<int> >::__vector_base' requested here
    explicit vector(size_type __n);
             ^
/Users/kmcrane/test2.cpp:2:21: note: in instantiation of member function 'std::__1::vector<int, std::__1::allocator<int> >::vector' requested here
   std::vector<int> x( 10 );
                    ^
/usr/local/opt/llvm/bin/../include/c++/v1/vector:324:64: note: 'std::__1::__vector_base_common<true>' declared here
_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS __vector_base_common<true>)
                                                               ^
In file included from input_line_3:1:
In file included from ./test2.h:4:
In file included from /usr/local/opt/llvm/bin/../include/c++/v1/vector:276:
In file included from /usr/local/opt/llvm/bin/../include/c++/v1/__bit_reference:15:
/usr/local/opt/llvm/bin/../include/c++/v1/algorithm:2587:12: error: type 'std::__1::__less<unsigned long, unsigned long>' does not provide a call operator
    return __comp(__b, __a) ? __b : __a;
           ^~~~~~
/usr/local/opt/llvm/bin/../include/c++/v1/algorithm:2596:19: note: in instantiation of function template specialization 'std::__1::min<unsigned long, std::__1::__less<unsigned long, unsigned
      long> >' requested here
    return _VSTD::min(__a, __b, __less<_Tp>());
                  ^
/usr/local/opt/llvm/bin/../include/c++/v1/vector:1014:19: note: in instantiation of function template specialization 'std::__1::min<unsigned long>' requested here
    return _VSTD::min<size_type>(__alloc_traits::max_size(this->__alloc()),
                  ^
/usr/local/opt/llvm/bin/../include/c++/v1/vector:991:15: note: in instantiation of member function 'std::__1::vector<int, std::__1::allocator<int> >::max_size' requested here
    if (__n > max_size())
              ^
/usr/local/opt/llvm/bin/../include/c++/v1/vector:1126:9: note: in instantiation of member function 'std::__1::vector<int, std::__1::allocator<int> >::__vallocate' requested here
        __vallocate(__n);
        ^
/Users/kmcrane/test2.cpp:2:21: note: in instantiation of member function 'std::__1::vector<int, std::__1::allocator<int> >::vector' requested here
   std::vector<int> x( 10 );

Here’s my setup:

cling version: 0.9
MacOS version 10.15.17
installed via Homebrew on August 28, 2021

Many thanks for taking a look!

Probably not related, but there are some pending issues with reloading things in cling:
https://sft.its.cern.ch/jira/browse/ROOT-8689

Thanks! Yeah, not clear it’s directly related but good to know.

This JIra issue is from @Axel . May be he can give your more details.

Totally related, this is one of the known issues we have and need to address when reloading templates.

Is this blocking your actual use case?

I tried to allow links to github.com even from new users - are you telling me this doesn’t work?

Is this blocking your actual use case?

Yes, though I have to confess that our usage is not related to ROOT. We are using cling to build an interactive console on top of the GeometryCentral and Polyscope libraries for polygon mesh processing/visualization. (I unfortunately can’t add links to these libraries, but if you Google them they will turn up at the top of the search). So far things work ok, but when we try to use some standard features in a script, it becomes impossible to “edit and re-run”, which is a common usage pattern for people used to working in, say, a MATLAB-like interactive environment.

For instance, we use range-based for loops which are defined in terms of templates, which seems to cause trouble for reloading. That’s why I constructed the minimal example above of using range-based for on a std vector, but in the end it sounds like it may be templates and not range-based loops that are the issue (in fact, I can confirm this with another example where I define a custom type with range-based loops inline—which works fine upon multiple invocations).

I tried to allow links to github even from new users - are you telling me this doesn’t work?

Correct. The forum simply prevents new users from posting links to any site (including GitHub).

There’s nothing worth confessing here. We need to fix this, but we needed to fix this since a while, and so far we didn’t manage to allocate the expert time we need for this. Do you have clang-expert volunteers on your side? (Just asking :slight_smile: )

Thanks for the info on posting links; I’ll investigate…

Does your code work if you remove #include <vector> (but still use vectors)? That could be a workaround. I saw that behaviour on ROOT 5, which needed this include but didn’t let you re-run the macro; at some point (probably since ROOT 6) this include became unnecessary at least when running from the interactive prompt. And you may also need to clear the vectors at the end of your macro to avoid problems on subsequent runs.

There are certainly some folks at CMU who know clang/LLVM well… but not that I know (well) personally!

Thanks for taking a look, and let me know if I can do anything else to help.

No, unfortunately I then just get the usual “implicit instantiation of undefined template.”

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