Skip to content

Commit

Permalink
Add Manylinux_2_28 workflow using deprecated github actions versions
Browse files Browse the repository at this point in the history
  • Loading branch information
ptheywood committed Sep 4, 2024
1 parent 42786c5 commit f1aef5a
Show file tree
Hide file tree
Showing 2 changed files with 355 additions and 0 deletions.
173 changes: 173 additions & 0 deletions .github/scripts/install_cuda_el8.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
# Install CUDA on Alma8/manylinux_2_28.

## -------------------
## Constants
## -------------------

# dnf install cuda-nvrtc-devel-11-4 cuda-compiler-11-4 cuda-cudart-devel-11-4 cuda-nvcc-11-4 cuda-nvrtc-11-4 cuda-nvtx-11-4 libcurand-devel-11-4

# List of sub-packages to install.
# @todo - pass this in from outside the script?
# @todo - check the specified subpackages exist via apt pre-install? apt-rdepends cuda-9-0 | grep "^cuda-"?

# Ideally choose from the list of meta-packages to minimise variance between cuda versions (although it does change too)
CUDA_PACKAGES_IN=(
"cuda-compiler"
"cuda-cudart-devel" # libcudart.so
"cuda-driver-devel" # libcuda.so
"cuda-nvtx"
"cuda-nvrtc-devel"
"libcurand-devel" # 11-0+
)

## -------------------
## Bash functions
## -------------------
# returns 0 (true) if a >= b
function version_ge() {
[ "$#" != "2" ] && echo "${FUNCNAME[0]} requires exactly 2 arguments." && exit 1
[ "$(printf '%s\n' "$@" | sort -V | head -n 1)" == "$2" ]
}
# returns 0 (true) if a > b
function version_gt() {
[ "$#" != "2" ] && echo "${FUNCNAME[0]} requires exactly 2 arguments." && exit 1
[ "$1" = "$2" ] && return 1 || version_ge $1 $2
}
# returns 0 (true) if a <= b
function version_le() {
[ "$#" != "2" ] && echo "${FUNCNAME[0]} requires exactly 2 arguments." && exit 1
[ "$(printf '%s\n' "$@" | sort -V | head -n 1)" == "$1" ]
}
# returns 0 (true) if a < b
function version_lt() {
[ "$#" != "2" ] && echo "${FUNCNAME[0]} requires exactly 2 arguments." && exit 1
[ "$1" = "$2" ] && return 1 || version_le $1 $2
}


## -------------------
## Select CUDA version
## -------------------

# Get the cuda version from the environment as $cuda.
CUDA_VERSION_MAJOR_MINOR=${cuda}

# Split the version.
# We (might/probably) don't know PATCH at this point - it depends which version gets installed.
CUDA_MAJOR=$(echo "${CUDA_VERSION_MAJOR_MINOR}" | cut -d. -f1)
CUDA_MINOR=$(echo "${CUDA_VERSION_MAJOR_MINOR}" | cut -d. -f2)
CUDA_PATCH=$(echo "${CUDA_VERSION_MAJOR_MINOR}" | cut -d. -f3)
# query rpm to find the major enterprise linux release
EL_MAJOR=$(rpm -E %{rhel})

echo "CUDA_MAJOR: ${CUDA_MAJOR}"
echo "CUDA_MINOR: ${CUDA_MINOR}"
echo "CUDA_PATCH: ${CUDA_PATCH}"
echo "EL_MAJOR: ${EL_MAJOR}"

# If we don't know the CUDA_MAJOR or MINOR, error.
if [ -z "${CUDA_MAJOR}" ] ; then
echo "Error: Unknown CUDA Major version. Aborting."
exit 1
fi
if [ -z "${CUDA_MINOR}" ] ; then
echo "Error: Unknown CUDA Minor version. Aborting."
exit 1
fi
# If we don't know the Ubuntu version, error.
if [ -z ${EL_MAJOR} ]; then
echo "Error: Unknown EL version. Aborting."
exit 1
fi

## -------------------------------
## Select CUDA packages to install
## -------------------------------
CUDA_PACKAGES=""
for package in "${CUDA_PACKAGES_IN[@]}"
do :
# CUDA < 11, lib* packages were actually cuda-cu* (generally, this might be greedy.)
if [[ ${package} == libcu* ]] && version_lt "$CUDA_VERSION_MAJOR_MINOR" "11.0" ; then
package="${package/libcu/cuda-cu}"
fi
# CUDA < 11, -devel- packages were actually -dev
if [[ ${package} == *devel* ]] && version_lt "$CUDA_VERSION_MAJOR_MINOR" "11.0" ; then
package="${package//devel/dev}"
fi
# Build the full package name and append to the string.
CUDA_PACKAGES+=" ${package}-${CUDA_MAJOR}-${CUDA_MINOR}"
done
echo "CUDA_PACKAGES ${CUDA_PACKAGES}"

## -----------------
## Prepare to install
## -----------------

CPU_ARCH="x86_64"
# Nvidia don't provide an explicit alma repo. 11.2's closest is RHEL.
# 12.4 includes rocky8/9, rhel7/8/9, cent7, so RHEL is the closes that should hopefully be fine, otherwise will have to switch to the much slower runfile installer.
DNF_REPO_URI="https://developer.download.nvidia.com/compute/cuda/repos/rhel${EL_MAJOR}/${CPU_ARCH}/cuda-rhel${EL_MAJOR}.repo"

echo "DNF_REPO_URI ${DNF_REPO_URI}"

## -----------------
## Check for root/sudo
## -----------------

# Detect if the script is being run as root, storing true/false in is_root.
is_root=false
if (( $EUID == 0)); then
is_root=true
fi
# Find if sudo is available
has_sudo=false
if command -v sudo &> /dev/null ; then
has_sudo=true
fi
# Decide if we can proceed or not (root or sudo is required) and if so store whether sudo should be used or not.
if [ "$is_root" = false ] && [ "$has_sudo" = false ]; then
echo "Root or sudo is required. Aborting."
exit 1
elif [ "$is_root" = false ] ; then
USE_SUDO=sudo
else
USE_SUDO=
fi

## -----------------
## Install
## -----------------
echo "Adding CUDA Repository"
$USE_SUDO dnf config-manager --add-repo ${DNF_REPO_URI}
$USE_SUDO dnf clean all

echo "Installing CUDA packages ${CUDA_PACKAGES}"
$USE_SUDO dnf -y install ${CUDA_PACKAGES}

if [[ $? -ne 0 ]]; then
echo "CUDA Installation Error."
exit 1
fi

## -----------------
## Set environment vars / vars to be propagated
## -----------------

CUDA_PATH=/usr/local/cuda-${CUDA_MAJOR}.${CUDA_MINOR}
echo "CUDA_PATH=${CUDA_PATH}"
export CUDA_PATH=${CUDA_PATH}
export PATH="$CUDA_PATH/bin:$PATH"
export LD_LIBRARY_PATH="$CUDA_PATH/lib:$LD_LIBRARY_PATH"
export LD_LIBRARY_PATH="$CUDA_PATH/lib64:$LD_LIBRARY_PATH"
# Check nvcc is now available.
nvcc -V

# If executed on github actions, make the appropriate echo statements to update the environment
if [[ $GITHUB_ACTIONS ]]; then
# Set paths for subsequent steps, using ${CUDA_PATH}
echo "Adding CUDA to CUDA_PATH, PATH and LD_LIBRARY_PATH"
echo "CUDA_PATH=${CUDA_PATH}" >> $GITHUB_ENV
echo "${CUDA_PATH}/bin" >> $GITHUB_PATH
echo "LD_LIBRARY_PATH=${CUDA_PATH}/lib:${LD_LIBRARY_PATH}" >> $GITHUB_ENV
echo "LD_LIBRARY_PATH=${CUDA_PATH}/lib64:${LD_LIBRARY_PATH}" >> $GITHUB_ENV
fi
182 changes: 182 additions & 0 deletions .github/workflows/Manylinux_2_28.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
# Build manylinux wheels, and upload them to the action for testing within a short time frame
name: Manylinux_2_28

# Run on branch push events (i.e. not tag pushes) and on pull requests
on:
# Branch pushes that do not only modify other workflow files
push:
branches:
- '**'
paths:
- "**"
- "!.github/**"
- ".github/scripts/install_cuda_el8.sh"
- ".github/workflows/Manylinux_2_28.yml"
# Disabled for now. See https://github.com/FLAMEGPU/FLAMEGPU2/pull/644
# pull_request:
# Allow manual invocation.
workflow_dispatch:

defaults:
run:
shell: bash

# A single job, which builds manylinux_2_28 wheels, which ships with GCC 12.
jobs:
build:
runs-on: ${{ matrix.cudacxx.os }}
# Run steps inside a manylinux container.
container: quay.io/pypa/manylinux_2_28_x86_64
strategy:
fail-fast: false
# Multiplicative build matrix
# optional exclude: can be partial, include: must be specific
matrix:
cudacxx:
- cuda: "12.0"
cuda_arch: "50"
hostcxx: gcc-toolset-12
os: ubuntu-22.04
- cuda: "11.2"
cuda_arch: "35"
hostcxx: gcc-toolset-9
os: ubuntu-22.04
python:
- "3.12"
config:
- name: "Release"
config: "Release"
SEATBELTS: "ON"
VISUALISATION:
- "ON"
- "OFF"

# Name the job based on matrix/env options
name: "build (${{ matrix.cudacxx.cuda }}, ${{matrix.python}}, ${{ matrix.VISUALISATION }}, ${{ matrix.config.name }}, ${{ matrix.cudacxx.os }})"

env:
# Control if the wheel should be repaired. This will fail until .so's are addressed
AUDITWHEEL_REPAIR: "OFF"
MANYLINUX: "manylinux_2_28"
ARCH: "x86_64"
# Control if static GLEW should be built and used or not.
USE_STATIC_GLEW: "ON"
# Compute the wheelhouse name which should be unique within the matrix. This must be unique per build matrix/job combination
ARTIFACT_NAME: wheel-manylinux_2_28-${{ matrix.cudacxx.cuda }}-${{matrix.python}}-${{ matrix.VISUALISATION }}-${{ matrix.config.name }}-${{ matrix.cudacxx.os }}
# Define constants
BUILD_DIR: "build"
FLAMEGPU_BUILD_TESTS: "OFF"
# Conditional based on matrix via awkward almost ternary
FLAMEGPU_BUILD_PYTHON: ${{ fromJSON('{true:"ON",false:"OFF"}')[matrix.python != ''] }}
# Port matrix options to environment, for more portability.
CUDA: ${{ matrix.cudacxx.cuda }}
CUDA_ARCH: ${{ matrix.cudacxx.cuda_arch }}
HOSTCXX: ${{ matrix.cudacxx.hostcxx }}
OS: ${{ matrix.cudacxx.os }}
CONFIG: ${{ matrix.config.config }}
FLAMEGPU_SEATBELTS: ${{ matrix.config.SEATBELTS }}
PYTHON: ${{ matrix.python}}
VISUALISATION: ${{ matrix.VISUALISATION }}
# Short term fix to use node16 not node20 for actions. This will stop working eventually, forcing our hand in dropping manylinux2014 support.
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true

steps:
- uses: actions/checkout@v3

# Downgrade the gcc-toolset in the image based on the build matrix
- name: Install RHEL gcc-toolset (EL 8)
if: ${{ startsWith(env.HOSTCXX, 'gcc-toolset-') }}
run: |
# Install gcc-toolset-X
yum install -y ${{ env.HOSTCXX }}
# Enable the toolset via source not scl enable which doesn't get on with multi-step GHA
source /opt/rh/${{ env.HOSTCXX }}/enable
# Export the new environment / compilers for subsequent steps.
echo "PATH=${PATH}" >> $GITHUB_ENV
echo "CC=$(which gcc)" >> $GITHUB_ENV
echo "CXX=$(which g++)" >> $GITHUB_ENV
echo "CUDAHOSTCXX=$(which g++)" >> $GITHUB_ENV
- name: Install CUDA (EL 8)
if: ${{ env.CUDA != '' }}
env:
cuda: ${{ env.CUDA }}
run: .github/scripts/install_cuda_el8.sh

- name: Install Visualisation Dependencies (EL 8)
if: ${{ env.VISUALISATION == 'ON' }}
run: |
yum install -y glew-devel fontconfig-devel SDL2-devel freetype-devel
# Build/Install DevIL from source.
yum install -y freeglut-devel
git clone --depth 1 https://github.com/DentonW/DevIL.git
cd DevIL/DevIL
mkdir -p build
cd build
cmake .. -DCMAKE_BUILD_TYPE=${{ env.CONFIG }} -Wno-error=dev
make -j `nproc`
make install
- name: Build and install GLEW including static GLEW
if: ${{ env.VISUALISATION == 'ON' && env.USE_STATIC_GLEW == 'ON' }}
env:
GLEW_VERSION: "2.2.0"
run: |
yum install -y wget
wget https://github.com/nigels-com/glew/releases/download/glew-${{ env.GLEW_VERSION }}/glew-${{ env.GLEW_VERSION }}.tgz
tar -zxf glew-${{ env.GLEW_VERSION }}.tgz
cd glew-${{ env.GLEW_VERSION }}
make
make install
- name: Add custom problem matchers for annotations
run: echo "::add-matcher::.github/problem-matchers.json"

# This patches a bug where ManyLinux doesn't generate buildnumber as git dir is owned by diff user
- name: Enable git safe-directory
run: git config --global --add safe.directory $GITHUB_WORKSPACE

- name: Configure cmake
run: >
cmake . -B "${{ env.BUILD_DIR }}"
-DCMAKE_BUILD_TYPE="${{ env.CONFIG }}"
-Werror=dev
-DCMAKE_WARN_DEPRECATED="OFF"
-DFLAMEGPU_WARNINGS_AS_ERRORS="ON"
-DCMAKE_CUDA_ARCHITECTURES="${{ env.CUDA_ARCH }}"
-DFLAMEGPU_BUILD_TESTS="${{ env.FLAMEGPU_BUILD_TESTS }}"
-DFLAMEGPU_BUILD_PYTHON="${{ env.FLAMEGPU_BUILD_PYTHON }}"
-DPYTHON3_EXACT_VERSION="${{ env.PYTHON }}"
-DFLAMEGPU_VISUALISATION="${{ env.VISUALISATION }}"
-DFLAMEGPU_ENABLE_NVTX="ON"
-DGLEW_USE_STATIC_LIBS="${{ env.USE_STATIC_GLEW }}"
-DOpenGL_GL_PREFERENCE:STRING=LEGACY
-DFLAMEGPU_BUILD_PYTHON_PATCHELF=ON
- name: Build python wheel
if: ${{ env.FLAMEGPU_BUILD_PYTHON == 'ON' }}
working-directory: ${{ env.BUILD_DIR }}
run: cmake --build . --target pyflamegpu --verbose -j `nproc`

# Run audithweel show for information, but do not repair.
- name: Run auditwheel show
working-directory: ${{ env.BUILD_DIR }}
run: auditwheel show lib/${{ env.CONFIG }}/python/dist/*whl

# Ideally we should use auditwheel repair to check/enforce conformity
# But we cannot due to cuda shared object (libcuda.so.1) dependencies which we cannot/shouldnot/wil not package into the wheel.
- name: Run auditwheel repair
if: ${{ env.AUDITWHEEL_REPAIR == 'ON' }}
working-directory: ${{ env.BUILD_DIR }}
run: auditwheel repair --plat ${{ env.MANYLINUX }}_${{ env.ARCH }} lib/${{ env.CONFIG }}/python/dist/*whl -w lib/${{ env.CONFIG }}/python/dist

# Upload wheel artifacts to the job on GHA, with a short retention
# Use a unique name per job matrix run, to avoid a risk of corruption according to the docs (although it should work with unique filenames)
- name: Upload Wheel Artifacts
if: ${{env.FLAMEGPU_BUILD_PYTHON == 'ON' }}
uses: actions/upload-artifact@v3
with:
name: ${{ env.ARTIFACT_NAME }}
path: ${{ env.BUILD_DIR }}/lib/${{ env.CONFIG }}/python/dist/*.whl
if-no-files-found: error
retention-days: 5

0 comments on commit f1aef5a

Please sign in to comment.