Skip to content

Conversation

@jp-pino
Copy link

@jp-pino jp-pino commented Sep 1, 2025

As mentioned in issue #216 some deprecated code has been removed from asio, making builds fail on boost >= 1.87. This is my attempt to fix this and try to improve the GitHub action to test more versions of Boost on each OS. Changes to the GitHub action were required to make sure that my changes remained backwards compatible.

I'm not an expert on what's going on under the hood in azmq but I just went through every part of the code that wasn't building and looked for the recommended alternative. Any feedback is appreciated.

We rely on azmq for some of our projects, so getting this fixed is of great interest to us.

I've removed the actions running on macos-11, macos-12 and ubuntu-20.04 since those runners have been deprecated. And I've added macos-13, macos-14, macos-15 and ubuntu-24.04 to the matrix, since those are the currently supported versions.

Some OS/Boost combinations that weren't being tested before still won't build (mostly macOS), so I would appreciate some help with this. I'm not sure how much of a priority this is for you. They could also be added to the exclusion list in the action.

Closes #216

@cbrl
Copy link

cbrl commented Oct 13, 2025

The failure that's happening with Ubuntu + Boost 1.70 might be expected: boostorg/thread#297. I think you'll see that with any version of Boost between 1.69 and 1.72.

Some of the macOS errors are caused by an incompatibility with Clang that was fixed in Boost 1.81: boostorg/numeric_conversion@50a1eae

@cbrl
Copy link

cbrl commented Oct 14, 2025

Anecdotally, I can say that I also haven't had any issues with these changes on Windows 11 with Boost 1.89.

The only problem I've had, which is an existing issue in the master branch, is that the async functions added in #195 don't compile when using some newer Asio completion token types. For example, azmq::async_send(socket, buffers, asio::deferred) will give a compilation error due to the usage of BOOST_ASIO_INITFN_RESULT_TYPE in the function signature.

It looks like Asio's async operations now use the return type of async_initiate directly instead of the result macro. For example, the signature of azmq::async_send might be

template<class CompletionToken, class ConstBufferSequence>
auto async_send(azmq::socket &socket, ConstBufferSequence const &buffers, CompletionToken &&token)
-> decltype(
      boost::asio::async_initiate<CompletionToken, void(boost::system::error_code, size_t)>(
          std::declval<async_send_initiation<ConstBufferSequence>>(), token))

I don't know if this necessarily needs to be fixed in this PR, but it's worth noting.

@jp-pino jp-pino marked this pull request as draft October 16, 2025 11:50
@jp-pino
Copy link
Author

jp-pino commented Nov 4, 2025

The branch was getting too polluted with my attempts at making it work for all versions so I cleaned it up a little.

The failure that's happening with Ubuntu + Boost 1.70 might be expected: boostorg/thread#297.

I've given up on getting it to work for 1.70 because of the issues commented by @cbrl. The point of the PR is not to fix Boost, so I guess that's something we can live with.

One of the breaking changes is the deprecation of FindBoost module as described by policy CMP0167.

A simple solution is to use:

# OLD behavior is to use the FindBoost module from cmake
# NEW behavior is to use the Boost CMake provided config files
# Boost 1.70 and above can use the new behavior
if (POLICY CMP0167)
  cmake_policy(SET CMP0167 NEW)
endif()

This however will make all builds for Boost < 1.70 fail. Currently I'm manually specifying in the tests which version of the Policy to use with -DCMAKE_POLICY_DEFAULT_CMP0167={OLD|NEW}.

The policy does specify that in future versions of cmake the FindBoost module might be removed altogether. We could consider dropping support for Boost 1.68 (Release Notes) which is pretty outdated by now (2018) and always set the policy to NEW.

@jp-pino
Copy link
Author

jp-pino commented Nov 4, 2025

Some of the macOS errors are caused by an incompatibility with Clang that was fixed in Boost 1.81: boostorg/numeric_conversion@50a1eae

@cbrl Should we then test on macOS only from 1.81 onwards?

@cbrl
Copy link

cbrl commented Nov 11, 2025

@cbrl Should we then test on macOS only from 1.81 onwards?

Probably. That specific error I linked to happens in Clang 16+, so only starting with macOS 15. However, macOS versions <15 still have other various compile errors in earlier versions of the Boost libraries.

@ACvanWyk
Copy link

@jp-pino . Thank you for the pull request. I also wanted to take a look at this before v1.90 of boost releases.

From your pull request boost version >= 1.68 is going to be supported, should we not just use boost::asio::io_context instead of boost::asio::io_service. The boost asio API was changed to boost::asio::io_context in v1.66 and I think it would be better to use the newer boost::asio::io_context.
Maybe we can use io_context and then for boost version < 1.66 use typedef io_service io_context?

@jp-pino
Copy link
Author

jp-pino commented Nov 26, 2025

@jp-pino . Thank you for the pull request. I also wanted to take a look at this before v1.90 of boost releases.

From your pull request boost version >= 1.68 is going to be supported, should we not just use boost::asio::io_context instead of boost::asio::io_service. The boost asio API was changed to boost::asio::io_context in v1.66 and I think it would be better to use the newer boost::asio::io_context. Maybe we can use io_context and then for boost version < 1.66 use typedef io_service io_context?

Instead of changing all references in the code to io_service (which seemed a bit more dangerous), I opted to introduce this io_service.hpp:

#pragma once

#include <boost/version.hpp>

#if BOOST_VERSION >= 108700
    #include <boost/asio/io_context.hpp>
    namespace boost::asio {
        typedef io_context io_service;   
    }
#else
    #include <boost/asio/io_service.hpp>
#endif

But I agree that since io_context already goes so far back and is now fully deprecated, maybe we should just go for io_context in the code directly. I'll make this change and update the PR in the coming days.

I think I'll keep the file, but change it around to typedef io_service io_context on boost versions < 1.66.

Also notices that in some places we're using this pattern:

#ifdef AZMQ_DETAIL_USE_IO_SERVICE
        actor_service(boost::asio::io_service & ios)
#else
        actor_service(boost::asio::io_context & ios)
#endif 

We can probably also get rid of this and rely on the typedef.

But guess we have to keep it for cases were we do this:

#ifdef AZMQ_DETAIL_USE_IO_SERVICE
            return make_pipe(get_io_service(), defer_start, std::forward<T>(data));
#else
            return make_pipe(get_io_context(), defer_start, std::forward<T>(data));
#endif

@jp-pino
Copy link
Author

jp-pino commented Nov 27, 2025

@jp-pino . Thank you for the pull request. I also wanted to take a look at this before v1.90 of boost releases.

From your pull request boost version >= 1.68 is going to be supported, should we not just use boost::asio::io_context instead of boost::asio::io_service. The boost asio API was changed to boost::asio::io_context in v1.66 and I think it would be better to use the newer boost::asio::io_context. Maybe we can use io_context and then for boost version < 1.66 use typedef io_service io_context?

Thinking about this about further, I'm only testing Boost 1.68 onwards because azmq has been requiring this version for 3 years now (this is in master):

azmq/CMakeLists.txt

Lines 22 to 29 in 4e8f18b

find_package(
Boost 1.68
COMPONENTS system
date_time
thread
chrono
random
REQUIRED)

I guess we can just use io_context and forget about typedef-ing io_service altogether. And also drop boost version checks for versions older than 1.68.

* Refactor io_service to io_context across the codebase for Boost compatibility

* Test against Boost 1.65

* Replace io_context.hpp with Boost's asio/io_context.hpp and update references across the codebase

* Remove testing against versions lower than 1.68

* Refactor documentation to reflect use of io_context

* Refactor code and documentation to reflect use of io_context
@jp-pino
Copy link
Author

jp-pino commented Nov 27, 2025

I've refactored the code to move away from io_service in favor of io_context. I believe all the tests that were previously passing are still passing now.

I took the liberty of dropping some of the checks for BOOST_VERSION that were older than 1.68 since they would always be true.

@jp-pino
Copy link
Author

jp-pino commented Nov 27, 2025

@aboseley @ACvanWyk should I exclude all the tests that currently fail? I'm excluding the tests that were failing. They're all related to boost not compiling for the specific platform because we're probably using gcc/clang versions way beyond what these older Boost versions probably support.

I was trying on another branch to patch older boost versions to get them compiling with very little success. I think it's beyond the scope of this PR to try to patch/fix old boost versions, and installing older gcc/clang might also be a bit of a pain.

@jp-pino jp-pino marked this pull request as ready for review November 27, 2025 16:20
The actor test is multithreaded. I think there's a race condition that might trigger sometimes, where btb could result in still having the old value (0).

I'm using std::future to make sure that the value is updated properly before testing it.
@ACvanWyk
Copy link

ACvanWyk commented Nov 28, 2025

I guess we can just use io_context and forget about typedef-ing io_service altogether. And also drop boost version checks for versions older than 1.66.

I agree. I think it would be better to cleanup it up now and get rid of the io_service stuff while everything else is being updated as well. There are a couple of things that I anyway think requires v1.66 and higher like asio::make_work_guard. I think it makes sense to say the minimum supported version is 1.68. The changes that you made to the CI also makes it easy to test different versions of boost.

I'm excluding the tests that were failing.

That makes sense it. I don't think it is worth the effort to try and fix boost.

Thank you for taking the time to add this PR. This looks good to me.
@aboseley : When this does get merged in could I also maybe suggest bumping the version for a new release?

@jp-pino
Copy link
Author

jp-pino commented Nov 28, 2025

I think there's some sort of race condition in the actor test, as the test fails sporadically. I tried to fix it with 0025c0c but seems like it's still failing sometimes. I ran the failing job again on my branch and it now passes.

This is probably beyond the scope of this PR and points to an underlying problem. Should we just take that in another issue? If so, do I leave my changes or revert them?

@aboseley aboseley merged commit 819b240 into zeromq:master Nov 30, 2025
34 of 35 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fails to build with Asio 1.33.0 / Boost 1.87

4 participants