Skip to content

Instantly share code, notes, and snippets.

@tdulcet
Last active October 22, 2023 15:55
Show Gist options
  • Save tdulcet/d03dd3be0314fca72a2250133d24f3fd to your computer and use it in GitHub Desktop.
Save tdulcet/d03dd3be0314fca72a2250133d24f3fd to your computer and use it in GitHub Desktop.
Ernst W. Mayer's makemake.sh script for Mlucas v21 posthumously released. Includes support for building Mfactor.
#!/bin/bash
# EWM: This is a makefile-only cutdown of Teal Dulcet's much more extensive Mlucas install/build/tune
# script, available at https://raw.github.com/tdulcet/Distributed-Computing-Scripts/master/mlucas.sh ;
# he does not explicitly use the GPL boilerplate as below, but assures me his version is GPL-covered.
################################################################################
# #
# (C) 2021 by Ernst W. Mayer and Teal Dulcet. #
# #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the #
# Free Software Foundation; either version 2 of the License, or (at your #
# option) any later version. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; see the file GPL.txt. If not, you may view one at #
# http://www.fsf.org/licenses/licenses.html, or obtain one by writing to the #
# Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #
# 02111-1307, USA. #
# #
################################################################################
# Exit if any of the commands fail:
set -e
shopt -s nocasematch
# for mode in avx512 avx2 avx sse2; do
# if grep -iq "$mode" /proc/cpuinfo; then
# echo -e "The CPU supports the ${mode^^} SIMD build mode.\n"
# ARGS+=( "-DUSE_${mode^^}" )
# break
# fi
# done
DIR=obj
Mlucas=Mlucas
Mfactor=Mfactor
TARGET=$Mlucas
ARGS=(-DUSE_THREADS) # Optional compile args
WORDS=''
# Optional link args
LARG=()
MODES=()
GMP=1
HWLOC=0
if echo "$OSTYPE" | grep -iq 'darwin'; then
echo -e "MacOS detected for build host.\n"
CPU_THREADS=$(sysctl -n hw.ncpu)
else # echo "$OSTYPE" | grep -iq 'linux'
echo -e "Assuming OS = Linux for build host.\n"
CPU_THREADS=$(nproc --all)
fi
if ! command -v make >/dev/null; then
echo "Error: This script requires Make" >&2
echo "On Ubuntu and Debian run: 'sudo apt-get update' and 'sudo apt-get install build-essential -y'" >&2
exit 1
fi
if [[ -n $CC ]]; then
if ! command -v "$CC" >/dev/null; then
echo "Error: $CC is not installed." >&2
exit 1
fi
elif ! command -v gcc >/dev/null; then
echo "Error: This script requires the GNU C compiler" >&2
echo "On Ubuntu and Debian run: 'sudo apt-get update' and 'sudo apt-get install build-essential -y'" >&2
exit 1
fi
# $0 contains script-name, but $@ starts with first ensuing cmd-line arg, if it exists:
echo "Total number of input parameters = $#"
# v21: Keep the cross-platform-build arch-specifying command-line flag, but now also need to
# support several added ones for 3rd-party-library usage. This needs to be in arbitrary argument
# order fashion, [details snipped]
arglist=("$@") # Local array into which we copy cmd-line args in order to be able to manipulate them
for i in "${!arglist[@]}"; do
echo "Arg[$i] = ${arglist[i]}"
done
# Now loop over the optional args and execute the above-described preprocessing step:
for arg in "$@"; do
case ${arg} in
'no_gmp')
GMP=0
;;
'use_hwloc')
HWLOC=1
;;
'avx512_skylake' | 'avx512_knl' | 'k1om' | 'avx2' | 'avx' | 'sse2' | 'asimd' | 'nosimd')
MODES+=("$arg")
;;
'mfac')
TARGET=$Mfactor
;;
'1word' | '2word' | '3word' | '4word' | 'nword')
WORDS=$arg
;;
*)
echo "Usage: $0 [SIMD build mode]" >&2
echo "Optional arguments must be 'no_gmp', 'use_hwloc' or one and only one of the supported SIMD-arithmetic types:" >&2
echo -e "\t[x86_64: avx512_skylake avx512_knl k1om avx2 avx sse2]; [Armv8: asimd]; or 'nosimd' for scalar-double build.\n" >&2
exit 1
;;
esac
done
if ((GMP)); then
LARG+=(-lgmp)
else
echo "Building sans Gnu-MP ... this means no GCDs will be taken in p-1 work."
ARGS+=(-DINCLUDE_GMP=0)
fi
if ((HWLOC)); then
echo "Building with HWLOC hardware-topology support."
ARGS+=(-DINCLUDE_HWLOC=1)
LARG+=(-lhwloc)
fi
if [[ $TARGET == "$Mfactor" ]]; then
DIR+=_mfac
trap "rm $PWD/src/factor.c" EXIT
cp -vf src/factor.c{.txt,}
fi
if [[ -n $WORDS ]]; then
if [[ $TARGET == "$Mfactor" ]]; then
arg=$WORDS
if [[ ${arg} == 'nword' ]]; then
WORDS=-DNWORD
else
WORDS=-DP"${arg::1}"WORD
fi
Mfactor+="_$arg"
TARGET=$Mfactor
else
echo "Error: The argument '$WORDS' requires 'mfac'." >&2
exit 1
fi
fi
# First if/elif clause handles cross-platform builds and non-default values for "Use GMP?" and "Use HWLOC?":
# o "Use GMP" = TRUE is default in link step, 'no_gmp' overrides;
# o "Use HWLOC" = FALSE is default, 'use_hwloc' overrides.
# Thx to tdulcet for offering a streamlined case-based syntax here, but ugh - non-matching ')', really?:
if [[ ${#MODES[*]} -gt 1 ]]; then
echo -e "Only one arch-specifying optional argument is allowed ... aborting." >&2
exit 1
fi
if [[ ${#MODES[*]} -eq 1 ]]; then
arg=${MODES[0]}
case ${arg} in
'avx512_skylake')
echo "Building for avx512_skylake SIMD in directory '${DIR}_${arg}'; the executable will be named '${TARGET}'"
ARGS+=(-DUSE_AVX512 -march=skylake-avx512)
;;
'avx512_knl')
echo "Building for avx512_knl SIMD in directory '${DIR}_${arg}'; the executable will be named '${TARGET}'"
ARGS+=(-DUSE_AVX512 -march=knl)
;;
'k1om')
echo "Building for 1st-gen Xeon Phi 512-bit SIMD in directory '${DIR}_${arg}'; the executable will be named '${TARGET}'"
ARGS+=(-DUSE_IMCI512)
;;
'avx2')
echo "Building for avx2 SIMD in directory '${DIR}_${arg}'; the executable will be named '${TARGET}'"
ARGS+=(-DUSE_AVX2 -mavx2)
;;
'avx')
echo "Building for avx SIMD in directory '${DIR}_${arg}'; the executable will be named '${TARGET}'"
ARGS+=(-DUSE_AVX -mavx)
;;
'sse2')
echo "Building for sse2 SIMD in directory '${DIR}_${arg}'; the executable will be named '${TARGET}'"
ARGS+=(-DUSE_SSE2)
;;
'asimd')
echo "Building for asimd SIMD in directory '${DIR}_${arg}'; the executable will be named '${TARGET}'"
ARGS+=(-DUSE_ARM_V8_SIMD)
;;
'nosimd')
echo "Building in scalar-double (no-SIMD) mode in directory '${DIR}_${arg}'; the executable will be named '${TARGET}'"
# This one's a no-op
;;
*)
echo "Unrecognized SIMD-build flag ... aborting." >&2
exit 1
;;
esac
DIR+="_$arg"
elif echo "$OSTYPE" | grep -iq 'darwin'; then
# MacOS:
if sysctl -a | grep machdep.cpu.features | grep -iq 'avx512'; then
echo -e "The CPU supports the AVX512 SIMD build mode.\n"
ARGS+=(-DUSE_AVX512 -march=native)
elif sysctl -a | grep machdep.cpu.features | grep -iq 'avx2'; then
echo -e "The CPU supports the AVX2 SIMD build mode.\n"
ARGS+=(-DUSE_AVX2 -march=native -mavx2)
elif sysctl -a | grep machdep.cpu.features | grep -iq 'avx'; then
echo -e "The CPU supports the AVX SIMD build mode.\n"
ARGS+=(-DUSE_AVX -march=native -mavx)
elif sysctl -a | grep machdep.cpu.features | grep -iq 'sse2'; then
echo -e "The CPU supports the SSE2 SIMD build mode.\n"
# On my Core2Duo Mac, 'native' gives "error: bad value for -march= switch":
ARGS+=(-DUSE_SSE2 -march=core2)
elif sysctl -a | grep machdep.cpu.features | grep -iq 'asimd'; then
echo -e "The CPU supports the ASIMD build mode.\n"
ARGS+=(-DUSE_ARM_V8_SIMD -march=native)
else
echo -e "The CPU supports no Mlucas-recognized ASIMD build mode ... building in scalar-double mode.\n"
ARGS+=(-march=native)
fi
else
# Linux:
if grep -iq 'avx512' /proc/cpuinfo; then
echo -e "The CPU supports the AVX512 SIMD build mode.\n"
ARGS+=(-DUSE_AVX512 -march=native)
elif grep -iq 'avx2' /proc/cpuinfo; then
echo -e "The CPU supports the AVX2 SIMD build mode.\n"
ARGS+=(-DUSE_AVX2 -march=native -mavx2)
elif grep -iq 'avx' /proc/cpuinfo; then
echo -e "The CPU supports the AVX SIMD build mode.\n"
ARGS+=(-DUSE_AVX -march=native -mavx)
elif grep -iq 'sse2' /proc/cpuinfo; then
echo -e "The CPU supports the SSE2 SIMD build mode.\n"
ARGS+=(-DUSE_SSE2 -march=native)
elif grep -iq 'asimd' /proc/cpuinfo; then
echo -e "The CPU supports the ASIMD build mode.\n"
ARGS+=(-DUSE_ARM_V8_SIMD -march=native)
else
echo -e "The CPU supports no Mlucas-recognized ASIMD build mode ... building in scalar-double mode.\n"
ARGS+=(-march=native)
fi
fi
if [[ -d $DIR ]]; then
echo "Warning: '$DIR' already exists"
fi
# -p prevents "File exists" warning if obj-dir already exists:
mkdir -p "$DIR"
cd "$DIR"
if [[ -x $TARGET ]]; then
echo "Error: '$DIR/$TARGET' already exists." >&2
exit 1
fi
# Clang-under-MacOS linker barfs if one tries to explicitly invoke standard libs - h/t tdulcet for the
# conditional-inline syntax. Some OSes put the GMP headers in /usr/local/include, so -I that path in the
# compile command. If said path does not exist, make silently ignores it.
# Re. the -g flag to include the debugging symbols, they bloat executable size but if someone's Mlucas
# crashes/segfaults, one can rerun with GDB (gdb -ex=r ./Mlucas) to see the filename, line number and
# stack trace of the issue. If one wishes, one can run 'strip -g Mlucas' to remove the debugging symbols:
cat <<EOF >Makefile
CC?=gcc
CFLAGS=-fdiagnostics-color -Wall -g -O3 # -flto=auto
CPPFLAGS=-I/usr/local/include
LDLIBS=$(echo "$OSTYPE" | grep -iq 'darwin' || echo "-lm -lpthread -lrt") ${LARG[@]}
OBJS=\$(patsubst ../src/%.c, %.o, \$(wildcard ../src/*.c))
OBJS_MFAC=getRealTime.o get_cpuid.o get_fft_radices.o get_fp_rnd_const.o imul_macro.o mi64.o qfloat.o rng_isaac.o \$(patsubst ../src/%.c, %.o, \$(wildcard ../src/two*.c)) types.o util.o threadpool.o factor.o
$Mlucas: \$(OBJS)
\$(CC) \$(LDFLAGS) \$(CFLAGS) -o \$@ \$^ \$(LDLIBS)
$Mfactor: \$(OBJS_MFAC)
\$(CC) \$(LDFLAGS) \$(CFLAGS) -o \$@ \$^ \$(LDLIBS)
factor.o: ../src/factor.c
\$(CC) \$(CFLAGS) \$(CPPFLAGS) -c ${ARGS[@]} -DFACTOR_STANDALONE $WORDS -DTRYQ=4 \$<
%.o: ../src/%.c
\$(CC) \$(CFLAGS) \$(CPPFLAGS) -c ${ARGS[@]} \$<
clean:
rm -f \$(OBJS) \$(OBJS_MFAC)
.phony: clean
EOF
# if [[ -e build.log ]]; then
# cp -vf --backup=t build.log{,}
# fi
echo -e "Building $TARGET"
printf "%'d CPU cores detected ... parallel-building using that number of make threads.\n" "$CPU_THREADS"
if ! time make -j "$CPU_THREADS" "$TARGET" >build.log 2>&1; then
echo -e "\n*** There were build errors - see '${DIR}/build.log' for details. ***\n" >&2
grep -A 2 'error:' build.log || tail build.log
# exit 1
fi
echo -e "\nWarnings:\n"
grep 'warning:' build.log | awk '{ print $NF }' | sort | uniq -c | sort -nr
echo -e "\nErrors:\n"
grep -A 2 'error:' build.log || echo "None"
echo
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment