Skip to content

Commit

Permalink
Add Spack-based CI workflow
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexanderRichert-NOAA committed Jan 29, 2024
1 parent b2750aa commit de06e8f
Show file tree
Hide file tree
Showing 3 changed files with 221 additions and 0 deletions.
85 changes: 85 additions & 0 deletions .github/workflows/Spack.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# This is a CI workflow for the NCEPLIBS-bufr project.
#
# This workflow builds NCEPLIBS-bufr with Spack, including installing with the
# "--test root" option to run the CTest suite. It also has a one-off job that
# validates the recipe by ensuring that every CMake option that should be set
# in the Spack recipe is so set.
#
# Alex Richert, Sep 2023
name: Spack
on:
push:
branches:
- develop
pull_request:
branches:
- develop

jobs:
# This job builds with Spack using every combination of variants and runs the CTest suite each time
Spack:

strategy:
matrix:
os: ["ubuntu-latest"]
variants: ["+python ~shared", "~python +shared"]
runs-on: ${{ matrix.os }}

steps:

- name: checkout-bufr
uses: actions/checkout@v4
with:
path: bufr

- name: install-python
if: ${{ contains(matrix.variants, '+python') }}
run: |
sudo apt install python3 python3-numpy
- name: spack-build-and-test
run: |
git clone -c feature.manyFiles=true https://github.com/spack/spack
. spack/share/spack/setup-env.sh
spack env create bufr-env $GITHUB_WORKSPACE/bufr/spack/spack.yaml
spack env activate bufr-env
cp $GITHUB_WORKSPACE/bufr/spack/package.py $SPACK_ROOT/var/spack/repos/builtin/packages/bufr/package.py
spack develop --no-clone --path $GITHUB_WORKSPACE/bufr bufr@develop
spack add bufr@develop%gcc@11 ${{ matrix.variants }}
spack external find cmake gmake python py-numpy
spack concretize
# Run installation and run CTest suite
spack install --verbose --fail-fast --test root
# Print test results
#cat $(spack location -i bufr)/.spack/install-time-test-log.txt
# Run 'spack load' and check that key build options were respected
spack load bufr
if [[ "${{ matrix.variants }}" =~ "+shared" ]]; then suffix="so" ; else suffix="a"; fi
libvar=BUFR_LIB4
ls ${BUFR_LIB4} | grep -cE "/libbufr_4\."$suffix'$'
- name: Upload test results
uses: actions/upload-artifact@v3
if: ${{ failure() }}
with:
name: spackci-ctest-output-${{ matrix.os }}-${{ matrix.variants }}
path: ${{ github.workspace }}/*/spack-build-*/Testing/Temporary/LastTest.log

# This job validates the Spack recipe by making sure each cmake build option is represented
recipe-check:
runs-on: ubuntu-latest

steps:

- name: checkout-bufr
uses: actions/checkout@v4
with:
path: bufr

- name: recipe-check
run: |
echo "If this jobs fails, look at the most recently output CMake option below and make sure that option appears in spack/package.py"
for opt in $(grep -ioP '^option\(\K(?!(ENABLE_DOCS))[^ ]+' $GITHUB_WORKSPACE/bufr/CMakeLists.txt) ; do
echo "Checking for presence of '$opt' CMake option in package.py"
grep -cP "define.+\b${opt}\b" $GITHUB_WORKSPACE/bufr/spack/package.py
done
120 changes: 120 additions & 0 deletions spack/package.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# 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 *


class Bufr(CMakePackage):
"""The NOAA bufr library contains subroutines, functions and other
utilities that can be used to read (decode) and write (encode)
data in BUFR, which is a WMO standard format for the exchange of
meteorological data. This is part of the NCEPLIBS project.
The library also includes a Python interface.
"""

homepage = "https://noaa-emc.github.io/NCEPLIBS-bufr"
url = "https://github.com/NOAA-EMC/NCEPLIBS-bufr/archive/refs/tags/v12.0.1.tar.gz"
git = "https://github.com/NOAA-EMC/NCEPLIBS-bufr"

maintainers("AlexanderRichert-NOAA", "edwardhartnett", "Hang-Lei-NOAA", "jbathegit")

version("develop", branch="develop")
version("12.0.1", sha256="525f26238dba6511a453fc71cecc05f59e4800a603de2abbbbfb8cbb5adf5708")
version("12.0.0", sha256="d01c02ea8e100e51fd150ff1c4a1192ca54538474acb1b7f7a36e8aeab76ee75")
version("11.7.1", sha256="6533ce6eaa6b02c0cb5424cfbc086ab120ccebac3894980a4daafd4dfadd71f8")
version("11.7.0", sha256="6a76ae8e7682bbc790321bf80c2f9417775c5b01a5c4f10763df92e01b20b9ca")
version("11.6.0", sha256="af4c04e0b394aa9b5f411ec5c8055888619c724768b3094727e8bb7d3ea34a54")
version("11.5.0", sha256="d154839e29ef1fe82e58cf20232e9f8a4f0610f0e8b6a394b7ca052e58f97f43")
version("11.4.0", sha256="946482405e675b99e8e0c221d137768f246076f5e9ba92eed6cae47fb68b7a26")

# Patch to not add "-c" to ranlib flags when using llvm-ranlib on Apple systems
patch("cmakelists-apple-llvm-ranlib.patch", when="@11.5.0:11.6.0")
# C test does not explicity link to -lm causing DSO error when building shared libs
patch("c-tests-libm.patch", when="@11.5.0:11.7.0")
# Patch to identify Python version correctly
patch("python-version.patch", when="@11.5:12.0.0 +python")

variant("python", default=False, description="Enable Python interface")
variant("shared", default=True, description="Build shared libraries", when="@11.5:")

extends("python", when="+python")

depends_on("python@3:", type=("build", "run"), when="+python")
depends_on("py-setuptools", type="build", when="+python")
depends_on("py-numpy", type=("build", "run"), when="+python")
depends_on("py-pip", type="build", when="+python")
depends_on("py-wheel", type="build", when="+python")

def url_for_version(self, version):
pre = "bufr_" if version < Version("12.0.1") else ""
return (
f"https://github.com/NOAA-EMC/NCEPLIBS-bufr/archive/refs/tags/{pre}v{version}.tar.gz"
)

# Need to make the lines shorter at least on some systems
def patch(self):
with when("@:11.7.1"):
filter_file("_lenslmax 120", "_lenslmax 60", "CMakeLists.txt")

def cmake_args(self):
args = [
self.define_from_variant("ENABLE_PYTHON", "python"),
self.define_from_variant("BUILD_SHARED_LIBS", "shared"),
self.define("BUILD_TESTS", self.run_tests),
]

return args

def flag_handler(self, name, flags):
"""
On macOS if a library built with the ar utility contains objects
with Fortran module data but no executable functions,
the symbols corresponding to the module data may not be resolved
when an object referencing them is linked against the library.
You can work around this by compiling with option -fno-common.
"""
fc = self.compiler.fc
if self.spec.satisfies("platform=darwin"):
if name == "fflags":
if "ifort" in fc or "gfortran" in fc:
flags.append("-fno-common")

# Bufr inserts a path into source code which may be longer than 132
if name == "fflags" and "gfortran" in fc:
flags.append("-ffree-line-length-none")

# Inject flags into CMake build
return (None, None, flags)

def _setup_bufr_environment(self, env, suffix):
libname = "libbufr_{0}".format(suffix)
shared = True if "+shared" in self.spec else False
# Bufr has _DA (dynamic allocation) libs in versions <= 11.5.0
append = "" if self.spec.satisfies("@11.5.0:") else "_DA"
lib = find_libraries(libname + append, root=self.prefix, shared=shared, recursive=True)
lib_envname = "BUFR_LIB{0}".format(suffix) + append
inc_envname = "BUFR_INC{0}".format(suffix) + append
include_dir = "{0}_{1}".format(self.prefix.include.bufr, suffix)

env.set(lib_envname, lib[0])
env.set(inc_envname, include_dir)

if self.spec.satisfies("+python"):
pyver = self.spec["python"].version.up_to(2)
pydir = join_path(os.path.dirname(lib[0]), f"python{pyver}", "site-packages")
env.prepend_path("PYTHONPATH", pydir)

def setup_run_environment(self, env):
suffixes = ["4"]
if not self.spec.satisfies("@12:"):
suffixes += ["8", "d"]
for suffix in suffixes:
self._setup_bufr_environment(env, suffix)

def check(self):
with working_dir(self.builder.build_directory):
make("test")
16 changes: 16 additions & 0 deletions spack/spack.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# This is a Spack Environment file the Spack.yml CI.
#
# It describes a set of packages to be installed, along with
# configuration settings.
spack:
specs: [bufr@develop]
view: false
concretizer:
unify: true

packages:
py-numpy:
externals:
- spec: py-numpy@1.21.5
prefix: /usr
buildable: false

0 comments on commit de06e8f

Please sign in to comment.