Gate needs to use at least the same C++ standard as ROOT
MacPorts installs ROOT6 with -Dcxx17=ON. As as consequence Gate fails to compile:
/usr/bin/clang++ -DG4INTY_USE_QT -DG4UI_USE -DG4UI_USE_QT -DG4UI_USE_TCSH -DG4VERBOSE -DG4VIS_USE -DG4VIS_USE_OPENGL -DG4VIS_USE_OPENGLQT -DG4_STORE_TRAJECTORY -F//System/Library/Frameworks -I/opt/local/libexec/root6/include/root -I/opt/local/include/libxml2 -I/path/to/gate/work/build -I/path/to/gate/work/Gate-8.1.p01/source/arf/include -I/path/to/gate/work/Gate-8.1.p01/source/geometry/include -I/path/to/gate/work/Gate-8.1.p01/source/physics/include -I/path/to/gate/work/Gate-8.1.p01/source/digits_hits/include -I/path/to/gate/work/Gate-8.1.p01/source/general/include -I/path/to/gate/work/Gate-8.1.p01/source/externals/clhep/include -I/path/to/gate/work/Gate-8.1.p01/source/externals/itk-mhd -I/path/to/gate/work/Gate-8.1.p01/source/externals/itk-mhd/itkzlib -I/path/to/gate/work/Gate-8.1.p01/source/externals/itk-mhd/src -I/path/to/gate/work/build/itk-mhd -isystem /opt/local/include/Geant4/Geant4.10.4/Geant4 -isystem /opt/local/include -isystem /opt/local/libexec/qt4/include -isystem /opt/local/libexec/qt4/include/QtCore -isystem /opt/local/libexec/qt4/include/QtGui -isystem /opt/local/libexec/qt4/include/QtOpenGL -pipe -Os -stdlib=libc++ -W -Wall -pedantic -Wno-non-virtual-dtor -Wno-long-long -Wwrite-strings -Wpointer-arith -Woverloaded-virtual -Wno-variadic-macros -Wshadow -pipe -Qunused-arguments -stdlib=libc++ -DG4USE_STD11 -std=c++11 -Wno-shadow -std=c++11 -arch x86_64 -mmacosx-version-min=10.9 -std=c++11 -o CMakeFiles/Gate.dir/source/arf/src/GateARFSD.cc.o -c /path/to/gate/work/Gate-8.1.p01/source/arf/src/GateARFSD.cc
In file included from /path/to/gate/work/Gate-8.1.p01/source/arf/src/GateARFTableMgr.cc:15:
In file included from /path/to/gate/work/Gate-8.1.p01/source/arf/include/GateARFTable.hh:17:
In file included from /opt/local/libexec/root6/include/root/TROOT.h:28:
In file included from /opt/local/libexec/root6/include/root/TDirectory.h:25:
In file included from /opt/local/libexec/root6/include/root/TNamed.h:26:
In file included from /opt/local/libexec/root6/include/root/TString.h:28:
/opt/local/libexec/root6/include/root/ROOT/RStringView.hxx:19:10: fatal error: 'string_view' file not found
#include <string_view>
^
Apparently Gate needs to be compiled with the same (or higher) C++ standard as ROOT6 (and probably Geant4 as well).
I could simply add -std=c++17 to CXXFLAGS, but that's probably not considered a very nice practice. Is there any way to communicate the standard that was used for compiling ROOT6? CMake has good support for figuring out which standard to use, provided that support files for dependencies are written in a proper way. I don't know if that's the case for ROOT, but it should be possible to fix it in case it is not.
geant4-config is already returning -std=c++11, but that's not the way how the need for C++11 was supposed to be communicated to Gate's CMake anyway.
To start with it would probably help if I could simply pass -Dcxx17=ON to Gate's CMake configuration, even if no C++11 standards were communicated between Geant4, ROOT and Gate.
(Our ticket is here: https://trac.macports.org/ticket/57735. I'll find a workaround, but it would be nice to have this fixed in a proper way.)
This isn't supposed to be done this way:
# we force the c++11 std. This is mandatory for Geant4 >= 10.2.
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
A nicer way could be
set_property(TARGET <target-name> PROPERTY CXX_STANDARD 11)
or
set (CMAKE_CXX_STANDARD 11)
or one of the few other methods. But in reality this should be automatically inherited from Geant4 and ROOT (if properly written).
Thanks for bringing this up.
I think that the original motivation for including -std=c++11 in Gate's CMAKE_CXX_FLAGS is that developers wanted to use C++11 language features in the code without being forced to enclose them in cumbersome proprocessor ifdefs that would either disable the feature or provide a C++03 workaround for compilers that do not support C++11.
The CMake line that we have now (hardcode -std=c++11 into the compiler flags) does something more restrictive than this motivation described in the provious paragraph: it freezes it at one C++ standard. I think that the line originates from many years ago, when the Gate developers could not yet imagine that in the future, a new C++ standard would be released every 3 years. A test that "the compiler should use the C++11 standard or newer" would have been better, but from staring at the CMake docs I could not figure out how to encode such a requirement in CMakeLists.txt.
Suppose that I manage to retrieve the C++ standard specs of Geant4, ROOT and ITK (if the user enables it), and they are all different; say one is C++11, one is C++14 and one is C++17; then which standard should I use for compiling Gate code? The newest? The oldest?
I wonder if maybe the simplest and laziest solution would be to just completely omit the standard specification from the Gate CMakeLists.txt file: let the compiler use its default standard. And in the installation docs we warn the users that Gate won't build with compilers that do not support c++11 or newer. Over time the number of users with those really old compilers should decay to zero anyway.
BTW: there may also be a standards that are too new, because they have removed language features that have been deprecated for a while, such as auto_ptr and gets(s). I don't think Gate uses these two particular features (however, ECAT and/or LMF does use gets), but there may be others that we do use. While browsing the https://isocpp.org web page to refresh my memory on this topic, I noticed that rand(), srand() and RAND_MAX are deprecated/removed, and those are actually used in our code (which I don't understand, because we already have a GateRandomEngine, and it does not make sense to use more than one random number generator in one program; fortunately it only happens in the GPU code, which we may axe anyway, and in the 'cluster_tools', where it's easy to replace it with something else).
Check https://www.youtube.com/watch?v=bsXLMQ6WgIk One of the relevant parts starts at cca. 19:15, but it's worth watching the whole video anyway.
The idea is that you are NOT the one determining the compiler standard, CMake should be doing that instead of you, and it would of course give you the newest required standard (it could be that for example Geant4 requires C++17 to be built, but only C++14 to use it). I didn't think of deprecated features, but if they are deprecated, the code should be fixed and the deprecated syntax should be expressed in a different way.
I wonder if maybe the simplest and laziest solution would be to just completely omit the standard specification from the Gate
CMakeLists.txtfile: let the compiler use its default standard. And in the installation docs we warn the users that Gate won't build with compilers that do not support c++11 or newer. Over time the number of users with those really old compilers should decay to zero anyway.
Please don't omit the standard. Just don't hardcode it into CXXFLAGS and let CMake do its magick.
On my CentOS8 boxe, I have Geant4 built by me using -std=c++11 (output of geant4-config) and root-config using -std=c++14 Trying to build gate9 fails in that situation and I get many errors like the following one: In file included from /usr/include/root/TBranchCacheInfo.h:26, from /usr/include/root/TBranch.h:30, from /usr/include/root/TLeaf.h:44, from /home/admin-local/rpmbuild/BUILD/Gate-9.0/source/io/src/GateRootTreeFile.cc:11: /usr/include/root/TString.h:110:13: error: expected type-specifier operator std::string_view() const { return std::string_view(Data(),fExtent); } ^~~ /usr/include/root/TString.h:275:32: error: 'string_view' in namespace 'std' does not name a type explicit TString(const std::string_view &sub);
=> When rebuilding geant4 with GEANT4_BUILD_CXXSTD="14" (same std as root is built with), gate builds fine.