net: declare io_context in the namespace Asio actually uses - #241
Merged
Conversation
backends/net/config.hpp forward-declares boost::asio::io_context so that the
configuration structs can hold a pointer to it without pulling in
io_context.hpp. Since Boost 1.91 that declaration can name a different type
than the real one.
Asio gained an inline version namespace in 1.91: with
BOOST_ASIO_ENABLE_VERSION_NAMESPACE its types live in
boost::asio::v<version>_<tags>, tagged with the configuration they were built
with, so two differently-configured Asios cannot silently share a mangled name.
A declaration in plain boost::asio is then a second, distinct io_context, and
every use of boost::asio::io_context is ambiguous between the two:
boost/asio/io_context.hpp: error C2872: 'io_context': ambiguous symbol
libremidi/backends/net/config.hpp(9): could be 'boost::asio::io_context'
boost/asio/io_context.hpp(193): or 'boost::asio::v103801_bdemo::io_context'
Declare it inside whichever namespace Asio itself would use. Asio's config
header defines the namespace macros - as empty, when the feature is off - so
pulling it in first both answers the question and costs far less than the
io_context.hpp this declaration exists to avoid; the macros only exist from
1.91 on, which is the version test, no version number needed. This header is
reachable in builds with no Boost at all, so the include is guarded by
__has_include, the same way config.hpp already tests for Boost.
Also declare it as a class rather than a struct, which is how Asio declares it;
the mismatch is what -Wmismatched-tags warns about.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XGta2LPAedDP3Txvyq8kTW
jcelerier
force-pushed
the
fix/asio-version-namespace
branch
from
August 5, 2026 13:39
5ca9375 to
80b74b9
Compare
The winmm, winmidi, winuwp and kdmapi headers each defined both macros unconditionally, as 1. Anything that had already defined them differently - Boost.Asio's config defines WIN32_LEAN_AND_MEAN empty, and build systems commonly pass them on the command line - made every translation unit reaching these headers warn, which under -Werror is a build failure. Guard them, the way backends/linux/dylib_loader.hpp already does. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XGta2LPAedDP3Txvyq8kTW
Removed comments regarding Boost.Asio version namespace handling.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
backends/net/config.hppforward-declaresboost::asio::io_contextso the configuration structs can hold a pointer to it without pulling inio_context.hpp. Since Boost 1.91 that declaration can name a different type than the real one.The problem
Asio gained an inline version namespace in 1.91. With
BOOST_ASIO_ENABLE_VERSION_NAMESPACE, its types live inboost::asio::v<version>_<tags>, tagged with the configuration they were built with, so two differently-configured Asios cannot silently share a mangled name. A declaration in plainboost::asiois then a second, distinctio_context, and every use is ambiguous:Every translation unit including this header fails to compile.
The fix
Declare it inside whichever namespace Asio itself would use:
The macros are empty when the feature is off, so this is the same plain declaration as before in that case — it does not impose the version namespace on anyone. They only exist from 1.91 on, hence the version check rather than an unconditional include.
boost/version.hppis cheap, anddetail/config.hppis far cheaper than theio_context.hppthis declaration exists to avoid.Also declares it as
classrather thanstruct, matching Asio (io_context.hpp:193) — the mismatch is what-Wmismatched-tagswarns about.Why it matters downstream
ossia/libossia#917 needs
BOOST_ASIO_ENABLE_VERSION_NAMESPACEon Windows: with Boost 1.91, Boost.Asio's global symbols lose theirboost_prefix and collide with the standalone Asio that score's LSL addon bundles (duplicate symbol: asio_signal_handler). This header was the only thing blocking it.Verified
Building libossia with MSVC / VS2026 against Boost 1.91, with the version namespace enabled:
libremidi.cpp,observer.cpp,midi_in.cpp,midi_out.cppall fail with C2872asio_v103801_bdemo_signal_handlerrather than the bareasio_signal_handler🤖 Generated with Claude Code
https://claude.ai/code/session_01XGta2LPAedDP3Txvyq8kTW