diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 49738a54..95fe715b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -25,23 +25,27 @@ jobs: version: 22 network: smp native_multi_image: 1 + brew_via_install: 1 FFLAGS: -fcoarray - os: macos-15 compiler: flang version: 22 network: smp + brew_via_install: 1 native_multi_image: 1 FFLAGS: -fcoarray - os: macos-15-intel compiler: flang version: 22 network: smp + brew_via_install: 1 native_multi_image: 1 FFLAGS: -fcoarray - os: macos-26 compiler: flang version: 22 network: smp + brew_via_install: 1 native_multi_image: 1 FFLAGS: -fcoarray @@ -177,7 +181,7 @@ jobs: echo "CXX=g++-${COMPILER_VERSION}" >> "$GITHUB_ENV" - name: Set flang variables - if: matrix.compiler == 'flang' + if: ${{ matrix.compiler == 'flang' && !matrix.brew_via_install }} run: | set -x echo "FC=flang-new" >> "$GITHUB_ENV" @@ -239,7 +243,7 @@ jobs: apt install -y build-essential pkg-config make git curl - name: Install macOS Dependencies - if: contains(matrix.os, 'macos') + if: ${{ contains(matrix.os, 'macos') && !matrix.brew_via_install }} run: | set -x brew update @@ -247,7 +251,7 @@ jobs: brew install gcc@12 - name: Install LLVM flang on macOS - if: contains(matrix.os, 'macos') && matrix.compiler == 'flang' + if: ${{ contains(matrix.os, 'macos') && matrix.compiler == 'flang' && !matrix.brew_via_install }} run: | set -x brew install llvm@${COMPILER_VERSION} flang @@ -258,6 +262,7 @@ jobs: echo "PATH=$(brew --prefix)/opt/llvm/bin:${PATH}" >> "$GITHUB_ENV" - name: Setup FPM + if: ${{ !matrix.brew_via_install }} uses: fortran-lang/setup-fpm@main with: github-token: ${{ secrets.GITHUB_TOKEN }} @@ -283,7 +288,9 @@ jobs: echo echo PATH="$PATH" for tool in ${FC} ${CC} ${CXX} fpm ; do - ( echo ; set -x ; w=$(which $tool) ; ls -al $w ; ls -alhL $w ; $tool --version ) + if command -v $tool > /dev/null 2>&1 ; then + ( echo ; set -x ; w=$(which $tool) ; ls -al $w ; ls -alhL $w ; $tool --version ) + fi done - name: Build Caffeine (install.sh) diff --git a/README.md b/README.md index 6282361a..3101849e 100644 --- a/README.md +++ b/README.md @@ -50,9 +50,7 @@ Prerequisites & Dependencies ### Build prerequisites The `install.sh` script uses the following packages: * Fortran and C compilers - * We regularly test with: GNU Fortran versions 13, 14, 15 and LLVM Flang versions 19, 20, 21 - * On macOS the Homebrew-installed `llvm` and `flang` packages may require some - additional settings, see [issue #228](https://github.com/BerkeleyLab/caffeine/issues/228) for the latest information. + * We regularly test with: LLVM Flang versions 19:22 and GNU Fortran versions 13:15 * [Fortran package manager] `fpm` * [pkg-config] * [realpath] @@ -98,7 +96,10 @@ env FC= CC= CXX= ./install.sh /dev/null 2>&1; then + BREW_PREFIX=`$BREW --prefix || exit 0` + if [ -z ${BREW_PREFIX:+x} ] || [ ! -d "$BREW_PREFIX" ] ; then + echo Warning: Failed to detect Homebrew prefix + BREW_PREFIX= + fi +fi -if [ -z ${FC+x} ] || [ -z ${CC+x} ] || [ -z ${CXX+x} ]; then - if command -v gfortran-$GCC_VERSION > /dev/null 2>&1; then - FC=`which gfortran-$GCC_VERSION` +if [ -z ${FC:+x} ] || [ -z ${CC:+x} ]; then + if command -v flang > /dev/null 2>&1; then + FC=`which flang` echo "Setting FC=$FC" + if [ -n "$BREW_PREFIX" ] && [[ $FC =~ $BREW_PREFIX ]] ; then + # We are using Homebrew flang, so prefer Homebrew clang/clang++ + export PATH="$BREW_PREFIX/opt/llvm/bin:$PATH" + fi fi - if command -v gcc-$GCC_VERSION > /dev/null 2>&1; then - CC=`which gcc-$GCC_VERSION` + if command -v clang > /dev/null 2>&1; then + CC=`which clang` echo "Setting CC=$CC" fi - if command -v g++-$GCC_VERSION > /dev/null 2>&1; then - CXX=`which g++-$GCC_VERSION` +fi +if [ -n "$CC" ] && ! command -v "$CC" > /dev/null 2>&1; then + echo "CC=$CC not found. If you don't yet have a C compiler, please leave environment variable CC unset." + exit 1 +fi +if [ -n "$FC" ] && ! command -v "$FC" > /dev/null 2>&1; then + echo "FC=$FC not found. If you don't yet have a Fortran compiler, please leave environment variable FC unset." + exit 1 +fi +if [ -z ${CXX:+x} ] && [ -n "$CC" ] ; then + # C++ is an optional dependency + # try to auto-detect from CC + if [[ $(basename $CC) =~ clang ]] ; then + CXX_guess=clang++ + else + CXX_guess=g++ + fi + if [[ $CC =~ (-[0-9]+)$ ]] ; then + CXX_guess=${CXX_guess}${BASH_REMATCH[0]} + fi + if command -v $CXX_guess > /dev/null 2>&1; then + CXX=`which $CXX_guess` echo "Setting CXX=$CXX" fi fi +set -u # error on use of undefined variable + if command -v pkg-config > /dev/null 2>&1; then PKG_CONFIG=`which pkg-config` fi @@ -163,7 +197,7 @@ ask_permission_to_use_homebrew() { cat << EOF -Either one or more of the environment variables FC, CC, and CXX are unset or +Either one or more of the environment variables FC and CC are unset or one or more of the following packages are not in the PATH: pkg-config, realpath, make, fpm. If you grant permission to install prerequisites, you will be prompted before each installation. @@ -212,9 +246,9 @@ exit_if_user_declines() case ${1:-} in *GASNet*) echo "Please ensure the $pkg.pc file is in $PKG_CONFIG_PATH and then rerun './install.sh'." ;; - *GCC*) - echo "To use compilers other than Homebrew-installed gcc-$GCC_VERSION, g++-$GCC_VERSION, and gfortran-$GCC_VERSION," - echo "please set the FC, CC, and CXX environment variables and rerun './install.sh'." ;; + *FC*) + echo "To use compilers other than Homebrew-installed LLVM flang and clang," + echo "please set the FC and CC environment variables and rerun './install.sh'." ;; *) echo "Please ensure that $1 is installed and in your PATH and then rerun './install.sh'." ;; esac @@ -228,13 +262,11 @@ if [ ! -d $DEPENDENCIES_DIR ]; then mkdir -p $DEPENDENCIES_DIR fi -if [ -z ${FC+x} ] || [ -z ${CC+x} ] || [ -z ${CXX+x} ] || [ -z ${PKG_CONFIG+x} ] || [ -z ${REALPATH+x} ] || [ -z ${MAKE+x} ] || [ -z ${FPM+x} ] ; then +if [ -z ${FC:+x} ] || [ -z ${CC:+x} ] || [ -z ${PKG_CONFIG:+x} ] || [ -z ${REALPATH:+x} ] || [ -z ${MAKE:+x} ] || [ -z ${FPM:+x} ] ; then ask_permission_to_use_homebrew exit_if_user_declines "brew" - BREW="brew" - if ! command -v $BREW > /dev/null 2>&1; then ask_permission_to_install_homebrew @@ -264,39 +296,54 @@ EOF fi fi - if [ -z ${FC+x} ] || [ -z ${CC+x} ] || [ -z ${CXX+x} ]; then - ask_permission_to_install_homebrew_package "gfortran, gcc, and g++" "gcc@$GCC_VERSION" - exit_if_user_declines "GCC" - "$BREW" install gcc@$GCC_VERSION - if [ uname == "Linux" ]; then - brew link --force glibc - fi + BREW_PREFIX=`$BREW --prefix || exit 0` + if [ -z ${BREW_PREFIX:+x} ] || [ ! -d "$BREW_PREFIX" ] ; then + echo Failed to detect Homebrew prefix + echo 1 fi - CC=`which gcc-$GCC_VERSION` - CXX=`which g++-$GCC_VERSION` - FC=`which gfortran-$GCC_VERSION` - if [ -z ${REALPATH+x} ] || [ -z ${MAKE+x} ] ; then + # fetch the latest package definitions: + $BREW update + + if [ -z ${FC:+x} ] || [ -z ${CC:+x} ] ; then + ask_permission_to_install_homebrew_package "'llvm' and 'flang'" + exit_if_user_declines "FC" + $BREW install llvm flang + + # Homebrew does not inject clang/clang++ into PATH on macOS + export PATH="$BREW_PREFIX/opt/llvm/bin:$PATH" + CC=`which clang` + CXX=`which clang++` + FC=`which flang-new` + for tool in $CC $CXX $FC ; do + if ! command -v $tool > /dev/null 2>&1 ; then + echo Failed to detect Homebrew compiler install at $tool + exit 1 + fi + done + fi + + if [ -z ${REALPATH:+x} ] || [ -z ${MAKE:+x} ] ; then ask_permission_to_install_homebrew_package "'realpath' and 'make'" "coreutils" - exit_if_user_declines "realpath" - "$BREW" install coreutils + exit_if_user_declines "realpath and make" + $BREW install coreutils + REALPATH=`which realpath` + MAKE=`which make` fi - REALPATH=`which realpath` - if [ -z ${PKG_CONFIG+x} ]; then + if [ -z ${PKG_CONFIG:+x} ]; then ask_permission_to_install_homebrew_package "'pkg-config'" exit_if_user_declines "pkg-config" - "$BREW" install pkg-config + $BREW install pkg-config + PKG_CONFIG=`which pkg-config` fi - PKG_CONFIG=`which pkg-config` - if [ -z ${FPM+x} ] ; then + if [ -z ${FPM:+x} ] ; then ask_permission_to_install_homebrew_package "'fpm'" exit_if_user_declines "fpm" - "$BREW" tap fortran-lang/hombrew-fortran - "$BREW" install fpm + $BREW install fpm + FPM=`which fpm` fi - FPM=`which fpm` fi PREFIX=${PREFIX:-"${HOME}/.local"} @@ -304,7 +351,7 @@ mkdir -p "$PREFIX" PREFIX=`$REALPATH "$PREFIX"` echo "PREFIX=$PREFIX" -if [ -z ${PKG_CONFIG_PATH+x} ]; then +if [ -z ${PKG_CONFIG_PATH:+x} ]; then PKG_CONFIG_PATH="$PREFIX/lib/pkgconfig" else PKG_CONFIG_PATH="$PREFIX/lib/pkgconfig:$PKG_CONFIG_PATH" @@ -317,6 +364,13 @@ if [[ $FPM_FC == *flang* ]]; then fi FPM_CC="$($REALPATH $(command -v $CC))" +# workaround issue #228: clang cannot find Homebrew flang's C header +if [ "${BREW_PREFIX:-unset}" != unset ] ; then + if [[ $FPM_FC =~ flang ]] && [[ $FPM_FC =~ $BREW_PREFIX ]] ; then + APPEND_CFLAGS="-I$(dirname $(find "$BREW_PREFIX/Cellar/flang" -name ISO_Fortran_binding.h | head -1))" + fi +fi + ask_package_permission() { cat << EOF @@ -436,7 +490,7 @@ cat << EOF > $CAFFEINE_PC CAFFEINE_FPM_LDFLAGS=$GASNET_LDFLAGS $GASNET_LIB_LOCATIONS CAFFEINE_FPM_FC=$FPM_FC CAFFEINE_FPM_CC=$GASNET_CC -CAFFEINE_FPM_CFLAGS=$GASNET_CFLAGS $GASNET_CPPFLAGS +CAFFEINE_FPM_CFLAGS=$GASNET_CFLAGS $GASNET_CPPFLAGS $APPEND_CFLAGS Name: caffeine Description: Coarray Fortran parallel runtime library URL: https://gitlab.lbl.gov/berkeleylab/caffeine