Tutorial Part 2: Using Spack Environments¶
In this tutorial, you’ll learn how to integrate Spack for dependency management. We’ll extend the CMake workflow from Part 1 to use Spack environments, create a Spack package for the project, and add Boost as a dependency.
Prerequisites¶
Spack installed and available in your environment
Your
myappproject from Part 1
Adding Boost Dependency¶
First, let’s modify our application to use Boost.
Update main.cpp¶
Edit main.cpp to use Boost:
#include <iostream>
#include <boost/version.hpp>
int main() {
std::cout << "Hello, World!" << std::endl;
std::cout << "Using Boost "
<< BOOST_VERSION / 100000 << "."
<< BOOST_VERSION / 100 % 1000 << "."
<< BOOST_VERSION % 100 << std::endl;
return 0;
}
Update CMakeLists.txt¶
Update CMakeLists.txt to find and link Boost:
cmake_minimum_required(VERSION 3.12)
project(myapp VERSION 1.0.0 LANGUAGES CXX)
find_package(Boost REQUIRED)
add_executable(myapp main.cpp)
target_link_libraries(myapp PRIVATE Boost::boost)
enable_testing()
add_test(NAME run_myapp COMMAND myapp)
Creating a Spack Package¶
Now we’ll create a Spack package for our project so Spack can manage it.
Create Spack Repository¶
Create a Spack repository directory in your project:
$ spack repo create . myapp
Create Package Recipe¶
Create spack_repo/packages/myapp/package.py:
$ spack create -r spack_repo/myapp myapp
from spack_repo.builtin.build_systems.cmake import CMakePackage
from spack.package import *
class Myapp(CMakePackage):
"""A simple application demonstrating Kessel with Spack"""
homepage = "https://example.com/myapp"
git = "https://github.com/myapp/myapp.git"
version("main", branch="main")
depends_on("boost")
Your project structure should now look like:
myapp/
├── .kessel/
│ └── workflows/
│ └── default.py
├── spack_repo/
│ └── myapp/
│ ├── repo.yaml
│ └── packages/
│ └── myapp/
│ └── package.py
├── CMakeLists.txt
└── main.cpp
Updating the Workflow¶
Now we’ll update the Kessel workflow to use Spack.
Extend with BuildEnvironment¶
Edit .kessel/workflows/default.py:
from kessel.workflows.base.spack import BuildEnvironment
from kessel.workflows.base.cmake import CMake
from kessel.workflows import *
class Default(BuildEnvironment, CMake):
steps = ["env", "configure", "build", "test"]
spack_env = environment("myapp-dev")
project_spec = environment("myapp@main")
This workflow:
Inherits from both
BuildEnvironment(for Spack) andCMake(for building)Adds an
envstep to set up the Spack environmentAdds a
configurestep that installs dependencies and configures CMakeSpecifies the Spack environment name (
myapp-dev)Specifies the project spec (
myapp@main)
Running with Spack¶
First Run¶
Run the workflow with Spack:
$ kessel run
On the first run, Kessel will:
Create a new Spack environment named
myapp-dev(if it doesn’t exist)Add
myapp@mainas a root spec to the environmentRegister the
myappSpack repository in the environmentInstall Boost and other dependencies
Configure the project with CMake
Build and test the application
Verifying the Build¶
Run the built executable:
$ ./build/myapp
Hello, World!
Using Boost 1.84.0
Subsequent Runs¶
On subsequent runs, Kessel will use the existing environment:
$ kessel run
This time, the environment already exists and dependencies are already installed, so the workflow runs much faster.
Working with the Spack Environment¶
Modify Environment¶
You can modify the environment and re-run:
$ spack add cmake@3.27
$ kessel run
Using Different Environments¶
You can specify a different environment at runtime:
$ kessel run -e myapp-test
This creates or uses an environment named myapp-test.
Adding More Dependencies¶
Update the Spack package to add more dependencies.
Edit spack_repo/packages/myapp/package.py:
from spack.package import *
class Myapp(CMakePackage):
"""A simple application demonstrating Kessel with Spack"""
homepage = "https://example.com/myapp"
git = "https://github.com/myapp/myapp.git"
version("main", branch="main")
depends_on("boost")
# Add more dependencies
variant("mpi", default=False, description="Enable MPI support")
depends_on("mpi", when="+mpi")
def cmake_args(self):
args = [
self.define_from_variant("ENABLE_MPI", "mpi")
]
return args
Then rebuild:
$ kessel reset
$ kessel run
Summary¶
In this tutorial, you:
Extended your project to use Boost
Created a Spack package for your project
Updated the workflow to use
BuildEnvironmentandCMakeConfigured Spack environment name and project spec
Ran the workflow with automatic Spack environment creation
Learned to work with Spack environments
Next Steps¶
In Tutorial Part 3: Creating a Spack Deployment, you’ll learn how to create a Spack deployment that can be used to target multiple systems, with pre-built environments and offline build capability.