Repository navigation
Conversation
A Windows consumer that includes <windows.h> before the sendspin headers, as most Win32 code does, failed in two places: - wingdi.h defines ERROR as 0, which turned the LogLevel::ERROR enumerator into `0 = 1`. client.h now sets the macro aside around LogLevel with push_macro/pop_macro, so the consumer's ERROR is restored after it. Code that names LogLevel::ERROR after <windows.h> still needs NOGDI or its own #undef ERROR. - windows.h's max() macro expanded std::numeric_limits<uint16_t>::max() in PlayerRoleConfig::pipeline_lead_time_ms(). It is now parenthesized. The library's own NOMINMAX/WIN32_LEAN_AND_MEAN/NOGDI stay private, so they never covered this.
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
The macro workarounds lack automated regression coverage, so either could be removed without failing the existing host tests.
1 open issue
What changed in this PR
This PR extends the Windows build support from #210 by making public headers tolerate a consumer including <windows.h> first, without changing the public API or the consumer’s macro settings.
Changes:
- Temporarily saves and undefines
ERRORaroundLogLevel, then restores it. - Protects
numeric_limits::max()from macro expansion while preserving lead-time saturation.
| File | Description |
|---|---|
| include/sendspin/config.h | Parenthesizes max to prevent Windows macro expansion. |
| include/sendspin/client.h | Shields the enum declaration from ERROR and documents the remaining consumer-side limitation. |
Review effort: Balanced
A compile-only translation unit includes the standard headers the public headers use, then defines ERROR, min() and max() as <windows.h> does, then includes client.h and persistence_codec.h, and asserts ERROR is restored after them. Dropping the parentheses on numeric_limits<uint16_t>::max() in config.h, the push_macro/#undef in client.h, or its pop_macro each fails the build. It stands in for a Windows CI job compiling against the real <windows.h>.
client.h only forward-declares the roles, so the check never compiled any of the seven public role headers under ERROR, min() and max(). Include each enabled role's header, guarded by its role option as a consumer would, and correct the comment that said client.h brought them in.
This branch has not been deployed
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.

A Windows consumer that includes
<windows.h>before the sendspin headers, as most Win32 code does, fails to compile them. The library'sNOMINMAX/WIN32_LEAN_AND_MEAN/NOGDIfrom #210 are private, so they never covered the public headers.Summary
LogLevel::ERROR. wingdi.h definesERRORas0, which turned the enumerator into0 = 1.client.hnow sets the macro aside aroundLogLevelwith#pragma push_macro("ERROR")/#undef ERROR/#pragma pop_macro("ERROR"), so the consumer's ownERRORis back after it. The pragmas are supported by GCC, Clang and MSVC, so the header needs no#ifdef _WIN32, and they are no-ops whereERRORis not defined.std::numeric_limits<uint16_t>::max()inPlayerRoleConfig::pipeline_lead_time_ms()was expanded by windows.h's function-likemax()macro. It is now(std::numeric_limits<uint16_t>::max)(), with a comment so the parentheses are not tidied away.Notes
LogLevel::ERRORafter<windows.h>still needsNOGDIor its own#undef ERROR; the comment aboveLogLevelsays so. Renaming the enumerator would remove that, but it would break the API for every consumer, so it is left alone.max()macro breaks the standard library headers before it reaches ours. The natural guard is a Windows CI job that compiles one translation unit including<windows.h>first and then every public header; that is planned as a follow-up along with building the library andbasic_clienton Windows in CI.Testing
/W4, every role enabled, one translation unit including every public header:<windows.h>first: failed with 3 errors before this change, compiles cleanly after it.<windows.h>after the sendspin headers, withNOMINMAX+WIN32_LEAN_AND_MEAN, and without<windows.h>: all compile cleanly.static_assert(ERROR == 0)after the headers holds, sopop_macrorestores wingdi's macro.NOGDI, consumer code can nameLogLevel::ERRORafter<windows.h>; without it, it fails in the consumer's own line, as the header comment says.sendspintarget builds with no warnings from the library's own sources.-Wall -Wextra -Wpedantic: both headers compile, a consumer's ownERRORmacro survives the include, andpipeline_lead_time_ms(0xFFFF)still saturates at0xFFFF. The rest of Linux is this PR's CI.