Skip to content

Commit ea52406

Browse files
committed
ci: Add macOS testing workflow using gfortran and system clang.
1 parent 184a89e commit ea52406

1 file changed

Lines changed: 237 additions & 0 deletions

File tree

Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
# Workflow to run the FTorch test suite using jobs for GNU Fortran compiler
2+
# and system Clang compilers (macOS arm64)
3+
name: Test suite (macOS CPU)
4+
5+
# Controls when the workflow will run
6+
on:
7+
# Triggers the workflow on pushes to the "main" branch, i.e., PR merges
8+
push:
9+
branches: [ "main" ]
10+
11+
# Triggers the workflow on pushes to open pull requests with code changes
12+
pull_request:
13+
paths:
14+
# This workflow
15+
- '.github/workflows/test_suite_macos_cpu_clang.yml'
16+
17+
# Allows you to run this workflow manually from the Actions tab
18+
workflow_dispatch:
19+
20+
# Cancel jobs running if new commits are pushed
21+
concurrency:
22+
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
23+
cancel-in-progress: true
24+
25+
# Write permissions are not required
26+
permissions: {}
27+
28+
# Workflow run - one or more jobs that can run sequentially or in parallel
29+
jobs:
30+
# Dynamically build matrix for job
31+
setup-matrix:
32+
name: setup matrix
33+
runs-on: macos-latest
34+
35+
# Terminate the job if it runs for more than 5 minutes
36+
timeout-minutes: 5
37+
38+
outputs:
39+
matrix: ${{ steps.set-matrix.outputs.matrix }}
40+
env:
41+
EVENT_NAME: ${{ github.event_name }}
42+
steps:
43+
- id: set-matrix
44+
run: |
45+
MATRIX_JSON='
46+
{
47+
"std": ["f2008", "f2018"],
48+
"compiler": ["clang"]
49+
}'
50+
# Convert json to compact line expected by github action
51+
MATRIX_JSON=$(echo "$MATRIX_JSON" | jq -c .)
52+
echo "matrix=${MATRIX_JSON}" >> $GITHUB_OUTPUT
53+
54+
test-suite:
55+
name: test suite (${{ matrix.compiler }}, ${{ matrix.std }})
56+
needs: setup-matrix
57+
# The type of runner that the job will run on
58+
runs-on: macos-latest
59+
strategy:
60+
fail-fast: false
61+
matrix: ${{ fromJSON(needs.setup-matrix.outputs.matrix) }}
62+
63+
# Terminate the job if it runs for more than 20 minutes
64+
timeout-minutes: 20
65+
66+
# Steps represent a sequence of tasks that will be executed as part of the job
67+
steps:
68+
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
69+
- name: Checkout FTorch repository
70+
with:
71+
persist-credentials: true
72+
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
73+
74+
- name: Setup Python
75+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
76+
with:
77+
python-version: '3.13'
78+
79+
- name: Install PyTorch
80+
run: |
81+
python -m pip install --upgrade pip
82+
python -m venv ftorch
83+
. ftorch/bin/activate
84+
pip install torch torchvision
85+
86+
- name: Install gfortran and OpenMPI
87+
# Install from source to avoid compiler mismatch between gfortran versions
88+
# between open-mpi installation and when building FTorch.
89+
run: |
90+
brew update
91+
brew install gcc openmpi libomp
92+
93+
- name: Ensure gfortran symlink exists
94+
run: |
95+
GFORTRAN_PATH=$(ls $(brew --prefix)/bin/gfortran-* | sort -V | tail -n 1)
96+
if [ ! -e "$(brew --prefix)/bin/gfortran" ]; then
97+
ln -s "$GFORTRAN_PATH" "$(brew --prefix)/bin/gfortran"
98+
fi
99+
ls -l $(brew --prefix)/bin/gfortran*
100+
101+
- name: Set compilers as GitHub environment variables
102+
run: |
103+
# Add homebrew to path
104+
echo "PATH=$(brew --prefix)/bin:$PATH" >> $GITHUB_ENV
105+
# brew installs gfortran-<version> from the gcc package, so extract this as generic FC
106+
echo "FC=$(brew --prefix)/bin/gfortran" >> $GITHUB_ENV
107+
echo "MPI_FC=$(brew --prefix)/bin/mpif90" >> $GITHUB_ENV
108+
# Use system clang for C and C++
109+
echo "CC=clang" >> $GITHUB_ENV
110+
echo "CXX=clang++" >> $GITHUB_ENV
111+
112+
- name: Install pFUnit
113+
run: |
114+
# TODO: Avoid version pinning (needed because version appears in install path)
115+
git clone -b v4.12.0 https://github.com/Goddard-Fortran-Ecosystem/pFUnit.git
116+
mkdir pFUnit/build
117+
cd pFUnit/build
118+
cmake ..\
119+
-DCMAKE_C_COMPILER=$CC \
120+
-DCMAKE_Fortran_COMPILER=$FC\
121+
-DMPI_Fortran_COMPILER=$MPI_FC
122+
make -j 4 install
123+
124+
- name: Build FTorch
125+
env:
126+
FORTRAN_STANDARD: ${{ matrix.std }}
127+
run: |
128+
. ftorch/bin/activate
129+
VN=$(python -c "import sys; print('.'.join(sys.version.split('.')[:2]))")
130+
export Torch_DIR=${VIRTUAL_ENV}/lib/python${VN}/site-packages
131+
export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:${Torch_DIR}/torch/lib
132+
export FTORCH_BUILD_DIR=$(pwd)/build
133+
mkdir -p ${FTORCH_BUILD_DIR}
134+
# Install to /tmp/ to ensure independent from the CMake build in standalone check.
135+
export FTORCH_INSTALL_DIR=/tmp/ftorch-install
136+
mkdir -p ${FTORCH_INSTALL_DIR}
137+
# NOTE: The pFUnit version (pinned during installation above) is used in the install path.
138+
export PFUNIT_DIR=$(pwd)/pFUnit/build/installed/PFUNIT-4.12
139+
cd ${FTORCH_BUILD_DIR}
140+
141+
cmake .. \
142+
-DPython_EXECUTABLE="$(which python)" \
143+
-DCMAKE_BUILD_TYPE=Release \
144+
-DCMAKE_C_COMPILER=$CC \
145+
-DCMAKE_CXX_COMPILER=$CXX \
146+
-DCMAKE_Fortran_COMPILER=$FC\
147+
-DCMAKE_INSTALL_PREFIX="${FTORCH_INSTALL_DIR}" \
148+
-DCMAKE_BUILD_TESTS=TRUE \
149+
-DCMAKE_PREFIX_PATH="${PFUNIT_DIR};${Torch_DIR}" \
150+
-DCMAKE_Fortran_FLAGS="-std=${FORTRAN_STANDARD}"\
151+
-DCMAKE_C_FLAGS="-Xpreprocessor -fopenmp -I$(brew --prefix libomp)/include" \
152+
-DCMAKE_CXX_FLAGS="-stdlib=libc++ -Xpreprocessor -fopenmp -I$(brew --prefix libomp)/include" \
153+
-DCMAKE_EXE_LINKER_FLAGS="-L$(brew --prefix libomp)/lib -lomp"
154+
cmake --build .
155+
cmake --install .
156+
157+
- name: Check pkg-config file
158+
run: |
159+
# pkg-config looks in the `build` directory for libraries
160+
export PKG_CONFIG_PATH=${PKG_CONFIG_PATH}:build
161+
162+
libs=$(pkg-config --libs ftorch)
163+
cflags=$(pkg-config --cflags ftorch)
164+
165+
# Assert linker flags not empty
166+
if [[ -z "${libs}" ]]
167+
then
168+
echo "::error ::pkg-config --libs ftorch returned empty output"
169+
exit 1
170+
fi
171+
172+
# Assert expected linker flags
173+
lib_dir=$(grep -oE "\-L.*/lib" <<< ${libs})
174+
lib=$(grep -oE "\-lftorch" <<< ${libs})
175+
if [[ -z "${lib_dir}" || -z "${lib}" ]]
176+
then
177+
echo "::error ::pkg-config --libs ftorch do not contain expected linker flags"
178+
exit 1
179+
fi
180+
181+
# Assert compiler flags not empty
182+
if [[ -z "${cflags}" ]]
183+
then
184+
echo "::error ::pkg-config --cflags ftorch returned empty output"
185+
exit 1
186+
fi
187+
188+
# Assert expected compiler flags
189+
include_dir=$(grep -oE "/include " <<< ${cflags})
190+
module_dir=$(grep -oE "/include/ftorch" <<< ${cflags})
191+
if [[ -z ${include_dir} || -z ${module_dir} ]]
192+
then
193+
echo "::error ::pkg-config --cflags ftorch do not contain expected compiler flags"
194+
exit 1
195+
fi
196+
197+
- name: Run unit tests
198+
run: |
199+
. ftorch/bin/activate
200+
VN=$(python -c "import sys; print('.'.join(sys.version.split('.')[:2]))")
201+
export Torch_DIR=${VIRTUAL_ENV}/lib/python${VN}/site-packages
202+
export FTORCH_BUILD_DIR=$(pwd)/build
203+
export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:${Torch_DIR}/torch/lib:${FTORCH_BUILD_DIR}/lib
204+
cd build
205+
ctest --verbose --tests-regex unit
206+
207+
- name: Run integration tests
208+
run: |
209+
. ftorch/bin/activate
210+
VN=$(python -c "import sys; print('.'.join(sys.version.split('.')[:2]))")
211+
export Torch_DIR=${VIRTUAL_ENV}/lib/python${VN}/site-packages
212+
export FTORCH_BUILD_DIR=$(pwd)/build
213+
export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:${Torch_DIR}/torch/lib:${FTORCH_BUILD_DIR}/lib
214+
cd build
215+
ctest --verbose --tests-regex example
216+
217+
# Check that we can successfully build and run an example outside the main FTorch build process
218+
- name: Standalone SimpleNet example
219+
env:
220+
FORTRAN_STANDARD: ${{ matrix.std }}
221+
run: |
222+
. ftorch/bin/activate
223+
VN=$(python -c "import sys; print('.'.join(sys.version.split('.')[:2]))")
224+
export Torch_DIR="${VIRTUAL_ENV}/lib/python${VN}/site-packages/torch"
225+
export FTORCH_INSTALL_DIR=/tmp/ftorch-install
226+
export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:${VIRTUAL_ENV}/lib/python${VN}/site-packages/torch/lib:${FTORCH_BUILD_DIR}/lib
227+
export EXAMPLE_BUILD_DIR="examples/2_SimpleNet/build"
228+
mkdir "${EXAMPLE_BUILD_DIR}"
229+
cd "${EXAMPLE_BUILD_DIR}"
230+
cmake .. \
231+
-DPython_EXECUTABLE="$(which python)" \
232+
-DCMAKE_BUILD_TYPE=Release \
233+
-DCMAKE_PREFIX_PATH="${FTORCH_INSTALL_DIR};${Torch_DIR}" \
234+
-DCMAKE_BUILD_TESTS=TRUE \
235+
-DCMAKE_Fortran_FLAGS="-std=${FORTRAN_STANDARD}"
236+
cmake --build .
237+
ctest -V

0 commit comments

Comments
 (0)