mirror of
https://github.com/FairRootGroup/FairMQ.git
synced 2026-06-15 08:17:05 +00:00
ci: add spack package for a tsan-instrumented libstdc++
- gcc ships no supported switch to build libstdc++ with -fsanitize=thread, and spack's gcc recipe filters all flags out of the target-library build (CXXFLAGS_FOR_TARGET is owned by its generated --with-build-config=spack makefile), so provide a dedicated libstdcxx-tsan package in a custom repo - build only the libstdc++-v3 subtree from the matching gcc release tarball, configured standalone against the already-installed toolchain (recipe modeled on https://iree.dev/developers/debugging/sanitizers/), instead of rebuilding all of gcc - the result is a drop-in runtime replacement for the compiler's libstdc++ (same soname and symbol versions), to be loaded only by the instrumented test executables - normalize the install layout after make install: the standalone build puts the runtime libraries into the multilib os dir (lib64 on x86_64) regardless of --libdir, and --with-toolexeclibdir only applies to cross builds - register the repo in the setup-deps action before creating the env
This commit is contained in:
committed by
Dennis Klein
parent
988ef81922
commit
331c50ab0e
1
.github/actions/setup-deps/action.yml
vendored
1
.github/actions/setup-deps/action.yml
vendored
@@ -69,6 +69,7 @@ runs:
|
||||
shell: spack-bash {0}
|
||||
run: |
|
||||
echo "::group::Install dependencies"
|
||||
spack repo add "$GITHUB_WORKSPACE/test/ci/spack_repo/fairmq_ci"
|
||||
spack env create fairmq test/ci/spack-${{ inputs.env }}.yaml
|
||||
spack -e fairmq add gcc@${{ inputs.gcc }}
|
||||
spack -e fairmq config add "packages:all:require:'%gcc@${{ inputs.gcc }}'"
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
import os
|
||||
import shutil
|
||||
|
||||
from spack_repo.builtin.build_systems.generic import Package
|
||||
|
||||
from spack.package import *
|
||||
|
||||
|
||||
class LibstdcxxTsan(Package):
|
||||
"""ThreadSanitizer-instrumented build of GCC's libstdc++.
|
||||
|
||||
GCC ships no supported way to produce a tsan-instrumented libstdc++ (and
|
||||
spack's gcc package offers no hook into the target-library flags), so this
|
||||
package builds only the libstdc++-v3 subtree from the GCC release tarball
|
||||
matching the toolchain, with -fsanitize=thread. The result is a drop-in
|
||||
runtime replacement for the compiler's own libstdc++ (same soname and
|
||||
symbol versions) that lets tsan observe the synchronization inside the
|
||||
C++ standard library (e.g. std::locale/std::regex lazy initialization).
|
||||
|
||||
Select it via LD_LIBRARY_PATH in the environment of the instrumented
|
||||
executables only. Like any shared library built with gcc
|
||||
-fsanitize=thread it carries unresolved __tsan_* symbols satisfied by the
|
||||
executable's libtsan, so loading it into an uninstrumented executable
|
||||
fails.
|
||||
|
||||
Recipe modeled on https://iree.dev/developers/debugging/sanitizers/.
|
||||
"""
|
||||
|
||||
homepage = "https://gcc.gnu.org/onlinedocs/libstdc++/"
|
||||
url = "https://ftp.gnu.org/gnu/gcc/gcc-15.2.0/gcc-15.2.0.tar.xz"
|
||||
|
||||
# Keep in lockstep with the gcc version used by the tsan CI job: a
|
||||
# libstdc++ older than the compiler may lack GLIBCXX symbol versions
|
||||
# that binaries built by that compiler reference. Checksums match the
|
||||
# version() directives in spack's gcc package.
|
||||
version("15.2.0", sha256="438fd996826b0c82485a29da03a72d71d6e3541a83ec702df4271f6fe025d24e")
|
||||
version("14.3.0", sha256="e0dc77297625631ac8e50fa92fffefe899a4eb702592da5c32ef04e2293aca3a")
|
||||
|
||||
depends_on("c", type="build")
|
||||
depends_on("cxx", type="build")
|
||||
depends_on("gmake", type="build")
|
||||
|
||||
def install(self, spec, prefix):
|
||||
# gthr-default.h only materializes in a configured libgcc build dir;
|
||||
# on POSIX targets it is a verbatim copy of gthr-posix.h. Providing it
|
||||
# up front spares building libgcc (and the in-tree compiler).
|
||||
gthr_include = join_path(self.stage.source_path, "spack-gthr")
|
||||
mkdirp(gthr_include)
|
||||
copy(
|
||||
join_path(self.stage.source_path, "libgcc", "gthr-posix.h"),
|
||||
join_path(gthr_include, "gthr-default.h"),
|
||||
)
|
||||
|
||||
flags = f"-I{gthr_include} -O2 -g -fno-omit-frame-pointer -fsanitize=thread"
|
||||
build_dir = join_path(self.stage.source_path, "spack-build")
|
||||
mkdirp(build_dir)
|
||||
with working_dir(build_dir):
|
||||
configure = Executable(
|
||||
join_path(self.stage.source_path, "libstdc++-v3", "configure")
|
||||
)
|
||||
configure(
|
||||
f"--prefix={prefix}",
|
||||
f"--libdir={prefix.lib}",
|
||||
"--disable-multilib",
|
||||
"--disable-libstdcxx-pch",
|
||||
"--enable-libstdcxx-threads=yes",
|
||||
"--with-default-libstdcxx-abi=new",
|
||||
f"CFLAGS={flags}",
|
||||
f"CXXFLAGS={flags}",
|
||||
"LDFLAGS=-fsanitize=thread",
|
||||
)
|
||||
make()
|
||||
make("install")
|
||||
|
||||
# The runtime libraries land in the multilib os dir (lib64 on
|
||||
# x86_64), --libdir notwithstanding (--with-toolexeclibdir only
|
||||
# applies to cross builds); normalize to lib/ for the consumer.
|
||||
if os.path.isdir(prefix.lib64):
|
||||
mkdirp(prefix.lib)
|
||||
for entry in os.listdir(prefix.lib64):
|
||||
shutil.move(join_path(prefix.lib64, entry), join_path(prefix.lib, entry))
|
||||
os.rmdir(prefix.lib64)
|
||||
|
||||
# Only the runtime library is consumed -- compilation uses the
|
||||
# compiler's own (identical) headers. Drop the rest to keep the
|
||||
# buildcache entry small.
|
||||
for directory in ("include", "share"):
|
||||
path = join_path(prefix, directory)
|
||||
if os.path.isdir(path):
|
||||
shutil.rmtree(path)
|
||||
3
test/ci/spack_repo/fairmq_ci/repo.yaml
Normal file
3
test/ci/spack_repo/fairmq_ci/repo.yaml
Normal file
@@ -0,0 +1,3 @@
|
||||
repo:
|
||||
namespace: fairmq_ci
|
||||
api: v2.0
|
||||
Reference in New Issue
Block a user