diff --git a/.github/workflows/build_wheels.yml b/.github/workflows/build_wheels.yml new file mode 100644 index 000000000..3e4330b10 --- /dev/null +++ b/.github/workflows/build_wheels.yml @@ -0,0 +1,42 @@ +name: swiftest + +on: push + +jobs: + build_wheels: + name: Build wheels on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-20.04, macos-11, macos-12, macos-13] + + steps: + - uses: actions/checkout@v3 + + - name: Build wheels + uses: pypa/cibuildwheel@v2.15.0 + env: + CIBW_ARCHS_MACOS: x86_64 arm64 + CIBW_ARCHS_LINUX: x86_64 aarch64 + with: + package-dir: . + output-dir: wheelhouse + config-file: "{package}/pyproject.toml" + + - uses: actions/upload-artifact@v3 + with: + path: ./wheelhouse/*.whl + + + build_sdist: + name: Build source distribution + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Build sdist + run: pipx run build --sdist + + - uses: actions/upload-artifact@v3 + with: + path: dist/*.tar.gz \ No newline at end of file diff --git a/.gitignore b/.gitignore index 9c5ee861f..ab0e8d718 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ swiftest_driver.sh !README.swifter dump* !**/.gitignore +!.github/workflows/build_wheels.yml !setup.py !examples/** !swiftest/** @@ -25,6 +26,7 @@ dump* *ipynb_checkpoints **/.DS_Store !version.txt +!LICENSE.txt !requirements.txt !pyproject.toml **/_skbuild diff --git a/CMakeLists.txt b/CMakeLists.txt index cb2aa413c..4a21a2d07 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,15 @@ CMAKE_MINIMUM_REQUIRED(VERSION 3.6.0...3.27.1) # Get version stored in text file FILE(READ "version.txt" VERSION) -PROJECT(swiftest VERSION ${VERSION} LANGUAGES C Fortran) +PROJECT(${SKBUILD_PROJECT_NAME} LANGUAGES C Fortran VERSION ${VERSION}) + +IF (CMAKE_Fortran_COMPILER_ID MATCHES "^Intel") + SET(COMPILER_OPTIONS "Intel" CACHE STRING "Compiler identified as Intel") +ELSEIF (CMAKE_Fortran_COMPILER_ID STREQUAL "GNU") + SET(COMPILER_OPTIONS "GNU" CACHE STRING "Compiler identified as gfortran") +ELSE () + MESSAGE(FATAL_ERROR "Compiler ${CMAKE_Fortran_COMPILER_ID} not recognized!") +ENDIF () # Set some options the user may choose OPTION(USE_COARRAY "Use Coarray Fortran for parallelization of test particles" OFF) @@ -29,28 +37,7 @@ IF(PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR) ENDIF() # Ensure scikit-build modules -FIND_PACKAGE(Python3 COMPONENTS Interpreter Development.Module REQUIRED) -IF (NOT SKBUILD) - EXECUTE_PROCESS( - COMMAND "${Python3_EXECUTABLE}" - -c "import os, skbuild; print(os.path.dirname(skbuild.__file__))" - OUTPUT_VARIABLE SKBLD_DIR - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - FILE(TO_CMAKE_PATH ${SKBLD_DIR} SKBLD_DIR) - LIST(APPEND CMAKE_MODULE_PATH "${SKBLD_DIR}/resources/cmake") - MESSAGE(STATUS "Looking in ${SKBLD_DIR}/resources/cmake for CMake modules") -ENDIF() - -# Detect when building against a conda environment set the _using_conda variable -# for use both in this file and in the parent -GET_FILENAME_COMPONENT(_python_bin_dir ${Python3_EXECUTABLE} DIRECTORY) -IF(EXISTS "${_python_bin_dir}/../conda-meta") - MESSAGE("-- Detected conda environment, setting INSTALL_RPATH_USE_LINK_PATH") - SET(_using_conda On) -ELSE() - SET(_using_conda Off) -ENDIF() +FIND_PACKAGE(Python COMPONENTS Interpreter Development.Module REQUIRED) # Add our local modules to the module path FILE(TO_CMAKE_PATH "${CMAKE_SOURCE_DIR}/cmake/Modules" LOCAL_MODULE_PATH) @@ -77,6 +64,9 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${BIN}) # Have the .mod files placed in the lib folder SET(CMAKE_Fortran_MODULE_DIRECTORY ${MOD}) +# Set the name of the swiftest library +SET(SWIFTEST_LIBRARY swiftest) + # The source for the SWIFTEST binary and have it placed in the bin folder ADD_SUBDIRECTORY(${SRC} ${BIN}) diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 000000000..965bb4c26 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,10 @@ +Copyright 2023 - David Minton +The Swiftest development team: David Minton, Carlisle Wishard, Jennifer Pouplin, Jake Elliott, Dana Singh, & Kaustub Anand + +This file is part of Swiftest. +Swiftest 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 3 of the License, or (at your option) any later version. +Swiftest 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 Swiftest. +If not, see: https://www.gnu.org/licenses. \ No newline at end of file diff --git a/buildscripts/_build_getopts.sh b/buildscripts/_build_getopts.sh index 0c92d1077..ac9e9586b 100755 --- a/buildscripts/_build_getopts.sh +++ b/buildscripts/_build_getopts.sh @@ -14,10 +14,9 @@ SCRIPT_DIR=$(realpath $(dirname $0)) ROOT_DIR=$(realpath ${SCRIPT_DIR}/..) # Parse arguments -USTMT="Usage: ${0} <-d /path/to/dependency/source> [-p /prefix/path|{/usr/local}] [-m MACOSX_DEPLOYMENT_TARGET|{11.0}]" -PREFIX=/usr/local -DEPENDENCY_DIR="${ROOT_DIR}/_dependencies" -MACOSX_DEPLOYMENT_TARGET="13.0" +USTMT="Usage: ${0} [-d /path/to/dependency/source] [-p /prefix/path] [-m MACOSX_DEPLOYMENT_TARGET]" +MACOSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET:-"$(sw_vers --ProductVersion)"} + while getopts ":d:p:m:h" ARG; do case "${ARG}" in d) @@ -46,26 +45,9 @@ while getopts ":d:p:m:h" ARG; do done read -r OS ARCH < <($SCRIPT_DIR/get_platform.sh) - -if [ -z ${DEPENDENCY_ENV_VARS+x} ]; then - . ${SCRIPT_DIR}/set_compilers.sh - - LD_LIBRARY_PATH="${PREFIX}/lib:${LD_LIBRARY_PATH}" - CPPFLAGS="${CPPFLAGS} -isystem ${PREFIX}/include" - LDFLAGS="${LDFLAGS} -L${PREFIX}/lib" - CPATH="${CPATH} ${PREFIX}/include}" - - HDF5_ROOT="${PREFIX}" - HDF5_LIBDIR="${HDF5_ROOT}/lib" - HDF5_INCLUDE_DIR="${HDF5_ROOT}/include" - HDF5_PLUGIN_PATH="${HDF5_LIBDIR}/plugin" - NCDIR="${PREFIX}" - NFDIR="${PREFIX}" - NETCDF_FORTRAN_HOME=${NFDIR} - NETCDF_HOME=${NCDIR} - - DEPENDENCY_ENV_VARS=true -fi +BUILD_DIR=${BUILD_DIR:-$(mktemp -ut swiftest_build.XXXXXXXX)} +PREFIX=${PREFIX:-${ROOT_DIR}} +DEPENDENCY_DIR=${DEPENDENCY_DIR:-${BUILD_DIR}} mkdir -p ${DEPENDENCY_DIR} mkdir -p ${PREFIX}/lib diff --git a/buildscripts/build_all.sh b/buildscripts/build_all.sh deleted file mode 100755 index d93933abe..000000000 --- a/buildscripts/build_all.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash -# This script will generate cross-platform wheels for the Swiftest Python package using Docker. If it is called from MacOS it will -# also generate a Mac build. -# -# Copyright 2023 - David Minton -# This file is part of Swiftest. -# Swiftest 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 3 of the License, or (at your option) any later version. -# Swiftest 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 Swiftest. -# If not, see: https://www.gnu.org/licenses. - -# Determine the platform and architecture -set -a -SCRIPT_DIR=$(realpath $(dirname $0)) -ARGS=$@ -. ${SCRIPT_DIR}/_build_getopts.sh ${ARGS} - -set -e -${SCRIPT_DIR}/build_dependencies.sh ${ARGS} -${SCRIPT_DIR}/build_swiftest.sh ${ARGS} \ No newline at end of file diff --git a/buildscripts/build_dependencies.sh b/buildscripts/build_dependencies.sh index f1eb625c3..8d8027aa6 100755 --- a/buildscripts/build_dependencies.sh +++ b/buildscripts/build_dependencies.sh @@ -17,47 +17,6 @@ set -a ARGS=$@ . ${SCRIPT_DIR}/_build_getopts.sh ${ARGS} -ZLIB_VER="1.3" -HDF5_VER="1_14_2" -NC_VER="4.9.2" -NF_VER="4.6.1" - -printf "*********************************************************\n" -printf "* FETCHING DEPENCENCY SOURCES *\n" -printf "*********************************************************\n" -printf "Copying files to ${DEPENDENCY_DIR}\n" -mkdir -p ${DEPENDENCY_DIR} -if [ ! -d ${DEPENDENCY_DIR}/zlib-${ZLIB_VER} ]; then - [ -d ${DEPENDENCY_DIR}/zlib-* ] && rm -rf ${DEPENDENCY_DIR}/zlib-* - curl -L https://github.com/madler/zlib/releases/download/v${ZLIB_VER}/zlib-${ZLIB_VER}.tar.gz | tar xvz -C ${DEPENDENCY_DIR} -fi - -printf "Checking if HDF5 source exists\n" -if [[ (-d ${DEPENDENCY_DIR}/hdfsrc) && (-f ${DEPENDENCY_DIR}/hdfsrc/README.md) ]]; then - OLDVER=$(grep version ${DEPENDENCY_DIR}/hdfsrc/README.md | awk '{print $3}' | sed 's/\./_/g') - printf "Existing copy of HDF5 source detected\n" - printf "Existing version : ${OLDVER}\n" - printf "Requested version: ${HDF5_VER}\n" - if [ "$OLDVER" != "${HDF5_VER}" ]; then - printf "Existing version of HDF5 source doesn't match requested. Deleting\n" - rm -rf ${DEPENDENCY_DIR}/hdfsrc - fi -fi - -if [ ! -d ${DEPENDENCY_DIR}/hdfsrc ]; then - curl -s -L https://github.com/HDFGroup/hdf5/releases/download/hdf5-${HDF5_VER}/hdf5-${HDF5_VER}.tar.gz | tar xvz -C ${DEPENDENCY_DIR} -fi - -if [ ! -d ${DEPENDENCY_DIR}/netcdf-c-${NC_VER} ]; then - [ -d ${DEPENDENCY_DIR}/netcdf-c-* ] && rm -rf ${DEPENDENCY_DIR}/netcdf-c-* - curl -s -L https://github.com/Unidata/netcdf-c/archive/refs/tags/v${NC_VER}.tar.gz | tar xvz -C ${DEPENDENCY_DIR} -fi - -if [ ! -d ${DEPENDENCY_DIR}/netcdf-fortran-${NF_VER} ]; then - [ -d ${DEPENDENCY_DIR}/netcdf-fortran-* ] && rm -rf ${DEPENDENCY_DIR}/netcdf-fortran-* - curl -s -L https://github.com/Unidata/netcdf-fortran/archive/refs/tags/v${NF_VER}.tar.gz | tar xvz -C ${DEPENDENCY_DIR} -fi - cd $ROOT_DIR printf "*********************************************************\n" printf "* STARTING DEPENDENCY BUILD *\n" @@ -66,34 +25,21 @@ printf "Using ${OS} compilers:\nFC: ${FC}\nCC: ${CC}\nCXX: ${CXX}\n" printf "Installing to ${PREFIX}\n" printf "\n" -set -e -if [ ! -f ${PREFIX}/lib/libz.a ]; then - ${SCRIPT_DIR}/build_zlib.sh ${ARGS} -else - echo "Found: ${PREFIX}/lib/libz.a" -fi - -if [ ! -f ${PREFIX}/lib/libhdf5.a ]; then - ${SCRIPT_DIR}/build_hdf5.sh ${ARGS} -else - echo "Found: ${PREFIX}/lib/libhdf5.a" +# Get the OpenMP Libraries +if [ $OS = "MacOSX" ]; then + ${SCRIPT_DIR}/get_lomp.sh ${ARGS} fi - -if [ ! -f ${PREFIX}/lib/libnetcdf.a ]; then - ${SCRIPT_DIR}/build_netcdf-c.sh ${ARGS} -else - echo "Found: ${PREFIX}/lib/libnetcdf.a" -fi - -if [ ! -f ${PREFIX}/lib/libnetcdff.a ]; then - ${SCRIPT_DIR}/build_netcdf-fortran.sh ${ARGS} -else - echo "Found: ${PREFIX}/lib/libnetcdff.a" -fi +set -e +${SCRIPT_DIR}/build_zlib.sh ${ARGS} +${SCRIPT_DIR}/build_hdf5.sh ${ARGS} +${SCRIPT_DIR}/build_netcdf-c.sh ${ARGS} +${SCRIPT_DIR}/build_netcdf-fortran.sh ${ARGS} printf "\n" printf "*********************************************************\n" printf "* DEPENDENCIES ARE BUILT *\n" printf "*********************************************************\n" printf "Dependencys are installed to: ${PREFIX}\n\n" + + diff --git a/buildscripts/build_hdf5.sh b/buildscripts/build_hdf5.sh index 9f170e0a1..d351bd47d 100755 --- a/buildscripts/build_hdf5.sh +++ b/buildscripts/build_hdf5.sh @@ -15,9 +15,32 @@ set -a ARGS=$@ . ${SCRIPT_DIR}/_build_getopts.sh ${ARGS} +HDF5_VER="1_14_2" +printf "*********************************************************\n" +printf "* FETCHING HDF5 SOURCE *\n" +printf "*********************************************************\n" +printf "Copying files to ${DEPENDENCY_DIR}\n" + +printf "Checking if HDF5 source exists\n" +if [[ (-d ${DEPENDENCY_DIR}/hdfsrc) && (-f ${DEPENDENCY_DIR}/hdfsrc/README.md) ]]; then + OLDVER=$(grep version ${DEPENDENCY_DIR}/hdfsrc/README.md | awk '{print $3}' | sed 's/\./_/g') + printf "Existing copy of HDF5 source detected\n" + printf "Existing version : ${OLDVER}\n" + printf "Requested version: ${HDF5_VER}\n" + if [ "$OLDVER" != "${HDF5_VER}" ]; then + printf "Existing version of HDF5 source doesn't match requested. Deleting\n" + rm -rf ${DEPENDENCY_DIR}/hdfsrc + fi +fi + +if [ ! -d ${DEPENDENCY_DIR}/hdfsrc ]; then + curl -s -L https://github.com/HDFGroup/hdf5/releases/download/hdf5-${HDF5_VER}/hdf5-${HDF5_VER}.tar.gz | tar xvz -C ${DEPENDENCY_DIR} +fi + + printf "\n" printf "*********************************************************\n" -printf "* BUILDING HDF5 STATIC LIBRARY *\n" +printf "* BUILDING HDF5 LIBRARY *\n" printf "*********************************************************\n" printf "LIBS: ${LIBS}\n" printf "CFLAGS: ${CFLAGS}\n" @@ -35,7 +58,7 @@ if [ $OS = "MacOSX" ]; then printf "echo arm-apple-darwin" > bin/config.sub fi fi -COPTS="--disable-shared --enable-build-mode=production --enable-tests=no --enable-tools=no --disable-fortran --disable-java --disable-cxx --prefix=${PREFIX} --with-zlib=${PREFIX}" +COPTS="--enable-build-mode=production --enable-tests=no --enable-tools=no --disable-fortran --disable-java --disable-cxx --prefix=${PREFIX} --with-zlib=${PREFIX}" ./configure ${COPTS} make if [ -w ${PREFIX} ]; then @@ -48,6 +71,3 @@ if [ $? -ne 0 ]; then printf "hdf5 could not be compiled.\n" exit 1 fi - -make distclean - diff --git a/buildscripts/build_netcdf-c.sh b/buildscripts/build_netcdf-c.sh index 82bc78380..8f692fac1 100755 --- a/buildscripts/build_netcdf-c.sh +++ b/buildscripts/build_netcdf-c.sh @@ -16,9 +16,22 @@ set -a ARGS=$@ . ${SCRIPT_DIR}/_build_getopts.sh ${ARGS} + +NC_VER="4.9.2" + +printf "*********************************************************\n" +printf "* FETCHING NETCDF-C SOURCE *\n" +printf "*********************************************************\n" +printf "Copying files to ${DEPENDENCY_DIR}\n" + +if [ ! -d ${DEPENDENCY_DIR}/netcdf-c-${NC_VER} ]; then + [ -d ${DEPENDENCY_DIR}/netcdf-c-* ] && rm -rf ${DEPENDENCY_DIR}/netcdf-c-* + curl -s -L https://github.com/Unidata/netcdf-c/archive/refs/tags/v${NC_VER}.tar.gz | tar xvz -C ${DEPENDENCY_DIR} +fi + printf "\n" printf "*********************************************************\n" -printf "* BUILDING NETCDF-C STATIC LIBRARY *\n" +printf "* BUILDING NETCDF-C LIBRARY *\n" printf "*********************************************************\n" printf "LIBS: ${LIBS}\n" printf "CFLAGS: ${CFLAGS}\n" @@ -30,10 +43,7 @@ printf "HDF5_ROOT: ${HDF5_ROOT}\n" printf "*********************************************************\n" cd ${DEPENDENCY_DIR}/netcdf-c-* -COPTS="--disable-shared --disable-dap --disable-byterange --disable-testsets --prefix=${PREFIX}" -if [ ! $OS = "MacOSX" ]; then - COPTS="${COPTS} --disable-libxml2" -fi +COPTS="--disable-testsets --disable-nczarr --prefix=${PREFIX}" printf "COPTS: ${COPTS}\n" ./configure $COPTS make && make check @@ -47,6 +57,4 @@ fi if [ $? -ne 0 ]; then printf "netcdf-c could not be compiled."\n exit 1 -fi - -make distclean \ No newline at end of file +fi \ No newline at end of file diff --git a/buildscripts/build_netcdf-fortran.sh b/buildscripts/build_netcdf-fortran.sh index 9e9a877cd..aea5e71aa 100755 --- a/buildscripts/build_netcdf-fortran.sh +++ b/buildscripts/build_netcdf-fortran.sh @@ -15,11 +15,19 @@ set -a ARGS=$@ . ${SCRIPT_DIR}/_build_getopts.sh ${ARGS} -LIBS="$(${PREFIX}/bin/nc-config --libs --static)" +NF_VER="4.6.1" +printf "*********************************************************\n" +printf "* FETCHING NETCDF-FORTRAN SOURCE *\n" +printf "*********************************************************\n" +printf "Copying files to ${DEPENDENCY_DIR}\n" +if [ ! -d ${DEPENDENCY_DIR}/netcdf-fortran-${NF_VER} ]; then + [ -d ${DEPENDENCY_DIR}/netcdf-fortran-* ] && rm -rf ${DEPENDENCY_DIR}/netcdf-fortran-* + curl -s -L https://github.com/Unidata/netcdf-fortran/archive/refs/tags/v${NF_VER}.tar.gz | tar xvz -C ${DEPENDENCY_DIR} +fi printf "\n" printf "*********************************************************\n" -printf "* BUILDING NETCDF-FORTRAN STATIC LIBRARY *\n" +printf "* BUILDING NETCDF-FORTRAN LIBRARY *\n" printf "*********************************************************\n" printf "LIBS: ${LIBS}\n" printf "CFLAGS: ${CFLAGS}\n" @@ -30,7 +38,7 @@ printf "LDFLAGS: ${LDFLAGS}\n" printf "*********************************************************\n" cd ${DEPENDENCY_DIR}/netcdf-fortran-* -./configure --disable-shared --with-pic --disable-zstandard-plugin --enable-large-file-tests=no --enable-filter-test=no --prefix=${PREFIX} +./configure --enable-large-file-tests=no --enable-static=no --enable-filter-test=no --prefix=${PREFIX} make && make check i if [ -w ${PREFIX} ]; then make install @@ -41,7 +49,4 @@ fi if [ $? -ne 0 ]; then printf "netcdf-fortran could not be compiled.\n" exit 1 -fi - -make distclean - +fi \ No newline at end of file diff --git a/buildscripts/build_swiftest.sh b/buildscripts/build_swiftest.sh deleted file mode 100755 index c4f06bb4c..000000000 --- a/buildscripts/build_swiftest.sh +++ /dev/null @@ -1,68 +0,0 @@ -#!/bin/bash -# This script will build the Swiftest package. It is assumed that compatible dependencies have been built already before this is run -# -# Copyright 2023 - David Minton -# This file is part of Swiftest. -# Swiftest 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 3 of the License, or (at your option) any later version. -# Swiftest 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 Swiftest. -# If not, see: https://www.gnu.org/licenses. -set -a -if [ -z ${SCRIPT_DIR+x} ]; then SCRIPT_DIR=$(realpath $(dirname $0)); fi -ARGS=$@ -. ${SCRIPT_DIR}/_build_getopts.sh ${ARGS} - -# Determine if we are in the correct directory (the script can either be run from the Swiftest project root directory or the -# buildscripts directory) -if [ ! -f "${ROOT_DIR}/setup.py" ]; then - echo "Error: setup.py not found" - exit 1 -fi - -printf "Using ${OS} compilers:\nFC: ${FC}\nCC: ${CC}\nCXX: ${CXX}\n\n" -printf "Installing to ${PREFIX}\n" -printf "Dependency libraries in ${PREFIX}\n" - - -SKBUILD_CONFIGURE_OPTIONS="-DBUILD_SHARED_LIBS=OFF" - -if [ $OS = "Intel" ]; then - FCFLAGS="${CFLAGS} -standard-semantics" - SKBUILD_CONFIGURE_OPTIONS="${SKBUILD_CONFIGURE_OPTIONS} -DMACHINE_CODE_VALUE=\"SSE2\"" -else - SKBUILD_CONFIGURE_OPTIONS="${SKBUILD_CONFIGURE_OPTIONS} -DMACHINE_CODE_VALUE=\"generic\"" -fi - -read -r OS ARCH < <($SCRIPT_DIR/get_platform.sh) -echo $OS $ARCH - -cd $ROOT_DIR - -printf "\n" -printf "*********************************************************\n" -printf "* BUILDING SWIFTEST *\n" -printf "*********************************************************\n" -printf "LIBS: ${LIBS}\n" -printf "CFLAGS: ${CFLAGS}\n" -printf "FFLAGS: ${FFLAGS}\n" -printf "FCFLAGS: ${FCFLAGS}\n" -printf "CPPFLAGS: ${CPPFLAGS}\n" -printf "CPATH: ${CPATH}\n" -printf "LD_LIBRARY_PATH: ${LD_LIBRARY_PATH}\n" -printf "LDFLAGS: ${LDFLAGS}\n" -printf "NETCDF_FORTRAN_HOME: ${NETCDF_FORTRAN_HOME}\n" -printf "SKBUILD_CONFIGURE_OPTIONS: ${SKBUILD_CONFIGURE_OPTIONS}\n" -if [ $OS = "MacOSX" ]; then - printf "MACOSX_DEPLOYMENT_TARGET: ${MACOSX_DEPLOYMENT_TARGET}\n" -fi -printf "*********************************************************\n" - -python3 -m pip install build pip -python3 -m build --sdist -if [ $OS = "MacOSX" ]; then - cibuildwheel --platform macos -elif [ $OS = "Linux" ]; then - cibuildwheel --platform linux -fi \ No newline at end of file diff --git a/buildscripts/build_zlib.sh b/buildscripts/build_zlib.sh index d65cad4f6..e21b75b47 100755 --- a/buildscripts/build_zlib.sh +++ b/buildscripts/build_zlib.sh @@ -15,8 +15,21 @@ set -a ARGS=$@ . ${SCRIPT_DIR}/_build_getopts.sh ${ARGS} + +ZLIB_VER="1.3" + +printf "*********************************************************\n" +printf "* FETCHING ZLIB SOURCE *\n" +printf "*********************************************************\n" +printf "Copying files to ${DEPENDENCY_DIR}\n" +mkdir -p ${DEPENDENCY_DIR} +if [ ! -d ${DEPENDENCY_DIR}/zlib-${ZLIB_VER} ]; then + [ -d ${DEPENDENCY_DIR}/zlib-* ] && rm -rf ${DEPENDENCY_DIR}/zlib-* + curl -L https://github.com/madler/zlib/releases/download/v${ZLIB_VER}/zlib-${ZLIB_VER}.tar.gz | tar xvz -C ${DEPENDENCY_DIR} +fi + printf "*********************************************************\n" -printf "* BUILDING ZLIB STATIC LIBRARY *\n" +printf "* BUILDING ZLIB LIBRARY *\n" printf "*********************************************************\n" printf "LIBS: ${LIBS}\n" printf "CFLAGS: ${CFLAGS}\n" @@ -27,7 +40,7 @@ printf "LDFLAGS: ${LDFLAGS}\n" printf "*********************************************************\n" cd ${DEPENDENCY_DIR}/zlib-* -./configure --prefix=${PREFIX} --static +./configure --prefix=${PREFIX} make if [ -w ${PREFIX} ]; then make install @@ -38,6 +51,4 @@ fi if [ $? -ne 0 ]; then printf "zlib could not be compiled.\n" exit 1 -fi - -make distclean \ No newline at end of file +fi \ No newline at end of file diff --git a/buildscripts/get_lomp.sh b/buildscripts/get_lomp.sh new file mode 100755 index 000000000..6b56e5b3c --- /dev/null +++ b/buildscripts/get_lomp.sh @@ -0,0 +1,83 @@ +#!/bin/bash +# This script will download the correct OpenMP library for a given MacOS deployment target +# +# Copyright 2023 - David Minton +# This file is part of Swiftest. +# Swiftest 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 3 of the License, or (at your option) any later version. +# Swiftest 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 Swiftest. +# If not, see: https://www.gnu.org/licenses. + +# Determine the platform and architecture +SCRIPT_DIR=$(realpath $(dirname $0)) +set -a +ARGS=$@ +. ${SCRIPT_DIR}/_build_getopts.sh ${ARGS} +printf "MACOSX_DEPLOYMENT_TARGET: ${MACOSX_DEPLOYMENT_TARGET}\n" + +TARGET_MAJOR=`echo $MACOSX_DEPLOYMENT_TARGET | cut -d. -f1` +TARGET_MINOR=`echo $MACOSX_DEPLOYMENT_TARGET | cut -d. -f2` +TARGET_REV=`echo $MACOSX_DEPLOYMENT_TARGET | cut -d. -f3` + +#Figure out which version to get +case $TARGET_MAJOR in + 13) + OMPVER="14.0.6" + DVER="20" + ;; + 12) + if ((TARGET_MINOR>=5)); then + OMPVER="14.0.6" + DVER="20" + else + OMPVER="13.0.0" + DVER="21" + fi + ;; + 11) + if ((TARGET_MINOR>=3)); then + OMPVER="12.0.1" + DVER="20" + else + OMPVER="11.0.1" + DVER="20" + fi + ;; + 10) + DVER="17" + case $TARGET_MINOR in + 15) + case $TARGET_REV in + 4) + OMPVER="10.0.0" + ;; + 2) + OMPVER="9.0.1" + ;; + esac + ;; + 14) + case $TARGET_REV in + 4) + OMPVER="8.0.1" + ;; + 3) + OMPVER="7.1.0" + ;; + esac + ;; + *) + OMPVER="7.1.0" + ;; + esac + ;; +esac + +filename="openmp-${OMPVER}-darwin${DVER}-Release.tar.gz" +#Download and install the libraries +printf "Downloading ${filename}\n" +curl -O https://mac.r-project.org/openmp/${filename} && \ + sudo tar fvxz ${filename} -C / && \ + rm ${filename} \ No newline at end of file diff --git a/buildscripts/intelbash.sh b/buildscripts/intelbash.sh new file mode 100755 index 000000000..7f42e5534 --- /dev/null +++ b/buildscripts/intelbash.sh @@ -0,0 +1,5 @@ +#!/bin/bash +ARGS=$@ + +eval "$(/usr/local/bin/brew shellenv)" +arch -x86_64 /bin/bash -c "${ARGS}" diff --git a/buildscripts/set_compilers.sh b/buildscripts/set_compilers.sh index 3ff88f8b1..7523628ee 100755 --- a/buildscripts/set_compilers.sh +++ b/buildscripts/set_compilers.sh @@ -15,7 +15,7 @@ # If not, see: https://www.gnu.org/licenses. # Parse arguments case "$OS" in - Intel|Linux|MacOSX) + Linux|MacOSX) ;; *) echo "Unknown compiler type: $OS" @@ -25,118 +25,31 @@ case "$OS" in ;; esac + set -a # Only replace compiler definitions if they are not already set case $OS in - Intel) - if [ ! -v FC ]; then - if command -v ifx &> /dev/null; then - FC=$(command -v ifx) - elif command -v ifort &> /dev/null; then - FC=$(command -v mpiifort) - else - printf "Error. Cannot find valid Intel Fortran compiler.\n" - exit 1 - fi - fi - if [ ! -v F77 ]; then - F77="${FC}" - fi - - if [ ! -v CC ]; then - if command -v icx &> /dev/null; then - CC=$(command -v icx) - elif command -v icc &> /dev/null; then - CC=$(command -v icc) - else - printf "Error. Cannot find valid Intel C compiler.\n" - exit 1 - fi - fi - - if [ ! -v CXX ]; then - if command -v icpx &> /dev/null; then - CXX=$(command -v icpx) - elif command -v icpc &> /dev/null; then - CXX=$(command -v icpc) - else - printf "Error. Cannot find valid Intel C++ compiler.\n" - exit 1 - fi - fi - - if command -v mpiifort &> /dev/null; then - I_MPI_F90=${FC} - FC=$(command -v mpiifort) - fi - - if command -v mpiicc &> /dev/null; then - I_MPI_CC =${CC} - CC=$(command -v mpiicc) - fi - - if command -v mpiicpc &> /dev/null; then - I_MPI_CXX =${CXX} - CXX=$(command -v mpiicpc) - fi - - CPP=${CPP:-$HOMEBRE_PREFIX/bin/cpp-13} - ;; Linux) - FC=${FC:-$(command -v gfortran)} - CC=${CC:-$(command -v gcc)} - CXX=${CXX:-$(command -v g++)} - CPP=${CPP:-$(command -v cpp)} + FC=$(command -v gfortran) + CC=$(command -v gcc) + CXX=$(command -v g++) + CPP=$(command -v cpp) ;; MacOSX) - if [ $ARCH = "arm64" ]; then - if $(brew --version &> /dev/null); then - brew install llvm@16 libomp - else - echo \"Please install Homebrew first\" - exit 1 - fi - COMPILER_PREFIX=${COMPILER_PREFIX:-"${HOMEBREW_PREFIX}/opt/llvm"} - CC=${CC:-${COMPILER_PREFIX}/bin/clang} - CXX=${CXX:-${COMPILER_PREFIX}/bin/clang++} - CPP=${CPP:-${COMPILER_PREFIX}/bin/clang-cpp} - AR=${AR:-${COMPILER_PREFIX}/bin/llvm-ar} - NM=${NM:-${COMPILER_PREFIX}/bin/llvm-nm} - RANLIB=${RANLIB:-${COMPILER_PREFIX}/bin/llvm-ranlib} - FROOT=$(realpath $(dirname $(command -v gfortran))/..) - FC=$(command -v gfortran) - LD_LIBRARY_PATH="${COMPILER_PREFIX}/lib:${FROOT}/lib:${LD_LIBRARY_PATH}" - LDFLAGS="-L${HOMEBREW_PREFIX}/opt/llvm/lib/c++ -Wl,-rpath,${HOMEBREW_PREFIX}/opt/llvm/lib/c+ -L${HOMEBREW_PREFIX}/opt/libomp/lib -Wl,-no_compact_unwind" - CPPFLAGS="-isystem ${HOMEBREW_PREFIX}/opt/libomp/include" - LIBS="-lomp ${LIBS}" - CPATH="${FROOT}/include:${CPATH}" - CXXFLAGS="${CFLAGS} ${CXXFLAGS}" - FCFLAGS="${CFLAGS} ${FCFLAGS}" - CFLAGS="-mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET} -Wno-deprecated-non-prototype ${CFLAGS}" - else - if $(brew --version &> /dev/null); then - brew install gcc - else - echo \"Please install Homebrew first\" - exit 1 - fi - COMPILER_PREFIX=${COMPILER_PREFIX:-"${HOMEBREW_PREFIX}/Cellar/gcc/13.1.0/"} - CC=${CC:-${COMPILER_PREFIX}/bin/gcc-13} - CXX=${CXX:-${COMPILER_PREFIX}/bin/g++-13} - CPP=${CPP:-${COMPILER_PREFIX}/bin/cpp-13} - AR=${AR:-${COMPILER_PREFIX}/bin/gcc-ar-13} - NM=${NM:-${COMPILER_PREFIX}/bin/gcc-nm-13} - RANLIB=${RANLIB:-${COMPILER_PREFIX}/bin/gcc-ranlib-13} - FC=${FC:-${COMPILER_PREFIX}/bin/gfortran-13} - LD_LIBRARY_PATH="${COMPILER_PREFIX}/lib/gcc/13:${LD_LIBRARY_PATH}" - LDFLAGS="-L${HOMEBREW_PREFIX}/opt/llvm/lib/c++ -Wl,-rpath,${HOMEBREW_PREFIX}/opt/llvm/lib/c+ -Wl,-no_compact_unwind" - CPPFLAGS="-isystem ${HOMEBREW_PREFIX}/opt/libomp/include" - LIBS="-lgomp ${LIBS}" - CPATH="${FROOT}/include:${CPATH}" - CXXFLAGS="${CFLAGS} ${CXXFLAGS}" - FCFLAGS="${CFLAGS} ${FCFLAGS}" - CFLAGS="-mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET} -Wno-deprecated-non-prototype ${CFLAGS}" - fi + FC=${HOMEBREW_PREFIX}/bin/gfortran-12 + CFLAGS="-mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET} -Wno-deprecated-non-prototype -arch ${ARCH}" + FCFLAGS="-mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET} -arch ${ARCH}" + FFLAGS=$FCFLAGS + LD_LIBRARY_PATH="" + CPATH="" + COMPILER_PREFIX="/usr" + CC=${COMPILER_PREFIX}/bin/clang + CXX=${COMPILER_PREFIX}/bin/clang++ + CPP=${COMPILER_PREFIX}/bin/cpp + AR=${COMPILER_PREFIX}/bin/ar + NM=${COMPILER_PREFIX}/bin/nm + RANLIB=${COMPILER_PREFIX}/bin/ranlib + LDFLAGS="-Wl,-no_compact_unwind" ;; *) printf "Unknown compiler type: ${OS}\n" @@ -145,4 +58,6 @@ case $OS in exit 1 ;; esac -F77=${FC} \ No newline at end of file +F77=${FC} + +printf "Using ${OS} compilers:\nFC: ${FC}\nCC: ${CC}\nCXX: ${CXX}\n\n" \ No newline at end of file diff --git a/cmake/Modules/FindCython.cmake b/cmake/Modules/FindCython.cmake index c59f0307c..c8de13112 100644 --- a/cmake/Modules/FindCython.cmake +++ b/cmake/Modules/FindCython.cmake @@ -20,7 +20,6 @@ # #============================================================================= # Copyright 2011 Kitware, Inc. -# Modified 2023 by David A. Minton (daminton@purdue.edu) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -57,7 +56,7 @@ else() endif() if(CYTHON_EXECUTABLE) - set(CYTHON_version_command "${CYTHON_EXECUTABLE} --version") # Added quotes to prevent the string from having a ; inserted in the space + set(CYTHON_version_command ${CYTHON_EXECUTABLE} --version) execute_process(COMMAND ${CYTHON_version_command} OUTPUT_VARIABLE CYTHON_version_output diff --git a/cmake/Modules/FindNETCDF.cmake b/cmake/Modules/FindNETCDF.cmake index c93c81e75..05f91e77c 100644 --- a/cmake/Modules/FindNETCDF.cmake +++ b/cmake/Modules/FindNETCDF.cmake @@ -9,10 +9,13 @@ # - Finds the NetCDF libraries -IF (NOT CMAKE_SYSTEM_NAME STREQUAL "Windows") +SET(NFPREFIX_DIR ${CMAKE_SOURCE_DIR} CACHE PATH "Location of provided NetCDF-Fortran dependencies") +SET(NFINCLUDE_DIR "${NFPREFIX_DIR}/include" CACHE PATH "Location of provided netcdf.mod") +IF(NOT CMAKE_SYSTEM_NAME STREQUAL "Windows") FIND_PATH(NFBIN NAMES nf-config HINTS + NFPREFIX_DIR ENV NETCDF_FORTRAN_HOME ENV PATH PATH_SUFFIXES @@ -67,14 +70,22 @@ MESSAGE(STATUS "NetCDF-Fortran include directory: ${NETCDF_INCLUDE_DIR}") IF (BUILD_SHARED_LIBS) SET(NETCDFF "netcdff") - SET(NETCDF "netcdf") ELSE () + SET(NCPREFIX_DIR ${CMAKE_SOURCE_DIR} CACHE PATH "Location of provided NetCDF-C dependencies") + SET(H5PREFIX_DIR ${CMAKE_SOURCE_DIR} CACHE PATH "Location of provided HDF5 dependencies") + SET(ZPREFIX_DIR ${CMAKE_SOURCE_DIR} CACHE PATH "Location of provided zlib dependencies") IF (CMAKE_SYSTEM_NAME STREQUAL "Windows") SET(NETCDFF "netcdff.lib") SET(NETCDF "netcdf.lib") + SET(HDF5 "libhdf5.lib") + SET(HDF5_HL "libhdf5_hl.lib") + SET(ZLIB "zlibstatic.lib") ELSE () SET(NETCDFF "libnetcdff.a") SET(NETCDF "libnetcdf.a") + SET(HDF5 "libhdf5.a") + SET(HDF5_HL "libhdf5_hl.a") + SET(ZLIB "libz.a") ENDIF() ENDIF() @@ -99,6 +110,7 @@ ELSE () FIND_LIBRARY(NETCDF_LIBRARY NAMES ${NETCDF} HINTS + ${NCPREFIX_DIR} ENV NETCDF_HOME ENV LD_LIBRARY_PATH PATH_SUFFIXES @@ -108,7 +120,46 @@ ELSE () ) MESSAGE(STATUS "NetCDF-C Library: ${NETCDF_LIBRARY}") - IF (NOT CMAKE_SYSTEM_NAME STREQUAL "Windows") + IF (CMAKE_SYSTEM_NAME STREQUAL "Windows") + FIND_LIBRARY(HDF5_LIBRARY + NAMES ${HDF5} + HINTS + ${H5PREFIX_DIR} + ENV HDF5_ROOT + ENV LD_LIBRARY_PATH + PATH_SUFFIXES + lib + ${CMAKE_LIBRARY_ARCHITECTURE} + REQUIRED + ) + + FIND_LIBRARY(HDF5_HL_LIBRARY + NAMES ${HDF5_HL} + HINTS + ${H5PREFIX_DIR} + ENV HDF5_ROOT + ENV LD_LIBRARY_PATH + PATH_SUFFIXES + lib + ${CMAKE_LIBRARY_ARCHITECTURE} + REQUIRED + ) + + FIND_LIBRARY(Z_LIBRARY + NAMES ${ZLIB} + HINTS + ${ZPREFIX_DIR} + ENV ZLIB_ROOT + ENV LD_LIBRARY_PATH + PATH_SUFFIXES + lib + ${CMAKE_LIBRARY_ARCHITECTURE} + REQUIRED + ) + + LIST(APPEND EXTRA_FLAGS ${HDF5_LIBRARY} ${HDF5_HL_LIBRARY} ${Z_LIBRARY}) + + ELSE () FIND_PATH(NCBIN NAMES nc-config HINTS @@ -143,13 +194,14 @@ ELSE () IF (DEFINED ENV{LIBS}) STRING(STRIP "$ENV{LIBS}" LIBS) - SEPARATE_ARGUMENTS(LIBS NATIVE_COMMAND "$LIBS") + SEPARATE_ARGUMENTS(LIBS NATIVE_COMMAND "${LIBS}") LIST(APPEND EXTRA_FLAGS ${LIBS}) ENDIF() # Note for posterity: When building static libraries, NETCDF_FORTRAN_LIBRARY must come *before* NETCDF_LIBRARY. Otherwise you get a bunch of "undefined reference to" errors SET(NETCDF_LIBRARIES ${NETCDF_FORTRAN_LIBRARY} ${NETCDF_LIBRARY} ${EXTRA_FLAGS} CACHE STRING "NetCDF Fortran and dependant static libraries") ENDIF () +MESSAGE(STATUS "NetCDF dependencies: ${NETCDF_LIBRARIES}") SET(NETCDF_FOUND TRUE) MARK_AS_ADVANCED(NETCDF_LIBRARIES NETCDF_INCLUDE_DIR) \ No newline at end of file diff --git a/cmake/Modules/FindPythonExtensions.cmake b/cmake/Modules/FindPythonExtensions.cmake new file mode 100644 index 000000000..59b30c2a2 --- /dev/null +++ b/cmake/Modules/FindPythonExtensions.cmake @@ -0,0 +1,597 @@ +#.rst: +# +# This module defines CMake functions to build Python extension modules and +# stand-alone executables. +# +# The following variables are defined: +# :: +# +# PYTHON_PREFIX - absolute path to the current Python +# distribution's prefix +# PYTHON_SITE_PACKAGES_DIR - absolute path to the current Python +# distribution's site-packages directory +# PYTHON_RELATIVE_SITE_PACKAGES_DIR - path to the current Python +# distribution's site-packages directory +# relative to its prefix +# PYTHON_SEPARATOR - separator string for file path +# components. Equivalent to ``os.sep`` in +# Python. +# PYTHON_PATH_SEPARATOR - separator string for PATH-style +# environment variables. Equivalent to +# ``os.pathsep`` in Python. +# PYTHON_EXTENSION_MODULE_SUFFIX - suffix of the compiled module. For example, on +# Linux, based on environment, it could be ``.cpython-35m-x86_64-linux-gnu.so``. +# +# +# +# The following functions are defined: +# +# .. cmake:command:: python_extension_module +# +# For libraries meant to be used as Python extension modules, either dynamically +# loaded or directly linked. Amend the configuration of the library target +# (created using ``add_library``) with additional options needed to build and +# use the referenced library as a Python extension module. +# +# python_extension_module( +# [LINKED_MODULES_VAR ] +# [FORWARD_DECL_MODULES_VAR ] +# [MODULE_SUFFIX ]) +# +# Only extension modules that are configured to be built as MODULE libraries can +# be runtime-loaded through the standard Python import mechanism. All other +# modules can only be included in standalone applications that are written to +# expect their presence. In addition to being linked against the libraries for +# these modules, such applications must forward declare their entry points and +# initialize them prior to use. To generate these forward declarations and +# initializations, see ``python_modules_header``. +# +# If ```` does not refer to a target, then it is assumed to refer to an +# extension module that is not linked at all, but compiled along with other +# source files directly into an executable. Adding these modules does not cause +# any library configuration modifications, and they are not added to the list of +# linked modules. They still must be forward declared and initialized, however, +# and so are added to the forward declared modules list. +# +# If the associated target is of type ``MODULE_LIBRARY``, the LINK_FLAGS target +# property is used to set symbol visibility and export only the module init function. +# This applies to GNU and MSVC compilers. +# +# Options: +# +# ``LINKED_MODULES_VAR `` +# Name of the variable referencing a list of extension modules whose libraries +# must be linked into the executables of any stand-alone applications that use +# them. By default, the global property ``PY_LINKED_MODULES_LIST`` is used. +# +# ``FORWARD_DECL_MODULES_VAR `` +# Name of the variable referencing a list of extension modules whose entry +# points must be forward declared and called by any stand-alone applications +# that use them. By default, the global property +# ``PY_FORWARD_DECL_MODULES_LIST`` is used. +# +# ``MODULE_SUFFIX `` +# Suffix appended to the python extension module file. +# The default suffix is retrieved using ``sysconfig.get_config_var("SO")"``, +# if not available, the default is then ``.so`` on unix and ``.pyd`` on +# windows. +# Setting the variable ``PYTHON_EXTENSION_MODULE_SUFFIX`` in the caller +# scope defines the value used for all extensions not having a suffix +# explicitly specified using ``MODULE_SUFFIX`` parameter. +# +# +# .. cmake:command:: python_standalone_executable +# +# python_standalone_executable() +# +# For standalone executables that initialize their own Python runtime +# (such as when building source files that include one generated by Cython with +# the --embed option). Amend the configuration of the executable target +# (created using ``add_executable``) with additional options needed to properly +# build the referenced executable. +# +# +# .. cmake:command:: python_modules_header +# +# Generate a header file that contains the forward declarations and +# initialization routines for the given list of Python extension modules. +# ```` is the logical name for the header file (no file extensions). +# ```` is the actual destination filename for the header file +# (e.g.: decl_modules.h). +# +# python_modules_header( [HeaderFilename] +# [FORWARD_DECL_MODULES_LIST ] +# [HEADER_OUTPUT_VAR ] +# [INCLUDE_DIR_OUTPUT_VAR ]) +# +# without the extension is used as the logical name. If only ```` is +# +# If only ```` is provided, and it ends in the ".h" extension, then it +# is assumed to be the ````. The filename of the header file +# provided, and it does not end in the ".h" extension, then the +# ```` is assumed to ``.h``. +# +# The exact contents of the generated header file depend on the logical +# ````. It should be set to a value that corresponds to the target +# application, or for the case of multiple applications, some identifier that +# conveyes its purpose. It is featured in the generated multiple inclusion +# guard as well as the names of the generated initialization routines. +# +# The generated header file includes forward declarations for all listed +# modules, as well as implementations for the following class of routines: +# +# ``int _(void)`` +# Initializes the python extension module, ````. Returns an integer +# handle to the module. +# +# ``void _LoadAllPythonModules(void)`` +# Initializes all listed python extension modules. +# +# ``void CMakeLoadAllPythonModules(void);`` +# Alias for ``_LoadAllPythonModules`` whose name does not depend on +# ````. This function is excluded during preprocessing if the +# preprocessing macro ``EXCLUDE_LOAD_ALL_FUNCTION`` is defined. +# +# ``void Py_Initialize_Wrapper();`` +# Wrapper arpund ``Py_Initialize()`` that initializes all listed python +# extension modules. This function is excluded during preprocessing if the +# preprocessing macro ``EXCLUDE_PY_INIT_WRAPPER`` is defined. If this +# function is generated, then ``Py_Initialize()`` is redefined to a macro +# that calls this function. +# +# Options: +# +# ``FORWARD_DECL_MODULES_LIST `` +# List of extension modules for which to generate forward declarations of +# their entry points and their initializations. By default, the global +# property ``PY_FORWARD_DECL_MODULES_LIST`` is used. +# +# ``HEADER_OUTPUT_VAR `` +# Name of the variable to set to the path to the generated header file. By +# default, ```` is used. +# +# ``INCLUDE_DIR_OUTPUT_VAR `` +# Name of the variable to set to the path to the directory containing the +# generated header file. By default, ``_INCLUDE_DIRS`` is used. +# +# Defined variables: +# +# ```` +# The path to the generated header file +# +# ```` +# Directory containing the generated header file +# +# +# Example usage +# ^^^^^^^^^^^^^ +# +# .. code-block:: cmake +# +# find_package(PythonExtensions) +# find_package(Cython) +# find_package(Boost COMPONENTS python) +# +# # Simple Cython Module -- no executables +# add_cython_target(_module.pyx) +# add_library(_module MODULE ${_module}) +# python_extension_module(_module) +# +# # Mix of Cython-generated code and C++ code using Boost Python +# # Stand-alone executable -- no modules +# include_directories(${Boost_INCLUDE_DIRS}) +# add_cython_target(main.pyx CXX EMBED_MAIN) +# add_executable(main boost_python_module.cxx ${main}) +# target_link_libraries(main ${Boost_LIBRARIES}) +# python_standalone_executable(main) +# +# # stand-alone executable with three extension modules: +# # one statically linked, one dynamically linked, and one loaded at runtime +# # +# # Freely mixes Cython-generated code, code using Boost-Python, and +# # hand-written code using the CPython API. +# +# # module1 -- statically linked +# add_cython_target(module1.pyx) +# add_library(module1 STATIC ${module1}) +# python_extension_module(module1 +# LINKED_MODULES_VAR linked_module_list +# FORWARD_DECL_MODULES_VAR fdecl_module_list) +# +# # module2 -- dynamically linked +# include_directories(${Boost_INCLUDE_DIRS}) +# add_library(module2 SHARED boost_module2.cxx) +# target_link_libraries(module2 ${Boost_LIBRARIES}) +# python_extension_module(module2 +# LINKED_MODULES_VAR linked_module_list +# FORWARD_DECL_MODULES_VAR fdecl_module_list) +# +# # module3 -- loaded at runtime +# add_cython_target(module3a.pyx) +# add_library(module3 MODULE ${module3a} module3b.cxx) +# target_link_libraries(module3 ${Boost_LIBRARIES}) +# python_extension_module(module3 +# LINKED_MODULES_VAR linked_module_list +# FORWARD_DECL_MODULES_VAR fdecl_module_list) +# +# # application executable -- generated header file + other source files +# python_modules_header(modules +# FORWARD_DECL_MODULES_LIST ${fdecl_module_list}) +# include_directories(${modules_INCLUDE_DIRS}) +# +# add_cython_target(mainA) +# add_cython_target(mainC) +# add_executable(main ${mainA} mainB.cxx ${mainC} mainD.c) +# +# target_link_libraries(main ${linked_module_list} ${Boost_LIBRARIES}) +# python_standalone_executable(main) +# +#============================================================================= +# Copyright 2011 Kitware, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#============================================================================= + +find_package(PythonInterp REQUIRED) +if(SKBUILD AND NOT PYTHON_LIBRARY) + set(PYTHON_LIBRARY "no-library-required") + find_package(PythonLibs) + unset(PYTHON_LIBRARY) + unset(PYTHON_LIBRARIES) +else() + find_package(PythonLibs) +endif() +include(targetLinkLibrariesWithDynamicLookup) + +set(_command " +import distutils.sysconfig +import itertools +import os +import os.path +import site +import sys + +result = None +rel_result = None +candidate_lists = [] + +try: + candidate_lists.append((distutils.sysconfig.get_python_lib(),)) +except AttributeError: pass + +try: + candidate_lists.append(site.getsitepackages()) +except AttributeError: pass + +try: + candidate_lists.append((site.getusersitepackages(),)) +except AttributeError: pass + +candidates = itertools.chain.from_iterable(candidate_lists) + +for candidate in candidates: + rel_candidate = os.path.relpath( + candidate, sys.prefix) + if not rel_candidate.startswith(\"..\"): + result = candidate + rel_result = rel_candidate + break + +sys.stdout.write(\";\".join(( + os.sep, + os.pathsep, + sys.prefix, + result, + rel_result, + distutils.sysconfig.get_config_var('EXT_SUFFIX') +))) +") + +execute_process(COMMAND "${PYTHON_EXECUTABLE}" -c "${_command}" + OUTPUT_VARIABLE _list + RESULT_VARIABLE _result) + +list(GET _list 0 _item) +set(PYTHON_SEPARATOR "${_item}") +mark_as_advanced(PYTHON_SEPARATOR) + +list(GET _list 1 _item) +set(PYTHON_PATH_SEPARATOR "${_item}") +mark_as_advanced(PYTHON_PATH_SEPARATOR) + +list(GET _list 2 _item) +set(PYTHON_PREFIX "${_item}") +mark_as_advanced(PYTHON_PREFIX) + +list(GET _list 3 _item) +set(PYTHON_SITE_PACKAGES_DIR "${_item}") +mark_as_advanced(PYTHON_SITE_PACKAGES_DIR) + +list(GET _list 4 _item) +set(PYTHON_RELATIVE_SITE_PACKAGES_DIR "${_item}") +mark_as_advanced(PYTHON_RELATIVE_SITE_PACKAGES_DIR) + +if(NOT DEFINED PYTHON_EXTENSION_MODULE_SUFFIX) + list(GET _list 5 _item) + set(PYTHON_EXTENSION_MODULE_SUFFIX "${_item}") +endif() + +function(_set_python_extension_symbol_visibility _target) + if(PYTHON_VERSION_MAJOR VERSION_GREATER 2) + set(_modinit_prefix "PyInit_") + else() + set(_modinit_prefix "init") + endif() + message("_modinit_prefix:${_modinit_prefix}") + if("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC") + set_target_properties(${_target} PROPERTIES LINK_FLAGS + "/EXPORT:${_modinit_prefix}${_target}" + ) + elseif("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + # Option to not run version script. See https://github.com/scikit-build/scikit-build/issues/668 + if(NOT DEFINED SKBUILD_GNU_SKIP_LOCAL_SYMBOL_EXPORT_OVERRIDE) + set(SKBUILD_GNU_SKIP_LOCAL_SYMBOL_EXPORT_OVERRIDE FALSE) + endif() + set(_script_path + ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${_target}-version-script.map + ) + # Export all symbols. See https://github.com/scikit-build/scikit-build/issues/668 + if(SKBUILD_GNU_SKIP_LOCAL_SYMBOL_EXPORT_OVERRIDE) + file(WRITE ${_script_path} + "{global: ${_modinit_prefix}${_target};};" + ) + else() + file(WRITE ${_script_path} + "{global: ${_modinit_prefix}${_target}; local: *;};" + ) + endif() + if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "SunOS") + set_property(TARGET ${_target} APPEND_STRING PROPERTY LINK_FLAGS + " -Wl,--version-script=\"${_script_path}\"" + ) + else() + set_property(TARGET ${_target} APPEND_STRING PROPERTY LINK_FLAGS + " -Wl,-M \"${_script_path}\"" + ) + endif() + endif() +endfunction() + +function(python_extension_module _target) + set(one_ops LINKED_MODULES_VAR FORWARD_DECL_MODULES_VAR MODULE_SUFFIX) + cmake_parse_arguments(_args "" "${one_ops}" "" ${ARGN}) + + set(_lib_type "NA") + if(TARGET ${_target}) + get_property(_lib_type TARGET ${_target} PROPERTY TYPE) + endif() + + set(_is_non_lib TRUE) + + set(_is_static_lib FALSE) + if(_lib_type STREQUAL "STATIC_LIBRARY") + set(_is_static_lib TRUE) + set(_is_non_lib FALSE) + endif() + + set(_is_shared_lib FALSE) + if(_lib_type STREQUAL "SHARED_LIBRARY") + set(_is_shared_lib TRUE) + set(_is_non_lib FALSE) + endif() + + set(_is_module_lib FALSE) + if(_lib_type STREQUAL "MODULE_LIBRARY") + set(_is_module_lib TRUE) + set(_is_non_lib FALSE) + endif() + + if(_is_static_lib OR _is_shared_lib OR _is_non_lib) + + if(_is_static_lib OR _is_shared_lib) + if(_args_LINKED_MODULES_VAR) + set(${_args_LINKED_MODULES_VAR} + ${${_args_LINKED_MODULES_VAR}} ${_target} PARENT_SCOPE) + else() + set_property(GLOBAL APPEND PROPERTY PY_LINKED_MODULES_LIST ${_target}) + endif() + endif() + + if(_args_FORWARD_DECL_MODULES_VAR) + set(${_args_FORWARD_DECL_MODULES_VAR} + ${${_args_FORWARD_DECL_MODULES_VAR}} ${_target} PARENT_SCOPE) + else() + set_property(GLOBAL APPEND PROPERTY + PY_FORWARD_DECL_MODULES_LIST ${_target}) + endif() + endif() + + if(NOT _is_non_lib) + include_directories("${PYTHON_INCLUDE_DIRS}") + endif() + + if(_is_module_lib) + set_target_properties(${_target} PROPERTIES + PREFIX "${PYTHON_MODULE_PREFIX}") + endif() + + if(_is_module_lib OR _is_shared_lib) + if(_is_module_lib) + + if(NOT _args_MODULE_SUFFIX) + set(_args_MODULE_SUFFIX "${PYTHON_EXTENSION_MODULE_SUFFIX}") + endif() + + if(_args_MODULE_SUFFIX STREQUAL "" AND WIN32 AND NOT CYGWIN) + set(_args_MODULE_SUFFIX ".pyd") + endif() + + if(NOT _args_MODULE_SUFFIX STREQUAL "") + set_target_properties(${_target} + PROPERTIES SUFFIX ${_args_MODULE_SUFFIX}) + endif() + endif() + + target_link_libraries_with_dynamic_lookup(${_target} ${PYTHON_LIBRARIES}) + + if(_is_module_lib) + _set_python_extension_symbol_visibility(${_target}) + endif() + endif() +endfunction() + +function(python_standalone_executable _target) + include_directories(${PYTHON_INCLUDE_DIRS}) + target_link_libraries(${_target} ${SKBUILD_LINK_LIBRARIES_KEYWORD} ${PYTHON_LIBRARIES}) +endfunction() + +function(python_modules_header _name) + set(one_ops FORWARD_DECL_MODULES_LIST + HEADER_OUTPUT_VAR + INCLUDE_DIR_OUTPUT_VAR) + cmake_parse_arguments(_args "" "${one_ops}" "" ${ARGN}) + + list(GET _args_UNPARSED_ARGUMENTS 0 _arg0) + # if present, use arg0 as the input file path + if(_arg0) + set(_source_file ${_arg0}) + + # otherwise, must determine source file from name, or vice versa + else() + get_filename_component(_name_ext "${_name}" EXT) + + # if extension provided, _name is the source file + if(_name_ext) + set(_source_file ${_name}) + get_filename_component(_name "${_source_file}" NAME_WE) + + # otherwise, assume the source file is ${_name}.h + else() + set(_source_file ${_name}.h) + endif() + endif() + + if(_args_FORWARD_DECL_MODULES_LIST) + set(static_mod_list ${_args_FORWARD_DECL_MODULES_LIST}) + else() + get_property(static_mod_list GLOBAL PROPERTY PY_FORWARD_DECL_MODULES_LIST) + endif() + + string(REPLACE "." "_" _header_name "${_name}") + string(TOUPPER ${_header_name} _header_name_upper) + set(_header_name_upper "_${_header_name_upper}_H") + set(generated_file ${CMAKE_CURRENT_BINARY_DIR}/${_source_file}) + + set(generated_file_tmp "${generated_file}.in") + file(WRITE ${generated_file_tmp} + "/* Created by CMake. DO NOT EDIT; changes will be lost. */\n") + + set(_chunk "") + set(_chunk "${_chunk}#ifndef ${_header_name_upper}\n") + set(_chunk "${_chunk}#define ${_header_name_upper}\n") + set(_chunk "${_chunk}\n") + set(_chunk "${_chunk}#include \n") + set(_chunk "${_chunk}\n") + set(_chunk "${_chunk}#ifdef __cplusplus\n") + set(_chunk "${_chunk}extern \"C\" {\n") + set(_chunk "${_chunk}#endif /* __cplusplus */\n") + set(_chunk "${_chunk}\n") + set(_chunk "${_chunk}#if PY_MAJOR_VERSION < 3\n") + file(APPEND ${generated_file_tmp} "${_chunk}") + + foreach(_module ${static_mod_list}) + file(APPEND ${generated_file_tmp} + "PyMODINIT_FUNC init${PYTHON_MODULE_PREFIX}${_module}(void);\n") + endforeach() + + file(APPEND ${generated_file_tmp} "#else /* PY_MAJOR_VERSION >= 3*/\n") + + foreach(_module ${static_mod_list}) + file(APPEND ${generated_file_tmp} + "PyMODINIT_FUNC PyInit_${PYTHON_MODULE_PREFIX}${_module}(void);\n") + endforeach() + + set(_chunk "") + set(_chunk "${_chunk}#endif /* PY_MAJOR_VERSION >= 3*/\n\n") + set(_chunk "${_chunk}#ifdef __cplusplus\n") + set(_chunk "${_chunk}}\n") + set(_chunk "${_chunk}#endif /* __cplusplus */\n") + set(_chunk "${_chunk}\n") + file(APPEND ${generated_file_tmp} "${_chunk}") + + foreach(_module ${static_mod_list}) + set(_import_function "${_header_name}_${_module}") + set(_prefixed_module "${PYTHON_MODULE_PREFIX}${_module}") + + set(_chunk "") + set(_chunk "${_chunk}int ${_import_function}(void)\n") + set(_chunk "${_chunk}{\n") + set(_chunk "${_chunk} static char name[] = \"${_prefixed_module}\";\n") + set(_chunk "${_chunk} #if PY_MAJOR_VERSION < 3\n") + set(_chunk "${_chunk} return PyImport_AppendInittab(") + set(_chunk "${_chunk}name, init${_prefixed_module});\n") + set(_chunk "${_chunk} #else /* PY_MAJOR_VERSION >= 3 */\n") + set(_chunk "${_chunk} return PyImport_AppendInittab(") + set(_chunk "${_chunk}name, PyInit_${_prefixed_module});\n") + set(_chunk "${_chunk} #endif /* PY_MAJOR_VERSION >= 3 */\n") + set(_chunk "${_chunk}}\n\n") + file(APPEND ${generated_file_tmp} "${_chunk}") + endforeach() + + file(APPEND ${generated_file_tmp} + "void ${_header_name}_LoadAllPythonModules(void)\n{\n") + foreach(_module ${static_mod_list}) + file(APPEND ${generated_file_tmp} " ${_header_name}_${_module}();\n") + endforeach() + file(APPEND ${generated_file_tmp} "}\n\n") + + set(_chunk "") + set(_chunk "${_chunk}#ifndef EXCLUDE_LOAD_ALL_FUNCTION\n") + set(_chunk "${_chunk}void CMakeLoadAllPythonModules(void)\n") + set(_chunk "${_chunk}{\n") + set(_chunk "${_chunk} ${_header_name}_LoadAllPythonModules();\n") + set(_chunk "${_chunk}}\n") + set(_chunk "${_chunk}#endif /* !EXCLUDE_LOAD_ALL_FUNCTION */\n\n") + + set(_chunk "${_chunk}#ifndef EXCLUDE_PY_INIT_WRAPPER\n") + set(_chunk "${_chunk}static void Py_Initialize_Wrapper()\n") + set(_chunk "${_chunk}{\n") + set(_chunk "${_chunk} ${_header_name}_LoadAllPythonModules();\n") + set(_chunk "${_chunk} Py_Initialize();\n") + set(_chunk "${_chunk}}\n") + set(_chunk "${_chunk}#define Py_Initialize Py_Initialize_Wrapper\n") + set(_chunk "${_chunk}#endif /* !EXCLUDE_PY_INIT_WRAPPER */\n\n") + + set(_chunk "${_chunk}#endif /* !${_header_name_upper} */\n") + file(APPEND ${generated_file_tmp} "${_chunk}") + + # with configure_file() cmake complains that you may not use a file created + # using file(WRITE) as input file for configure_file() + execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${generated_file_tmp}" "${generated_file}" + OUTPUT_QUIET ERROR_QUIET) + + set(_header_output_var ${_name}) + if(_args_HEADER_OUTPUT_VAR) + set(_header_output_var ${_args_HEADER_OUTPUT_VAR}) + endif() + set(${_header_output_var} ${generated_file} PARENT_SCOPE) + + set(_include_dir_var ${_name}_INCLUDE_DIRS) + if(_args_INCLUDE_DIR_OUTPUT_VAR) + set(_include_dir_var ${_args_INCLUDE_DIR_OUTPUT_VAR}) + endif() + set(${_include_dirs_var} ${CMAKE_CURRENT_BINARY_DIR} PARENT_SCOPE) +endfunction() + +include(UsePythonExtensions) diff --git a/cmake/Modules/SetCompileFlag.cmake b/cmake/Modules/SetCompileFlag.cmake index d094009ed..69e3526f8 100644 --- a/cmake/Modules/SetCompileFlag.cmake +++ b/cmake/Modules/SetCompileFlag.cmake @@ -71,7 +71,7 @@ FUNCTION(SET_COMPILE_FLAG FLAGVAR FLAGVAL LANG) # Now, loop over each flag FOREACH(flag ${FLAGLIST}) - + EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E echo_append "Checking compiler option ${flag}: ") UNSET(FLAG_WORKS) # Check the flag for the given language IF(LANG STREQUAL "C") @@ -105,11 +105,14 @@ end program dummyprog # If this worked, use these flags, otherwise use other flags IF(FLAG_WORKS) + EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E echo "OK") # Append this flag to the end of the list that already exists SET(${FLAGVAR} "${FLAGVAL} ${flag}" CACHE STRING "Set the ${FLAGVAR} flags" FORCE) SET(FLAG_FOUND TRUE) BREAK() # We found something that works, so exit + ELSE(FLAG_WORKS) + EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E echo "NO") ENDIF(FLAG_WORKS) ENDFOREACH(flag ${FLAGLIST}) diff --git a/cmake/Modules/SetFortranFlags.cmake b/cmake/Modules/SetFortranFlags.cmake index 5d319f5d4..c5514e749 100644 --- a/cmake/Modules/SetFortranFlags.cmake +++ b/cmake/Modules/SetFortranFlags.cmake @@ -63,311 +63,398 @@ ENDIF(CMAKE_Fortran_FLAGS_RELEASE AND CMAKE_Fortran_FLAGS_TESTING AND CMAKE_Fort # flag is given in the call). This way unknown compiles are supported. ####################################################################### +IF (CMAKE_SYSTEM_NAME STREQUAL "Windows") + SET(WINOPT True) +ELSE () + SET(WINOPT False) +ENDIF () ##################### ### GENERAL FLAGS ### ##################### + # Free form IF (COMPILER_OPTIONS STREQUAL "GNU") + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}" + Fortran "-ffree-form" # GNU + ) + + # Don't add underscores in symbols for C-compatability + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}" + Fortran "-fno-underscoring" # GNU + ) + # Compile code assuming that IEEE signaling NaNs may generate user-visible traps during floating-point operations. + # Setting this option disables optimizations that may change the number of exceptions visible with signaling NaNs. + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}" + Fortran "-fsignaling-nans " # GNU + ) + + # Allows for lines longer than 80 characters without truncation + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}" + Fortran "-ffree-line-length-512" # GNU (gfortran) + ) + + # Sets the dialect standard + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}" + Fortran "-std=f2018" + ) +ELSEIF (COMPILER_OPTIONS STREQUAL "Intel") + # Disables right margin wrapping in list-directed output + IF (WINOPT) SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}" - Fortran "-ffree-form" # GNU - ) - - # Don't add underscores in symbols for C-compatability - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}" - Fortran "-fno-underscoring" # GNU - ) - # Compile code assuming that IEEE signaling NaNs may generate user-visible traps during floating-point operations. - # Setting this option disables optimizations that may change the number of exceptions visible with signaling NaNs. + Fortran "/wrap-margin-" # Intel Windows + ) + # Aligns a variable to a specified boundary and offset SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}" - Fortran "-fsignaling-nans " # GNU - ) - - # Allows for lines longer than 80 characters without truncation + Fortran "/align:all /align:array64byte" # Intel + ) + # Enables changing the variable and array memory layout SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}" - Fortran "-ffree-line-length-512" # GNU (gfortran) - ) -ELSEIF (COMPILER_OPTIONS STREQUAL "Intel") - # Disables right margin wrapping in list-directed output + Fortran "/Qpad" # Intel Windows + ) + ELSE () SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}" - Fortran "-no-wrap-margin" # Intel - "/wrap-margin-" # Intel Windows - ) - + Fortran "-no-wrap-margin" # Intel + ) # Aligns a variable to a specified boundary and offset SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}" - Fortran "-align all -align array64byte" # Intel - "/align:all /align:array64byte" # Intel Windows - ) - + Fortran "-align all -align array64byte" # Intel + ) # Enables changing the variable and array memory layout SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}" - Fortran "-pad" # Intel - "/Qpad" # Intel Windows - ) + Fortran "-pad" # Intel Windows + ) + ENDIF () +ENDIF () + +IF (NOT BUILD_SHARED_LIBS AND NOT WINOPT) + SET_COMPILE_FLAG(CMAKE_FORTRAN_FLAGS "${CMAKE_FORTRAN_FLAGS}" + Fortran "-fPIC" + ) + + IF (COMPILER_OPTIONS STREQUAL "Intel") + # Use static Intel libraries + SET_COMPILE_FLAG(CMAKE_Fortran_LINK_FLAGS "${CMAKE_Fortran_LINK_FLAGS}" + Fortran "-static-intel" # Intel + ) + # Use static Intel MPI libraries + SET_COMPILE_FLAG(CMAKE_Fortran_LINK_FLAGS "${CMAKE_Fortran_LINK_FLAGS}" + Fortran "-static_mpi" # Intel + ) + + IF (USE_OPENMP) + SET_COMPILE_FLAG(CMAKE_Fortran_LINK_FLAGS "${CMAKE_Fortran_LINK_FLAGS}" + Fortran "-qopenmp-link=static" # Intel + ) + ENDIF (USE_OPENMP) + + ELSEIF (COMPILER_OPTIONS STREQUAL "GNU") + # # Set GNU static libraries + # SET_COMPILE_FLAG(CMAKE_Fortran_LINK_FLAGS "${CMAKE_Fortran_LINK_FLAGS}" + # Fortran "-static-libgfortran" + # ) + # SET_COMPILE_FLAG(CMAKE_Fortran_LINK_FLAGS "${CMAKE_Fortran_LINK_FLAGS}" + # Fortran "-static-libgcc" + # ) + # SET_COMPILE_FLAG(CMAKE_Fortran_LINK_FLAGS "${CMAKE_Fortran_LINK_FLAGS}" + # Fortran "-static-libstdc++" + # ) + # SET_COMPILE_FLAG(CMAKE_Fortran_LINK_FLAGS "${CMAKE_Fortran_LINK_FLAGS}" + # Fortran "-static-libquadmath" + # ) + IF (USE_OPENMP) + SET_COMPILE_FLAG(CMAKE_Fortran_LINK_FLAGS "${CMAKE_Fortran_LINK_FLAGS}" + Fortran "-lomp" + "-lgomp" + ) + ENDIF (USE_OPENMP) + ENDIF () ENDIF () -IF (NOT BUILD_SHARED_LIBS) - SET_COMPILE_FLAG(CMAKE_FORTRAN_FLAGS "${CMAKE_FORTRAN_FLAGS}" - Fortran "-fPIC" - ) +IF (USE_SIMD) + IF (COMPILER_OPTIONS STREQUAL "Intel") + SET(MACHINE_CODE_VALUE "Host" CACHE STRING "Tells the compiler which processor features it may target, including which instruction sets and optimizations it may generate.") + + IF (MACHINE_CODE_VALUE STREQUAL "generic") + SET(MACHINE_CODE_VALUE "SSE2" CACHE STRING "SSE2 is the safest option when compiling for non-host compatibility" FORCE) + ENDIF() - IF (COMPILER_OPTIONS STREQUAL "Intel") - # Use static Intel libraries - SET_COMPILE_FLAG(CMAKE_Fortran_LINK_FLAGS "${CMAKE_Fortran_LINK_FLAGS}" - Fortran "-static-intel" # Intel + # Enables OpenMP SIMD compilation when OpenMP parallelization is disabled. + IF (NOT USE_OPENMP) + IF (WINOPT) + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}" + Fortran "/Qopenmp- /Qopenmp-simd" # Intel ) - # Use static Intel MPI libraries - SET_COMPILE_FLAG(CMAKE_Fortran_LINK_FLAGS "${CMAKE_Fortran_LINK_FLAGS}" - Fortran "-static_mpi" # Intel + ELSE () + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}" + Fortran "-qno-openmp -qopenmp-simd>" # Intel ) + ENDIF () + ENDIF (NOT USE_OPENMP) - IF (USE_OPENMP) - SET_COMPILE_FLAG(CMAKE_Fortran_LINK_FLAGS "${CMAKE_Fortran_LINK_FLAGS}" - Fortran "-qopenmp-link=static" # Intel - ) - ENDIF (USE_OPENMP) - ELSEIF (COMPILER_OPTIONS STREQUAL "GNU") - # Set GNU static libraries - SET_COMPILE_FLAG(CMAKE_Fortran_LINK_FLAGS "${CMAKE_Fortran_LINK_FLAGS}" - Fortran "-static-libgfortran" + # Optimize for an old enough processor that it should run on most computers + IF (WINOPT) + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}" + Fortran "/Qx${MACHINE_CODE_VALUE}" # Intel ) - SET_COMPILE_FLAG(CMAKE_Fortran_LINK_FLAGS "${CMAKE_Fortran_LINK_FLAGS}" - Fortran "-static-libgcc" + # Generate an extended set of vector functions + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}" + Fortran "/Qvecabi:cmdtarget" # Intel Windows ) - SET_COMPILE_FLAG(CMAKE_Fortran_LINK_FLAGS "${CMAKE_Fortran_LINK_FLAGS}" - Fortran "-static-libstdc++" + ELSE () + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}" + Fortran "-x${MACHINE_CODE_VALUE}" # Intel ) - SET_COMPILE_FLAG(CMAKE_Fortran_LINK_FLAGS "${CMAKE_Fortran_LINK_FLAGS}" - Fortran "-static-libquadmath" + # Generate an extended set of vector functions + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}" + Fortran "-vecabi=cmdtarget" # Intel ) - IF (USE_OPENMP) - SET_COMPILE_FLAG(CMAKE_Fortran_LINK_FLAGS "${CMAKE_Fortran_LINK_FLAGS}" - Fortran "-lgomp" - ) - ENDIF (USE_OPENMP) ENDIF () -ENDIF (NOT BUILD_SHARED_LIBS) - -IF (USE_SIMD) - - IF (COMPILER_OPTIONS STREQUAL "Intel") - SET(MACHINE_CODE_VALUE "Host" CACHE STRING "Tells the compiler which processor features it may target, including which instruction sets and optimizations it may generate.") - - IF (MACHINE_CODE_VALUE STREQUAL "generic") - SET(MACHINE_CODE_VALUE "SSE2" CACHE STRING "SSE2 is the safest option when compiling for non-host compatibility" FORCE) - ENDIF() + ELSEIF (COMPILER_OPTIONS STREQUAL "GNU") + SET(MACHINE_CODE_VALUE "native" CACHE STRING "Tells the compiler which processor features it may target, including which instruction sets and optimizations it may generate.") - # Enables OpenMP SIMD compilation when OpenMP parallelization is disabled. - IF (NOT USE_OPENMP) - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}" - Fortran "-qno-openmp -qopenmp-simd" # Intel - Fortran "/Qopenmp- /Qopenmp-simd" # Intel Windows - ) - ENDIF (NOT USE_OPENMP) + # Enables OpenMP SIMD compilation when OpenMP parallelization is disabled. + IF (NOT USE_OPENMP) + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}" + Fortran "-fno-openmp -fopenmp-simd" # GNU + ) + ENDIF (NOT USE_OPENMP) - # Optimize for an old enough processor that it should run on most computers + IF (MACHINE_CODE_VALUE STREQUAL "Host") + SET(MACHINE_CODE_VALUE "native" CACHE STRING "native is the GNU equivalent of Host" FORCE) + ENDIF () + + IF (APPLE) SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}" - Fortran "-x${MACHINE_CODE_VALUE}" # Intel - "/Qx${MACHINE_CODE_VALUE}" # Intel Windows + Fortran "-mtune=${MACHINE_CODE_VALUE}" ) - - # Generate an extended set of vector functions + ELSE () SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}" - Fortran "-vecabi=cmdtarget" # Intel - "/Qvecabi:cmdtarget" # Intel Windows - ) - ELSEIF (COMPILER_OPTIONS STREQUAL "GNU") - SET(MACHINE_CODE_VALUE "native" CACHE STRING "Tells the compiler which processor features it may target, including which instruction sets and optimizations it may generate.") - - # Enables OpenMP SIMD compilation when OpenMP parallelization is disabled. - IF (NOT USE_OPENMP) - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}" - Fortran "-fno-openmp -fopenmp-simd" # GNU - ) - ENDIF (NOT USE_OPENMP) - - IF (MACHINE_CODE_VALUE STREQUAL "Host") - SET(MACHINE_CODE_VALUE "native" CACHE STRING "native is the GNU equivalent of Host" FORCE) - ENDIF () - - IF (APPLE) - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}" - Fortran "-mtune=${MACHINE_CODE_VALUE}" - ) - ELSE () - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}" - Fortran "-march=${MACHINE_CODE_VALUE}" - ) - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}" - Fortran "-mtune=${MACHINE_CODE_VALUE}" - ) - ENDIF () - + Fortran "-march=${MACHINE_CODE_VALUE}" + ) + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}" + Fortran "-mtune=${MACHINE_CODE_VALUE}" + ) ENDIF () - SET(MACHINE_CODE_VALUE ${MACHINE_CODE_VALUE} CACHE STRING "Tells the compiler which processor features it may target, including which instruction sets and optimizations it may generate.") -ENDIF (USE_SIMD) + + ENDIF () + SET(MACHINE_CODE_VALUE ${MACHINE_CODE_VALUE} CACHE STRING "Tells the compiler which processor features it may target, including which instruction sets and optimizations it may generate.") +ENDIF (USE_SIMD) ################### ### DEBUG FLAGS ### ################### IF (CMAKE_BUILD_TYPE STREQUAL "DEBUG" OR CMAKE_BUILD_TYPE STREQUAL "TESTING" ) - # Disable optimizations - IF (COMPILER_OPTIONS STREQUAL "Intel") - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" - Fortran REQUIRED "-O0" # All compilers not on Windows - "/Od" # Intel Windows - ) - - # Turn on all warnings - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" - Fortran "-warn all" # Intel - "/warn:all" # Intel Windows - ) - - # Tells the compiler to issue compile-time messages for nonstandard language elements (Fortran 2018). - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" - Fortran "-stand f18" # Intel - "/stand:f18" # Intel Windows - ) - - # Traceback - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" - Fortran "-traceback" # Intel Group - "/traceback" # Intel Windows - ) - - # Check everything - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" - Fortran "-check all" # Intel - "/check:all" # Intel Windows - ) - - # Initializes matrices/arrays with NaN values - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" - Fortran "-init=snan,arrays" # Intel - "/Qinit:snan,arrays" # Intel Windows - ) - - # Does not generate an interface block for each routine in a source file - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" - Fortran "-nogen-interfaces" # Intel - "/nogen-interfaces" # Intel Windows - ) - - # Does not generate aposition independent executable - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" - Fortran "-no-pie" # Intel - ) - - # Does not set denormal results from floating-point calculations to zero - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" - Fortran "-no-ftz" # Intel - "/Qftz-" # Intel Windows - ) - - # Enables floating-point invalid, divide-by-zero, and overflow exceptions - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" - Fortran "-fpe-all=0" # Intel - "/fpe-all:0" # Intel Windows - ) - - # Enables floating-point invalid, divide-by-zero, and overflow exceptions - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" - Fortran "-fpe0" # Intel - "/fpe:0" # Intel Windows - ) - - # Enables debug info - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" - Fortran "-debug all" # Intel - "/debug:all" # Intel Windows - ) - - # Disables additional interprocedural optimizations for a single file compilation - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" - Fortran "-no-ip" # Intel - "/Qip-" # Intel Windows - ) - - # Disables prefetch insertion optimization - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" - Fortran "-qno-opt-prefetch" # Intel - "/Qopt-prefetch-" # Intel Windows - ) - - ELSEIF (COMPILER_OPTIONS STREQUAL "GNU") - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" - Fortran REQUIRED "-Og" # GNU (gfortran) - ) - - # Turn on all warnings - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" - Fortran "-Wall" # GNU - ) - # This enables some extra warning flags that are not enabled by -Wall - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" - Fortran "-Wextra" # GNU - ) - - # Disable the warning that arrays may be uninitialized, which comes up due to a known bug in gfortran - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" - Fortran "-Wno-maybe-uninitialized" # GNU - ) - # Disable the warning about unused dummy arguments. These primarily occur due to interface rules for type-bound procedures used in extendable types. - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" - Fortran "-Wno-unused-dummy-argument" # GNU - ) - - # Tells the compiler to issue compile-time messages for nonstandard language elements (Fortran 2018). - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" - Fortran "-fstd=f2018" # GNU - ) - - # Traceback - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" - Fortran "-fbacktrace" # GNU (gfortran) - ) - - # Sanitize - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" - Fortran "-fsanitize=address, undefined" # Gnu - ) - - # Check everything - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" - Fortran "-fcheck=all" # GNU - ) - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" - Fortran "-fstack-check" # GNU - ) - - # Initializes matrices/arrays with NaN values - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" - Fortran "-finit-real=snan" # GNU - ) - - # Generates non position-independent code - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" - Fortran "-fno-PIE" # GNU - ) - - # Enables floating-point invalid, divide-by-zero, and overflow exceptions - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" - Fortran "-ffpe-trap=zero,overflow,underflow" # GNU - ) - - # List of floating-point exceptions, whose flag status is printed to ERROR_UNIT when invoking STOP and ERROR STOP - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" - Fortran "-ffpe-summary=all" # GNU - ) + # Disable optimizations + IF (COMPILER_OPTIONS STREQUAL "Intel") + IF (WINOPT) + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran REQUIRED "/Od" # Intel Windows + ) + + # Turn on all warnings + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "/warn:all" # Intel Windows + ) + + # Tells the compiler to issue compile-time messages for nonstandard language elements (Fortran 2018). + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "/stand:f18" # Intel Windows + ) + + # Traceback + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "/traceback" # Intel Windows + ) + + # Check everything + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "/check:all" # Intel Windows + ) + + # Initializes matrices/arrays with NaN values + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "/Qinit:snan,arrays" # Intel Windows + ) + + # Does not generate an interface block for each routine in a source file + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "/nogen-interfaces" # Intel Windows + ) + + # Does not set denormal results from floating-point calculations to zero + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "/Qftz-" # Intel Windows + ) + + # Enables floating-point invalid, divide-by-zero, and overflow exceptions + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "/fpe-all:0" # Intel Windows + ) + + # Enables floating-point invalid, divide-by-zero, and overflow exceptions + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "/fpe:0" # Intel Windows + ) + + # Enables debug info + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "/debug:all" # Intel Windows + ) + + # Disables additional interprocedural optimizations for a single file compilation + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "/Qip-" # Intel Windows + ) + + # Disables prefetch insertion optimization + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "/Qopt-prefetch-" # Intel Windows + ) + ELSE () + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran REQUIRED "-O0" # All compilers not on Windows + ) + + # Turn on all warnings + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "-warn all" # Intel + ) + + # Tells the compiler to issue compile-time messages for nonstandard language elements (Fortran 2018). + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "-stand f18" # Intel + ) + + # Traceback + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "-traceback" # Intel Group + ) + + # Check everything + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "-check all" # Intel + ) + + # Initializes matrices/arrays with NaN values + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "-init=snan,arrays" # Intel + ) + + # Does not generate an interface block for each routine in a source file + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "-nogen-interfaces" # Intel + ) + + # Does not generate aposition independent executable + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "-no-pie" # Intel + ) + + # Does not set denormal results from floating-point calculations to zero + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "-no-ftz" # Intel + ) + + # Enables floating-point invalid, divide-by-zero, and overflow exceptions + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "-fpe-all=0" # Intel + ) + + # Enables floating-point invalid, divide-by-zero, and overflow exceptions + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "-fpe0" # Intel + ) + + # Enables debug info + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "-debug all" # Intel + ) + + # Disables additional interprocedural optimizations for a single file compilation + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "-no-ip" # Intel + ) + + # Disables prefetch insertion optimization + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "-qno-opt-prefetch" # Intel + ) - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" - Fortran "-fstack-check" # GNU - ) ENDIF () + + ELSEIF (COMPILER_OPTIONS STREQUAL "GNU") + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran REQUIRED "-Og" # GNU (gfortran) + ) + + # Turn on all warnings + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "-Wall" # GNU + ) + # This enables some extra warning flags that are not enabled by -Wall + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "-Wextra" # GNU + ) + + # Disable the warning that arrays may be uninitialized, which comes up due to a known bug in gfortran + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "-Wno-maybe-uninitialized" # GNU + ) + # Disable the warning about unused dummy arguments. These primarily occur due to interface rules for type-bound procedures used in extendable types. + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "-Wno-unused-dummy-argument" # GNU + ) + + # Tells the compiler to issue compile-time messages for nonstandard language elements (Fortran 2018). + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "-fstd=f2018" # GNU + ) + + # Traceback + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "-fbacktrace" # GNU (gfortran) + ) + + # Sanitize + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "-fsanitize=address, undefined" # Gnu + ) + + # Check everything + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "-fcheck=all" # GNU + ) + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "-fstack-check" # GNU + ) + + # Initializes matrices/arrays with NaN values + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "-finit-real=snan" # GNU + ) + + # Generates non position-independent code + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "-fno-PIE" # GNU + ) + + # Enables floating-point invalid, divide-by-zero, and overflow exceptions + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "-ffpe-trap=zero,overflow,underflow" # GNU + ) + + # List of floating-point exceptions, whose flag status is printed to ERROR_UNIT when invoking STOP and ERROR STOP + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "-ffpe-summary=all" # GNU + ) + + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" + Fortran "-fstack-check" # GNU + ) + ENDIF () ENDIF () @@ -377,11 +464,16 @@ ENDIF () IF (CMAKE_BUILD_TYPE STREQUAL "TESTING" ) - # Optimizations + # Optimizations + IF (WINOPT) SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_TESTING "${CMAKE_Fortran_FLAGS_DEBUG}" - Fortran REQUIRED "-O3" # All compilers not on Windows - "/O3" # Intel Windows - ) + REQUIRED "/O3" # Intel Windows + ) + ELSE () + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_TESTING "${CMAKE_Fortran_FLAGS_DEBUG}" + REQUIRED "-O3" # All compilers not on Windows + ) + ENDIF () ENDIF () ##################### @@ -392,69 +484,102 @@ ENDIF () IF (CMAKE_BUILD_TYPE STREQUAL "RELEASE" OR CMAKE_BUILD_TYPE STREQUAL "PROFILE") - IF (COMPILER_OPTIONS STREQUAL "Intel") - # Unroll loops - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" - Fortran "-unroll" # Intel - "/unroll" # Intel Windows - - ) - - # Inline functions - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" - Fortran "-inline" # Intel - "/Qinline" # Intel Windows - ) - - # Calls the Matrix Multiply library - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" - Fortran "-qopt-matmul" # Intel - "/Qopt-matmul" # Intel Windows - ) - - # Aligns a variable to a specified boundary and offset - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" - Fortran "-align all" # Intel - "/align:all" # Intel Windows - ) - - # No floating-point exceptions - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" - Fortran "-fp-model no-except" # Intel - "/fp:no-except" # Intel Windows - ) - - # Generate fused multiply-add instructions - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" - Fortran "-fma" # Intel - "/Qfma" # Intel Windows - ) - - # Tells the compiler to link to certain libraries in the Intel oneAPI Math Kernel Library (oneMKL). - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" - Fortran "-qmkl=cluster" # Intel - "-qmkl" # Intel - "/Qmkl:cluster" # Intel Windows - "/Qmkl" # Intel Windows - ) - - # Enables additional interprocedural optimizations for a single file compilation - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" - Fortran "-ip" # Intel - "/Qip" # Intel Windows - ) - - ELSEIF(COMPILER_OPTIONS STREQUAL "GNU") - # Unroll loops - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" - Fortran "-funroll-loops" # GNU - ) - - # Inline functions - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" - Fortran "-finline-functions" # GNU - ) - ENDIF () + IF (COMPILER_OPTIONS STREQUAL "Intel") + IF (WINOPT) + # Unroll loops + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" + Fortran "/unroll" # Intel Windows + ) + + # Inline functions + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" + Fortran "/Qinline" # Intel Windows + ) + + # Calls the Matrix Multiply library + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" + Fortran "/Qopt-matmul" # Intel Windows + ) + + # Aligns a variable to a specified boundary and offset + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" + Fortran "/align:all" # Intel Windows + ) + + # No floating-point exceptions + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" + Fortran "/fp:no-except" # Intel Windows + ) + + # Generate fused multiply-add instructions + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" + Fortran "/Qfma" # Intel Windows + ) + + # Tells the compiler to link to certain libraries in the Intel oneAPI Math Kernel Library (oneMKL). + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" + Fortran "/Qmkl:cluster" # Intel Windows + "/Qmkl" # Intel Windows + ) + + # Enables additional interprocedural optimizations for a single file compilation + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" + Fortran "/Qip" # Intel Windows + ) + ELSE () + # Unroll loops + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" + Fortran "-unroll" # Intel + ) + + # Inline functions + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" + Fortran "-inline" # Intel + ) + + # Calls the Matrix Multiply library + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" + Fortran "-qopt-matmul" # Intel + ) + + # Aligns a variable to a specified boundary and offset + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" + Fortran "-align all" # Intel + ) + + # No floating-point exceptions + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" + Fortran "-fp-model no-except" # Intel + ) + + # Generate fused multiply-add instructions + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" + Fortran "-fma" # Intel + ) + + # Tells the compiler to link to certain libraries in the Intel oneAPI Math Kernel Library (oneMKL). + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" + Fortran "-qmkl=cluster" # Intel + "-qmkl" # Intel + ) + + # Enables additional interprocedural optimizations for a single file compilation + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" + Fortran "-ip" # Intel + ) + ENDIF () + + ELSEIF(COMPILER_OPTIONS STREQUAL "GNU") + # Unroll loops + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" + Fortran "-funroll-loops" # GNU + ) + + # Inline functions + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" + Fortran "-finline-functions" # GNU + ) + ENDIF () ENDIF () @@ -463,60 +588,83 @@ ENDIF () ##################### IF (COMPILER_OPTIONS STREQUAL "Intel") + IF (WINOPT) # Some subroutines require more strict floating point operation optimizations for repeatability SET_COMPILE_FLAG(STRICTMATH_FLAGS "${STRICTMATH_FLAGS}" - Fortran "-fp-model=precise" # Intel - "/fp:precise" # Intel Windows - ) + Fortran "/fp:precise" # Intel Windows + ) SET_COMPILE_FLAG(STRICTMATH_FLAGS "${STRICTMATH_FLAGS}" - Fortran "-prec-div" # Intel - "/Qprec-div" # Intel Windows - ) + Fortran "/Qprec-div" # Intel Windows + ) SET_COMPILE_FLAG(STRICTMATH_FLAGS "${STRICTMATH_FLAGS}" - Fortran "-prec-sqrt" # Intel - "/Qprec-sqrt" # Intel Windows - ) + Fortran "/Qprec-sqrt" # Intel Windows + ) SET_COMPILE_FLAG(STRICTMATH_FLAGS "${STRICTMATH_FLAGS}" - Fortran "-assume protect-parens" # Intel - "/assume:protect-parens" # Intel Windows - ) + Fortran "/assume:protect-parens" # Intel Windows + ) # Improves floating-point precision and consistency SET_COMPILE_FLAG(STRICTMATH_FLAGS "${STRICTMATH_FLAGS}" - Fortran "-mp1" # Intel - "/Qprec" # Intel Windows - ) + Fortran "/Qprec" # Intel Windows + ) - # Most subroutines can use aggressive optimization of floating point operations without problems. + # Most subroutines can use aggressive optimization of floating point operations without problems. SET_COMPILE_FLAG(FASTMATH_FLAGS "${FASTMATH_FLAGS}" - Fortran "-fp-model=fast" # Intel - "/fp:fast" # Intel Windows - ) + Fortran "/fp:fast" # Intel Windows + ) + ELSE () + # Some subroutines require more strict floating point operation optimizations for repeatability + SET_COMPILE_FLAG(STRICTMATH_FLAGS "${STRICTMATH_FLAGS}" + Fortran "-fp-module=precise" # Intel + ) + SET_COMPILE_FLAG(STRICTMATH_FLAGS "${STRICTMATH_FLAGS}" + Fortran "-prec-div" # Intel + ) -ELSEIF (COMPILER_OPTIONS STREQUAL "GNU") + SET_COMPILE_FLAG(STRICTMATH_FLAGS "${STRICTMATH_FLAGS}" + Fortran "-prec-sqrt" # Intel + ) - # Some subroutines require more strict floating point operation optimizations for repeatability SET_COMPILE_FLAG(STRICTMATH_FLAGS "${STRICTMATH_FLAGS}" - Fortran "-fno-unsafe-math-optimizations" # GNU - ) - # Disable transformations and optimizations that assume default floating-point rounding behavior. + Fortran "-assume protect-parens" # Intel + ) + + # Improves floating-point precision and consistency SET_COMPILE_FLAG(STRICTMATH_FLAGS "${STRICTMATH_FLAGS}" - Fortran "-frounding-math" - ) + Fortran "-mp1" # Intel Windows + ) - # Most subroutines can use aggressive optimization of floating point operations without problems. + # Most subroutines can use aggressive optimization of floating point operations without problems. SET_COMPILE_FLAG(FASTMATH_FLAGS "${FASTMATH_FLAGS}" - Fortran "-ffast-math" # GNU - ) + Fortran "-fp-model=fast" # Intel Windows + ) + + ENDIF () + +ELSEIF (COMPILER_OPTIONS STREQUAL "GNU") + + # Some subroutines require more strict floating point operation optimizations for repeatability + SET_COMPILE_FLAG(STRICTMATH_FLAGS "${STRICTMATH_FLAGS}" + Fortran "-fno-unsafe-math-optimizations" # GNU + ) + # Disable transformations and optimizations that assume default floating-point rounding behavior. + SET_COMPILE_FLAG(STRICTMATH_FLAGS "${STRICTMATH_FLAGS}" + Fortran "-frounding-math" + ) + + # Most subroutines can use aggressive optimization of floating point operations without problems. + SET_COMPILE_FLAG(FASTMATH_FLAGS "${FASTMATH_FLAGS}" + Fortran "-ffast-math" # GNU + ) ENDIF () # Debug mode always uses strict math SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" - Fortran ${STRICTMATH_FLAGS} + Fortran ${STRICTMATH_FLAGS} ) ##################### @@ -524,16 +672,21 @@ SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" ##################### IF (CMAKE_BUILD_TYPE STREQUAL "PROFILE") - IF (COMPILER_OPTIONS STREQUAL "Intel") - # Enables the optimization reports to be generated - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_PROFILE "${CMAKE_Fortran_FLAGS_RELEASE}" - Fortran "-O2 -pg -qopt-report=5 -traceback -p -g3" # Intel - "/O2 /Qopt-report:5 /traceback /Z7" # Intel Windows - ) - ELSEIF (COMPILER_OPTIONS STREQUAL "GNU") - # Enables the optimization reports to be generated - SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_PROFILE "${CMAKE_Fortran_FLAGS_RELEASE}" - Fortran "-O2 -pg -fbacktrace" # GNU - ) + IF (COMPILER_OPTIONS STREQUAL "Intel") + # Enables the optimization reports to be generated + IF (WINOPT) + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_PROFILE "${CMAKE_Fortran_FLAGS_RELEASE}" + Fortran "/O2 /Qopt-report:5 /traceback /Z7" # Intel Windows + ) + ELSE () + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_PROFILE "${CMAKE_Fortran_FLAGS_RELEASE}" + Fortran "-O2 -pg -qopt-report=5 -traceback -p -g3" # Intel + ) ENDIF () + ELSEIF (COMPILER_OPTIONS STREQUAL "GNU") + # Enables the optimization reports to be generated + SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_PROFILE "${CMAKE_Fortran_FLAGS_RELEASE}" + Fortran "-O2 -pg -fbacktrace" # GNU + ) + ENDIF () ENDIF () diff --git a/cmake/Modules/UseCython.cmake b/cmake/Modules/UseCython.cmake new file mode 100644 index 000000000..4e0fa7907 --- /dev/null +++ b/cmake/Modules/UseCython.cmake @@ -0,0 +1,383 @@ +#.rst: +# +# The following functions are defined: +# +# .. cmake:command:: add_cython_target +# +# Create a custom rule to generate the source code for a Python extension module +# using cython. +# +# add_cython_target( [] +# [EMBED_MAIN] +# [C | CXX] +# [PY2 | PY3] +# [OUTPUT_VAR ]) +# +# ```` is the name of the new target, and ```` +# is the path to a cython source file. Note that, despite the name, no new +# targets are created by this function. Instead, see ``OUTPUT_VAR`` for +# retrieving the path to the generated source for subsequent targets. +# +# If only ```` is provided, and it ends in the ".pyx" extension, then it +# is assumed to be the ````. The name of the input without the +# extension is used as the target name. If only ```` is provided, and it +# does not end in the ".pyx" extension, then the ```` is assumed to +# be ``.pyx``. +# +# The Cython include search path is amended with any entries found in the +# ``INCLUDE_DIRECTORIES`` property of the directory containing the +# ```` file. Use ``include_directories`` to add to the Cython +# include search path. +# +# Options: +# +# ``EMBED_MAIN`` +# Embed a main() function in the generated output (for stand-alone +# applications that initialize their own Python runtime). +# +# ``C | CXX`` +# Force the generation of either a C or C++ file. By default, a C file is +# generated, unless the C language is not enabled for the project; in this +# case, a C++ file is generated by default. +# +# ``PY2 | PY3`` +# Force compilation using either Python-2 or Python-3 syntax and code +# semantics. By default, Python-2 syntax and semantics are used if the major +# version of Python found is 2. Otherwise, Python-3 syntax and semantics are +# used. +# +# ``OUTPUT_VAR `` +# Set the variable ```` in the parent scope to the path to the +# generated source file. By default, ```` is used as the output +# variable name. +# +# Defined variables: +# +# ```` +# The path of the generated source file. +# +# Cache variables that affect the behavior include: +# +# ``CYTHON_ANNOTATE`` +# Whether to create an annotated .html file when compiling. +# +# ``CYTHON_FLAGS`` +# Additional flags to pass to the Cython compiler. +# +# Example usage +# ^^^^^^^^^^^^^ +# +# .. code-block:: cmake +# +# find_package(Cython) +# +# # Note: In this case, either one of these arguments may be omitted; their +# # value would have been inferred from that of the other. +# add_cython_target(cy_code cy_code.pyx) +# +# add_library(cy_code MODULE ${cy_code}) +# target_link_libraries(cy_code ...) +# +#============================================================================= +# Copyright 2011 Kitware, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#============================================================================= + +# Configuration options. +set(CYTHON_ANNOTATE OFF + CACHE BOOL "Create an annotated .html file when compiling *.pyx.") + +set(CYTHON_FLAGS "" CACHE STRING + "Extra flags to the cython compiler.") +mark_as_advanced(CYTHON_ANNOTATE CYTHON_FLAGS) + +set(CYTHON_CXX_EXTENSION "cxx") +set(CYTHON_C_EXTENSION "c") + +get_property(languages GLOBAL PROPERTY ENABLED_LANGUAGES) + +function(add_cython_target _name) + set(options EMBED_MAIN C CXX PY2 PY3) + set(options1 OUTPUT_VAR) + cmake_parse_arguments(_args "${options}" "${options1}" "" ${ARGN}) + + list(GET _args_UNPARSED_ARGUMENTS 0 _arg0) + + # if provided, use _arg0 as the input file path + if(_arg0) + set(_source_file ${_arg0}) + + # otherwise, must determine source file from name, or vice versa + else() + get_filename_component(_name_ext "${_name}" EXT) + + # if extension provided, _name is the source file + if(_name_ext) + set(_source_file ${_name}) + get_filename_component(_name "${_source_file}" NAME_WE) + + # otherwise, assume the source file is ${_name}.pyx + else() + set(_source_file ${_name}.pyx) + endif() + endif() + + set(_embed_main FALSE) + + if("C" IN_LIST languages) + set(_output_syntax "C") + elseif("CXX" IN_LIST languages) + set(_output_syntax "CXX") + else() + message(FATAL_ERROR "Either C or CXX must be enabled to use Cython") + endif() + + if(_args_EMBED_MAIN) + set(_embed_main TRUE) + endif() + + if(_args_C) + set(_output_syntax "C") + endif() + + if(_args_CXX) + set(_output_syntax "CXX") + endif() + + # Doesn't select an input syntax - Cython + # defaults to 2 for Cython 2 and 3 for Cython 3 + set(_input_syntax "default") + + if(_args_PY2) + set(_input_syntax "PY2") + endif() + + if(_args_PY3) + set(_input_syntax "PY3") + endif() + + set(embed_arg "") + if(_embed_main) + set(embed_arg "--embed") + endif() + + set(cxx_arg "") + set(extension "c") + if(_output_syntax STREQUAL "CXX") + set(cxx_arg "--cplus") + set(extension "cxx") + endif() + + set(py_version_arg "") + if(_input_syntax STREQUAL "PY2") + set(py_version_arg "-2") + elseif(_input_syntax STREQUAL "PY3") + set(py_version_arg "-3") + endif() + + set(generated_file "${CMAKE_CURRENT_BINARY_DIR}/${_name}.${extension}") + set_source_files_properties(${generated_file} PROPERTIES GENERATED TRUE) + + set(_output_var ${_name}) + if(_args_OUTPUT_VAR) + set(_output_var ${_args_OUTPUT_VAR}) + endif() + set(${_output_var} ${generated_file} PARENT_SCOPE) + + file(RELATIVE_PATH generated_file_relative + ${CMAKE_BINARY_DIR} ${generated_file}) + + set(comment "Generating ${_output_syntax} source ${generated_file_relative}") + set(cython_include_directories "") + set(pxd_dependencies "") + set(c_header_dependencies "") + + # Get the include directories. + get_directory_property(cmake_include_directories + DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + INCLUDE_DIRECTORIES) + list(APPEND cython_include_directories ${cmake_include_directories}) + + # Determine dependencies. + # Add the pxd file with the same basename as the given pyx file. + get_source_file_property(pyx_location ${_source_file} LOCATION) + get_filename_component(pyx_path ${pyx_location} PATH) + get_filename_component(pyx_file_basename ${_source_file} NAME_WE) + unset(corresponding_pxd_file CACHE) + find_file(corresponding_pxd_file ${pyx_file_basename}.pxd + PATHS "${pyx_path}" ${cmake_include_directories} + NO_DEFAULT_PATH) + if(corresponding_pxd_file) + list(APPEND pxd_dependencies "${corresponding_pxd_file}") + endif() + + # pxd files to check for additional dependencies + set(pxds_to_check "${_source_file}" "${pxd_dependencies}") + set(pxds_checked "") + set(number_pxds_to_check 1) + while(number_pxds_to_check GREATER 0) + foreach(pxd ${pxds_to_check}) + list(APPEND pxds_checked "${pxd}") + list(REMOVE_ITEM pxds_to_check "${pxd}") + + # look for C headers + file(STRINGS "${pxd}" extern_from_statements + REGEX "cdef[ ]+extern[ ]+from.*$") + foreach(statement ${extern_from_statements}) + # Had trouble getting the quote in the regex + string(REGEX REPLACE + "cdef[ ]+extern[ ]+from[ ]+[\"]([^\"]+)[\"].*" "\\1" + header "${statement}") + unset(header_location CACHE) + find_file(header_location ${header} PATHS ${cmake_include_directories}) + if(header_location) + list(FIND c_header_dependencies "${header_location}" header_idx) + if(${header_idx} LESS 0) + list(APPEND c_header_dependencies "${header_location}") + endif() + endif() + endforeach() + + # check for pxd dependencies + # Look for cimport statements. + set(module_dependencies "") + file(STRINGS "${pxd}" cimport_statements REGEX cimport) + foreach(statement ${cimport_statements}) + if(${statement} MATCHES from) + string(REGEX REPLACE + "from[ ]+([^ ]+).*" "\\1" + module "${statement}") + else() + string(REGEX REPLACE + "cimport[ ]+([^ ]+).*" "\\1" + module "${statement}") + endif() + list(APPEND module_dependencies ${module}) + endforeach() + + # check for pxi dependencies + # Look for include statements. + set(include_dependencies "") + file(STRINGS "${pxd}" include_statements REGEX include) + foreach(statement ${include_statements}) + string(REGEX REPLACE + "include[ ]+[\"]([^\"]+)[\"].*" "\\1" + module "${statement}") + list(APPEND include_dependencies ${module}) + endforeach() + + list(REMOVE_DUPLICATES module_dependencies) + list(REMOVE_DUPLICATES include_dependencies) + + # Add modules to the files to check, if appropriate. + foreach(module ${module_dependencies}) + unset(pxd_location CACHE) + find_file(pxd_location ${module}.pxd + PATHS "${pyx_path}" ${cmake_include_directories} + NO_DEFAULT_PATH) + if(pxd_location) + list(FIND pxds_checked ${pxd_location} pxd_idx) + if(${pxd_idx} LESS 0) + list(FIND pxds_to_check ${pxd_location} pxd_idx) + if(${pxd_idx} LESS 0) + list(APPEND pxds_to_check ${pxd_location}) + list(APPEND pxd_dependencies ${pxd_location}) + endif() # if it is not already going to be checked + endif() # if it has not already been checked + endif() # if pxd file can be found + endforeach() # for each module dependency discovered + + # Add includes to the files to check, if appropriate. + foreach(_include ${include_dependencies}) + unset(pxi_location CACHE) + find_file(pxi_location ${_include} + PATHS "${pyx_path}" ${cmake_include_directories} + NO_DEFAULT_PATH) + if(pxi_location) + list(FIND pxds_checked ${pxi_location} pxd_idx) + if(${pxd_idx} LESS 0) + list(FIND pxds_to_check ${pxi_location} pxd_idx) + if(${pxd_idx} LESS 0) + list(APPEND pxds_to_check ${pxi_location}) + list(APPEND pxd_dependencies ${pxi_location}) + endif() # if it is not already going to be checked + endif() # if it has not already been checked + endif() # if include file can be found + endforeach() # for each include dependency discovered + endforeach() # for each include file to check + + list(LENGTH pxds_to_check number_pxds_to_check) + endwhile() + + # Set additional flags. + set(annotate_arg "") + if(CYTHON_ANNOTATE) + set(annotate_arg "--annotate") + endif() + + set(cython_debug_arg "") + set(line_directives_arg "") + if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR + CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") + set(cython_debug_arg "--gdb") + set(line_directives_arg "--line-directives") + endif() + + # Include directory arguments. + list(REMOVE_DUPLICATES cython_include_directories) + set(include_directory_arg "") + foreach(_include_dir ${cython_include_directories}) + set(include_directory_arg + ${include_directory_arg} "--include-dir" "${_include_dir}") + endforeach() + + list(REMOVE_DUPLICATES pxd_dependencies) + list(REMOVE_DUPLICATES c_header_dependencies) + + string(REGEX REPLACE " " ";" CYTHON_FLAGS_LIST "${CYTHON_FLAGS}") + + # Add the command to run the compiler. + add_custom_command(OUTPUT ${generated_file} + COMMAND ${CYTHON_EXECUTABLE} + ARGS ${cxx_arg} ${include_directory_arg} ${py_version_arg} + ${embed_arg} ${annotate_arg} ${cython_debug_arg} + ${line_directives_arg} ${CYTHON_FLAGS_LIST} ${pyx_location} + --output-file ${generated_file} + DEPENDS ${_source_file} + ${pxd_dependencies} + IMPLICIT_DEPENDS ${_output_syntax} + ${c_header_dependencies} + COMMENT ${comment}) + + # NOTE(opadron): I thought about making a proper target, but after trying it + # out, I decided that it would be far too convenient to use the same name as + # the target for the extension module (e.g.: for single-file modules): + # + # ... + # add_cython_target(_module.pyx) + # add_library(_module ${_module}) + # ... + # + # The above example would not be possible since the "_module" target name + # would already be taken by the cython target. Since I can't think of a + # reason why someone would need the custom target instead of just using the + # generated file directly, I decided to leave this commented out. + # + # add_custom_target(${_name} DEPENDS ${generated_file}) + + # Remove their visibility to the user. + set(corresponding_pxd_file "" CACHE INTERNAL "") + set(header_location "" CACHE INTERNAL "") + set(pxd_location "" CACHE INTERNAL "") +endfunction() diff --git a/cmake/Modules/UsePythonExtensions.cmake b/cmake/Modules/UsePythonExtensions.cmake new file mode 100644 index 000000000..c411e20c4 --- /dev/null +++ b/cmake/Modules/UsePythonExtensions.cmake @@ -0,0 +1,320 @@ +#.rst: +# +# The following functions are defined: +# +# .. cmake:command:: add_python_library +# +# Add a library that contains a mix of C, C++, Fortran, Cython, F2PY, Template, +# and Tempita sources. The required targets are automatically generated to +# "lower" source files from their high-level representation to a file that the +# compiler can accept. +# +# +# add_python_library( +# SOURCES [source1 [source2 ...]] +# [INCLUDE_DIRECTORIES [dir1 [dir2 ...]] +# [LINK_LIBRARIES [lib1 [lib2 ...]] +# [DEPENDS [source1 [source2 ...]]]) +# +# +# Example usage +# ^^^^^^^^^^^^^ +# +# .. code-block:: cmake +# +# find_package(PythonExtensions) +# +# file(GLOB arpack_sources ARPACK/SRC/*.f ARPACK/UTIL/*.f) +# +# add_python_library(arpack_scipy +# SOURCES ${arpack_sources} +# ${g77_wrapper_sources} +# INCLUDE_DIRECTORIES ARPACK/SRC +# ) +# +# .. cmake:command:: add_python_extension +# +# Add a extension that contains a mix of C, C++, Fortran, Cython, F2PY, Template, +# and Tempita sources. The required targets are automatically generated to +# "lower" source files from their high-level representation to a file that the +# compiler can accept. +# +# +# add_python_extension( +# SOURCES [source1 [source2 ...]] +# [INCLUDE_DIRECTORIES [dir1 [dir2 ...]] +# [LINK_LIBRARIES [lib1 [lib2 ...]] +# [DEPENDS [source1 [source2 ...]]]) +# +# +# Example usage +# ^^^^^^^^^^^^^ +# +# .. code-block:: cmake +# +# find_package(PythonExtensions) +# +# file(GLOB arpack_sources ARPACK/SRC/*.f ARPACK/UTIL/*.f) +# +# add_python_extension(arpack_scipy +# SOURCES ${arpack_sources} +# ${g77_wrapper_sources} +# INCLUDE_DIRECTORIES ARPACK/SRC +# ) +# +# +#============================================================================= +# Copyright 2011 Kitware, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#============================================================================= + +macro(_remove_whitespace _output) + string(REGEX REPLACE "[ \r\n\t]+" " " ${_output} "${${_output}}") + string(STRIP "${${_output}}" ${_output}) +endmacro() + +function(add_python_library _name) + set(options STATIC SHARED MODULE) + set(multiValueArgs SOURCES INCLUDE_DIRECTORIES LINK_LIBRARIES COMPILE_DEFINITIONS DEPENDS) + cmake_parse_arguments(_args "${options}" "" "${multiValueArgs}" ${ARGN} ) + + # Validate arguments to allow simpler debugging + if(NOT _args_SOURCES) + message( + FATAL_ERROR + "You have called add_python_library for library ${_name} without " + "any source files. This typically indicates a problem with " + "your CMakeLists.txt file" + ) + endif() + + # Initialize the list of sources + set(_sources ${_args_SOURCES}) + + # Generate targets for all *.src files + set(_processed ) + foreach(_source IN LISTS _sources) + if(${_source} MATCHES ".pyf.src$" OR ${_source} MATCHES "\\.f\\.src$") + if(NOT NumPy_FOUND) + message( + FATAL_ERROR + "NumPy is required to process *.src Template files" + ) + endif() + string(REGEX REPLACE "\\.[^.]*$" "" _source_we ${_source}) + add_custom_command( + OUTPUT ${_source_we} + COMMAND ${NumPy_FROM_TEMPLATE_EXECUTABLE} + ${CMAKE_CURRENT_SOURCE_DIR}/${_source} + ${CMAKE_CURRENT_BINARY_DIR}/${_source_we} + DEPENDS ${_source} ${_args_DEPENDS} + COMMENT "Generating ${_source_we} from template ${_source}" + ) + list(APPEND _processed ${_source_we}) + elseif(${_source} MATCHES "\\.c\\.src$") + if(NOT NumPy_FOUND) + message( + FATAL_ERROR + "NumPy is required to process *.src Template files" + ) + endif() + string(REGEX REPLACE "\\.[^.]*$" "" _source_we ${_source}) + add_custom_command( + OUTPUT ${_source_we} + COMMAND ${NumPy_CONV_TEMPLATE_EXECUTABLE} + ${CMAKE_CURRENT_SOURCE_DIR}/${_source} + ${CMAKE_CURRENT_BINARY_DIR}/${_source_we} + DEPENDS ${_source} ${_args_DEPENDS} + COMMENT "Generating ${_source_we} from template ${_source}" + ) + list(APPEND _processed ${_source_we}) + elseif(${_source} MATCHES "\\.pyx\\.in$") + if(NOT Cython_FOUND) + message( + FATAL_ERROR + "Cython is required to process *.in Tempita files" + ) + endif() + string(REGEX REPLACE "\\.[^.]*$" "" _source_we ${_source}) + configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/${_source} + ${CMAKE_CURRENT_BINARY_DIR}/${_source} + COPYONLY + ) + set(_tempita_command + " + import os; + import sys; + from Cython.Tempita import Template; + cwd = os.getcwd(); + open(os.path.join(cwd, '${_source_we}'), 'w+') + .write( + Template.from_filename(os.path.join(cwd, '${_source}'), + encoding=sys.getdefaultencoding()).substitute() + ) + " + ) + _remove_whitespace(_tempita_command) + add_custom_command( + OUTPUT ${_source_we} + COMMAND ${PYTHON_EXECUTABLE} -c "${_tempita_command}" + DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${_source}" + ${_args_DEPENDS} + ) + list(APPEND _processed ${_source_we}) + else() + list(APPEND _processed ${_source}) + endif() + endforeach() + set(_sources ${_processed}) + + # If we're building a Python extension and we're given only Fortran sources, + # We can conclude that we need to generate a Fortran interface file + list(FILTER _processed EXCLUDE REGEX "(\\.f|\\.f90)$") + if(NOT _processed AND _args_MODULE) + if(NOT NumPy_FOUND) + message( + FATAL_ERROR + "NumPy is required to process *.pyf F2PY files" + ) + endif() + set(_sources_abs ) + foreach(_source IN LISTS _sources) + if(NOT IS_ABSOLUTE ${_source}) + set(_source ${CMAKE_CURRENT_SOURCE_DIR}/${_source}) + endif() + list(APPEND _sources_abs ${_source}) + endforeach() + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${_name}.pyf + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${F2PY_EXECUTABLE} + ARGS -h ${_name}.pyf -m ${_name} --overwrite-signature + ${_sources_abs} + DEPENDS ${_sources} ${_args_DEPENDS} + COMMENT "Generating ${_name} Fortran interface file" + ) + list(APPEND _sources ${_name}.pyf) + endif() + + # Are there F2PY targets? + set(_has_f2py_targets OFF) + set(_has_cython_targets OFF) + + # Generate targets for all *.pyx and *.pyf files + set(_processed ) + foreach(_source IN LISTS _sources) + if(${_source} MATCHES \\.pyx$) + if(NOT Cython_FOUND) + message( + FATAL_ERROR + "Cython is required to process *.pyx Cython files" + ) + endif() + string(REGEX REPLACE "\\.[^.]*$" "" _pyx_target_name ${_source}) + set(_has_cython_targets ON) + add_cython_target(${_pyx_target_name} + ${_source} + OUTPUT_VAR _pyx_target_output + DEPENDS ${_args_DEPENDS} + ) + list(APPEND _processed ${_pyx_target_output}) + elseif(${_source} MATCHES \\.pyf$) + if(NOT NumPy_FOUND) + message( + FATAL_ERROR + "NumPy is required to process *.pyf F2PY files" + ) + endif() + string(REGEX REPLACE "\\.[^.]*$" "" _pyf_target_name ${_source}) + set(_has_f2py_targets ON) + add_f2py_target(${_pyf_target_name} + ${_source} + OUTPUT_VAR _pyf_target_output + DEPENDS ${_args_DEPENDS} + ) + list(APPEND _processed ${_pyf_target_output}) + else() + list(APPEND _processed ${_source}) + endif() + endforeach() + set(_sources ${_processed}) + + if(_args_SHARED) + add_library(${_name} SHARED ${_sources}) + elseif(_args_MODULE) + add_library(${_name} MODULE ${_sources}) + else() + # Assume static + add_library(${_name} STATIC ${_sources}) + endif() + + target_include_directories(${_name} PRIVATE ${_args_INCLUDE_DIRECTORIES}) + target_link_libraries(${_name} ${SKBUILD_LINK_LIBRARIES_KEYWORD} ${_args_LINK_LIBRARIES}) + + if(_has_f2py_targets) + target_include_directories(${_name} PRIVATE ${F2PY_INCLUDE_DIRS}) + target_link_libraries(${_name} ${SKBUILD_LINK_LIBRARIES_KEYWORD} ${F2PY_LIBRARIES}) + endif() + + if(_args_COMPILE_DEFINITIONS) + target_compile_definitions(${_name} PRIVATE ${_args_COMPILE_DEFINITIONS}) + endif() + + if(_args_DEPENDS) + add_custom_target( + "${_name}_depends" + DEPENDS ${_args_DEPENDS} + ) + add_dependencies(${_name} "${_name}_depends") + endif() +endfunction() + +function(add_python_extension _name) + # FIXME: make sure that extensions with the same name can happen + # in multiple directories + + set(multiValueArgs SOURCES INCLUDE_DIRECTORIES LINK_LIBRARIES COMPILE_DEFINITIONS DEPENDS) + cmake_parse_arguments(_args "" "" "${multiValueArgs}" ${ARGN} ) + + # Validate arguments to allow simpler debugging + if(NOT _args_SOURCES) + message( + FATAL_ERROR + "You have called add_python_extension for library ${_name} without " + "any source files. This typically indicates a problem with " + "your CMakeLists.txt file" + ) + endif() + + add_python_library(${_name} MODULE + SOURCES ${_args_SOURCES} + INCLUDE_DIRECTORIES ${_args_INCLUDE_DIRECTORIES} + LINK_LIBRARIES ${_args_LINK_LIBRARIES} + COMPILE_DEFINITIONS ${_args_COMPILE_DEFINITIONS} + DEPENDS ${_args_DEPENDS} + ) + python_extension_module(${_name}) + + file(RELATIVE_PATH _relative "${CMAKE_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}") + if(_relative STREQUAL "") + set(_relative ".") + endif() + + install( + TARGETS ${_name} + LIBRARY DESTINATION "${_relative}" + RUNTIME DESTINATION "${_relative}" + ) +endfunction() diff --git a/cmake/Modules/targetLinkLibrariesWithDynamicLookup.cmake b/cmake/Modules/targetLinkLibrariesWithDynamicLookup.cmake new file mode 100644 index 000000000..a583f42cd --- /dev/null +++ b/cmake/Modules/targetLinkLibrariesWithDynamicLookup.cmake @@ -0,0 +1,597 @@ +#.rst: +# +# Public Functions +# ^^^^^^^^^^^^^^^^ +# +# The following functions are defined: +# +# .. cmake:command:: target_link_libraries_with_dynamic_lookup +# +# :: +# +# target_link_libraries_with_dynamic_lookup( []) +# +# +# Useful to "weakly" link a loadable module. For example, it should be used +# when compiling a loadable module when the symbols should be resolve from +# the run-time environment where the module is loaded, and not a specific +# system library. +# +# Like proper linking, except that the given ```` are not necessarily +# linked. Instead, the ```` is produced in a manner that allows for +# symbols unresolved within it to be resolved at runtime, presumably by the +# given ````. If such a target can be produced, the provided +# ```` are not actually linked. +# +# It links a library to a target such that the symbols are resolved at +# run-time not link-time. +# +# The linker is checked to see if it supports undefined +# symbols when linking a shared library. If it does then the library +# is not linked when specified with this function. +# +# On platforms that do not support weak-linking, this function works just +# like ``target_link_libraries``. +# +# .. note:: +# +# For OSX it uses ``undefined dynamic_lookup``. This is similar to using +# ``-shared`` on Linux where undefined symbols are ignored. +# +# For more details, see `blog `_ +# from Tim D. Smith. +# +# +# .. cmake:command:: check_dynamic_lookup +# +# Check if the linker requires a command line flag to allow leaving symbols +# unresolved when producing a target of type ```` that is +# weakly-linked against a dependency of type ````. +# +# ```` +# can be one of "STATIC", "SHARED", "MODULE", or "EXE". +# +# ```` +# can be one of "STATIC", "SHARED", or "MODULE". +# +# Long signature: +# +# :: +# +# check_dynamic_lookup( +# +# +# []) +# +# +# Short signature: +# +# :: +# +# check_dynamic_lookup() # set to "MODULE" +# # set to "SHARED" +# +# +# The result is cached between invocations and recomputed only when the value +# of CMake's linker flag list changes; ``CMAKE_STATIC_LINKER_FLAGS`` if +# ```` is "STATIC", and ``CMAKE_SHARED_LINKER_FLAGS`` otherwise. +# +# +# Defined variables: +# +# ```` +# Whether the current C toolchain supports weak-linking for target binaries of +# type ```` that are weakly-linked against a dependency target of +# type ````. +# +# ```` +# List of flags to add to the linker command to produce a working target +# binary of type ```` that is weakly-linked against a dependency +# target of type ````. +# +# ``HAS_DYNAMIC_LOOKUP__`` +# Cached, global alias for ```` +# +# ``DYNAMIC_LOOKUP_FLAGS__`` +# Cached, global alias for ```` +# +# +# Private Functions +# ^^^^^^^^^^^^^^^^^ +# +# The following private functions are defined: +# +# .. warning:: These functions are not part of the scikit-build API. They +# exist purely as an implementation detail and may change from version +# to version without notice, or even be removed. +# +# We mean it. +# +# +# .. cmake:command:: _get_target_type +# +# :: +# +# _get_target_type( ) +# +# +# Shorthand for querying an abbreviated version of the target type +# of the given ````. +# +# ```` is set to: +# +# - "STATIC" for a STATIC_LIBRARY, +# - "SHARED" for a SHARED_LIBRARY, +# - "MODULE" for a MODULE_LIBRARY, +# - and "EXE" for an EXECUTABLE. +# +# Defined variables: +# +# ```` +# The abbreviated version of the ````'s type. +# +# +# .. cmake:command:: _test_weak_link_project +# +# :: +# +# _test_weak_link_project( +# +# +# ) +# +# +# Attempt to compile and run a test project where a target of type +# ```` is weakly-linked against a dependency of type ````: +# +# - ```` can be one of "STATIC", "SHARED", "MODULE", or "EXE". +# - ```` can be one of "STATIC", "SHARED", or "MODULE". +# +# Defined variables: +# +# ```` +# Whether the current C toolchain can produce a working target binary of type +# ```` that is weakly-linked against a dependency target of type +# ````. +# +# ```` +# List of flags to add to the linker command to produce a working target +# binary of type ```` that is weakly-linked against a dependency +# target of type ````. +# + +function(_get_target_type result_var target) + set(target_type "SHARED_LIBRARY") + if(TARGET ${target}) + get_property(target_type TARGET ${target} PROPERTY TYPE) + endif() + + set(result "STATIC") + + if(target_type STREQUAL "STATIC_LIBRARY") + set(result "STATIC") + endif() + + if(target_type STREQUAL "SHARED_LIBRARY") + set(result "SHARED") + endif() + + if(target_type STREQUAL "MODULE_LIBRARY") + set(result "MODULE") + endif() + + if(target_type STREQUAL "EXECUTABLE") + set(result "EXE") + endif() + + set(${result_var} ${result} PARENT_SCOPE) +endfunction() + + +function(_test_weak_link_project + target_type + lib_type + can_weak_link_var + project_name) + + set(gnu_ld_ignore "-Wl,--unresolved-symbols=ignore-all") + set(osx_dynamic_lookup "-undefined dynamic_lookup") + set(no_flag "") + + if(CMAKE_CROSSCOMPILING) + set(link_flag_spec "no_flag") + set(link_flag "${${link_flag_spec}}") + set(test_skipping_reason "") + set(test_pass FALSE) + + if(APPLE AND NOT CMAKE_CROSSCOMPILING_EMULATOR) + set(link_flag_spec "osx_dynamic_lookup") + set(link_flag "${${link_flag_spec}}") + set(test_skipping_reason " (Cross compiling without emulator on macOS)") + set(test_pass TRUE) + endif() + + if(test_pass) + set(test_description "Weak Link ${target_type} -> ${lib_type} (${link_flag_spec})") + message(STATUS "Performing Test ${test_description} - Assuming Success${test_skipping_reason}") + set(${can_weak_link_var} ${test_pass} PARENT_SCOPE) + set(${project_name} ${link_flag} PARENT_SCOPE) + return() + endif() + endif() + + foreach(link_flag_spec gnu_ld_ignore osx_dynamic_lookup no_flag) + set(link_flag "${${link_flag_spec}}") + + set(test_project_dir "${PROJECT_BINARY_DIR}/CMakeTmp") + set(test_project_dir "${test_project_dir}/${project_name}") + set(test_project_dir "${test_project_dir}/${link_flag_spec}") + set(test_project_dir "${test_project_dir}/${target_type}") + set(test_project_dir "${test_project_dir}/${lib_type}") + + set(test_project_src_dir "${test_project_dir}/src") + set(test_project_bin_dir "${test_project_dir}/build") + + file(MAKE_DIRECTORY ${test_project_src_dir}) + file(MAKE_DIRECTORY ${test_project_bin_dir}) + + set(mod_type "STATIC") + set(link_mod_lib TRUE) + set(link_exe_lib TRUE) + set(link_exe_mod FALSE) + + if("${target_type}" STREQUAL "EXE") + set(link_exe_lib FALSE) + set(link_exe_mod TRUE) + else() + set(mod_type "${target_type}") + endif() + + if("${mod_type}" STREQUAL "MODULE") + set(link_mod_lib FALSE) + endif() + + + file(WRITE "${test_project_src_dir}/CMakeLists.txt" " + cmake_minimum_required(VERSION ${CMAKE_VERSION}) + project(${project_name} C) + + include_directories(${test_project_src_dir}) + + add_library(number ${lib_type} number.c) + add_library(counter ${mod_type} counter.c) + ") + + if("${mod_type}" STREQUAL "MODULE") + file(APPEND "${test_project_src_dir}/CMakeLists.txt" " + set_target_properties(counter PROPERTIES PREFIX \"\") + ") + endif() + + if(link_mod_lib) + file(APPEND "${test_project_src_dir}/CMakeLists.txt" " + target_link_libraries(counter ${SKBUILD_LINK_LIBRARIES_KEYWORD} number) + ") + elseif(NOT link_flag STREQUAL "") + file(APPEND "${test_project_src_dir}/CMakeLists.txt" " + set_target_properties(counter PROPERTIES LINK_FLAGS \"${link_flag}\") + ") + endif() + + file(APPEND "${test_project_src_dir}/CMakeLists.txt" " + add_executable(main main.c) + ") + + if(link_exe_lib) + file(APPEND "${test_project_src_dir}/CMakeLists.txt" " + target_link_libraries(main ${SKBUILD_LINK_LIBRARIES_KEYWORD} number) + ") + elseif(NOT link_flag STREQUAL "") + file(APPEND "${test_project_src_dir}/CMakeLists.txt" " + target_link_libraries(main ${SKBUILD_LINK_LIBRARIES_KEYWORD} \"${link_flag}\") + ") + endif() + + if(link_exe_mod) + file(APPEND "${test_project_src_dir}/CMakeLists.txt" " + target_link_libraries(main ${SKBUILD_LINK_LIBRARIES_KEYWORD} counter) + ") + else() + file(APPEND "${test_project_src_dir}/CMakeLists.txt" " + target_link_libraries(main ${SKBUILD_LINK_LIBRARIES_KEYWORD} \"${CMAKE_DL_LIBS}\") + ") + endif() + + file(WRITE "${test_project_src_dir}/number.c" " + #include + + static int _number; + void set_number(int number) { _number = number; } + int get_number() { return _number; } + ") + + file(WRITE "${test_project_src_dir}/number.h" " + #ifndef _NUMBER_H + #define _NUMBER_H + extern void set_number(int); + extern int get_number(void); + #endif + ") + + file(WRITE "${test_project_src_dir}/counter.c" " + #include + int count() { + int result = get_number(); + set_number(result + 1); + return result; + } + ") + + file(WRITE "${test_project_src_dir}/counter.h" " + #ifndef _COUNTER_H + #define _COUNTER_H + extern int count(void); + #endif + ") + + file(WRITE "${test_project_src_dir}/main.c" " + #include + #include + #include + ") + + if(NOT link_exe_mod) + file(APPEND "${test_project_src_dir}/main.c" " + #include + ") + endif() + + file(APPEND "${test_project_src_dir}/main.c" " + int my_count() { + int result = get_number(); + set_number(result + 1); + return result; + } + + int main(int argc, char **argv) { + int result; + ") + + if(NOT link_exe_mod) + file(APPEND "${test_project_src_dir}/main.c" " + void *counter_module; + int (*count)(void); + + counter_module = dlopen(\"./counter.so\", RTLD_LAZY | RTLD_GLOBAL); + if(!counter_module) goto error; + + count = dlsym(counter_module, \"count\"); + if(!count) goto error; + ") + endif() + + file(APPEND "${test_project_src_dir}/main.c" " + result = count() != 0 ? EXIT_FAILURE : + my_count() != 1 ? EXIT_FAILURE : + my_count() != 2 ? EXIT_FAILURE : + count() != 3 ? EXIT_FAILURE : + count() != 4 ? EXIT_FAILURE : + count() != 5 ? EXIT_FAILURE : + my_count() != 6 ? EXIT_FAILURE : EXIT_SUCCESS; + ") + + if(NOT link_exe_mod) + file(APPEND "${test_project_src_dir}/main.c" " + goto done; + error: + fprintf(stderr, \"Error occurred:\\n %s\\n\", dlerror()); + result = 1; + + done: + if(counter_module) dlclose(counter_module); + ") + endif() + + file(APPEND "${test_project_src_dir}/main.c" " + return result; + } + ") + + set(_rpath_arg) + if(APPLE AND ${CMAKE_VERSION} VERSION_GREATER 2.8.11) + set(_rpath_arg "-DCMAKE_MACOSX_RPATH='${CMAKE_MACOSX_RPATH}'") + endif() + + try_compile(project_compiles + "${test_project_bin_dir}" + "${test_project_src_dir}" + "${project_name}" + CMAKE_FLAGS + "-DCMAKE_SHARED_LINKER_FLAGS='${CMAKE_SHARED_LINKER_FLAGS}'" + "-DCMAKE_ENABLE_EXPORTS=ON" + ${_rpath_arg} + OUTPUT_VARIABLE compile_output) + + set(project_works 1) + set(run_output) + + if(project_compiles) + execute_process(COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} + "${test_project_bin_dir}/main" + WORKING_DIRECTORY "${test_project_bin_dir}" + RESULT_VARIABLE project_works + OUTPUT_VARIABLE run_output + ERROR_VARIABLE run_output) + endif() + + set(test_description + "Weak Link ${target_type} -> ${lib_type} (${link_flag_spec})") + + if(project_works EQUAL 0) + set(project_works TRUE) + message(STATUS "Performing Test ${test_description} - Success") + else() + set(project_works FALSE) + message(STATUS "Performing Test ${test_description} - Failed") + file(APPEND ${CMAKE_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/CMakeError.log + "Performing Test ${test_description} failed with the " + "following output:\n" + "BUILD\n-----\n${compile_output}\nRUN\n---\n${run_output}\n") + endif() + + set(${can_weak_link_var} ${project_works} PARENT_SCOPE) + if(project_works) + set(${project_name} ${link_flag} PARENT_SCOPE) + break() + endif() + endforeach() +endfunction() + +function(check_dynamic_lookup) + # Two signatures are supported: + + if(ARGC EQUAL "1") + # + # check_dynamic_lookup() + # + set(target_type "MODULE") + set(lib_type "SHARED") + set(has_dynamic_lookup_var "${ARGV0}") + set(link_flags_var "unused") + + elseif(ARGC GREATER "2") + # + # check_dynamic_lookup( + # + # + # []) + # + set(target_type "${ARGV0}") + set(lib_type "${ARGV1}") + set(has_dynamic_lookup_var "${ARGV2}") + if(ARGC EQUAL "3") + set(link_flags_var "unused") + else() + set(link_flags_var "${ARGV3}") + endif() + else() + message(FATAL_ERROR "missing arguments") + endif() + + _check_dynamic_lookup( + ${target_type} + ${lib_type} + ${has_dynamic_lookup_var} + ${link_flags_var} + ) + set(${has_dynamic_lookup_var} ${${has_dynamic_lookup_var}} PARENT_SCOPE) + if(NOT "x${link_flags_var}x" STREQUAL "xunusedx") + set(${link_flags_var} ${${link_flags_var}} PARENT_SCOPE) + endif() +endfunction() + +function(_check_dynamic_lookup + target_type + lib_type + has_dynamic_lookup_var + link_flags_var + ) + + # hash the CMAKE_FLAGS passed and check cache to know if we need to rerun + if("${target_type}" STREQUAL "STATIC") + string(MD5 cmake_flags_hash "${CMAKE_STATIC_LINKER_FLAGS}") + else() + string(MD5 cmake_flags_hash "${CMAKE_SHARED_LINKER_FLAGS}") + endif() + + set(cache_var "HAS_DYNAMIC_LOOKUP_${target_type}_${lib_type}") + set(cache_hash_var "HAS_DYNAMIC_LOOKUP_${target_type}_${lib_type}_hash") + set(result_var "DYNAMIC_LOOKUP_FLAGS_${target_type}_${lib_type}") + + if( NOT DEFINED ${cache_hash_var} + OR NOT "${${cache_hash_var}}" STREQUAL "${cmake_flags_hash}") + unset(${cache_var} CACHE) + endif() + + if(NOT DEFINED ${cache_var}) + + if(CMAKE_CROSSCOMPILING AND NOT CMAKE_CROSSCOMPILING_EMULATOR) + set(skip_test TRUE) + endif() + + _test_weak_link_project(${target_type} + ${lib_type} + has_dynamic_lookup + link_flags) + + set(caveat " (when linking ${target_type} against ${lib_type})") + + set(${cache_var} "${has_dynamic_lookup}" + CACHE BOOL + "linker supports dynamic lookup for undefined symbols${caveat}") + mark_as_advanced(${cache_var}) + + set(${result_var} "${link_flags}" + CACHE STRING + "linker flags for dynamic lookup${caveat}") + mark_as_advanced(${result_var}) + + set(${cache_hash_var} "${cmake_flags_hash}" + CACHE INTERNAL "hashed flags for ${cache_var} check") + endif() + + set(${has_dynamic_lookup_var} "${${cache_var}}" PARENT_SCOPE) + set(${link_flags_var} "${${result_var}}" PARENT_SCOPE) +endfunction() + +function(target_link_libraries_with_dynamic_lookup target) + _get_target_type(target_type ${target}) + + set(link_props) + set(link_items) + set(link_libs) + + foreach(lib ${ARGN}) + _get_target_type(lib_type ${lib}) + check_dynamic_lookup(${target_type} + ${lib_type} + has_dynamic_lookup + dynamic_lookup_flags) + + if(has_dynamic_lookup) + if(dynamic_lookup_flags) + if("${target_type}" STREQUAL "EXE") + list(APPEND link_items "${dynamic_lookup_flags}") + else() + list(APPEND link_props "${dynamic_lookup_flags}") + endif() + endif() + elseif(${lib} MATCHES "(debug|optimized|general)") + # See gh-255 + else() + list(APPEND link_libs "${lib}") + endif() + endforeach() + + if(link_props) + list(REMOVE_DUPLICATES link_props) + endif() + + if(link_items) + list(REMOVE_DUPLICATES link_items) + endif() + + if(link_libs) + list(REMOVE_DUPLICATES link_libs) + endif() + + if(link_props) + set_target_properties(${target} + PROPERTIES LINK_FLAGS "${link_props}") + endif() + + set(links "${link_items}" "${link_libs}") + if(links) + target_link_libraries(${target} ${SKBUILD_LINK_LIBRARIES_KEYWORD} "${links}") + endif() +endfunction() diff --git a/distclean.cmake b/distclean.cmake index d01195c6c..c0ce74642 100644 --- a/distclean.cmake +++ b/distclean.cmake @@ -19,7 +19,7 @@ ELSE() SET(TOPDIR "${CMAKE_SOURCE_DIR}") ENDIF() -SET(CIBW_DIR "_skbuild" "swiftest.egg-info") +SET(CIBW_DIR "_skbuild" "swiftest.egg-info" "_cmake_test_compile") MACRO(GET_PARENT_DIRECTORIES search_string return_list grandparents) FILE(GLOB_RECURSE new_list ${search_string}) @@ -46,8 +46,10 @@ FILE(GLOB_RECURSE CMAKEINSTALL "${TOPDIR}/*cmake_install.cmake" FILE(GLOB_RECURSE MAKEFILE "${TOPDIR}/*Makefile") FILE(GLOB_RECURSE CMAKETESTFILES "${TOPDIR}/*CTestTestfile.cmake") SET(TOPDIRECTORIES "${TOPDIR}/lib" + "${TOPDIR}/libexec" "${TOPDIR}/bin" "${TOPDIR}/include" + "${TOPDIR}/share" ) # CMake has trouble finding directories recursively, so locate these diff --git a/environment.yml b/environment.yml index 015c642f1..933cb3fe1 100644 --- a/environment.yml +++ b/environment.yml @@ -7,9 +7,9 @@ channels: dependencies: - python>=3.8 - numpy>=1.24.3 - - pandas>=1.5.3 - scipy>=1.10.1 - xarray>=2022.11.0 + - distributed>=2022.1 - dask>=2022.1 - bottleneck>=1.3.5 - h5netcdf>=1.0.2 @@ -20,4 +20,4 @@ dependencies: - tqdm>=4.65.0 - x264>=1!157.20191217 - ffmpeg>=4.3.2 - - py>=1.11 \ No newline at end of file + - cython>=3.0.0 diff --git a/pyproject.toml b/pyproject.toml index d81ff9775..8d8eb8761 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,31 +1,108 @@ +[project] +name = "swiftest" +version = "2023.9.0" +authors=[ + {name = 'David A. Minton', email='daminton@purdue.edu'}, + {name = 'Carlisle Wishard'}, + {name = 'Jennifer Pouplin'}, + {name = 'Jake Elliott'}, + {name = 'Dana Singh'}, + {name = 'Kaustub Anand'}, +] +maintainers = [ + {name = 'David A. Minton', email='daminton@purdue.edu'}, +] +readme = "README.md" +requires-python=">=3.8" +license={file = "LICENSE.txt"} +classifiers=[ +'Development Status :: 3 - Alpha', +'Intended Audience :: Science/Research', +'Topic :: Scientific/Engineering :: Astronomy', +'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)', +'Programming Language :: Python :: 3', +] +keywords=['astronomy','astrophysics', 'planetary', 'nbody integrator', 'symplectic', 'wisdom-holman'] +dependencies = [ + 'numpy>=1.24.3', + 'scipy>=1.10.1', + 'xarray>=2022.11.0', + 'dask>=2022.1', + 'distributed>=2022.1', + 'bottleneck>=1.3.5', + 'h5netcdf>=1.0.2', + 'netcdf4>=1.6.2', + 'matplotlib>=3.7.1', + 'astropy>=5.1', + 'astroquery>=0.4.6', + 'tqdm>=4.65.0', + 'cython>=3.0.0', +] + +[project.urls] +Repository = 'https://github.itap.purdue.edu/MintonGroup/swiftest' + [build-system] requires = [ - "setuptools>=42", - "scikit-build>=0.17", - "cmake>=3.5.0", + "scikit-build-core", "cython>=3.0.0", - "ninja", "pytest", ] -build-backend = "setuptools.build_meta" +build-backend = "scikit_build_core.build" + +[tool.scikit-build] +cmake.args = ["-DBUILD_SHARED_LIBS=ON","-DUSE_SIMD=OFF"] +sdist.include = ["src/globals/globals_module.f90.in","swiftest/*.py","swiftest/*.pyx","swiftest/*.h"] [tool.cibuildwheel] -environment = {SKBUILD_CONFIGURE_OPTIONS="-DBUILD_SHARED_LIBS=OFF"} test-command = "pytest {package}/tests" -test-requires = ['pytest','cython'] -test-skip = "cp312-*" -skip = "pp* *i686 *-manylinux_i686 *_ppc64le *_s390x *-musllinux* *-win32" +test-requires = ['pytest'] +skip = "cp312-* pp* *i686 *-manylinux_i686 *_ppc64le *_s390x *-musllinux* *-win32" +build-verbosity = 1 -[tool.cibuildwheel.linux] -environment = {FFLAGS="${FFLAGS} -fPIC", CFLAGS="${CFLAGS} -fPIC", LDFLAGS="${LDFLAGS} -fPIE", LIBS="-lgomp"} -before-all = [ - "yum install doxygen -y || apt-get install doxygen -y", - "buildscripts/build_dependencies.sh -d /_dependencies -p /usr/local", -] +[tool.cibuildwheel.macos.environment] +ROOT_DIR="$(pwd)" +ARCH="$(uname -m)" +MACOSX_DEPLOYMENT_TARGET="$(sw_vers -productVersion)" +PREFIX="${ROOT_DIR}" +HOMEBREW_PREFIX="$(brew --prefix)" +LD_LIBRARY_PATH="/usr/local/lib:${PREFIX}/lib:${HOMEBREW_PREFIX}/lib" +LDFLAGS="-Wl,-rpath,${ROOT_DIR}/lib -Wl,-no_compact_unwind -L${PREFIX}/lib -L${HOMEBREW_PREFIX}/lib" +CPATH="/usr/local/include:${PREFIX}/include:${HOMEBREW_PREFIX}/include:${ROOT_DIR}/include" +CPPFLAGS="-isystem ${PREFIX}/include -isystem /usr/local/include" +LIBS="-lomp" +CFLAGS="-mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET} -Wno-deprecated-non-prototype -arch ${ARCH}" +FCFLAGS="-mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET} -arch ${ARCH}" +FFFLAGS="-mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET} -arch ${ARCH}" +HDF5_ROOT="${PREFIX}" +HDF5_LIBDIR="${HDF5_ROOT}/lib" +HDF5_INCLUDE_DIR="${HDF5_ROOT}/include" +HDF5_PLUGIN_PATH="${HDF5_LIBDIR}/plugin" +NETCDF_FORTRAN_HOME="${PREFIX}" +NETCDF_INCLUDE="${PREFIX}" +NCDIR="${PREFIX}" +NFDIR="${PREFIX}" +FC="$(command -v gfortran-12)" +CC="/usr/bin/clang" +CXX="/usr/bin/clang++" +CPP="/usr/bin/cpp" +AR="/usr/bin/ar" +NM="/usr/bin/nm" +RANLIB="/usr/bin/ranlib" [tool.cibuildwheel.macos] before-all = [ - "buildscripts/build_dependencies.sh -d ${TMPDIR} -p ${TMPDIR} -m ${MACOSX_DEPLOYMENT_TARGET}" + "brew install coreutils", + "LIBS=\"\" buildscripts/build_dependencies.sh -p ${PREFIX} -d ${TMPDIR}/swiftest.build -m ${MACOSX_DEPLOYMENT_TARGET}" ] - \ No newline at end of file +[tool.cibuildwheel.linux] +before-all = [ + "yum install doxygen libxml2-devel libcurl-devel -y", + "buildscripts/build_dependencies.sh -p /usr/local" +] +[tool.cibuildwheel.linux.environment] +NETCDF_FORTRAN_HOME="/usr/local" +NETCDF_INCLUDE="/usr/local/include" +LD_LIBRARY_PATH="/usr/local/lib:/project/lib" +CPATH="/usr/local/include:/project/include" diff --git a/requirements.txt b/requirements.txt index e8492468c..79d85b58b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,6 +4,7 @@ scipy>=1.10.1 xarray>=2022.11.0 dask>=2022.1 bottleneck>=1.3.5 +distributed>=2022.1 h5netcdf>=1.0.2 netcdf4>=1.6.2 matplotlib>=3.7.1 diff --git a/setup.py b/setup.py deleted file mode 100644 index a327a2cce..000000000 --- a/setup.py +++ /dev/null @@ -1,63 +0,0 @@ -""" - Copyright 2022 - David Minton, Carlisle Wishard, Jennifer Pouplin, Jake Elliott, & Dana Singh - This file is part of Swiftest. - Swiftest 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 3 of the License, or (at your option) any later version. - Swiftest 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 Swiftest. - If not, see: https://www.gnu.org/licenses. -""" - -from skbuild import setup -from pathlib import Path - -with open('version.txt') as version_file: - version = version_file.read().strip() - -setup(name='swiftest', - version=version, - author='David A. Minton', - author_email='daminton@purdue.edu', - url='https://github.itap.purdue.edu/MintonGroup/swiftest', - long_description=Path("README.md").read_text(encoding="utf-8"), - long_description_content_type="text/markdown", - python_requires=">=3.8", - license="GPLv3", - classifiers=[ - # How mature is this project? Common values are - # 3 - Alpha - # 4 - Beta - # 5 - Production/Stable - 'Development Status :: 3 - Alpha', - - # Indicate who your project is intended for - 'Intended Audience :: Science/Research', - 'Topic :: Scientific/Engineering :: Astronomy', - - # Pick your license as you wish (should match "license" above) - 'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)', - - # Specify the Python versions you support here. In particular, ensure - # that you indicate whether you support Python 2, Python 3 or both. - 'Programming Language :: Python :: 3', - ], - keywords='astronomy astrophysics planetary nbody integrator symplectic wisdom-holman', - install_requires= [ - 'numpy>=1.24.3', - 'scipy>=1.10.1', - 'xarray>=2022.11.0', - 'dask>=2022.1', - 'bottleneck>=1.3.5', - 'h5netcdf>=1.0.2', - 'netcdf4>=1.6.2', - 'matplotlib>=3.7.1', - 'astropy>=5.1', - 'astroquery>=0.4.6', - 'tqdm>=4.65.0', - 'cython>=3.0.0', - ], - packages=['swiftest'], - test_suite="swiftest.tests", - ) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 403336a8f..661c72cb8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -16,17 +16,9 @@ IF(NOT CMAKE_Fortran_COMPILER_SUPPORTS_F90) MESSAGE(FATAL_ERROR "Fortran compiler does not support F90") ENDIF(NOT CMAKE_Fortran_COMPILER_SUPPORTS_F90) -IF (CMAKE_Fortran_COMPILER_ID MATCHES "^Intel") - SET(COMPILER_OPTIONS "Intel" CACHE STRING "Compiler identified as Intel") -ELSEIF (CMAKE_Fortran_COMPILER_ID STREQUAL "GNU") - SET(COMPILER_OPTIONS "GNU" CACHE STRING "Compiler identified as gfortran") -ELSE () - MESSAGE(FATAL_ERROR "Compiler not recognized!") -ENDIF () - INCLUDE(SetParallelizationLibrary) INCLUDE(SetUpNetCDF) -IF (COMPILER_OPTIONS STREQUAL "Intel") +IF (COMPILER_OPTIONS STREQUAL "Intel" AND NOT CMAKE_SYSTEM_NAME STREQUAL "Windows") INCLUDE(SetMKL) ENDIF () @@ -148,7 +140,6 @@ ADD_EXECUTABLE(${SWIFTEST_DRIVER} ${DRIVER_src}) # Add the needed libraries ##################################################### # Create a library from the source files, except the driver -SET(SWIFTEST_LIBRARY swiftest) ADD_LIBRARY(${SWIFTEST_LIBRARY} ${SWIFTEST_src}) IF (NOT BUILD_SHARED_LIBS) SET_PROPERTY(TARGET ${SWIFTEST_LIBRARY} PROPERTY POSITION_INDEPENDENT_CODE) @@ -164,6 +155,11 @@ IF(USE_OPENMP OR USE_SIMD) SET_PROPERTY(TARGET ${SWIFTEST_LIBRARY} ${SWIFTEST_DRIVER} APPEND_STRING PROPERTY LINK_FLAGS "${OpenMP_Fortran_FLAGS} ") ENDIF() +IF (CMAKE_SYSTEM_NAME STREQUAL "Windows") + SET_PROPERTY(TARGET ${SWIFTEST_LIBRARY} ${SWIFTEST_DRIVER} APPEND_STRING PROPERTY LINK_FLAGS "/NODEFAULTLIB") +ENDIF() + + IF(USE_COARRAY) TARGET_COMPILE_DEFINITIONS(${SWIFTEST_LIBRARY} PUBLIC -DCOARRAY) TARGET_COMPILE_DEFINITIONS(${SWIFTEST_DRIVER} PUBLIC -DCOARRAY) @@ -172,10 +168,9 @@ IF(USE_COARRAY) ENDIF(USE_COARRAY) # Check to see if the compiler allows for local-spec in do concurrent statements. Set a preprocessor variable if it does -IF (USE_OPENMP) - SET(TESTFILE "${CMAKE_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}") - SET(TESTFILE "${TESTFILE}/CMakeTmp/testFortranDoConcurrentLoc.f90") - FILE(WRITE "${TESTFILE}" +SET(TESTFILE "${CMAKE_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}") +SET(TESTFILE "${TESTFILE}/CMakeTmp/testFortranDoConcurrentLoc.f90") +FILE(WRITE "${TESTFILE}" " program TestDoConcurrentLoc integer :: i @@ -185,12 +180,31 @@ do concurrent(i = 1:10) shared(a) end do end program TestDoConcurrentLoc ") - TRY_COMPILE(DOCONLOC_WORKS ${CMAKE_BINARY_DIR} ${TESTFILE} - COMPILE_DEFINITIONS "${CMAKE_Fortran_FLAGS}" OUTPUT_VARIABLE OUTPUT) - IF (DOCONLOC_WORKS) - TARGET_COMPILE_DEFINITIONS(${SWIFTEST_DRIVER} PRIVATE -DDOCONLOC) - ENDIF (DOCONLOC_WORKS) -ENDIF (USE_OPENMP) +TRY_COMPILE(DOCONLOC_WORKS ${CMAKE_BINARY_DIR} ${TESTFILE} COMPILE_DEFINITIONS "${CMAKE_Fortran_FLAGS}" OUTPUT_VARIABLE OUTPUT) +IF (DOCONLOC_WORKS) + MESSAGE(STATUS "DO CONCURRENT supports locality-spec") + TARGET_COMPILE_DEFINITIONS(${SWIFTEST_DRIVER} PRIVATE -DDOCONLOC) +ELSE () + MESSAGE(STATUS "DO CONCURRENT does not support locality-spec") +ENDIF (DOCONLOC_WORKS) + +# Check to see if quad precision is supported +SET(TESTFILE "${CMAKE_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}") +SET(TESTFILE "${TESTFILE}/CMakeTmp/testFortranQuadPrecisionReal.f90") +FILE(WRITE "${TESTFILE}" +" +program TestQuadPrecisionReal +integer, parameter :: QP = selected_Real_kind(30) +real(QP) :: x +end program TestQuadPrecisionReal +") +TRY_COMPILE(QUADPREC ${CMAKE_BINARY_DIR} ${TESTFILE} COMPILE_DEFINITIONS "${CMAKE_Fortran_FLAGS}" OUTPUT_VARIABLE OUTPUT) +IF (QUADPREC) + MESSAGE(STATUS "Quad precision real is supported") + TARGET_COMPILE_DEFINITIONS(${SWIFTEST_DRIVER} PRIVATE -DQUADPREC) +ELSE () + MESSAGE(STATUS "Quad precision real is not supported") +ENDIF () ##################################### diff --git a/src/coarray/coarray_clone.f90 b/src/coarray/coarray_clone.f90 index 893cff147..ea33f8544 100644 --- a/src/coarray/coarray_clone.f90 +++ b/src/coarray/coarray_clone.f90 @@ -469,6 +469,7 @@ module subroutine coarray_component_clone_lgt_arr1D(var,src_img) end subroutine coarray_component_clone_lgt_arr1D +#ifdef QUADPREC module subroutine coarray_component_clone_QP(var,src_img) !! author: David A. Minton !! @@ -503,5 +504,6 @@ module subroutine coarray_component_clone_QP(var,src_img) return end subroutine coarray_component_clone_QP +#endif end submodule s_coarray_clone \ No newline at end of file diff --git a/src/coarray/coarray_module.f90 b/src/coarray/coarray_module.f90 index b034f8786..22ce10c55 100644 --- a/src/coarray/coarray_module.f90 +++ b/src/coarray/coarray_module.f90 @@ -71,11 +71,13 @@ module subroutine coarray_component_clone_lgt_arr1D(var,src_img) integer(I4B), intent(in),optional :: src_img end subroutine coarray_component_clone_lgt_arr1D +#ifdef QUADPREC module subroutine coarray_component_clone_QP(var,src_img) implicit none real(QP), intent(inout) :: var integer(I4B), intent(in),optional :: src_img end subroutine coarray_component_clone_QP +#endif end interface diff --git a/src/globals/globals_module.f90 b/src/globals/globals_module.f90 index 309a5d14e..a12c018ce 100644 --- a/src/globals/globals_module.f90 +++ b/src/globals/globals_module.f90 @@ -24,7 +24,11 @@ module globals integer, parameter :: SP = real32 !! Symbolic name for kind types of single-precision reals integer, parameter :: DP = real64 !! Symbolic name for kind types of double-precision reals - integer, parameter :: QP = real128 !! Symbolic name for kind types of quad-precision reals +#ifdef QUADPREC + integer, parameter :: QP = selected_Real_kind(30) !! Symbolic name for kind types of quad-precision reals +#else + integer, parameter :: QP = real64 !! Stick to DP +#endif real(DP), parameter :: PIBY2 = 1.570796326794896619231321691639751442099_DP !! Definition of /(\pi / 2\) real(DP), parameter :: PI = 3.141592653589793238462643383279502884197_DP !! Definition of /(\pi\) @@ -44,7 +48,7 @@ module globals integer(I4B), parameter :: UPPERCASE_OFFSET = iachar('A') - iachar('a') !! ASCII character set parameter for lower to upper !! conversion - offset between upper and lower - character(*), parameter :: VERSION = "2023.8.0" !! Swiftest version + character(*), parameter :: VERSION = "2023.9.0" !! Swiftest version !> Symbolic name for integrator types character(*), parameter :: UNKNOWN_INTEGRATOR = "UKNOWN INTEGRATOR" diff --git a/src/globals/globals_module.f90.in b/src/globals/globals_module.f90.in index 8d107af1e..ef22ab97a 100644 --- a/src/globals/globals_module.f90.in +++ b/src/globals/globals_module.f90.in @@ -24,7 +24,11 @@ module globals integer, parameter :: SP = real32 !! Symbolic name for kind types of single-precision reals integer, parameter :: DP = real64 !! Symbolic name for kind types of double-precision reals - integer, parameter :: QP = real128 !! Symbolic name for kind types of quad-precision reals +#ifdef QUADPREC + integer, parameter :: QP = selected_Real_kind(30) !! Symbolic name for kind types of quad-precision reals +#else + integer, parameter :: QP = real64 !! Stick to DP +#endif real(DP), parameter :: PIBY2 = 1.570796326794896619231321691639751442099_DP !! Definition of /(\pi / 2\) real(DP), parameter :: PI = 3.141592653589793238462643383279502884197_DP !! Definition of /(\pi\) diff --git a/src/misc/solver_module.f90 b/src/misc/solver_module.f90 index 872db6428..81f2cab40 100644 --- a/src/misc/solver_module.f90 +++ b/src/misc/solver_module.f90 @@ -20,7 +20,9 @@ module solver interface solve_linear_system module procedure solve_linear_system_dp +#ifdef QUADPREC module procedure solve_linear_system_qp +#endif end interface interface solve_roots @@ -81,7 +83,7 @@ function solve_linear_system_dp(A,b,n,lerr) result(x) return end function solve_linear_system_dp - +#ifdef QUADPREC function solve_linear_system_qp(A,b,n,lerr) result(x) !! Author: David A. Minton !! @@ -115,7 +117,7 @@ function solve_linear_system_qp(A,b,n,lerr) result(x) return end function solve_linear_system_qp - +#endif function solve_wbs(u) result(x) ! solve with backward substitution !! Based on code available on Rosetta Code: https://rosettacode.org/wiki/Gaussian_elimination#Fortran diff --git a/src/operator/operator_cross.f90 b/src/operator/operator_cross.f90 index 72c24a176..3ca3e28cf 100644 --- a/src/operator/operator_cross.f90 +++ b/src/operator/operator_cross.f90 @@ -42,6 +42,7 @@ pure module function operator_cross_dp(A, B) result(C) return end function operator_cross_dp +#ifdef QUADPREC pure module function operator_cross_qp(A, B) result(C) implicit none real(QP), dimension(:), intent(in) :: A, B @@ -53,6 +54,7 @@ pure module function operator_cross_qp(A, B) result(C) C(3) = A(1) * B(2) - A(2) * B(1) return end function operator_cross_qp +#endif pure module function operator_cross_i1b(A, B) result(C) implicit none @@ -124,6 +126,7 @@ pure module function operator_cross_el_dp(A, B) result(C) return end function operator_cross_el_dp +#ifdef QUADPREC pure module function operator_cross_el_qp(A, B) result(C) implicit none real(QP), dimension(:,:), intent(in) :: A, B @@ -137,6 +140,7 @@ pure module function operator_cross_el_qp(A, B) result(C) end do return end function operator_cross_el_qp +#endif pure module function operator_cross_el_i1b(A, B) result(C) implicit none diff --git a/src/operator/operator_mag.f90 b/src/operator/operator_mag.f90 index 721e4a930..5c3d6538e 100644 --- a/src/operator/operator_mag.f90 +++ b/src/operator/operator_mag.f90 @@ -65,6 +65,7 @@ pure module function operator_mag_el_dp(A) result(B) return end function operator_mag_el_dp +#ifdef QUADPREC pure module function operator_mag_el_qp(A) result(B) implicit none real(QP), dimension(:,:), intent(in) :: A @@ -79,6 +80,7 @@ pure module function operator_mag_el_qp(A) result(B) end do return end function operator_mag_el_qp +#endif end submodule s_operator_mag diff --git a/src/operator/operator_module.f90 b/src/operator/operator_module.f90 index 8c351236b..93879117a 100644 --- a/src/operator/operator_module.f90 +++ b/src/operator/operator_module.f90 @@ -37,12 +37,14 @@ pure module function operator_cross_dp(A, B) result(C) real(DP), dimension(NDIM) :: C end function operator_cross_dp +#ifdef QUADPREC pure module function operator_cross_qp(A, B) result(C) !$omp declare simd(operator_cross_qp) implicit none real(QP), dimension(:), intent(in) :: A, B real(QP), dimension(NDIM) :: C end function operator_cross_qp +#endif pure module function operator_cross_i1b(A, B) result(C) !$omp declare simd(operator_cross_i1b) @@ -84,11 +86,13 @@ pure module function operator_cross_el_dp(A, B) result(C) real(DP), dimension(:,:), allocatable :: C end function operator_cross_el_dp +#ifdef QUADPREC pure module function operator_cross_el_qp(A, B) result(C) implicit none real(QP), dimension(:,:), intent(in) :: A, B real(QP), dimension(:,:), allocatable :: C end function operator_cross_el_qp +#endif pure module function operator_cross_el_i1b(A, B) result(C) implicit none @@ -134,13 +138,14 @@ pure module function operator_mag_dp(A) result(B) real(DP) :: B end function operator_mag_dp +#ifdef QUADPREC pure module function operator_mag_qp(A) result(B) !$omp declare simd(operator_mag_qp) implicit none real(QP), dimension(:), intent(in) :: A real(QP) :: B end function operator_mag_qp - +#endif pure module function operator_mag_el_sp(A) result(B) implicit none real(SP), dimension(:,:), intent(in) :: A @@ -153,11 +158,14 @@ pure module function operator_mag_el_dp(A) result(B) real(DP), dimension(:), allocatable :: B end function operator_mag_el_dp +#ifdef QUADPREC pure module function operator_mag_el_qp(A) result(B) implicit none real(QP), dimension(:,:), intent(in) :: A real(QP), dimension(:), allocatable :: B end function operator_mag_el_qp +#endif + end interface @@ -180,12 +188,14 @@ pure module function operator_unit_dp(A) result(B) real(DP), dimension(NDIM) :: B end function operator_unit_dp +#ifdef QUADPREC pure module function operator_unit_qp(A) result(B) !$omp declare simd(operator_unit_qp) implicit none real(QP), dimension(:), intent(in) :: A real(QP), dimension(NDIM) :: B end function operator_unit_qp +#endif pure module function operator_unit_el_sp(A) result(B) implicit none @@ -199,11 +209,13 @@ pure module function operator_unit_el_dp(A) result(B) real(DP), dimension(:,:), allocatable :: B end function operator_unit_el_dp +#ifdef QUADPREC pure module function operator_unit_el_qp(A) result(B) implicit none real(QP), dimension(:,:), intent(in) :: A real(QP), dimension(:,:), allocatable :: B end function operator_unit_el_qp +#endif end interface diff --git a/src/operator/operator_unit.f90 b/src/operator/operator_unit.f90 index 2a14f6645..067df74eb 100644 --- a/src/operator/operator_unit.f90 +++ b/src/operator/operator_unit.f90 @@ -56,7 +56,7 @@ pure module function operator_unit_dp(A) result(B) return end function operator_unit_dp - +#ifdef QUADPREC pure module function operator_unit_qp(A) result(B) implicit none ! Arguments @@ -75,7 +75,7 @@ pure module function operator_unit_qp(A) result(B) return end function operator_unit_qp - +#endif pure module function operator_unit_el_sp(A) result(B) implicit none @@ -116,6 +116,7 @@ pure module function operator_unit_el_dp(A) result(B) return end function operator_unit_el_dp +#ifdef QUADPREC pure module function operator_unit_el_qp(A) result(B) implicit none ! Arguments @@ -134,6 +135,7 @@ pure module function operator_unit_el_qp(A) result(B) return end function operator_unit_el_qp +#endif end submodule s_operator_unit diff --git a/src/swiftest/swiftest_io.f90 b/src/swiftest/swiftest_io.f90 index 9eb3bed2c..9a8095116 100644 --- a/src/swiftest/swiftest_io.f90 +++ b/src/swiftest/swiftest_io.f90 @@ -2774,7 +2774,7 @@ module subroutine swiftest_io_param_writer_one_logical(param_name, param_value, return end subroutine swiftest_io_param_writer_one_logical - +#ifdef QUADPREC module subroutine swiftest_io_param_writer_one_QP(param_name, param_value, unit) !! author: David A. Minton !! @@ -2794,7 +2794,7 @@ module subroutine swiftest_io_param_writer_one_QP(param_name, param_value, unit) return end subroutine swiftest_io_param_writer_one_QP - +#endif module subroutine swiftest_io_read_in_body(self, param) !! author: The Purdue Swiftest Team - David A. Minton, Carlisle A. Wishard, Jennifer L.L. Pouplin, and Jacob R. Elliott diff --git a/src/swiftest/swiftest_module.f90 b/src/swiftest/swiftest_module.f90 index 7437c49bc..acddf4d04 100644 --- a/src/swiftest/swiftest_module.f90 +++ b/src/swiftest/swiftest_module.f90 @@ -850,12 +850,14 @@ module subroutine swiftest_io_param_writer_one_logical(param_name, param_value, integer(I4B), intent(in) :: unit !! Open file unit number to print parameter to end subroutine swiftest_io_param_writer_one_logical +#ifdef QUADPREC module subroutine swiftest_io_param_writer_one_QP(param_name, param_value, unit) implicit none character(len=*), intent(in) :: param_name !! Name of parameter to print real(QP), intent(in) :: param_value !! Value of parameter to print integer(I4B), intent(in) :: unit !! Open file unit number to print parameter to end subroutine swiftest_io_param_writer_one_QP +#endif end interface io_param_writer_one interface diff --git a/src/swiftest/swiftest_util.f90 b/src/swiftest/swiftest_util.f90 index 6659bf69e..94813be38 100644 --- a/src/swiftest/swiftest_util.f90 +++ b/src/swiftest/swiftest_util.f90 @@ -3331,22 +3331,22 @@ module subroutine swiftest_util_version() !! Adapted from David E. Kaufmann's Swifter routine: util_version.f90 implicit none write(*, 200) VERSION - 200 format(/, "************* Swiftest: Version ", f3.1, " *************", //, & - "Based off of Swifter:", //, & - "Authors:", //, & - " The Purdue University Swiftest Development team ", /, & - " Lead by David A. Minton ", /, & - " Carlisle Wishard, Jennifer Pouplin, Jacob Elliott, Dana Singh." & - "Please address comments and questions to:", //, & - " David A. Minton", /, & - " Department Earth, Atmospheric, & Planetary Sciences ",/, & - " Purdue University", /, & - " 550 Stadium Mall Drive", /, & - " West Lafayette, Indiana 47907", /, & - " 765-250-8034 ", /, & - " daminton@purdue.edu", /, & - "Special thanks to Hal Levison and Martin Duncan for the original",/,& - "SWIFTER and SWIFT codes that made this possible.", //, & + 200 format(/, "************* Swiftest: Version ", f3.1, " *************",/, & + "Based off of Swifter:",/, & + "Authors:",/, & + " The Purdue University Swiftest Development team ",/, & + " Lead by David A. Minton ",/, & + " Carlisle Wishard, Jennifer Pouplin, Jacob Elliott, Dana Singh.",/,& + "Please address comments and questions to:",/, & + " David A. Minton",/, & + " Department Earth, Atmospheric, & Planetary Sciences ",/, & + " Purdue University",/, & + " 550 Stadium Mall Drive",/, & + " West Lafayette, Indiana 47907", /, & + " 765-494-3292 ",/, & + " daminton@purdue.edu",/, & + "Special thanks to Hal Levison, Martin Duncan, and David Kaufmann",/, & + "for the original SWIFTER and SWIFT codes that made this possible.",/, & "************************************************", /) diff --git a/swiftest/CMakeLists.txt b/swiftest/CMakeLists.txt index 9a73977af..6bdf332d1 100644 --- a/swiftest/CMakeLists.txt +++ b/swiftest/CMakeLists.txt @@ -33,11 +33,11 @@ ADD_LIBRARY(${SWIFTEST_BINDINGS} MODULE ${SWIFTEST_BINDINGS}) IF (NOT BUILD_SHARED_LIBS) SET_PROPERTY(TARGET ${SWIFTEST_BINDINGS} PROPERTY POSITION_INDEPENDENT_CODE) ENDIF () + +TARGET_LINK_LIBRARIES(${SWIFTEST_BINDINGS} ${SWIFTEST_LIBRARY} ${NETCDF_LIBRARIES}) IF(USE_OPENMP OR USE_SIMD) - SET_PROPERTY(TARGET ${SWIFTEST_BINDINGS} APPEND_STRING PROPERTY COMPILE_FLAGS "${OpenMP_Fortran_FLAGS} ") + SET_PROPERTY(TARGET ${SWIFTEST_BINDINGS} APPEND_STRING PROPERTY LINK_FLAGS "${OpenMP_Fortran_FLAGS} ") ENDIF() - -TARGET_LINK_LIBRARIES(${SWIFTEST_BINDINGS} swiftest ${NETCDF_LIBRARIES}) PYTHON_EXTENSION_MODULE(${SWIFTEST_BINDINGS}) TARGET_INCLUDE_DIRECTORIES(${SWIFTEST_BINDINGS} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${MOD} ${NETCDF_INCLUDE_DIR}) INSTALL(TARGETS ${SWIFTEST_BINDINGS} LIBRARY DESTINATION swiftest) \ No newline at end of file diff --git a/version.txt b/version.txt index a4fb2c126..882e30299 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -2023.8.0 \ No newline at end of file +2023.9.0 \ No newline at end of file