Building root with standard set to C++20 results in compilation errors on Linux

Hi,
So I was building root from source with the following cmake options (setting it to build with the standard set to C++20)

cmake -DCMAKE_CXX_STANDARD=20 -DCMAKE_INSTALL_PREFIX=/home/jade/bin/root ..

I’ve attached the configuration results (
my-config.txt (14.2 KB))which didn’t have any errors. But about 75% into the build, I get a bunch of compilation errors:

In file included from <module-includes>:1:
/home/jade/root/linux-build/etc/cling/Interpreter/RuntimeUniverse.h:27:10: fatal error: could not build module 'Cling_Runtime_Extra'
#include "cling/Interpreter/Visibility.h"
 ~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
input_line_2:1:10: fatal error: could not build module 'Cling_Runtime'
#include <cling/Interpreter/RuntimeUniverse.h>
 ~~~~~~~~^
In file included from input_line_3:1:
In file included from /home/jade/root/linux-build/etc/cling/lib/clang/13.0.0/include/assert.h:8:
In file included from /usr/include/assert.h:35:
In file included from /usr/include/features.h:485:
/usr/include/x86_64-linux-gnu/gnu/stubs.h:7:11: fatal error: 'gnu/stubs-32.h' file not found
# include <gnu/stubs-32.h>
...
/home/jade/root/linux-build/include/TClassEdit.h:34:10: note: submodule of top-level module 'std' implicitly imported here
#include <typeinfo>
         ^
/home/jade/root/linux-build/include/TClassEdit.h:126:49: error: no type named 'string' in namespace 'std'
      virtual bool ExistingTypeCheck(const std::string & /*tname*/,
                                           ~~~~~^
/home/jade/root/linux-build/include/TClassEdit.h:127:43: error: no type named 'string' in namespace 'std'
                                     std::string & /*result*/) = 0;
                                     ~~~~~^
/home/jade/root/linux-build/include/TClassEdit.h:128:51: error: no type named 'string' in namespace 'std'
      virtual void GetPartiallyDesugaredName(std::string & /*nameLong*/) = 0;
                                             ~~~~~^
/home/jade/root/linux-build/include/TClassEdit.h:129:63: error: no type named 'string' in namespace 'std'
      virtual bool IsAlreadyPartiallyDesugaredName(const std::string & /*nondef*/,
                                                         ~~~~~^
/home/jade/root/linux-build/include/TClassEdit.h:130:63: error: no type named 'string' in namespace 'std'
                                                   const std::string & /*nameLong*/) = 0;

I’ve attached error log to that shows all the compilation errors(
compile-error.txt (15.2 KB)).

I had initially built root without specifying the C++ standard (which I believe defaulted to C++14) and had no build issues. Is there other cmake options I should be adding to get it build for C++20?


Please read tips for efficient and successful posting and posting code

Please fill also the fields below. Note that root -b -q will tell you this info, and starting from 6.28/06 upwards, you can call .forum bug from the ROOT prompt to pre-populate a topic.

_ROOT Version:v6-28-06
_Platform:Ubuntu 20.04
_Compiler:gcc 9.4.0


Hi,

Could your error be caused by missing libc-dev?

Best,
Alvaro

Hi @atd , libc-dev is already installed on my system:

$sudo apt-get install -y libc-dev
Reading package lists... Done
Building dependency tree       
Reading state information... Done
Note, selecting 'libc6-dev' instead of 'libc-dev'
libc6-dev is already the newest version (2.31-0ubuntu9.12).
libc6-dev set to manually installed.
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

$ sudo apt-get install -y libc6-dev
Reading package lists... Done
Building dependency tree       
Reading state information... Done
libc6-dev is already the newest version (2.31-0ubuntu9.12).
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

I have no problem building root from source without specifying -DCMAKE_CXX_STANDARD=20 (which I believe defaults to C++14). I don’t think I’d be able to build root at all if I was missing libc-dev.

It only becomes a problem when I specify -DCMAKE_CXX_STANDARD=20. It’s my understanding that c++20 is supported, no?

@atd, I looked a little further on the stackoverflow link you referred to and it looks like that missing gnu/stubs-32.h could be found by installing g++-multilib on ubuntu. So once I installed it, the compilation error of a missing gnu/stubs-32.h goes away, but there remains other compilation errors, which I’ve attached.
compile-errors.txt (15.0 KB)

One of the compilation errors notes this:

While building module 'ROOT_Foundation_Stage1_NoRTTI' imported from /home/jade/root/linux-build/include/Rtypes.h:197:
In file included from <module-includes>:2:
In file included from /home/jade/root/linux-build/include/ROOT/RStringView.hxx:15:
/home/jade/root/linux-build/include/RConfigure.h:30:4: warning: "The C++ standard in this build does not match ROOT configuration (201709L); this might cause unexpected issues" [-W#warnings]
#  warning "The C++ standard in this build does not match ROOT configuration (201709L); this might cause unexpected issues"
   ^
While building module 'Core':
While building module 'ROOT_Foundation_Stage1_NoRTTI' imported from /home/jade/root/linux-build/include/Rtypes.h:197:
/home/jade/root/linux-build/etc/cling/std.modulemap:69:12: error: header 'compare' not found
    header "compare"

What does it mean that the “C++ standard in this build does not match the ROOT configuration”? When I cmake configured this build for C++20, it didn’t result in any error then.

Hi @jade2 ,

ROOT’s C++ interpreter is detecting that it was asked to just-in-time compile something with C++20 while it was compiled with C++17. Could it be that you are using an old build directory, or that some old build artifacts are getting picked up?

Starting a build from an empty directory should remove this error.

Cheers,
Enrico

Hi @eguiraud,
So I did start off with an empty directory before triggering cmake to configure when I got this complaint while building:

In file included from /home/jade/root/linux-build/include/ROOT/RConfig.hxx:23:
/home/jade/root/linux-build/include/RConfigure.h:30:4: warning: "The C++ standard in this build does not match ROOT configuration (201709L); this might cause unexpected issues" [-W#warnings]
#  warning "The C++ standard in this build does not match ROOT configuration (201709L); this might cause unexpected issues"
   ^
While building module 'Core':
While building module 'ROOT_Rtypes' imported from /home/jade/root/linux-build/include/Rtypes.h:23:
/home/jade/root/linux-build/etc/cling/std.modulemap:69:12: error: header 'compare' not found
    header "compare"

I even went as far to removing the build directory and recreate a new build directory before re-triggering the cmake configuration, setting it for C++20 on that new build directory (the configuration results can be found here config-log.txt (14.9 KB)), but still getting the same errors and warnings when I attempt to build (here’s the full log of all the errors of that new build tmp.txt (15.2 KB)).

Some of the errors even notes that std is undefined:

/home/jade/root/linux-build/etc/cling/Interpreter/DynamicExprInfo.h:40:7: error: use of undeclared identifier 'std'
      std::string m_Result;

I can’t make sense of these error.

I built this from root git branch (HEAD detached at v6-28-06) and this is the compiler I’m using:

$ g++ --version
g++ (Ubuntu 9.4.0-1ubuntu1~20.04.2) 9.4.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Is it possible that some parts of the root code is not built for C++20, but requires C++17?

Ah, alright, thank you for the extra details.

  • ROOT v6.28.06 did not support C++20. You should try with latest master or at least with v6.28.10
  • gcc 9 does not have good C++20 support (see here). I think you will need at least gcc 10, which added std::span and the three-way comparison operator. But 12 or 13 would be better.

As a test I’m building latest master with gcc 13.2.1 passing the following cmake commands:

mkdir cmake-build && \
cmake -S . -B cmake-build -G Ninja -DCMAKE_INSTALL_PREFIX=cmake-build/install -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_STANDARD=20 -Dtesting=ON -Droottest=OFF && \
cmake --build cmake-build -- -j16 install

So far no errors, I’ll report here when done.

Cheers,
Enrico

Hmmm, so I had checked out the latest stable branch from the root repository (which at the time was v6-28-06). I’m leery of building off of master because it might not be stable. Is master really the only branch that supports C++20?

Compilation just finished without errors.

I think v6-30-00-patches is your best bet in terms of C++20 support and stability. It’s the branch that will soon become the v6.30.00 release. (As I mentioned you might also need a more recent gcc).

Cheers,
Enrico

P.S.

I can confirm the v6-30-00-patches branch is tested with C++20 nightly builds (Ubuntu 22.04, gcc 11).

Hi @eguiraud, so I just updated gcc/g++ to version 10.5.0 and went ahead and checked out the v6-30-00-patches branch (see attached config results here config-log.txt (14.2 KB)).

Now I started the build and I do still see these warning as it builds, but doesn’t result in any compilation error:

In file included from /home/jade/root/linux-build/include/ROOT/RConfig.hxx:23:
/home/jade/root/linux-build/include/RConfigure.h:30:4: warning: "The C++ standard in this build does not match ROOT configuration (201709L); this might cause unexpected issues" [-W#warnings]
#  warning "The C++ standard in this build does not match ROOT configuration (201709L); this might cause unexpected issues"

I don’t know why these warnings are reappearing when I did update to a newer gcc/g++ compiler and built it with branch v6-30-00-patches.

Anyway, the build did finish without compilation errors despite that warning. Do I need to be concern of that warning – that is, is it going to produce undefined behaviors while using root?


P.S. concerning my earlier builds that failed (when I had the wrong branch and older compiler), shouldn’t the cmake configuration fail when I tried to set the C++ standard to C++20 against a git branch (v6-28-06) that didn’t support it (that is the cmake files should have verified the max C++ standard it supported). It would have save a lot of confusion on why the build was failing.

P.S. concerning my earlier builds that failed (when I had the wrong branch and older compiler), shouldn’t the cmake configuration fail when I tried to set the C++ standard to C++20 against a git branch (v6-28-06) that didn’t support it (that is the cmake files should have verified the max C++ standard it supported). It would have save a lot of confusion on why the build was failing.

I think this is a very good idea, because you are not the only one who had this problem in the last months or years :slight_smile:

Can you make an improvement request on GitHub about it, so we can find a solution in the ROOT team?

Thanks a lot!

@jonas, should I also file a ticket for the warning I’m getting during compilation:

In file included from /home/jade/root/linux-build/include/ROOT/RConfig.hxx:23:
/home/jade/root/linux-build/include/RConfigure.h:30:4: warning: "The C++ standard in this build does not match ROOT configuration (201709L); this might cause unexpected issues" [-W#warnings]

This complaint comes up several times during the build. The build succeeds, but I don’t know how this warning will impact root’s performance.

PS Improvements to ROOT’s CMake configurations has been posted.

About the warning: it should not be there, and I can’t reproduce it.
Could it be you have a pre-existing ROOT installation that is somehow conflicting with the build process?

Compiling ROOT with one C++ standard and ROOT-based applications with another can cause problems (mostly due of the C++ interpreter), but it does not seem that’s the case for you, so I don’t understand why the warning is triggered.

Regardless of whether I have some pre-existing ROOT installed or not, that shouldn’t impact the build, due to the following reasons:

  • I do have a C++17 version of root installed on my machine, but the way I have my .bashrc setup is, it doesn’t setup root by default (e.g. it doesn’t trigger any thisroot.* which would have defined the root binary path). So my terminal environment by default does not recognize any root installs, unless one explicitly sources a thisroot.* script.

  • The location of where I have my pre-existing root installs is not on any system path. It’s located in my home directory (~/bin/root-<version>).

  • Granted I did have several terminal windows open and I might have sourced the C++17 version of thisroot.* script on one of them and then inadvertently triggered the build in the same terminal. But the thisroot.* scripts largely setups environment variables so that root binary and its tools would be recognized in one’s path, which shouldn’t impact the build configuration (it would be bad design if the build configuration were dependent on environment variables — I hope that is not the case). The build configuration should largely come from either root’s CMake files or inputs to cmake arguments. So this is at least my theory of why the build shouldn’t be impacted by pre-existing ROOT installations (which btw sits in a different subdirectoriy that differs to the directory specified by my current build via CMAKE_INSTALL_PREFIX).

But for the sake of verifying it, I opened a new terminal. I first verified that root wasn’t defined in that terminal, cleared the build directory, before triggering the cmake configuration followed by a build:

~/root/linux-build(v6-30-00-patches)$ which root
~/root/linux-build(v6-30-00-patches)$ rm -rf *
~/root/linux-build(v6-30-00-patches)$ cmake -DCMAKE_CXX_STANDARD=20 -DCMAKE_INSTALL_PREFIX=/home/jade/bin/root-v6-31-00-patches -Dtesting=ON -Droottest=OFF  .. > config-log.txt 2>&1

I’m attaching cmake configuration results here:
config-log.txt (14.2 KB).

So the build still spews this message but only started spewing 68% into the build (not continuously spewing this message):

[ 68%] Generating G__Core.cxx, ../lib/Core.pcm
While building module 'Core':
While building module 'ROOT_Rtypes' imported from /home/jade/root/linux-build/include/Rtypes.h:23:
In file included from <module-includes>:1:
In file included from /home/jade/root/linux-build/include/RtypesCore.h:23:
In file included from /home/jade/root/linux-build/include/ROOT/RConfig.hxx:23:
/home/jade/root/linux-build/include/RConfigure.h:30:4: warning: "The C++ standard in this build does not match ROOT configuration (201709L); this might cause unexpected issues" [-W#warnings]
#  warning "The C++ standard in this build does not match ROOT configuration (201709L); this might cause unexpected issues"

Oddly in enough, for this build, it actually failed and I’m not sure why (last night’s build passed with same settings). I don’t see any compilation error other than this linking dependencies error:

In file included from /home/jade/root/linux-build/include/ROOT/TFuture.hxx:15:
/home/jade/root/linux-build/include/RConfigure.h:30:4: warning: "The C++ standard in this build does not match ROOT configuration (201709L); this might cause unexpected issues" [-W#warnings]
#  warning "The C++ standard in this build does not match ROOT configuration (201709L); this might cause unexpected issues"
   ^
[ 73%] Building CXX object graf2d/primitivesv7/CMakeFiles/ROOTGraphicsPrimitives.dir/src/RText.cxx.o
Scanning dependencies of target G__Imt
[ 73%] Building CXX object core/imt/CMakeFiles/G__Imt.dir/G__Imt.cxx.o
[ 73%] Linking CXX executable RRawFileNetXNG
[ 74%] Linking CXX executable TNetXNGFileTest
/usr/bin/ld: warning: libXrdXml.so.3, needed by /home/jade/bin/root-v6-31-00-patches/lib/libXrdCl.so.3, not found (try using -rpath or -rpath-link)
/usr/bin/ld: /home/jade/bin/root-v6-31-00-patches/lib/libXrdCl.so.3: undefined reference to `XrdXmlMetaLink::DeleteAll(XrdOucFileInfo**, int)'
/usr/bin/ld: /home/jade/bin/root-v6-31-00-patches/lib/libXrdCl.so.3: undefined reference to `XrdXmlMetaLink::ConvertAll(char const*, int&, int)'
collect2: error: ld returned 1 exit status
make[2]: *** [net/netxng/test/CMakeFiles/RRawFileNetXNG.dir/build.make:95: net/netxng/test/RRawFileNetXNG] Error 1
make[1]: *** [CMakeFiles/Makefile2:53687: net/netxng/test/CMakeFiles/RRawFileNetXNG.dir/all] Error 2

I’m attaching the build log here:
build-log.txt (716.5 KB)

Summary:

  • I demonstrated that spawning a new terminal that has no knowledge (e.g. no path to where root is) of root, still causes that spewing of that configuration warning during build.
  • The current build failed. Last night I ran the same exact build (granted not in the same terminal), using the same compiler and cmake options and it succeeded. My guess here is the one of the modules being built has a missing dependency (libXrdCl.so.3 depends on libXrdXml.so.3). Someone should look to see the cmake setup of library libXrdCl. Because the build is run in parallel, this failure is likely a race condition. My build last night got lucky, in that by the time libXrdCl.so was generated libXrdXml.so was already built.

I looked into this a bit more on the failure to build (at least the most recent build) and I had noticed that in the config results (config-log.txt I had loaded up in my previous post), it had this:

-- Looking for XROOTD
-- Found Xrootd version num: 5.5.2 (setting -DROOTXRDVERS=500050002)
--              libXrdMain not found: xproofd will be a wrapper around xrootd
--              libXrdClient not found: use built-in
--              include_dirs: /home/jade/bin/root-v6-31-00-patches/include;/home/jade/root/proof/xrdinc
--              libraries: /home/jade/bin/root-v6-31-00-patches/lib/libXrdUtils.so;/home/jade/bin/root-v6-31-00-patches/lib/libXrdCl.so

And that really confused me on why it was looking at the specified CMAKE_INSTALL_PREFIX directory I passed to cmake, in search for Xrootd. I realized that I had not cleaned out that installed directory, but why would a cmake configuration put that in the path to search for XROOTD libraries? @eguiraud, was this what you were referring to earlier about having previous installations of root???

The successful build yesterday was using the same prefix and did install it to that directory. I didn’t think that to start a new build with the same installation prefix would require me to have to delete the contents of that installation directory; I thought it would suffice to just delete the build directory. In any case, I went ahead and deleted the installation directory and build directory and now the build passes, but it did NOT get rid of the spewing warnings coming out of the build. This still occurs during the build:

In file included from /home/jade/root/linux-build/include/ROOT/RConfig.hxx:23:
/home/jade/root/linux-build/include/RConfigure.h:30:4: warning: "The C++ standard in this build does not match ROOT configuration (201709L); this might cause unexpected issues" [-W#warnings]

On the issue of those warnings about “The C++ standard in this build does not match ROOT configuration (201709L)”, I went digging into the root code and it looks like it’s coming from config/RConfigure.in :

#define ROOT__cplusplus @__cplusplus@
#if defined(__cplusplus) && (__cplusplus != ROOT__cplusplus)
# if defined(_MSC_VER)
#  pragma message("The C++ standard in this build does not match ROOT configuration (@__cplusplus@); this might cause unexpected issues. And please make sure you are using the -Zc:__cplusplus compilation flag")
# else
#  warning "The C++ standard in this build does not match ROOT configuration (@__cplusplus@); this might cause unexpected issues"
# endif
#endif

I don’t know enough about .in files but I suspect that this RConfigure.in is used to generate the RConfigure.h which is one of header files that is associated with this warning. Based on the code above, that warning is issued when __cplusplus is not equal to ROOT__cplusplus, where ROOT__cplusplus is set to @__cplusplus@ (not quite sure what is the difference between __cplusplus and @__cplusplus@). Unfortunately I couldn’t quite figure out how to modify the code above so that the warning message would print out what the __cplusplus value is, in addition to the ROOT__cplusplus value it printed, so that I can see how they differed.

But I was curious given my compiler, what the __cplusplus value is and so wrote this simple C++ code that prints it out:

int main() {

    std::cout << "__cplusplus is " << __cplusplus << std::endl;
    return 0;
}

and built it and ran it:

$ g++ --version
g++ (Ubuntu 10.5.0-1ubuntu1~20.04) 10.5.0
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ g++ -std=c++2a print_cpp.cpp
$ ./a.out
__cplusplus is 201709

So when using the same compiler used to build root, the __cplusplus has a value of 201709. The warning message coming from that root code notes, “does not match ROOT configuration (201709L)”. The only difference here I see is the “L” at the end of this “ROOT configuration” value.

I don’t really understand the motive of this check in RConfigure.in, but it might be the case that something buggy is going on in that code. I’ve exhausted everything on my end on why that warning is appearing on my build of root.

Wow, thank you for digging into these problems @jade2 ! Fantastic investigative work :smiley:

It really shouldn’t matter if the CMAKE_INSTALL_PREFIX already contains a ROOT installation, but it evidently does (and I think I have seen something similar before). I would categorize this as a bug in ROOT’s build system (cc: @bellenot @Axel ).

I think the L is just to make that value a long int when written as a literal in the code. cout wouldn’t print it. So that’s the same value. You can verify by putting just this line in a foo.h file:

const static auto foo = __cplusplus;

and run g++ -std=c++2a -E foo.h (for me it shows __cplusplus expands to 202002L).

I looked into this a bit more but I still don’t understand how those values could end up being different. __cplusplus comes from the compiler and the flags passed to it. ROOT__cplusplus comes from these lines in cmake/modules/RootConfiguration.cmake:

try_compile(has__cplusplus "${CMAKE_BINARY_DIR}" SOURCES "${CMAKE_SOURCE_DIR}/config/__cplusplus.cxx"
            OUTPUT_VARIABLE __cplusplus_PPout)
string(REGEX MATCH "__cplusplus=([0-9]+)" __cplusplus "${__cplusplus_PPout}")
set(__cplusplus ${CMAKE_MATCH_1}L)

where __cplusplus.cxx is just:

#define _STRINGIFY(x) #x
#define STRINGIFY(x) _STRINGIFY(x)

// `#pragma message` is supported in well-known compilers including gcc, clang, icc, and MSVC
#pragma message("__cplusplus=" STRINGIFY(__cplusplus))

int main(void)
{
   return 0;
}

and try_compile should use exactly the same compiler and compiler flags that are used for the rest of ROOT, so __cplusplus should have the exact same value.

If you want you can use the STRINGIFY trick used there to change the warning message in RConfigure.in so that it shows both values. I don’t have other ideas :confused:

EDIT:
it could very well be that using a newer compiler and v6.28.10 or the v6.30 branch the problem just goes away – as I mentioned I cannot reproduce it, and I don’t think I have seen it discussed between ROOT devs, on GitHub or on the forum (not that I am aware of everything that happens everywhere all the time :sweat_smile:).

it could very well be that using a newer compiler and v6.28.10 or the v6.30 branch the problem just goes away

But I am using a new compiler (gcc/g++ 10.5.0) as I noted before here where I had upgraded my compiler on my ubuntu. Which compiler are you using for your build?

If you want you can use the STRINGIFY trick used there to change the warning message in RConfigure.in so that it shows both values.

Does STRINGIFY work for an *.in file (code you referenced that uses STRINGIFY is a C++ code)? I don’t know how to code in *.in files, but I went ahead and tried what you suggested to added the changes to that file:

$ git diff config/RConfigure.in
diff --git a/config/RConfigure.in b/config/RConfigure.in
index 2228d682bd..9ac21b7d4d 100644
--- a/config/RConfigure.in
+++ b/config/RConfigure.in
@@ -21,13 +21,15 @@
 #endif
 
 #define EXTRAICONPATH "@extraiconpath@"
+#define _STRINGIFY(x) #x
+#define STRINGIFY(x) _STRINGIFY(x)
 
 #define ROOT__cplusplus @__cplusplus@
 #if defined(__cplusplus) && (__cplusplus != ROOT__cplusplus)
 # if defined(_MSC_VER)
 #  pragma message("The C++ standard in this build does not match ROOT configuration (@__cplusplus@); this might cause unexpected issues. And please make sure you are using the -Zc:__cplusplus compilation flag")
 # else
-#  warning "The C++ standard in this build does not match ROOT configuration (@__cplusplus@); this might cause unexpected issues"
+#  warning "The C++ standard in this build (STRINGIFY(__cplusplus)) does not match ROOT configuration (@__cplusplus@); this might cause unexpected issues"
 # endif
 #endif

And still it didn’t translate what the __cpluplus value is. This is how that message looks like in the build log:

In file included from /home/jade/root/linux-build/include/ROOT/RConfig.hxx:23:
/home/jade/root/linux-build/include/RConfigure.h:32:4: warning: "The C++ standard in this build (STRINGIFY(__cplusplus)) does not match ROOT configuration (201709L); this might cause unexpected issues" [-W#warnings]
#  warning "The C++ standard in this build (STRINGIFY(__cplusplus)) does not match ROOT configuration (201709L); this might cause unexpected issues"

As I said, I don’t know how to code this *.in file to get it to printout the __cplusplus. Could you reach out to the person who owns this code? He/she should update it to put out a more practical error message by noting how they differ, rather than leaving it for users to find this code and update the message themselves to get more information on why this warning is spewing.

Remaining issues clarified at Root branch v6-30-00-patches for C++20 Not Quite Working - #6 by eguiraud .