Skip to content

Commit fbe271c

Browse files
committed
ci(refactor): extract setup logic into setup-build
Create a new composite action "setup-build" by extracting common setup logic from the test/deploy workflows. This action sets up the build environment and runs the configure script.
1 parent 1d5e40b commit fbe271c

File tree

3 files changed

+417
-249
lines changed

3 files changed

+417
-249
lines changed
Lines changed: 357 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,357 @@
1+
name: setup-build
2+
description: >-
3+
Set up the build environment by installing necessary tools and dependencies.
4+
It sets the CONFIG_ARGS environment variable. If necessary, it also sets
5+
CPATH, LIBRARY_PATH, FORMPATH and DISTNAME, and runs autoreconf or extracts
6+
a tar.gz archive, and lastly invokes ./configure.
7+
inputs:
8+
features:
9+
description: A list of features to enable, separated by spaces.
10+
required: false
11+
default: ''
12+
13+
runs:
14+
using: composite
15+
steps:
16+
- name: Initialize setup
17+
id: setup
18+
env:
19+
available_features: >-
20+
form=false tform=false parform=false vorm=false tvorm=false parvorm=false
21+
gmp=true mpfr=true zlib=true
22+
bash=false msys2=false debian=false container=false
23+
untar=false autoreconf=false configure=true deploy=false
24+
valgrind=false coverage=false
25+
latex=false latex2html=false
26+
formlib=false forcer=false color=false
27+
shell: bash
28+
run: |
29+
### Initialize setup ###
30+
31+
# First, parse the input.
32+
33+
available_features=$(echo "$available_features" | awk '{$1=$1; print}')
34+
35+
feature_names=''
36+
for entry in $available_features; do
37+
# Get "name=value".
38+
feat_name=$(echo "$entry" | cut -d '=' -f 1)
39+
feat_value=$(echo "$entry" | cut -d '=' -f 2)
40+
feature_names="$feature_names $feat_name"
41+
# Initialize the feature variable.
42+
eval "feat_${feat_name}=${feat_value}"
43+
done
44+
feature_names=$(echo "$feature_names" | awk '{$1=$1; print}')
45+
46+
input_features=$(echo "${{ inputs.features }}" | awk '{$1=$1; print}')
47+
feature_pattern='^('$(echo "$feature_names" | tr ' ' '|')')$'
48+
no_feature_pattern='^('$(echo "no$feature_names" | sed 's/ /|no/g')')$'
49+
50+
for feat in $input_features; do
51+
if [[ $feat =~ $feature_pattern ]]; then
52+
eval "feat_${feat}=true"
53+
elif [[ $feat =~ $no_feature_pattern ]]; then
54+
feat=${feat#no}
55+
eval "feat_${feat}=false"
56+
else
57+
echo "Error: unknown feature: $feat"
58+
exit 1
59+
fi
60+
done
61+
62+
# Some features are enabled automatically,
63+
# while others may require extra setup.
64+
65+
has_scalar=false
66+
has_threaded=false
67+
has_mpi=false
68+
has_bin=false
69+
if $feat_form || $feat_vorm; then
70+
has_scalar=true
71+
fi
72+
if $feat_tform || $feat_tvorm; then
73+
has_threaded=true
74+
fi
75+
if $feat_parform || $feat_parvorm; then
76+
has_mpi=true
77+
fi
78+
if $has_scalar || $has_threaded || $has_mpi; then
79+
has_bin=true
80+
fi
81+
82+
if ! $has_bin; then
83+
feat_gmp=false
84+
feat_mpfr=false
85+
feat_zlib=false
86+
fi
87+
88+
if [ -f /etc/os-release ] && grep -qi '^ID=debian' /etc/os-release; then
89+
feat_debian=true
90+
fi
91+
92+
if [ -f /.dockerenv ]; then
93+
feat_container=true
94+
fi
95+
96+
if [ ! -f configure.ac ] && ls form-*.tar.gz 1>/dev/null 2>&1; then
97+
feat_untar=true
98+
fi
99+
100+
if [ ! -f configure ] && [ -f configure.ac ]; then
101+
feat_autoreconf=true
102+
fi
103+
104+
if $feat_color || $feat_forcer; then
105+
feat_formlib=true
106+
items=''
107+
$feat_color && items="$items-color"
108+
$feat_forcer && items="$items-forcer"
109+
echo "formlib-key=formlib$items" >>"$GITHUB_OUTPUT"
110+
echo "formlib-restore-keys=formlib-" >>"$GITHUB_OUTPUT"
111+
echo "FORMPATH=${{ github.workspace }}/formlib" >>"$GITHUB_ENV"
112+
fi
113+
114+
# Output the feature variables.
115+
116+
for feat in $feature_names; do
117+
value=$(eval "echo \$feat_${feat}")
118+
echo "$feat=$value"
119+
echo "$feat=$value" >>"$GITHUB_OUTPUT"
120+
done
121+
122+
# Make CONFIG_ARGS.
123+
124+
args='--disable-dependency-tracking'
125+
126+
if $has_scalar; then
127+
args="$args --enable-scalar"
128+
else
129+
args="$args --disable-scalar"
130+
fi
131+
if $has_threaded; then
132+
args="$args --enable-threaded"
133+
else
134+
args="$args --disable-threaded"
135+
fi
136+
if $has_mpi; then
137+
args="$args --enable-parform"
138+
else
139+
args="$args --disable-parform"
140+
fi
141+
142+
if $feat_vorm || $feat_tvorm || $feat_parvorm; then
143+
args="$args --enable-debug"
144+
fi
145+
146+
if $feat_coverage; then
147+
args="$args --enable-coverage"
148+
fi
149+
150+
if $has_bin; then
151+
if $feat_deploy; then
152+
# Avoid compiler optimizations specific to the build host.
153+
args="$args --disable-native"
154+
# Enable static linking whenever possible.
155+
if ${{ runner.os != 'macOS' }}; then
156+
args="$args --enable-static-link"
157+
fi
158+
fi
159+
160+
if ${{ runner.os == 'Windows' }}; then
161+
args="$args --with-api=windows"
162+
else
163+
args="$args --with-api=posix"
164+
fi
165+
else
166+
# This avoids checking optimization flags.
167+
args="$args --disable-native"
168+
fi
169+
170+
if $feat_gmp; then
171+
args="$args --with-gmp"
172+
else
173+
args="$args --without-gmp"
174+
fi
175+
176+
if $feat_mpfr; then
177+
args="$args --with-mpfr"
178+
else
179+
args="$args --without-mpfr"
180+
fi
181+
182+
if $feat_zlib; then
183+
args="$args --with-zlib"
184+
else
185+
args="$args --without-zlib"
186+
fi
187+
188+
echo "CONFIG_ARGS=$args" >>"$GITHUB_ENV"
189+
190+
# Determine DISTNAME if possible.
191+
192+
if [ -f ./scripts/git-version-gen.sh ] && command -v git >/dev/null 2>&1; then
193+
echo "DISTNAME=form-$(./scripts/git-version-gen.sh -r | sed '2q;d' | sed 's/^v//')" >>"$GITHUB_ENV"
194+
fi
195+
196+
# awalsh128/cache-apt-pkgs-action does not allow empty packages argument.
197+
# See: https://github.com/awalsh128/cache-apt-pkgs-action/issues/149
198+
# As a workaround, we need to check if any packages need to be installed.
199+
- name: Install dependencies (Ubuntu)
200+
if: >-
201+
runner.os == 'Linux' && steps.setup.outputs.container == 'false' && (
202+
steps.setup.outputs.coverage == 'true' ||
203+
steps.setup.outputs.mpfr == 'true' ||
204+
steps.setup.outputs.valgrind == 'true'
205+
)
206+
uses: awalsh128/cache-apt-pkgs-action@v1
207+
with:
208+
packages: >-
209+
${{ steps.setup.outputs.coverage == 'true' && 'lcov' || '' }}
210+
${{ steps.setup.outputs.mpfr == 'true' && 'libmpfr-dev' || '' }}
211+
${{ steps.setup.outputs.valgrind == 'true' && 'valgrind' || '' }}
212+
version: 1.0
213+
214+
# Because we use i386/debian containers, here we do not assume that
215+
# awalsh128/cache-apt-pkgs-action works properly.
216+
# See: https://github.com/actions/cache/issues/675
217+
- name: Install dependencies (Debian)
218+
if: steps.setup.outputs.debian == 'true' && steps.setup.outputs.container == 'true'
219+
shell: bash
220+
run: |
221+
### Install dependencies ###
222+
223+
apt-get update
224+
apt-get install -y -q automake g++ git make ruby \
225+
${{ steps.setup.outputs.coverage == 'true' && 'lcov' || '' }} \
226+
${{ steps.setup.outputs.gmp == 'true' && 'libgmp-dev' || '' }} \
227+
${{ steps.setup.outputs.mpfr == 'true' && 'libmpfr-dev' || '' }} \
228+
${{ steps.setup.outputs.valgrind == 'true' && 'valgrind' || '' }} \
229+
${{ steps.setup.outputs.zlib == 'true' && 'zlib1g-dev' || '' }}
230+
231+
- name: Install dependencies (Windows)
232+
if: runner.os == 'Windows' && steps.setup.outputs.msys2 == 'true'
233+
uses: msys2/setup-msys2@v2
234+
with:
235+
update: true
236+
install: >-
237+
make
238+
mingw-w64-x86_64-gcc
239+
mingw-w64-x86_64-ruby
240+
${{ steps.setup.outputs.gmp == 'true' && 'mingw-w64-x86_64-gmp' || '' }}
241+
${{ steps.setup.outputs.mpfr == 'true' && 'mingw-w64-x86_64-mpfr' || '' }}
242+
${{ steps.setup.outputs.zlib == 'true' && 'mingw-w64-x86_64-zlib' || '' }}
243+
244+
# awalsh128/cache-apt-pkgs-action does not work for MPICH.
245+
# See: https://github.com/awalsh128/cache-apt-pkgs-action/issues/57#issuecomment-1304062077
246+
- name: Install MPI if necessary
247+
if: runner.os == 'Linux' && (steps.setup.outputs.parform == 'true' || steps.setup.outputs.parvorm == 'true')
248+
shell: bash
249+
run: |
250+
### Install MPI ###
251+
252+
sudo apt-get update
253+
sudo apt-get install -y -q libmpich-dev
254+
255+
# Currently, cache-apt-pkgs-action doesn't work for LaTeX.
256+
# See: https://github.com/awalsh128/cache-apt-pkgs-action/issues/57
257+
- name: Install LaTeX.
258+
if: runner.os == 'Linux' && (steps.setup.outputs.latex == 'true' || steps.setup.outputs.latex2html == 'true')
259+
shell: bash
260+
run: |
261+
### Install LaTeX ###
262+
263+
sudo apt-get update
264+
sudo apt-get install -y -q \
265+
${{ steps.setup.outputs.latex == 'true' && 'texlive-latex-extra' || '' }} \
266+
${{ steps.setup.outputs.latex2html == 'true' && 'latex2html' || '' }}
267+
268+
# --static fails on macOS but we want to statically link
269+
# the brewed gmp. The linker supports neither -Wl,-static nor
270+
# -l:libgmp.a to make partial static links possible.
271+
# As a workaround, we make a library directory with libgmp.a
272+
# but without libgmp.dylib so that the linker has to link libgmp.a.
273+
# Note that the Homebrew installation path for Apple Silicon (arm64)
274+
# differs from the one on macOS Intel (x86-64).
275+
- name: Set up statically linked libraries (macOS)
276+
if: runner.os == 'macOS' && steps.setup.outputs.deploy
277+
shell: bash
278+
run: |
279+
### Set up statically linked libraries ###
280+
281+
mkdir static-lib
282+
if [ "$RUNNER_ARCH" == "ARM64" ]; then
283+
brew_dir=/opt/homebrew
284+
# Include directories, not located in the usual places,
285+
# must be explicitly appended to the include paths.
286+
export CPATH="$brew_dir/opt/gmp/include:$brew_dir/opt/mpfr/include:${CPATH:-}"
287+
echo "CPATH=$CPATH" >>"$GITHUB_ENV"
288+
else
289+
brew_dir=/usr/local
290+
fi
291+
ln -s $brew_dir/opt/gmp/lib/libgmp.a static-lib/libgmp.a
292+
ln -s $brew_dir/opt/mpfr/lib/libmpfr.a static-lib/libmpfr.a
293+
export LIBRARY_PATH="$(pwd)/static-lib:${LIBRARY_PATH:-}"
294+
echo "LIBRARY_PATH=$LIBRARY_PATH" >>"$GITHUB_ENV"
295+
296+
- name: Cache FORM library
297+
id: cache-formlib
298+
if: steps.setup.outputs.formlib == 'true'
299+
uses: actions/cache@v4
300+
with:
301+
path: formlib
302+
key: ${{ steps.setup.outputs.formlib-key }}
303+
restore-keys: ${{ steps.setup.outputs.formlib-restore-keys }}
304+
305+
- name: Install FORM libraries if necessary
306+
if: steps.setup.outputs.formlib == 'true' && steps.cache-formlib.outputs.cache-hit != 'true'
307+
shell: bash
308+
run: |
309+
### Install FORM libraries ###
310+
311+
mkdir -p formlib
312+
if ${{ steps.setup.outputs.forcer }} && [ ! -f formlib/forcer.h ]; then
313+
wget https://github.com/benruijl/forcer/archive/v1.0.0.tar.gz -O - | tar -x --gzip
314+
mv forcer-1.0.0/forcer.h formlib
315+
mv forcer-1.0.0/forcer formlib
316+
rm -rf forcer-1.0.0
317+
fi
318+
if ${{ steps.setup.outputs.color }} && [ ! -f formlib/color.h ]; then
319+
wget https://www.nikhef.nl/~form/maindir/packages/color/color.h -P formlib
320+
fi
321+
322+
# Fix dubious ownership in containers for Git operations.
323+
# See: https://github.com/actions/runner/issues/2033#issuecomment-1204205989
324+
- name: Fix dubious ownership
325+
if: steps.setup.outputs.container == 'true'
326+
shell: bash
327+
run: |
328+
### Fix dubious ownership
329+
330+
chown -R $(id -u):$(id -g) $PWD
331+
332+
- name: Uncompress tarball
333+
if: steps.setup.outputs.untar == 'true'
334+
shell: bash
335+
run: |
336+
### Uncompress tarball ###
337+
338+
echo "DISTNAME=$(basename form-*.tar.gz .tar.gz)" >>"$GITHUB_ENV"
339+
340+
tar -xf form-*.tar.gz --strip-components 1
341+
rm *.tar.gz
342+
343+
- name: Run Autoreconf
344+
if: steps.setup.outputs.autoreconf == 'true'
345+
shell: bash
346+
run: |
347+
### Run Autoreconf ###
348+
349+
autoreconf -i
350+
351+
- name: Configure
352+
if: steps.setup.outputs.configure == 'true'
353+
shell: ${{ steps.setup.outputs.msys2 == 'true' && 'msys2' || 'bash' }} {0}
354+
run: |
355+
### Configure ###
356+
357+
./configure ${{ env.CONFIG_ARGS }}

0 commit comments

Comments
 (0)