ROOT 6.32 and Boost.Asio Conflict?


ROOT 6.32.04
Built for linuxx8664gcc on Aug 14 2024, 04:01:00
From tags/v6-32-04@v6-32-04
With c++ (Ubuntu 13.2.0-23ubuntu4) 13.2.0


Dear ROOT Team,

TLDR;

I tried to use Boost.Asio with ROOT. And I got an access issue:

[...] error: 'impl_type' is a private member of 'boost::asio::io_context'
io_context::impl_type& [...]

ROOT 6.32

Here are the instructions to reproduce the error with Docker:

$ docker run -it rootproject/root bash
root@6a9d1cebd5fe:/opt# apt install -y libboost-dev
[...]
root@6a9d1cebd5fe:/opt# root -e "#include <boost/asio.hpp>"
   ------------------------------------------------------------------
  | Welcome to ROOT 6.32.04                        https://root.cern |
  | (c) 1995-2024, The ROOT Team; conception: R. Brun, F. Rademakers |
  | Built for linuxx8664gcc on Aug 14 2024, 04:01:00                 |
  | From tags/v6-32-04@v6-32-04                                      |
  | With c++ (Ubuntu 13.2.0-23ubuntu4) 13.2.0                        |
  | Try '.help'/'.?', '.demo', '.license', '.credits', '.quit'/'.q'  |
   ------------------------------------------------------------------

root [0] 
In file included from ROOT_cli_0:1:
In file included from /usr/include/boost/asio.hpp:21:
In file included from /usr/include/boost/asio/any_completion_handler.hpp:28:
In file included from /usr/include/boost/asio/associated_cancellation_slot.hpp:20:
In file included from /usr/include/boost/asio/cancellation_signal.hpp:304:
/usr/include/boost/asio/impl/cancellation_signal.ipp:82:20: error: 'auto_delete_helper' is a private member of 'boost::asio::cancellation_slot'
cancellation_slot::auto_delete_helper::~auto_delete_helper()
                   ^
/usr/include/boost/asio/cancellation_signal.hpp:283:10: note: declared private here
  struct auto_delete_helper
         ^
In file included from ROOT_cli_0:1:
In file included from /usr/include/boost/asio.hpp:32:
In file included from /usr/include/boost/asio/basic_datagram_socket.hpp:20:
In file included from /usr/include/boost/asio/basic_socket.hpp:22:
In file included from /usr/include/boost/asio/detail/io_object_impl.hpp:23:
In file included from /usr/include/boost/asio/io_context.hpp:1525:
/usr/include/boost/asio/impl/io_context.ipp:49:13: error: 'impl_type' is a private member of 'boost::asio::io_context'
io_context::impl_type& io_context::add_impl(io_context::impl_type* impl)
            ^
/usr/include/boost/asio/io_context.hpp:199:35: note: declared private here
  typedef detail::io_context_impl impl_type;
                                  ^
root [1] .q
root@6a9d1cebd5fe:/opt#

ROOT 6.30

A previous version of ROOT didn’t encounter this issue, e.g.:

$ docker run -it rootproject/root:6.30.06-ubuntu22.04 bash
root@00af6dd3723e:/opt# apt install -y libboost-dev
[...]
root@00af6dd3723e:/opt# root -e "#include <boost/asio.hpp>"
   ------------------------------------------------------------------
  | Welcome to ROOT 6.30/06                        https://root.cern |
  | (c) 1995-2024, The ROOT Team; conception: R. Brun, F. Rademakers |
  | Built for linuxx8664gcc on Apr 03 2024, 10:42:17                 |
  | From tags/v6.30.06-0-g4f4e716372@v6.30.06-0-g4f4e716372          |
  | With c++ (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0                   |
  | Try '.help'/'.?', '.demo', '.license', '.credits', '.quit'/'.q'  |
   ------------------------------------------------------------------

root [0] 
root [1] .q
root@00af6dd3723e:/opt# 

Do you know how to solve this problem?

Best Regards,

Salomon

Dear @Salomon ,

Thanks for reaching out to the forum. Let me try to reproduce your problem and I’ll come back to you. Cheers,
Vincenzo

Dear @Salomon ,

Meanwhile, I found that it looks to be related only to the interactive session of ROOT. A compiled program does not seem to be affected:

#include <boost/asio.hpp>

int main(){}
$: g++ -o test.out test.cpp `root-config --cflags --glibs`

The above works.
Vincenzo

Dear @vpadulan,

Thank you for your answer and your MWE.

I propose to consider another minimal example: Uranie CEA / Prerequisites / Prerequisites Detection / Detect ROOT + Boost · GitLab

On Ubuntu 22, tested prerequisites are:

  • CMake 3.22: cmake/jammy-updates […]
  • ROOT 6.32: installed from source
  • Boost 1.74: libboost-system-dev/jammy […]

Include in Source

Please consider commit: Resolve "[43042] Boost.Asio" (1076e11c) · Commits · Uranie CEA / Prerequisites / Prerequisites Detection / Detect ROOT + Boost · GitLab

Building was successful:

$ cmake -DCMAKE_INSTALL_PREFIX=${CI_PROJECT_DIR}/install ../ -DCMAKE_CXX_STANDARD=${CXX_STANDARD}
-- The C compiler identification is GNU 11.4.0
-- The CXX compiler identification is GNU 11.4.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found Boost: /usr/lib/x86_64-linux-gnu/cmake/Boost-1.74.0/BoostConfig.cmake (found suitable version "1.74.0", minimum required is "1.66") found components: coroutine system 
[...]
-- Configuring done
-- Generating done
[...]
$ cmake --build . --target install -j $(nproc)
[ 20%] Generating G__LinkBoost.cxx, libLinkBoost_rdict.pcm, libLinkBoost.rootmap
Scanning dependencies of target G__LinkBoost
[ 40%] Building CXX object CMakeFiles/G__LinkBoost.dir/G__LinkBoost.cxx.o
[ 40%] Built target G__LinkBoost
[ 60%] Building CXX object CMakeFiles/LinkBoost.dir/src/Routine.cpp.o
[ 80%] Building CXX object CMakeFiles/LinkBoost.dir/src/Process.cpp.o
[100%] Linking CXX shared library libLinkBoost.so
[100%] Built target LinkBoost
Install the project...
[...]

Include in Header

Now, please consider commit: include in header (ee9ebd1f) · Commits · Uranie CEA / Prerequisites / Prerequisites Detection / Detect ROOT + Boost · GitLab
where:

#include <boost/asio.hpp>

was moved from src/Process.cpp to inc/Process.hpp.

Then the access error was triggered:

$ cmake -DCMAKE_INSTALL_PREFIX=${CI_PROJECT_DIR}/install ../ -DCMAKE_CXX_STANDARD=${CXX_STANDARD}
-- The C compiler identification is GNU 11.4.0
-- The CXX compiler identification is GNU 11.4.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found Boost: /usr/lib/x86_64-linux-gnu/cmake/Boost-1.74.0/BoostConfig.cmake (found suitable version "1.74.0", minimum required is "1.66") found components: coroutine system 
[...]
-- Configuring done
-- Generating done
[...]
$ cmake --build . --target install -j $(nproc)
[ 20%] Generating G__LinkBoost.cxx, libLinkBoost_rdict.pcm, libLinkBoost.rootmap
In file included from input_line_9:43:
In file included from /[...]/detect-root-boost/inc/Process.hpp:4:
In file included from /usr/include/boost/asio.hpp:24:
In file included from /usr/include/boost/asio/basic_datagram_socket.hpp:20:
In file included from /usr/include/boost/asio/basic_socket.hpp:22:
In file included from /usr/include/boost/asio/detail/io_object_impl.hpp:23:
In file included from /usr/include/boost/asio/io_context.hpp:1521:
/usr/include/boost/asio/impl/io_context.ipp:49:13: error: 'impl_type' is a private member of 'boost::asio::io_context'
io_context::impl_type& io_context::add_impl(io_context::impl_type* impl)
            ^
/usr/include/boost/asio/io_context.hpp:216:35: note: declared private here
  typedef detail::io_context_impl impl_type;
                                  ^
Error: /[...]/detect-root-boost/outputs/root/bin/rootcling: compilation failure (/[...]/detect-root-boost/build/libLinkBoost2d5735396f_dictUmbrella.h)
gmake[2]: *** [CMakeFiles/G__LinkBoost.dir/build.make:82 : G__LinkBoost.cxx] Erreur 1
gmake[1]: *** [CMakeFiles/Makefile2:138 : CMakeFiles/G__LinkBoost.dir/all] Erreur 2
gmake: *** [Makefile:146 : all] Erreur 2

Could you test this minimal example, please?

Dear ROOT Team,

I would like to know if you were able to run this second MWE (Detect ROOT + Boost).

Best regards,

Yes I can confirm this issue. The code compiles with boost in the header file using ROOT 6.30.08 on lxplus8, but not ROOT 6.32.04 on lxplus9.

That is because you’re using ROOT_STANDARD_LIBRARY_PACKAGE to declare your library, which then calls rootcling to build the dictionaries anyway.

Would it be an option to factorize your code better such that all classes that you need to tell Cling about are declared in headers that don’t include any boost headers? You can also hide the boost stuff behind an #ifndef __CLING__ if you want.

If you absolutely need to include the boost headers, then please feel free to open a GitHub issue about this problem:

But if I were in your situation, I would first try to factorize the code better. That will also have other benefits. I guess the only reason why it wouldn’t factorize is because you use boost types as data members for the classes you declare to ROOT cling. Any I guess that would blow up in any case :slight_smile:

Thank you very much for you answer.

With my client, we have to deal with a case where a data member is pointer to a structure with a boost type.

Here is a demo: Resolve "[43112]" (ba66a0b9) · Commits · Uranie CEA / Prerequisites / Prerequisites Detection / Detect ROOT + Boost · GitLab

And the test passed:

2: Test command: /.../detect-root-boost/outputs/root/bin/root "-q" "/.../detect-root-boost/test_process.C"
2: Working Directory: /.../detect-root-boost/build
2: Environment variable modifications: 
2:  LD_LIBRARY_PATH=path_list_prepend:/.../detect-root-boost/install/lib64
2: Test timeout computed to be: 1500
2:    ------------------------------------------------------------------
2:   | Welcome to ROOT 6.32.04                        https://root.cern |
2:   | (c) 1995-2024, The ROOT Team; conception: R. Brun, F. Rademakers |
2:   | Built for linuxx8664gcc on Sep 02 2024, 08:10:06                 |
2:   | From tags/v6-32-04@v6-32-04                                      |
2:   | With c++ (GCC) 8.4.1 20200928 (Red Hat 8.4.1-1)                  |
2:   | Try '.help'/'.?', '.demo', '.license', '.credits', '.quit'/'.q'  |
2:    ------------------------------------------------------------------
2: 
2: 
2: Processing /.../detect-root-boost/test_process.C...
2/2 Test #2: process ..........................   Passed    1.22 sec

However I wonder if there is a better alternative to:

  • struct Context; predeclaration in Process.hpp
  • manual allocation.

This hack was used to avoid boost inclusion in the header.

This is not a hack, this is a completely valid use of forward declarations to avoid some dependency like boost to leak into other parts of the project, like the dictionary generation.

Just be careful to forward declare correctly. The boost::asio::io_context is not a class but a struct. But you wrap it in your own Context struct anyway, which you then forward declare! This is very good, because then you have full control if forward declaration and actual declaration are matching.

Also, another tool that might come handy is the __CLING__ preprocessor macro, which is only defined when you use the interpreter Cling (like in the dictionary generation where you’re getting the error). So you can do maybe something like:

#ifndef __CLING__
// when using Cling, forward declare "Context"
// to avoid indirect inclusion of boost/asio header
namespace MWE {
   struct Context;
}
#else
// otherwise, include full header for convenience
// (maybe this is not even adding convenience in any case,
// then just forget about this preprocessor conditionals).
#include <context.hpp>
#endif