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}
|
shell: spack-bash {0}
|
||||||
run: |
|
run: |
|
||||||
echo "::group::Install dependencies"
|
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 env create fairmq test/ci/spack-${{ inputs.env }}.yaml
|
||||||
spack -e fairmq add gcc@${{ inputs.gcc }}
|
spack -e fairmq add gcc@${{ inputs.gcc }}
|
||||||
spack -e fairmq config add "packages:all:require:'%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