Skip to content

address review findings on the windows onetbb build - #272

Merged
kevinushey merged 2 commits into
masterfrom
bugfix/windows-onetbb-review-fixes
Jul 28, 2026
Merged

address review findings on the windows onetbb build#272
kevinushey merged 2 commits into
masterfrom
bugfix/windows-onetbb-review-fixes

Conversation

@kevinushey

Copy link
Copy Markdown
Contributor

Follow-up to #269, which was merged before these review findings were applied.
Two are behaviour fixes; the rest tighten things #269 introduced.

Fixes

configure.R: derive the TBB library names whenever an Rtools tree is adopted.
#269 gated the whole Windows block on oneapi/ being present, but that block
does two jobs: deciding whether to adopt the tree, and deriving TBB_NAME /
TBB_MALLOC_NAME from the archive names. Gating both broke an explicitly
configured legacy TBB_LIB: the names fell back to tbb / tbbmalloc, so
PKG_LIBS emitted -ltbb against a directory holding libtbb_static.a. The
_static alternation in the pattern exists precisely for this, and both the
legacy pkgLibs branch and buildTbbStub's "re-export the static tbb library
wholesale" branch still contemplate a non-oneTBB Windows TBB. An explicitly
configured TBB is now honoured whatever its vintage; auto-discovery next to
gcc still requires oneTBB.

configure.R: don't let the cmake probe throw. The probe now runs on
Windows, where the whole point is degrading to tinythread -- but
system(..., intern = TRUE)[[1L]] raises a subscript error if CMAKE points
at nothing runnable, and numeric_version() raises on output it can't parse.
Either turned the intended fallback into a hard configure failure. Any probe
failure is now treated as "no usable cmake": non-fatal on Windows, still a
hard error off it.

R/tbb.R + downstream check: the -ltbb fallback isn't free. The ordering
rationale is right, but the comment presented the fallback as pure upside. The
stub links -ltbb12 itself, so it embeds its own copy of the oneTBB runtime; a
package resolving some symbols from RcppParallel.dll and the rest from the
stub would straddle two independent schedulers, and an observer registered with
one would never fire for arenas owned by the other. In practice most of the
archive is pulled into RcppParallel.dll transitively (arena.cpp references
observer_list), but the failure mode changed from a link error to a silent
correctness bug. The comment now says so, and tbb-downstream-check.R asserts
via objdump -p that nothing lands on the stub -- which also answers one of
#269's own open CI questions.

GNU.cmake: probe with an empty file, not the null device. gcc -c NUL
was plausible but unverified and depends on gcc accepting a device name as an
input file. A file(WRITE ...) probe works identically everywhere and drops
the WIN32 branch entirely.

install.libs.R: don't log the Windows static build as a failure.
.install.libs's shlibPattern still matches ^tbb.*\.dll$ on Windows, so a
bundled Windows build logged no tbb runtime libraries found in 'tbb/build/lib_release'. Benign -- the archive is linked into
RcppParallel.dll -- but it reads like a failure in exactly the logs someone
consults when this goes wrong.

Smaller items

  • windows-11-arm added to the downstream matrix: RcppParallelLibs()
    changed for every Windows platform, and arm64 has both its own vendored
    patch and itt_notify compiled out.
  • Corrected the required cmake version in the error message (>= 3.5, matching
    the check and SystemRequirements).
  • Renamed useBundledTbb to buildBundledTbb in configure.R, so it no
    longer collides with the useBundledTbb() function in install.libs.R.
  • Restored the trailing newline in observer_proxy.cpp.
  • rstan.yaml pins against DESCRIPTION rather than a .9000 suffix, so it
    survives development version bumps.
  • actions/checkout@v3 -> v4, and consistent ${R_ARCH_BIN} in the
    downstream Makevars.
  • Regenerated patches/legacy_tbb_abi.diff and patches/mingw_gnu_cmake.diff
    to match the amended sources.

Verification

  • Configure decision matrix -- simulated 10 toolchains by sourcing the real
    configure.R into a mocked environment. Rtools43+ output is byte-identical
    to build the bundled onetbb on windows when rtools has no onetbb #269
    , so its compatibility claim still holds. Confirmed against the
    pre-fix code that both bugs were real: the explicit legacy TBB_LIB case
    produced TBB_NAME: tbb, and an unparseable cmake version aborted configure
    with invalid version specification.
  • macOS -- full R CMD INSTALL plus all 9 test files; the downstream check
    passes end-to-end (CXX_STD confirmed honoured).
  • CMake probe -- tested standalone: the empty probe file compiles without
    "no input files", and the unparseable-version fallback prevents the
    math(EXPR) failure.
  • Import-table parsing -- unit-tested against synthetic objdump output,
    including case-insensitivity and the last-block boundary.
  • Patches -- all five reverse-apply cleanly against the vendored tree.

What still needs CI

Unchanged from #269: none of the Windows behaviour is testable locally. Two
additions here can legitimately turn CI red and are the ones to watch --
the windows-11-arm downstream job, and the import assertion, which fails if
anything genuinely does resolve from the stub. Both surface information rather
than assume it.

Note patches/windows_arm64.diff does not reverse-apply (it references
src/tbb/build/, which is .Rbuildignored). That predates #269 and is left
alone here.

- configure: derive TBB_NAME / TBB_MALLOC_NAME whenever an Rtools tree is
  adopted, not only when it is oneTBB. gating both on 'oneapi' broke an
  explicitly configured legacy TBB_LIB, which linked -ltbb against a
  directory holding libtbb_static.a
- configure: don't let the cmake probe throw. it now runs on Windows, where
  an unrunnable CMAKE or unparseable --version output has to degrade to
  tinythread rather than fail the configure
- configure: correct the required cmake version in the error message (3.5,
  matching the check and DESCRIPTION), and rename useBundledTbb to
  buildBundledTbb so it no longer collides with the install.libs.R function
- install.libs.R: report the Windows static build explicitly instead of
  logging 'no tbb runtime libraries found', which reads like a failure
- tbb.R: note that the stub carries its own oneTBB runtime, so resolving
  against it means a second scheduler rather than a free fallback
- downstream check: assert the built library imports nothing from the
  tbb.dll stub, which is the property that comment now relies on
- GNU.cmake: probe with an empty file rather than the null device, which
  drops the WIN32 special case and removes the unverified 'gcc -c NUL'
- add windows-11-arm to the downstream matrix, restore the trailing newline
  in observer_proxy.cpp, pin rstan.yaml against DESCRIPTION, checkout@v4
- regenerate patches/legacy_tbb_abi.diff and patches/mingw_gnu_cmake.diff
CI disproved the premise of the import assertion added in the previous
commit. On both windows-latest configurations -- the Rtools45 oneTBB and the
bundled build -- the downstream library takes its entire TBB surface (13
tbb::detail::r1:: entry points, including isolate_within_arena and observe)
from tbb.dll, and imports nothing at all from RcppParallel.dll. R CMD SHLIB
links RcppParallel.dll against an export list generated from the package's
own objects, so the TBB entry points pulled out of the static library are
never re-exported; '-ltbb' is therefore load-bearing, not a fallback.

So assert the invariant that does hold and does matter: the TBB surface must
come from exactly one module. A library split across RcppParallel.dll and the
stub would register observers with one scheduler while its tasks ran in the
other, which is silent, unlike the link error this replaced.

Two further defects in the check itself:

- an objdump that cannot read the file exited non-zero having printed no
  import table, which parsed as 'no imports' and passed vacuously. This is
  what made the windows-11-arm job green: Sys.which() finds the runner's
  x86_64 objdump, which cannot read an aarch64 PE.
- the export table follows the import tables and lists the library's own
  inlined tbb::detail::d1:: instantiations. Left in, it was absorbed into the
  last 'DLL Name:' block and credited that library with TBB imports it never
  had -- harmless only because tbb.dll happened to be listed last.

Also correct the tbbLdFlags() comment, which described RcppParallel.dll as
re-exporting an incidental part of the runtime.
@kevinushey
kevinushey merged commit 69dac53 into master Jul 28, 2026
9 of 18 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.

1 participant