Make header-only builds work from any number of translation units - #104
Open
susilehtola wants to merge 1 commit into
Open
Make header-only builds work from any number of translation units#104susilehtola wants to merge 1 commit into
susilehtola wants to merge 1 commit into
Conversation
The runtime generator's definitions in generators/impl/ had external linkage, so including impl.hpp from two translation units produced duplicate symbols. The README documented the constraint honestly -- include it "exactly once per project" -- but that is not something a downstream project can enforce across its own dependencies. Marking the definitions unconditionally inline does not work either: an inline function that is not odr-used in a translation unit is never emitted, so the precompiled libintegratorxx would export nothing and the default build would fail to link. The two modes genuinely want different linkage, and the whole point of the precompiled default is to keep the large angular dispatch out of consumer translation units. Give them different linkage explicitly: * INTEGRATORXX_GENERATOR_LINKAGE (impl/linkage.hpp) expands to `inline` when INTEGRATORXX_HEADER_ONLY is defined and to nothing otherwise. * The CMake header-only branch now defines INTEGRATORXX_HEADER_ONLY on the interface target; previously the option only changed the target type, so nothing in the sources could tell the modes apart. * In header-only mode the public generator headers include their own implementations at the end of the file, where the declarations are already visible. The impl headers include the public ones back, which #pragma once reduces to a no-op. * test/lib_impl.cxx existed only to instantiate the generator once for the header-only test build, and is no longer needed. impl.hpp had no include guard at all; add one. Verified both ways: the default build still exports the generator symbols from libintegratorxx.a and passes 9/9 tests, the header-only build passes 9/9 tests, and two translation units that both include impl.hpp now link. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FDTFYJMQ76iujDFNHzZyXF
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.
The runtime generator's definitions in generators/impl/ had external
linkage, so including impl.hpp from two translation units produced
duplicate symbols. The README documented the constraint honestly --
include it "exactly once per project" -- but that is not something a
downstream project can enforce across its own dependencies.
Marking the definitions unconditionally inline does not work either: an
inline function that is not odr-used in a translation unit is never
emitted, so the precompiled libintegratorxx would export nothing and the
default build would fail to link. The two modes genuinely want different
linkage, and the whole point of the precompiled default is to keep the
large angular dispatch out of consumer translation units.
Give them different linkage explicitly:
inlinewhen INTEGRATORXX_HEADER_ONLY is defined and to nothing otherwise.
the interface target; previously the option only changed the target
type, so nothing in the sources could tell the modes apart.
implementations at the end of the file, where the declarations are
already visible. The impl headers include the public ones back, which
#pragma once reduces to a no-op.
the header-only test build, and is no longer needed.
impl.hpp had no include guard at all; add one.
Verified both ways: the default build still exports the generator symbols
from libintegratorxx.a and passes 9/9 tests, the header-only build passes
9/9 tests, and two translation units that both include impl.hpp now link.
Co-Authored-By: Claude Opus 5 (1M context) noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01FDTFYJMQ76iujDFNHzZyXF