diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index e69de29..0000000 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 4eb9cce..0000000 --- a/.travis.yml +++ /dev/null @@ -1,40 +0,0 @@ -language: c - -sudo: required - -before_install: - - sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test - - sudo apt-get update -qq - -install: - - sudo apt-get install -qq gfortran-7 - - sudo update-alternatives --install /usr/bin/gfortran gfortran /usr/bin/gfortran-7 90 - - sudo apt install git - - sudo apt install cmake - - sudo git clone https://github.com/Reference-LAPACK/lapack.git - - pushd lapack - - sudo mkdir build - - pushd build - - sudo cmake -DCMAKE_INSTALL_LIBDIR=$HOME/.local/lapack .. - - sudo cmake - - sudo make - - sudo make install - - popd - - popd - - sudo git clone https://github.com/jchristopherson/ferror.git - - pushd ferror - - sudo mkdir build - - pushd build - - sudo cmake -DCMAKE_INSTALL_LIBDIR=$HOME/.local/ferror .. - - sudo cmake - - sudo make - - sudo make install - - popd - - popd - -before_script: - - mkdir build - - cd build - - cmake .. - -script: make diff --git a/CMakeLists.txt b/CMakeLists.txt index 8fc2190..46becbd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,128 +1,54 @@ # Master CMAKE Build Script -cmake_minimum_required(VERSION 3.7) -project(linalg C CXX Fortran) +cmake_minimum_required(VERSION 3.17) +project( + linalg + LANGUAGES Fortran C + VERSION 1.7.0 +) -# Define version information -set(linalg_VERSION_MAJOR 1) -set(linalg_VERSION_MINOR 6) -set(linalg_VERSION_PATCH 0) -set(linalg_VERSION ${linalg_VERSION_MAJOR}.${linalg_VERSION_MINOR}.${linalg_VERSION_PATCH}) +# Utilize the GNU installation structure +include(GNUInstallDirs) -# Set a default build type if none was specified -if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - message(STATUS "Setting build type to 'Debug' as none was specified.") - set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE) - # Set the possible values of build type for cmake-gui - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release") -endif() - -# By default, shared library -option(BUILD_SHARED_LIBS "Build shared libraries" OFF) - -# Get compiler info -get_filename_component (Fortran_COMPILER_NAME ${CMAKE_Fortran_COMPILER} NAME) +# Get helper macros and functions +include("${PROJECT_SOURCE_DIR}/cmake/helper.cmake") -# Export all symbols on Windows when building shared libraries -SET(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE) - -# Locate the module files -set(CMAKE_Fortran_MODULE_DIRECTORY ${PROJECT_SOURCE_DIR}/include) - -# Define output directories, if undefined -if (NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY) - message(STATUS "LINALG output directories undefined. Using default directories.") - if (CMAKE_BUILD_TYPE MATCHES Debug) - # Debug Build - message(STATUS "LINALG: Debug Build") - if (BUILD_SHARED_LIBS) - message(STATUS "LINALG: Build shared library") - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin/Debug) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin/Debug) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin/Debug) - else() - message(STATUS "LINALG: Build static library") - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib/Debug) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib/Debug) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib/Debug) - endif () - elseif (CMAKE_BUILD_TYPE MATCHES Release) - # Release Build - message(STATUS "LINALG: Release Build") - if (BUILD_SHARED_LIBS) - message(STATUS "LINALG: Build shared library") - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin/Release) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin/Release) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin/Release) - else() - message(STATUS "LINALG: Build static library") - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib/Release) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib/Release) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib/Release) - endif () - else () - # Default Condition - if (BUILD_SHARED_LIBS) - message(STATUS "LINALG: Build shared library") - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin/Debug) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin/Debug) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin/Debug) - else() - message(STATUS "LINALG: Build static library") - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib/Debug) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib/Debug) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib/Debug) - endif () - endif () -endif() +# Confgiure everything +add_subdirectory(configure) -# FFLAGS depend on the compiler -if (Fortran_COMPILER_NAME MATCHES "gfortran.*") - # gfortran - set(CMAKE_Fortran_FLAGS_RELEASE "-funroll-all-loops -fno-f2c -O3 -Wl,--allow-multiple-definition") - set(CMAKE_Fortran_FLAGS_DEBUG "-fno-f2c -O0 -g -Wall -Wno-c-binding-type -Wl,--allow-multiple-definition") -elseif (Fortran_COMPILER_NAME MATCHES "ifort.*") - # ifort (untested) - set(CMAKE_Fortran_FLAGS_RELEASE "-f77rtl -O3") - set(CMAKE_Fortran_FLAGS_DEBUG "-f77rtl -O0 -g") -else (Fortran_COMPILER_NAME MATCHES "gfortran.*") - message ("CMAKE_Fortran_COMPILER full path: " ${CMAKE_Fortran_COMPILER}) - message ("Fortran compiler: " ${Fortran_COMPILER_NAME}) - message ("No optimized Fortran compiler flags are known, we just try -O2...") - set(CMAKE_Fortran_FLAGS_RELEASE "-O2 -Wl,--allow-multiple-definition") - set(CMAKE_Fortran_FLAGS_DEBUG "-O0 -g -Wall -Wl,--allow-multiple-definition") -endif() - -# What else to build -option(BUILD_LINALG_EXAMPLES "Build LINALG examples?" OFF) -option(BUILD_LINALG_TESTS "Build LINALG tests?" OFF) - -# Locate the dependencies +# Deal with the dependencies find_package(BLAS) find_package(LAPACK) -find_package(ferror 1.3.0) - -if (BLAS_FOUND) - message(STATUS "BLAS library found.") -endif() +find_package(ferror 1.4.0 QUIET) +add_subdirectory(dependencies) -if (LAPACK_FOUND) - message(STATUS "LAPACK library found.") -endif() - -if (ferror_FOUND) - message(STATUS "FERROR library found.") - set(ferror_LIBRARIES ferror) -endif() - -# Locate the files +# Source add_subdirectory(src) +add_fortran_library( + ${PROJECT_NAME} + ${PROJECT_INCLUDE_DIR} + ${CMAKE_INSTALL_INCLUDEDIR} + ${PROJECT_VERSION} + ${PROJECT_VERSION_MAJOR} + ${LINALG_SOURCES} +) +target_link_libraries(${PROJECT_NAME} ${BLAS_LIBRARIES} ${LAPACK_LIBRARIES}) +link_library(${PROJECT_NAME} ${ferror_LIBRARY} ${ferror_INCLUDE_DIR}) + +# Installation +add_subdirectory(install) + +# Testing +option(BUILD_TESTING "Build tests") +include(CTest) +message(STATUS "Build tests: ${BUILD_TESTING}") +if (BUILD_TESTING) + enable_testing() + add_subdirectory(tests) +endif() +# Examples +option(BUILD_LINALG_EXAMPLES "Build LINALG examples") +message(STATUS "Build LINALG examples: ${BUILD_LINALG_EXAMPLES}") if (BUILD_LINALG_EXAMPLES) - message(STATUS "Building LINALG examples.") add_subdirectory(examples) -endif() - -if (BUILD_LINALG_TESTS) - message(STATUS "Building LINALG tests.") - add_subdirectory(tests) -endif() +endif() \ No newline at end of file diff --git a/README.md b/README.md index 113cd0f..b8788e3 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,13 @@ # linalg A linear algebra library that provides a user-friendly interface to several BLAS and LAPACK routines. The examples below provide an illustration of just how simple it is to perform a few common linear algebra operations. -## Status -![Build Status](https://travis-ci.org/jchristopherson/linalg.svg?branch=master) - ## Example 1 This example solves a normally defined system of 3 equations of 3 unknowns. ```fortran program example use iso_fortran_env - use linalg_core + use linalg implicit none ! Local Variables @@ -61,7 +58,7 @@ This example solves an overdefined system of 3 equations of 2 uknowns. ```fortran program example use iso_fortran_env - use linalg_core + use linalg implicit none ! Local Variables @@ -120,7 +117,7 @@ This example computes the eigenvalues and eigenvectors of a mechanical system co ! Notice: x1" = the second time derivative of x1. program example use iso_fortran_env - use linalg_core + use linalg implicit none ! Define the model parameters diff --git a/cmake/helper.cmake b/cmake/helper.cmake new file mode 100644 index 0000000..ce2ea3e --- /dev/null +++ b/cmake/helper.cmake @@ -0,0 +1,75 @@ +# helper.cmake +# +# A collection of macros and functions making life with CMake and Fortran a +# bit simpler. + +# Use to include and export headers +function(include_headers lib dir install_dir) + target_include_directories( + ${lib} + INTERFACE + $ + $ + ) +endfunction() + +# Use instead of add_library. +function(add_fortran_library lib_name mod_dir include_install_dir version major) + add_library(${lib_name} ${ARGN}) + set_target_properties( + ${lib_name} + PROPERTIES + POSITION_INDEPENDENT_CODE TRUE + OUTPUT_NAME ${lib_name} + VERSION ${version} + SOVERSION ${major} + Fortran_MODULE_DIRECTORY ${include_install_dir} + ) + target_include_directories( + ${lib_name} + PUBLIC + $ + $ + ) +endfunction() + +# Installs the library +function(install_library lib_name lib_install_dir bin_install_dir mod_dir install_dir) + install( + TARGETS ${lib_name} + EXPORT ${lib_name}Targets + RUNTIME DESTINATION ${bin_install_dir} + LIBRARY DESTINATION ${lib_install_dir} + ARCHIVE DESTINATION ${lib_install_dir} + INCLUDES DESTINATION ${install_dir}/include + ) + install( + DIRECTORY ${mod_dir} + DESTINATION ${install_dir} + ) +endfunction() + +# Install the documentation files +function(install_documentation doc_dir install_dir) + install( + DIRECTORY ${doc_dir} + DESTINATION ${install_dir} + ) +endfunction() + +# Links the supplied library +function(link_library targ lib include_dir) + target_link_libraries(${targ} ${lib}) + target_include_directories(${targ} PUBLIC ${include_dir}) +endfunction() + +# ------------------------------------------------------------------------------ +# Helpful Macros +macro(print_all_variables) + message(STATUS "---------- CURRENTLY DEFINED VARIABLES -----------") + get_cmake_property(varNames VARIABLES) + foreach(varName ${varNames}) + message(STATUS ${varName} = ${${varName}}) + endforeach() + message(STATUS "---------- END ----------") +endmacro() \ No newline at end of file diff --git a/configure/CMakeLists.txt b/configure/CMakeLists.txt new file mode 100644 index 0000000..f114e3c --- /dev/null +++ b/configure/CMakeLists.txt @@ -0,0 +1,23 @@ +# Get the macros and functions we'll need +include("${PROJECT_SOURCE_DIR}/cmake/helper.cmake") + +# Set a default build type if none was specified +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + message(STATUS "Setting build type to 'Release' as none was specified.") + set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE) + # Set the possible values of build type for cmake-gui + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release") +endif() + +# By default, static library +option(BUILD_SHARED_LIBS "Build shared libraries" OFF) + +# Export all symbols on Windows when building libraries +set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE) + +# Utilize the GNU installation structure +include(GNUInstallDirs) + +# Locate the local include directory +set(PROJECT_INCLUDE_DIR ${PROJECT_BINARY_DIR}/include) +set(PROJECT_INCLUDE_DIR ${PROJECT_INCLUDE_DIR} PARENT_SCOPE) \ No newline at end of file diff --git a/dependencies/BLAS/CMakeLists.txt b/dependencies/BLAS/CMakeLists.txt new file mode 100644 index 0000000..9426e0d --- /dev/null +++ b/dependencies/BLAS/CMakeLists.txt @@ -0,0 +1,7 @@ +# If found, use the installed version; else, import the library +if (${BLAS_FOUND}) + # Inform the user of what's going on + message(STATUS "BLAS library found.") +else() + message(STATUS "BLAS library not found. The reference BLAS will be used.") +endif() \ No newline at end of file diff --git a/dependencies/CMakeLists.txt b/dependencies/CMakeLists.txt new file mode 100644 index 0000000..f2d36e5 --- /dev/null +++ b/dependencies/CMakeLists.txt @@ -0,0 +1,14 @@ +# Get the macros and functions we'll need +include("${PROJECT_SOURCE_DIR}/cmake/helper.cmake") +include(FetchContent) + +# Get BLAS +add_subdirectory(BLAS) + +# Get LAPACK +add_subdirectory(LAPACK) + +# Get FERROR +add_subdirectory(ferror) +set(ferror_LIBRARY ${ferror_LIBRARY} PARENT_SCOPE) +set(ferror_INCLUDE_DIR ${ferror_INCLUDE_DIR} PARENT_SCOPE) diff --git a/dependencies/LAPACK/CMakeLists.txt b/dependencies/LAPACK/CMakeLists.txt new file mode 100644 index 0000000..fe64388 --- /dev/null +++ b/dependencies/LAPACK/CMakeLists.txt @@ -0,0 +1,27 @@ +# If found, use the installed version; else, import the library +if (${LAPACK_FOUND}) + # Inform the user of what's going on + message(STATUS "LAPACK library found.") +else() + # Inform the user of what's going on + message(STATUS "LAPACK not found. Downloading the reference LAPACK.") + + # Fetch the proper content + FetchContent_Declare( + LAPACK + GIT_REPOSITORY "https://github.com/Reference-LAPACK/lapack" + ) + + FetchContent_MakeAvailable(LAPACK) + + if (WIN32) + if (BUILD_SHARED_LIBS) + add_custom_command( + TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + $ + $ + $