re-export tbbmalloc from RcppParallel.dll on windows#262
Merged
Conversation
downstream packages on windows link with '-lRcppParallel' alone, and so can only use tbb symbols that RcppParallel.dll exports. the tbb runtime symbols come along implicitly -- RcppParallel references them, so those archive members are linked in and re-exported via their '-export:' directives -- but nothing references the tbbmalloc entry points, so packages using the scalable allocator (e.g. via RcppArmadillo's ARMA_USE_TBB_ALLOC) fail to link with undefined references to scalable_malloc and scalable_free. link tbbmalloc with --whole-archive so its objects are always included and re-exported. tbbmalloc must precede tbb on the link line: both archives bundle an itt_notify object defining the same symbols, and with tbbmalloc's copy already linked, tbb's is never pulled in. older (non-oneTBB) toolchains like rtools42 keep the plain link: there, tbb and tbbmalloc both define DllMain and so cannot be linked wholesale, and their objects carry no '-export:' directives to re-export anyhow.
generates a small package using scalable_malloc and scalable_free via the RcppParallel::CxxFlags() / RcppParallelLibs() flags, installs it, and confirms the allocator can be used. on windows, this exercises the tbbmalloc re-export from RcppParallel.dll; elsewhere, the run-time resolution of tbbmalloc symbols loaded by RcppParallel::.onLoad(). the test builds a package, so it runs only on CI (or with NOT_CRAN), and only when the tbb backend is enabled.
R CMD check sets R_TESTS=startup.Rs when running tests, which breaks R sub-processes run with a different working directory. the Rscript invocations in the test package's Makevars failed at startup because of this, expanding CxxFlags() and RcppParallelLibs() to nothing, so compilation failed with tbb/scalable_allocator.h not found.
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.
Problem
RcppParallel 6.0.0 broke linking for downstream Windows packages that use the TBB scalable allocator (e.g. via RcppArmadillo's
ARMA_USE_TBB_ALLOC):Seen in the wild building mr.mashr on r-universe: https://github.com/r-universe/cran/actions/runs/30078654393/job/89436369922
On Windows,
RcppParallelLibs()emits only-lRcppParallel, so downstream packages can only use TBB symbols thatRcppParallel.dllexports. The tbb runtime symbols come along implicitly: RcppParallel references them, so those members of the static Rtoolslibtbb12.aare linked in, and re-exported via the-export:directives embedded in the objects (merged with R'stmp.def). But nothing in RcppParallel references the tbbmalloc entry points, so no member oflibtbbmalloc.ais ever linked in, andscalable_mallocand friends are not exported. (5.1.11 additionally emitted-L$(TBB_LIB) -ltbb -ltbbmallocfor downstream packages, so they got these symbols statically from Rtools; that was dropped in 6.0.0.)Fix
Link tbbmalloc into
RcppParallel.dllwith--whole-archive, so its objects are always included and theirscalable_*API is re-exported. Downstream flags are unchanged.Two details:
itt_notifyobject defining the same 189 strong symbols. With tbbmalloc's copy linked first, tbb's is never pulled in (nothing in libtbb12 requires symbols unique to its own itt object); the reverse order fails withduplicate symbol: __itt_fini_ittlib.DllMain, so tbbmalloc cannot be linked wholesale; its objects also carry no-export:directives, so nothing would be re-exported anyhow. No change in behavior on those toolchains.Note that plain tbbmalloc does not replace the default allocator -- that is
tbbmalloc_proxy's job, which is a separate archive (and not shipped by Rtools at all). Verified against the actual Rtools archives:libtbbmalloc.adefines thescalable_*API and internal helpers only; nomalloc/free/operator newoverrides, and noDllMainon oneTBB toolchains.Validation
Simulated R's exact link (def file + flag order) with clang/lld against the real Rtools43/44/45 archives:
scalable_*symbols, plus the same 70tbb::detail::r1symbols as the shipped 6.0.0 binary