Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 137 additions & 0 deletions packages/g4beamline/package.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# Copyright 2013-2023 Lawrence Livermore National Security, LLC and other
# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)

import os

from spack.package import *
from spack.build_systems.cmake import CMakeBuilder as _SpackCMakeBuilder


class G4beamline(CMakePackage):
"""G4beamline: a particle-tracking simulation program built on top of
Geant4. Provides a scripting layer that lets users describe beamline
geometries without writing C++ Geant4 code. Maintained by Tom Roberts at
Muons Inc."""

homepage = "https://muonsinc.com/Website1/tiki-index.php?page=G4beamline"

# Upstream does not publish a stable, machine-fetchable tarball URL
# (the download lives behind a Tiki wiki page). The hashes below were
# computed against the tarballs archived in
# /cvmfs/mu2e.opensciencegrid.org/DataFiles/G4beamlin
url = "file:///cvmfs/mu2e.opensciencegrid.org/DataFiles/G4beamline/G4beamline-3.08-source.tar"

def url_for_version(self, version):
return "file:///cvmfs/mu2e.opensciencegrid.org/DataFiles/G4beamline/G4beamline-{0}-source.tar".format(
version
)

maintainers("oksuzian")

version(
"3.08b",
sha256="6000e4811fa7263d5a7551fa6821640b5cd10e0bfea58d987f9a4df92500ad3f",
)
version(
"3.08a",
sha256="27416645283b88bbbc9d464f11cbb86ee4c862ead83c3f83c3c004df92acf4cb",
)
version(
"3.08",
sha256="55519c23ed10c8430d4cc727ce4af7873f0abff93bb5ccf18d80a01e20b49c55",
)

variant("gui", default=False, description="Build the Qt-based GUI")
variant("visual", default=False, description="Build OpenGL visualization support")

depends_on("cmake@3.16:", type="build")
depends_on("geant4@11.0:11.2", when="@3.08:3.08a")
depends_on("geant4@11.3:", when="@3.08b")
depends_on("geant4 +qt", when="+gui")
depends_on("geant4 +opengl", when="+visual")
depends_on("root")
depends_on("fftw")
depends_on("gsl")
depends_on("xerces-c")

def patch(self):
# 1. Geant4Data: by default G4beamline downloads its own copy of the
# Geant4 datasets into a private directory. Flip the default to
# `false` so it instead picks up G4LEDATA / G4NEUTRONHPDATA / ...
# from the geant4 spack package's run environment.
filter_file(
r"static\s+bool\s+setup\s*\(\s*bool\s+overwriteEnv\s*=\s*true\s*\)\s*;",
r"static bool setup(bool overwriteEnv=false);",
"g4bl/Geant4Data.hh",
)

# 2. BLEvaluator: upstream allocates with `new[]` but frees with
# `free()`. Replace the free() with delete[].
filter_file(
r"free\(in\);",
r"delete[] in;",
"g4bl/BLEvaluator.hh",
)

# The two patches below were applied upstream in 3.08b, so they only
# need to run for older releases.
if self.spec.satisfies("@:3.08a"):
# 3. BLRunManager: Geant4 11.3 added a required argument to
# G4StackManager::PrepareNewEvent.
filter_file(
r"stackManager->PrepareNewEvent\(\s*\)\s*;",
r"stackManager->PrepareNewEvent(currentEvent);",
"g4bl/BLRunManager.cc",
)

# 4. Newer GCC drops the `sighandler_t` typedef from <signal.h>
# in some contexts. Use an explicit function-pointer type at
# the declaration site; the local typedef on line ~87 is left
# in place but no longer needed.
filter_file(
r"sighandler_t\s+prevSighandler",
r"void (*prevSighandler)(int)",
"g4bl/BLRootNTuple.cc",
)

def setup_run_environment(self, env):
env.set("G4BL_DIR", self.prefix)
env.prepend_path("PATH", self.prefix.bin)

def setup_dependent_run_environment(self, env, dependent_spec):
env.set("G4BL_DIR", self.prefix)
env.prepend_path("PATH", self.prefix.bin)


class CMakeBuilder(_SpackCMakeBuilder):
def cmake_args(self):
# G4beamline's CMakeLists reads GSL_DIR / FFTW_DIR from the env (or
# accepts them as cache vars) instead of using find_package(). Pass
# the spack prefixes explicitly.
spec = self.pkg.spec
return [
self.define_from_variant("G4BL_GUI", "gui"),
self.define_from_variant("G4BL_VISUAL", "visual"),
self.define("GSL_DIR", spec["gsl"].prefix),
self.define("FFTW_DIR", spec["fftw"].prefix),
]

def install(self, pkg, spec, prefix):
# Run upstream's CMake install target first. It populates
# bin/doc/examples/etc. inside the build directory (and also bundles
# everything into a tgz that ignores CMAKE_INSTALL_PREFIX, which is
# why the spack prefix would otherwise be left empty and trigger
# "Nothing was installed!").
super().install(pkg, spec, prefix)

# Now hand-copy just the artifacts we actually want into the spack
# prefix, matching the layout Kevin documented on the Mu2e wiki.
for d in ("bin", "doc", "examples", "share", "test", "validation"):
src = join_path(self.build_directory, d)
if os.path.isdir(src):
install_tree(src, join_path(prefix, d))
readme = join_path(self.build_directory, "README.txt")
if os.path.isfile(readme):
install(readme, prefix)
155 changes: 155 additions & 0 deletions packages/mu2e-ort/package.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
# Copyright 2013-2024 Lawrence Livermore National Security, LLC and other
# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)

from spack.package import *
import os


class Mu2eOrt(CMakePackage):
"""ONNX Runtime: cross-platform, high performance ML inferencing and training accelerator"""

homepage = "https://onnxruntime.ai/"
url = "https://github.com/microsoft/onnxruntime/archive/refs/tags/v1.25.1.tar.gz"
git = "https://github.com/microsoft/onnxruntime.git"

maintainers("rlcee")

license("MIT")

# patch version to force rebuild after tweaking recipe
# version("1.25.1c", sha256="b0c49a093976bf84f099a19aa13a46bd1d213e1d13b34ffe3b0916657209a844")
# version("1.25.1b", sha256="b0c49a093976bf84f099a19aa13a46bd1d213e1d13b34ffe3b0916657209a844")
# version("1.25.1a", sha256="b0c49a093976bf84f099a19aa13a46bd1d213e1d13b34ffe3b0916657209a844")
version(
"1.25.1",
sha256="b0c49a093976bf84f099a19aa13a46bd1d213e1d13b34ffe3b0916657209a844",
)

# Build system
depends_on("cmake@3.26:", type="build")
depends_on("python@3.8:", type="build")

# Core dependencies
# Note: protobuf, re2, abseil-cpp, and flatbuffers are ALL vendored by ONNX Runtime
# Using system versions causes the build to create shared library dependencies
# that won't be found at runtime. ONNX Runtime is designed to statically link
# all these dependencies into libonnxruntime.so for portability.
# depends_on("protobuf") # REMOVED - must be vendored
# depends_on("re2")
# depends_on("abseil-cpp")
# depends_on("flatbuffers")
depends_on("nlohmann-json")

# Optional: CUDA support
variant("cuda", default=False, description="Build with CUDA support")
depends_on("cuda", when="+cuda")
depends_on("cudnn", when="+cuda")

# Build variants
variant("shared", default=True, description="Build shared libraries")
variant("tests", default=False, description="Build and run tests")

# The build.sh script is a Python wrapper around CMake
# We need to bypass it and call CMake directly in Spack

# Tell Spack this is a CMake project but the root CMakeLists.txt
# is in the cmake subdirectory
root_cmakelists_dir = "cmake"

def cmake_args(self):
"""
Generate CMake arguments.

The build.sh script normally calls tools/ci_build/build.py which:
1. Parses command-line arguments
2. Translates them to CMake flags
3. Runs cmake with those flags

In Spack, we bypass build.sh/build.py and call CMake directly,
providing the same flags that build.py would generate.
"""
args = [
# Build configuration
# CRITICAL: Do NOT use BUILD_SHARED_LIBS - it's a global CMake variable
# that affects ALL subprojects including vendored dependencies!
# When BUILD_SHARED_LIBS=ON, vendored protobuf/abseil/re2 build as shared libs
# that are never installed, causing unresolved dependencies.
# self.define_from_variant("BUILD_SHARED_LIBS", "shared"), # WRONG!
# Instead, use ONNX Runtime's specific flag
self.define("onnxruntime_BUILD_SHARED_LIB", self.spec.satisfies("+shared")),
# Explicitly set BUILD_SHARED_LIBS=OFF to ensure vendored deps are static
self.define("BUILD_SHARED_LIBS", False),
# Architecture compatibility: Force x86_64_v2 for portability
# This ensures the binary runs on older CPUs without AVX/AVX2
# Building on x86_64_v3 with default flags may generate AVX instructions
# that will crash on x86_64_v2 machines with "Illegal instruction"
self.define("CMAKE_C_FLAGS", "-march=x86-64-v2 -mtune=generic"),
self.define("CMAKE_CXX_FLAGS", "-march=x86-64-v2 -mtune=generic"),
# Disable warnings as errors (needed for GCC compatibility)
self.define("onnxruntime_ENABLE_WERROR", False),
# Core build options (matching our successful build)
self.define("onnxruntime_BUILD_UNIT_TESTS", self.spec.satisfies("+tests")),
self.define("onnxruntime_BUILD_BENCHMARKS", False),
# Disable language bindings (we only need C++ library)
self.define("onnxruntime_BUILD_CSHARP", False),
self.define("onnxruntime_BUILD_JAVA", False),
self.define("onnxruntime_BUILD_NODEJS", False),
self.define("onnxruntime_BUILD_OBJC", False),
self.define("onnxruntime_BUILD_SHARED_LIB", self.spec.satisfies("+shared")),
self.define("onnxruntime_BUILD_APPLE_FRAMEWORK", False),
# Disable Python bindings
self.define("onnxruntime_ENABLE_PYTHON", False),
# CRITICAL: Prevent CMake from finding system dependencies!
# Even without depends_on("protobuf"), Spack's unified view allows CMake
# to find protobuf automatically via find_package(). When found, ONNX Runtime
# uses it and creates shared library dependencies that won't be installed.
# We must explicitly disable find_package() for vendored dependencies.
self.define("CMAKE_DISABLE_FIND_PACKAGE_Protobuf", True),
self.define("CMAKE_DISABLE_FIND_PACKAGE_absl", True),
self.define("CMAKE_DISABLE_FIND_PACKAGE_re2", True),
self.define("CMAKE_DISABLE_FIND_PACKAGE_Flatbuffers", True),
# This forces ONNX Runtime to vendor and statically link these dependencies
# into libonnxruntime.so, creating a self-contained library with only system deps
# Disable training (we only need inference)
self.define("onnxruntime_ENABLE_TRAINING", False),
self.define("onnxruntime_ENABLE_TRAINING_OPS", False),
self.define("onnxruntime_ENABLE_TRAINING_APIS", False),
# Keep all operators (full-featured build)
# Note: We're NOT using --disable_contrib_ops or --disable_ml_ops
# to maintain full inference capability
]

# CUDA support
if self.spec.satisfies("+cuda"):
args.extend(
[
self.define("onnxruntime_USE_CUDA", True),
self.define("onnxruntime_USE_CUDNN", True),
self.define(
"CMAKE_CUDA_ARCHITECTURES", "70;75;80;86"
), # Adjust as needed
]
)

return args

def setup_build_environment(self, env):
"""Set up the build environment."""
# Ensure Python is available for the build process
# (Some build scripts still need Python even though we're using CMake directly)
env.set("PYTHONPATH", self.stage.source_path)

@run_after("install")
def check_install(self):
"""Verify the installation."""
if self.spec.satisfies("+shared"):
# Check that the shared library was installed
# ONNX Runtime installs to lib64 on some systems
lib_path = join_path(self.prefix.lib64, "libonnxruntime.so")
if not os.path.exists(lib_path):
# Try lib directory as fallback
lib_path = join_path(self.prefix.lib, "libonnxruntime.so")
if not os.path.exists(lib_path):
raise InstallError("Shared library not found in lib or lib64")
Loading