diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 48a1ca30b..df76dfeba 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -18,10 +18,11 @@ env: CONAN_REVISIONS_ENABLED: 1 OMP_NUM_THREADS: 2 CONAN_CPU_COUNT: 2 + USE_CONAN: 0 jobs: make-documentation: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - name: Check out sopt uses: actions/checkout@v3 @@ -42,13 +43,25 @@ jobs: - name: Install dependencies run: | sudo apt update - sudo apt install openmpi-bin libopenmpi-dev libyaml-cpp-dev doxygen graphviz + sudo apt install openmpi-bin libopenmpi-dev libyaml-cpp-dev doxygen graphviz ccache + if [[ "$USE_CONAN" = 0 ]]; then + sudo apt install libeigen3-dev libspdlog-dev libtiff-dev + git clone https://github.com/catchorg/Catch2.git -b v3.4.0 + mkdir Catch2/build + cd Catch2/build + cmake .. -DBUILD_TESTING=OFF -DCMAKE_INSTALL_PREFIX=${PWD} + make -j$(nproc --ignore 1) + make -j$(nproc --ignore 1) install + cd - + fi - name: Install Conan id: conan + if: env.USE_CONAN != '0' uses: turtlebrowser/get-conan@main with: - version: 1.59.0 + version: 1.60.2 + #version: 2.0.9 - name: Install Tensorflow API on Ubuntu uses: UCL/install-tensorflow-action@main @@ -64,20 +77,52 @@ jobs: ref: master - name: Create cppflow package - run: conan create ./cppflow/ -pr:h=default -pr:b=default + run: | + if [[ "$USE_CONAN" = 1 ]]; then + #conan profile detect + #sed -i'' -e "s|generators|#generators|1" ./cppflow/conanfile.py + conan create ./cppflow/ -pr:h=default -pr:b=default + else + mkdir cppflow/build + cd cppflow/build + cmake .. -DCMAKE_INSTALL_PREFIX=${PWD} + make -j$(nproc --ignore 1) + make -j$(nproc --ignore 1) install + fi - name: Configure run: | - conan install doxygen/1.9.4@#2af713e135f12722e3536808017ba086 --update - conan install ${{github.workspace}} -if ${{github.workspace}}/build --build missing -s compiler.libcxx=libstdc++11 -o mpi=off -o openmp=off -o docs=on -o cppflow=on -pr:h=default -pr:b=default + if [[ "$USE_CONAN" = 1 ]]; then + # Doxygen currently broken in Conan v1 and v2 + #conan install doxygen/1.9.4@#2af713e135f12722e3536808017ba086 --update + conan install ${{github.workspace}} -if ${{github.workspace}}/build --build missing -s compiler.libcxx=libstdc++11 -o mpi=off -o openmp=off -o docs=off -o cppflow=on -pr:h=default -pr:b=default + else + export PATH=${{github.workspace}}/cppflow/build:$PATH + export PATH=${{github.workspace}}/Catch2/build:$PATH + export CMAKE_PREFIX_PATH=${{github.workspace}}/Catch2/build/lib/cmake/Catch2:$CMAKE_PREFIX_PATH + mkdir ${{github.workspace}}/build + cd ${{github.workspace}}/build + cmake .. -DCMAKE_INSTALL_PREFIX=${PWD} -Ddompi=OFF -Dopenmp=OFF -Ddocs=ON -Dcppflow=ON + fi - name: Build - run: conan build ${{github.workspace}} -bf ${{github.workspace}}/build + run: | + if [[ "$USE_CONAN" = 1 ]]; then + conan build ${{github.workspace}} -bf ${{github.workspace}}/build + else + export PATH=${{github.workspace}}/cppflow/build:$PATH + export PATH=${{github.workspace}}/Catch2/build:$PATH + cd ${{github.workspace}}/build + make -j$(nproc --ignore 1) + make -j$(nproc --ignore 1) install + fi - name: Make Docweb run: | - cd build - make docweb VERBOSE=1 + if [[ "$USE_CONAN" = 0 ]]; then + cd build + make docweb VERBOSE=1 + fi - name: Deploy to GH pages if: ${{github.event_name == 'push'}} diff --git a/.gitignore b/.gitignore index 39af8ca9e..c92725f45 100644 --- a/.gitignore +++ b/.gitignore @@ -82,6 +82,7 @@ python/tests/__pycache__ *~ ### CMake ### +CMakeUserPresets.json CMakeLists.txt.user CMakeCache.txt CMakeFiles @@ -93,6 +94,7 @@ install_manifest.txt compile_commands.json CTestTestfile.cmake _deps +local # CMake External projects (created by CMake fetchcontent module) *-prefix/ @@ -129,4 +131,4 @@ _deps # Executables *.exe *.out -*.app \ No newline at end of file +*.app diff --git a/CMakeLists.txt b/CMakeLists.txt index eae7a238a..c021eee59 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ if(PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR) message(FATAL_ERROR "In-source builds are not allowed!\nCreate a \"build\" dir and remove:\n- ${CMAKE_SOURCE_DIR}/CMakeCache.txt\n- ${CMAKE_SOURCE_DIR}/CMakeFiles") endif() -project(Sopt +project(sopt DESCRIPTION "Sparse OPTimisation using state-of-the-art convex optimisation algorithms." HOMEPAGE_URL "http://astro-informatics.github.io/sopt/" LANGUAGES CXX) @@ -28,14 +28,33 @@ execute_process( # Location of extra cmake includes for the project list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake_files) list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/build) -# Downloads and installs GreatCMakeCookOff -# It contains a number of cmake recipes -include(LookUp-GreatCMakeCookOff) # Version and git hash id -include(VersionAndGitRef) -set_version(3.1.0) -get_gitref() +find_package(Git) + +# Set version variable +set(SOPT_VERSION 3.1.0) + +# If git is found and this is a git workdir, then figure out build id +# Stores results in SOPT_VERSION and SOPT_GITREF +if(GIT_FOUND) + execute_process( + COMMAND ${GIT_EXECUTABLE} rev-parse HEAD + RESULT_VARIABLE HASH_RESULT + OUTPUT_VARIABLE GIT_HASH + ERROR_QUIET + ) + if(HASH_RESULT EQUAL 0) + string(STRIP "${GIT_HASH}" GIT_HASH) + else() + set(GIT_HASH "NA") + endif() +else() + set(GIT_HASH "NA") +endif() + +set(SOPT_GITREF ${GIT_HASH}) + option(tests "Enable testing" on) option(benchmarks "Enable benchmarking" off) @@ -53,7 +72,7 @@ if(NOT CMAKE_BUILD_TYPE) endif() message(STATUS "Building sopt in ${CMAKE_BUILD_TYPE} mode") -if(tests) +if(tests OR examples) enable_testing() endif() @@ -75,14 +94,11 @@ if(SOPT_MPI) DetectIntegerArchitecture(SOPT) endif() -if(tests OR examples) - enable_testing() -endif() - if(tests) - find_package(Catch) + find_package(Catch2) include(AddCatchTest) endif() + if(examples) include(AddExample) endif() @@ -92,6 +108,8 @@ if(benchmarks) include(AddBenchmark) endif() +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-command-line-argument") + if(tests AND coverage) # Enable code coverage. set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage") @@ -107,3 +125,4 @@ add_subdirectory(cpp) # Exports all Sopt so other packages can access it include(export_sopt) + diff --git a/README.md b/README.md index 360066c67..d4b846cc7 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,10 @@ -Sparse OPTimisation Library -=========================== +# Sparse OPTimisation Library [![build](https://github.com/astro-informatics/sopt/actions/workflows/cmake.yml/badge.svg?branch=development)](https://github.com/astro-informatics/sopt/actions/workflows/cmake.yml?query=branch%3Adevelopment+) [![codecov](https://codecov.io/gh/astro-informatics/sopt/branch/development/graph/badge.svg)](https://codecov.io/gh/astro-informatics/sopt) [![DOI](http://img.shields.io/badge/DOI-10.5281/zenodo.2584256-blue.svg?style=flat)](https://doi.org/10.5281/zenodo.2584256) -Description -------------- +## Description **SOPT** is an open-source `C++` package available under the [license](#license) below. It performs Sparse OPTimisation using state-of-the-art convex optimisation algorithms. It solves a variety of sparse regularisation problems, including the Sparsity Averaging Reweighted Analysis (SARA) algorithm. @@ -18,34 +16,31 @@ Description This documentation outlines the necessary and optional [dependencies](#dependencies-installation) upon which **SOPT** should be built, before describing [installation](#installing-and-building-SOPT) and [testing](#testing) details and [Matlab](#Matlab) support. [Contributors](#contributors), [references](#references-and-citation) and [license](#license) information then follows. -Dependencies installation -------------------------- +## Dependencies installation -**SOPT** is mostly written in `C++11`. Pre-requisites and dependencies are listed in following and minimal versions required are tested against `Travis CI` meaning that they come natively with OSX and the Ubuntu Trusty release. These are also the default ones fetched by `CMake`. +**SOPT** is mostly written in `C++17`. Pre-requisites and dependencies are listed in following and minimal versions required are tested against `Travis CI` meaning that they come natively with OSX and the Ubuntu Trusty release. These are also the default ones fetched by `CMake`. `C++` minimal dependencies: - [CMake](http://www.cmake.org/) v3.9.2 A free software that allows cross-platform compilation. - [GCC](https://gcc.gnu.org) v7.3.0 GNU compiler for `C++`. -- [UCL/GreatCMakeCookOff](https://github.com/UCL/GreatCMakeCookOff) Collection of `CMake` recipes. Downloaded automatically if absent. - [OpenMP](http://openmp.org/wp/) v4.8.4 (Trusty) - Optional - Speeds up some of the operations. -- [Cppflow](https://github.com/UCL/cppflow) - Optional - A warpper for the Tensorflow C API allowing us to read Tensorflow models into SOPT. Needed if you are using a learned prior. -- [Conan](https://docs.conan.io/en/latest/installation.html) - C++ package manager which installs the following: - - [Eigen3](http://eigen.tuxfamily.org/index.php?title=Main_Page) v3.2.0 (Trusty) Modern `C++` linear algebra. Downloaded automatically if absent. - - [spdlog](https://github.com/gabime/spdlog) v* - Optional - Logging library. Downloaded automatically if - absent. - - [Catch2](https://github.com/catchorg/Catch2) v2.2.3 - Optional - A `C++` - unit-testing framework only needed for testing. Downloaded automatically if absent. - - [google/benchmark](https://github.com/google/benchmark) - Optional - A `C++` - micro-benchmarking framework only needed for benchmarks. Downloaded automatically if absent. - - [tiff](http://www.libtiff.org/) v4.0.3 (Trusty) Tag Image File Format library - only installed if needed. +- [Cppflow](https://github.com/UCL/cppflow) v2.0.0 - Optional - A warpper for the Tensorflow C API allowing us to read Tensorflow models into SOPT. Needed if you are using a learned prior. +- [Eigen3](http://eigen.tuxfamily.org/index.php?title=Main_Page) v3.4.0 (Trusty) Modern `C++` linear algebra. Downloaded automatically if absent. +- [spdlog](https://github.com/gabime/spdlog) v1.12.0 - Optional - Logging library. Downloaded automatically if + absent. +- [Catch2](https://github.com/catchorg/Catch2) v3.4.0 - Optional - A `C++` + unit-testing framework only needed for testing. Downloaded automatically if absent. +- [google/benchmark](https://github.com/google/benchmark) - Optional - A `C++` + micro-benchmarking framework only needed for benchmarks. Downloaded automatically if absent. +- [tiff](http://www.libtiff.org/) v4.5.1 (Trusty) Tag Image File Format library - only installed if needed. -Installing and building SOPT ----------------------------- - -You can build **SOPT** entirely from the source code. +## Installing and building SOPT +### Using Conan v2 (recommended) +[Conan](https://docs.conan.io/en/latest/installation.html) is a C++ package manager that helps deal with most of the C++ dependencies +as well as the **SOPT** installation: 1. If you are using a learned prior you must install the Tensorflow C API and `cppflow` package: - Install [TensorFlow C API](https://www.tensorflow.org/install/lang_c) @@ -53,10 +48,11 @@ You can build **SOPT** entirely from the source code. ``` bash git clone git@github.com:UCL/cppflow.git - conan create ./cppflow/ -pr:h=default -pr:b=default + conan create ./cppflow/ ``` Note that conan requires you to specify the host (h) and the build (b) profiles on the command - line (`-pr:h=default -pr:b=default`), if you haven't defined them in your conan profile. + line (`-pr:h=default -pr:b=default`), unless you have defined them in your conan profile. + You can set up a default profile for your system using `conan profile detect` (only needs to be done once). 1. Once the mandatory dependencies are present, `git clone` from the [GitHub repository](https://github.com/astro-informatics/sopt): @@ -70,17 +66,20 @@ You can build **SOPT** entirely from the source code. cd /path/to/code mkdir build cd build - conan install .. --build missing -pr:h=default -pr:b=default - conan build .. + conan install .. -of . --build missing + conan build .. -of . ``` - - To install in directory `INSTALL_FOLDER`, add the following options to the conan build command: +Things to note: - ``` bash - conan build .. -bf INSTALL_FOLDER -if . - ``` +- To install in directory `INSTALL_FOLDER`, add the following options to the conan build command: + + ``` bash + conan build .. -of INSTALL_FOLDER + ``` - - CMake build options should be passed as options to `conan install` using the `-o` flag with a value `on` or `off`. Possible options are +- CMake build options should be passed as options to `conan install` using the `-o` flag with a value `on` or `off`. +Possible options are: - tests (default on) - benchmarks (default off) @@ -90,28 +89,53 @@ You can build **SOPT** entirely from the source code. - mpi (default on) - docs (default off) - coverage (default off) - - cppflow (default off) + - cppflow (default off) - For example, to build with both MPI and OpenMP off you would use +For example, to build with both MPI and OpenMP off you would use - ``` bash - conan install .. --build missing -o openmp=off -o mpi=off -pr:h=default -pr:b=default - conan build .. - ``` +``` bash +conan install .. -of . --build missing -o openmp=off -o mpi=off -pr:h=default -pr:b=default +conan build .. -of . +``` -Common errors -------- + +### Using CMake + +If the dependencies are already available on your system, you can also install **SOPT** manually like so + + ``` bash + cd /path/to/code + mkdir build + cd build + cmake .. -DCMAKE_INSTALL_PREFIX=${PWD}/../local + make -j + make -j install + ``` + +On MacOS, you can also install most of the dependencies with Homebrew e.g. + + ``` bash + brew install libtensorflow eigen tiff spdlog catch2 + ``` + + + +## Common errors If you are using the g++ compiler and get an error to do with the package `spdlog`, try adding the option `-s compiler.libcxx=libstdc++11` to the `conan build` command. This option is also necessary when building with gcc on MacOS. -Conan tips -------- -You can set commonly used options, choices of compilers, etc. in a [conan profile](https://docs.conan.io/en/latest/reference/profiles.html). You can list profiles available on your system using `conan profile list` and select the profile you want to use with `conan install` with `conan install .. -pr my_profile`. CMake build options can also be added to the profile under `[options]`. Here is an example of a conan profile for building with a homebrew installed gcc 11 on MacOS. +## Conan tips -``` -GCC_PATH=/usr/local/Cellar/gcc/11.2.0_3/bin/ +You can set commonly used options, choices of compilers etc. in a +[conan profile](https://docs.conan.io/en/latest/reference/profiles.html). +You can list profiles available on your system using `conan profile list` and +select the profile you want to use with `conan install` with +`conan install .. -pr my_profile`. +CMake build options can also be added to the profile under `[options]`. +Here is an example of a conan profile for building with a homebrew installed gcc 11 on MacOS. +``` [settings] os=Macos os_build=Macos @@ -123,13 +147,9 @@ compiler.libcxx=libstdc++11 build_type=Release [options] [build_requires] -[env] -CC=$GCC_PATH/gcc-11 -CXX=$GCC_PATH/g++-11 ``` -Testing -------- +## Testing To check everything went all right, run the test suite: @@ -138,22 +158,25 @@ cd /path/to/code/build ctest . ``` -Matlab ------- +## Matlab -A separate Matlab implementation is provided with **SOPT**. This implementation includes some (but not all) of the optimisation algorithms implemented in the `C++` code, including the SARA algorithm. +A separate Matlab implementation is provided with **SOPT**. +This implementation includes some (but not all) of the optimisation algorithms implemented in the `C++` code, including the SARA algorithm. -The Matlab implementation is contained in the matlab directory. This is a stand-alone implementation and does not call any of the `C++` code. In future, Matlab interfaces to the `C++` code may also be included in **SOPT**. +The Matlab implementation is contained in the matlab directory. +This is a stand-alone implementation and does not call any of the `C++` code. +In future, Matlab interfaces to the `C++` code may also be included in **SOPT**. -See `matlab/README.txt` for an overview of the Matlab implementation. The stand-alone Matlab implementation is also self-documenting; corresponding documentation can be found in `matlab/doc`. We thank Gilles Puy for contributing to this Matlab implementation. +See `matlab/README.txt` for an overview of the Matlab implementation. +The stand-alone Matlab implementation is also self-documenting; +corresponding documentation can be found in `matlab/doc`. +We thank Gilles Puy for contributing to this Matlab implementation. -Contributors ------------- +## Contributors Check the [contributors](@ref sopt_contributors) page ([github](cpp/docs/SOPT_CONTRIBUTORS.md)). -References and citation ------------------------ +## References and citation If you use **SOPT** for work that results in publication, please reference the [webpage](#webpage) and our related academic papers: @@ -167,11 +190,10 @@ If you use **SOPT** for work that results in publication, please reference the [ Analysis (SARA): a novel algorithm for radio-interferometric imaging" _Mon. Not. Roy. Astron. Soc._ **426(2):1223-1234** (2012) [arXiv:1205.3123](http://arxiv.org/abs/arXiv:1205.3123) -License -------- +## License > SOPT: Sparse OPTimisation package -> Copyright (C) 2013-2019 +> Copyright (C) 2013-2023 > > This program is free software; you can redistribute it and/or > modify it under the terms of the GNU General Public License as @@ -188,19 +210,16 @@ License > Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA > 02110-1301, USA. -Webpage -------- +## Webpage - [Documentation](http://astro-informatics.github.io/sopt) - [Repository](https://github.com/astro-informatics/sopt) -Support -------- +## Support For any questions or comments, feel free to contact [Jason McEwen](http://www.jasonmcewen.org), or add an issue to the [issue tracker](https://github.com/astro-informatics/sopt/issues). -Notes ------ +## Notes The code is given for educational purpose. For the `Matlab` version of the code see the folder matlab. diff --git a/cmake_files/AddCatchTest.cmake b/cmake_files/AddCatchTest.cmake new file mode 100644 index 000000000..f8874cb6f --- /dev/null +++ b/cmake_files/AddCatchTest.cmake @@ -0,0 +1,105 @@ +# First finds or downloads catch + +# Function to create a common main +function(common_catch_main) + if(TARGET common_catch_main_object) + return() + endif() + file(WRITE "${CMAKE_BINARY_DIR}/common_catch_main.cc" + "#define CATCH_CONFIG_MAIN\n" + "#include \"catch2/catch_test_macros.hpp\"\n" + ) + add_library(common_catch_main_object OBJECT "${CMAKE_BINARY_DIR}/common_catch_main.cc") + if(Catch2_FOUND) + target_link_libraries(common_catch_main_object PRIVATE Catch2::Catch2) + endif() +endfunction() + +# A function to create a test, once a an executable exists +function(add_catch_test_with_seed testname testexec seed) + cmake_parse_arguments(catch "NOCATCHLABEL" "WORKING_DIRECTORY" "LABELS;ARGUMENTS" ${ARGN}) + + unset(EXTRA_ARGS) + if(catch_WORKING_DIRECTORY) + set(EXTRA_ARGS WORKING_DIRECTORY ${catch_WORKING_DIRECTORY}) + endif() + set(arguments ${catch_ARGUMENTS}) + if(NOT "${seed}" STREQUAL "") + list(APPEND arguments --rng-seed ${seed}) + else() + list(APPEND arguments --rng-seed time) + endif() + + if(CATCH_JUNIT) + add_test(NAME ${testname} + COMMAND ${testexec} + ${arguments} + -r junit + -o ${PROJECT_BINARY_DIR}/Testing/${testname}.xml + ) + else() + add_test(NAME ${testname} COMMAND ${testexec} ${arguments} ${EXTRA_ARGS}) + endif() + + if(NOT catch_NOCATCHLABEL) + list(APPEND catch_LABELS catch) + endif() + set_tests_properties(${testname} PROPERTIES LABELS "${catch_LABELS}") +endfunction() + +# Then adds a function to create a test +function(add_catch_test testname) + cmake_parse_arguments(catch + "NOMAIN;NOTEST;NOCATCHLABEL" + "SEED;WORKING_DIRECTORY;COMMON_MAIN;PRECOMMAND" + "LIBRARIES;DEPENDS;INCLUDES;LABELS;ARGUMENTS" + ${ARGN} + ) + + # Source deduce from testname if possible + unset(source) + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${testname}.cc") + set(source ${testname}.cc) + elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${testname}.cpp") + set(source ${testname}.cpp) + elseif("${catch_UNPARSED_ARGUMENTS}" STREQUAL "") + message(FATAL_ERROR "No source given or found for ${testname}") + endif() + + # By default, uses a common main function for all, compiled once + # We create here + if(catch_NOMAIN) + add_executable(test_${testname} ${source} ${catch_UNPARSED_ARGUMENTS}) + elseif(catch_COMMON_MAIN) + add_executable(test_${testname} + ${source} $ ${catch_UNPARSED_ARGUMENTS}) + else() + common_catch_main() + add_executable(test_${testname} + ${source} $ ${catch_UNPARSED_ARGUMENTS}) + endif() + + if(catch_LIBRARIES) + target_link_libraries(test_${testname} ${catch_LIBRARIES} Catch2::Catch2) + endif() + if(TARGET lookup_dependencies) + add_dependencies(test_${testname} lookup_dependencies) + endif() + + if(catch_NOCATCHLABEL) + set(catch_NOCATCHLABEL "NOCATCHLABEL") + else() + unset(catch_NOCATCHLABEL) + endif() + set(test_command test_${testname}) + if(catch_PRECOMMAND) + set(test_command "${catch_PRECOMMAND} ${test_command}") + endif() + if(NOT catch_NOTEST) + add_catch_test_with_seed( + test_${testname} "test_${testname}" "${catch_SEED}" ${catch_UNPARSED_ARGUMENTS} + ${catch_NOCATCHLABEL} WORKING_DIRECTORY ${catch_WORKING_DIRECTORY} + LABELS ${catch_LABELS} ARGUMENTS ${catch_ARGUMENTS} + ) + endif() +endfunction() diff --git a/cmake_files/LookUp-GreatCMakeCookOff.cmake b/cmake_files/LookUp-GreatCMakeCookOff.cmake deleted file mode 100644 index 72566466d..000000000 --- a/cmake_files/LookUp-GreatCMakeCookOff.cmake +++ /dev/null @@ -1,58 +0,0 @@ -# This file is part of the GreatCMakeCookOff package and distributed under the MIT Licences. -# Upon inclusion in a cmake file, it will download the GreatCMakeCookOff and make itself known to -# CMake. It should be added explicitely to build systems that make use of recipes from the cook-off. -# And it should be included prior to using cook-off recipes: -# -# ```{CMake} -# include(LookUp-GreatCMakeCookOff) -# ``` - - -# First attempts to find the package -set(COOKOFF_DOWNLOAD_DIR "${PROJECT_BINARY_DIR}/external/src/GreatCMakeCookOff") -find_package(GreatCMakeCookOff NO_MODULE PATHS "${COOKOFF_DOWNLOAD_DIR}" QUIET) - -# Otherwise attempts to download it. -# Does not use ExternalProject_Add to avoid doing a recursive cmake step. -if(NOT GreatCMakeCookOff_FOUND) - message(STATUS "[GreatCMakeCookOff] not found. Will attempt to clone it.") - - # Need git for cloning. - find_package(Git) - if(NOT GIT_FOUND) - message(FATAL_ERROR "[Git] not found. Cannot download GreatCMakeCookOff") - endif() - - # Remove GreatCMakeCookOff directory if it exists - if(EXISTS "${COOKOFF_DOWNLOAD_DIR}") - execute_process( - COMMAND ${CMAKE_COMMAND} -E remove_directory "${COOKOFF_DOWNLOAD_DIR}" - OUTPUT_QUIET - ) - endif() - if(NOT COOKOFF_GITREPO) - set(COOKOFF_GITREPO https://github.com/UCL/GreatCMakeCookOff.git) - endif() - execute_process( - COMMAND ${GIT_EXECUTABLE} clone "${COOKOFF_GITREPO}" - "${COOKOFF_DOWNLOAD_DIR}" - RESULT_VARIABLE CLONING_COOKOFF - OUTPUT_QUIET - ERROR_VARIABLE CLONING_ERROR - ) - - if(NOT ${CLONING_COOKOFF} EQUAL 0) - message(STATUS "${CLONING_ERROR}") - message(FATAL_ERROR "[GreatCMakeCookOff] git cloning failed.") - else() - message(STATUS "[GreatCMakeCookOff] downloaded to ${COOKOFF_DOWNLOAD_DIR}") - find_package(GreatCMakeCookOff NO_MODULE PATHS "${COOKOFF_DOWNLOAD_DIR}" QUIET) - endif() - - set(GreatCMakeCookOff_DIR "${COOKOFF_DOWNLOAD_DIR}/cmake") - set(GreatCMakeCookOff_FOUND TRUE) -endif() -unset(COOKOFF_DOWNLOAD_DIR) - -# Adds GreatCMakeCookOff to module paths -initialize_cookoff() diff --git a/cmake_files/SoptConfig.in.cmake b/cmake_files/SoptConfig.in.cmake deleted file mode 100644 index e65f229ab..000000000 --- a/cmake_files/SoptConfig.in.cmake +++ /dev/null @@ -1,20 +0,0 @@ -get_filename_component(Sopt_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) -message(STATUS "Linking to sopt package in ${Sopt_CMAKE_DIR}") -set(Sopt_INCLUDE_DIRS "@ALL_INCLUDE_DIRS@") -if(NOT TARGET libsopt AND EXISTS "${Sopt_CMAKE_DIR}/SoptCTargets.cmake") - include("${Sopt_CMAKE_DIR}/SoptCTargets.cmake") -endif() -if(NOT TARGET sopt AND EXISTS "${Sopt_CMAKE_DIR}/SoptCPPTargets.cmake") - include("${Sopt_CMAKE_DIR}/SoptCPPTargets.cmake") -endif() - -unset(Sopt_LIBRARIES) -if(TARGET sopt) - list(APPEND Sopt_LIBRARIES sopt) - set(Sopt_CPP_LIBRARY sopt) -endif() -if(TARGET libsopt) - list(APPEND Sopt_LIBRARIES libsopt) - set(Sopt_C_LIBRARY libsopt) -endif() -set(Sopt_HAS_MPI @SOPT_MPI@) diff --git a/cmake_files/dependencies.cmake b/cmake_files/dependencies.cmake index 3d7216fdf..f1b9b2133 100644 --- a/cmake_files/dependencies.cmake +++ b/cmake_files/dependencies.cmake @@ -1,9 +1,13 @@ # On different platforms the CMakeDeps generator in conan seems to install eigen -# as either "eigen" or "Eigen3" because the recipe does not explicitly define the -# name (yet). To work around this we have to check for both. -find_package(eigen) -find_package(Eigen3) -if(NOT (eigen_FOUND OR Eigen3_FOUND)) +# as either "eigen" or "Eigen3", so we need to work around this for now. +find_package(eigen NAMES Eigen3) +if(eigen_FOUND OR Eigen3_FOUND) + if(eigen_INCLUDE_DIR) + set(EIGEN3_INCLUDE_DIR ${eigen_INCLUDE_DIR} CACHE INTERNAL "") + elseif(Eigen3_INCLUDE_DIR) + set(EIGEN3_INCLUDE_DIR ${Eigen3_INCLUDE_DIR} CACHE INTERNAL "") + endif() +else() message(FATAL_ERROR "Eigen is required") endif() @@ -20,10 +24,9 @@ if(logging) endif() if(docs) - cmake_policy(SET CMP0057 NEW) - find_package(doxygen REQUIRED dot) - if(NOT doxygen_FOUND) - mesage(FATAL_ERROR "Could not find Doxygen or dot") + find_package(Doxygen REQUIRED dot) + if(NOT Doxygen_FOUND) + message(FATAL_ERROR "Could not find Doxygen or dot") endif() endif() diff --git a/cmake_files/export_sopt.cmake b/cmake_files/export_sopt.cmake index 6861eed0b..c1c66cb59 100644 --- a/cmake_files/export_sopt.cmake +++ b/cmake_files/export_sopt.cmake @@ -1,18 +1,18 @@ -# Exports Sopt so other packages can access it -export(TARGETS sopt FILE "${PROJECT_BINARY_DIR}/SoptCPPTargets.cmake") +# Exports sopt so other packages can access it +export(TARGETS sopt FILE "${PROJECT_BINARY_DIR}/soptCPPTargets.cmake") # Avoids creating an entry in the cmake registry. if(NOT NOEXPORT) - export(PACKAGE Sopt) + export(PACKAGE sopt) endif() # First in binary dir set(ALL_INCLUDE_DIRS "${PROJECT_SOURCE_DIR}/cpp" "${PROJECT_BINARY_DIR}/include") -configure_File(cmake_files/SoptConfig.in.cmake - "${PROJECT_BINARY_DIR}/SoptConfig.cmake" @ONLY +configure_File(cmake_files/soptConfig.in.cmake + "${PROJECT_BINARY_DIR}/soptConfig.cmake" @ONLY ) -configure_File(cmake_files/SoptConfigVersion.in.cmake - "${PROJECT_BINARY_DIR}/SoptConfigVersion.cmake" @ONLY +configure_File(cmake_files/soptConfigVersion.in.cmake + "${PROJECT_BINARY_DIR}/soptConfigVersion.cmake" @ONLY ) # Then for installation tree @@ -20,17 +20,17 @@ file(RELATIVE_PATH REL_INCLUDE_DIR "${CMAKE_INSTALL_PREFIX}/share/cmake/sopt" "${CMAKE_INSTALL_PREFIX}/include" ) -set(ALL_INCLUDE_DIRS "\${Sopt_CMAKE_DIR}/${REL_INCLUDE_DIR}") -configure_file(cmake_files/SoptConfig.in.cmake - "${PROJECT_BINARY_DIR}/CMakeFiles/SoptConfig.cmake" @ONLY +set(ALL_INCLUDE_DIRS "\${sopt_CMAKE_DIR}/${REL_INCLUDE_DIR}") +configure_file(cmake_files/soptConfig.in.cmake + "${PROJECT_BINARY_DIR}/CMakeFiles/soptConfig.cmake" @ONLY ) # Finally install all files install(FILES - "${PROJECT_BINARY_DIR}/CMakeFiles/SoptConfig.cmake" - "${PROJECT_BINARY_DIR}/SoptConfigVersion.cmake" + "${PROJECT_BINARY_DIR}/CMakeFiles/soptConfig.cmake" + "${PROJECT_BINARY_DIR}/soptConfigVersion.cmake" DESTINATION share/cmake/sopt COMPONENT dev ) -install(EXPORT SoptCPPTargets DESTINATION share/cmake/sopt COMPONENT dev) +install(EXPORT soptCPPTargets DESTINATION share/cmake/sopt COMPONENT dev) diff --git a/cmake_files/soptConfig.in.cmake b/cmake_files/soptConfig.in.cmake new file mode 100644 index 000000000..b1c8b67cf --- /dev/null +++ b/cmake_files/soptConfig.in.cmake @@ -0,0 +1,20 @@ +get_filename_component(sopt_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) +message(STATUS "Linking to sopt package in ${sopt_CMAKE_DIR}") +set(sopt_INCLUDE_DIR "@ALL_INCLUDE_DIRS@") +if(NOT TARGET libsopt AND EXISTS "${sopt_CMAKE_DIR}/soptCTargets.cmake") + include("${sopt_CMAKE_DIR}/soptCTargets.cmake") +endif() +if(NOT TARGET sopt AND EXISTS "${sopt_CMAKE_DIR}/soptCPPTargets.cmake") + include("${sopt_CMAKE_DIR}/soptCPPTargets.cmake") +endif() + +unset(sopt_LIBRARIES) +if(TARGET sopt) + list(APPEND sopt_LIBRARIES sopt) + set(sopt_CPP_LIBRARY sopt) +endif() +if(TARGET libsopt) + list(APPEND sopt_LIBRARIES libsopt) + set(sopt_C_LIBRARY libsopt) +endif() +set(sopt_HAS_MPI @SOPT_MPI@) diff --git a/cmake_files/SoptConfigVersion.in.cmake b/cmake_files/soptConfigVersion.in.cmake similarity index 80% rename from cmake_files/SoptConfigVersion.in.cmake rename to cmake_files/soptConfigVersion.in.cmake index 296018a4c..95acd242e 100644 --- a/cmake_files/SoptConfigVersion.in.cmake +++ b/cmake_files/soptConfigVersion.in.cmake @@ -1,4 +1,4 @@ -set(PACKAGE_VERSION "@Sopt_VERSION@") +set(PACKAGE_VERSION "@SOPT_VERSION@") set(MPI_COMPONENT @SOPT_MPI@) if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}") set(PACKAGE_VERSION_COMPATIBLE FALSE) @@ -8,6 +8,6 @@ else() set(PACKAGE_VERSION_EXACT FALSE) endif() endif() -if(Sopt_FIND_REQUIRED_MPI AND NOT MPI_COMPONENT) +if(sopt_FIND_REQUIRED_MPI AND NOT MPI_COMPONENT) set(PACKAGE_VERSION_COMPATIBLE FALSE) endif() diff --git a/conanfile.py b/conanfile.py index 641169cb9..03e1ccfda 100644 --- a/conanfile.py +++ b/conanfile.py @@ -3,7 +3,7 @@ from conan.tools.files import symlinks import os -class SoptConan(ConanFile): +class soptConan(ConanFile): name = "sopt" version = "4.0.0" url = "https://github.com/astro-informatics/sopt" @@ -12,8 +12,8 @@ class SoptConan(ConanFile): settings = "os", "compiler", "build_type", "arch" - requires = ["eigen/3.3.7","catch2/2.13.7","benchmark/1.6.0", "libtiff/4.4.0",] - generators = "CMakeDeps" + requires = ["eigen/3.4.0","catch2/3.4.0","benchmark/1.8.2", "libtiff/4.5.1",] + #generators = "CMakeDeps" exports_sources = "cpp/*", "cmake_files/*", "CMakeLists.txt" options = {"docs":['on','off'], "examples":['on','off'], @@ -37,7 +37,7 @@ class SoptConan(ConanFile): def requirements(self): if self.options.logging == 'on': - self.requires("spdlog/1.9.2") + self.requires("spdlog/1.12.0") if self.options.cppflow == 'on': self.requires("cppflow/2.0.0") diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 14e2ac6b4..513c524de 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -11,11 +11,11 @@ else() set(SOPT_TEST_LOG_LEVEL off) endif() -set(version ${Sopt_VERSION}) -string(REGEX REPLACE "\\." ";" version "${Sopt_VERSION}") -list(GET version 0 Sopt_VERSION_MAJOR) -list(GET version 1 Sopt_VERSION_MINOR) -list(GET version 2 Sopt_VERSION_PATCH) +set(version ${SOPT_VERSION}) +string(REGEX REPLACE "\\." ";" version "${SOPT_VERSION}") +list(GET version 0 SOPT_VERSION_MAJOR) +list(GET version 1 SOPT_VERSION_MINOR) +list(GET version 2 SOPT_VERSION_PATCH) configure_file(sopt/config.in.h "${PROJECT_BINARY_DIR}/include/sopt/config.h") diff --git a/cpp/docs/CMakeLists.txt b/cpp/docs/CMakeLists.txt index ce1fffea2..3f1d88364 100644 --- a/cpp/docs/CMakeLists.txt +++ b/cpp/docs/CMakeLists.txt @@ -20,7 +20,13 @@ add_custom_target(doc ALL # This will create a target in the Makefile that's used to push docs to github.io -add_custom_target(docweb - COMMAND sed -i -e 's@namespacesopt@http://astro-informatics.github.io/sopt/&@g' -e 's@@&http://astro-informatics.github.io/sopt/@g' ${CMAKE_CURRENT_BINARY_DIR}/html/sopt.tag - DEPENDS doc) +if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + add_custom_target(docweb + COMMAND sed -i '' -e 's@namespacesopt@http://astro-informatics.github.io/sopt/&@g' -e 's@@&http://astro-informatics.github.io/sopt/@g' ${CMAKE_CURRENT_BINARY_DIR}/html/sopt.tag + DEPENDS doc) +else() + add_custom_target(docweb + COMMAND sed -i -e 's@namespacesopt@http://astro-informatics.github.io/sopt/&@g' -e 's@@&http://astro-informatics.github.io/sopt/@g' ${CMAKE_CURRENT_BINARY_DIR}/html/sopt.tag + DEPENDS doc) +endif() diff --git a/cpp/sopt/CMakeLists.txt b/cpp/sopt/CMakeLists.txt index ec1f9ee02..e782d6ea4 100644 --- a/cpp/sopt/CMakeLists.txt +++ b/cpp/sopt/CMakeLists.txt @@ -32,8 +32,8 @@ if (cppflow) endif() add_library(sopt SHARED ${sources}) -set(version "${Sopt_VERSION_MAJOR}.${Sopt_VERSION_MINOR}.${Sopt_VERSION_PATCH}") -set(soversion "${Sopt_VERSION_MAJOR}.${Sopt_VERSION_MINOR}") +set(version "${SOPT_VERSION_MAJOR}.${SOPT_VERSION_MINOR}.${SOPT_VERSION_PATCH}") +set(soversion "${SOPT_VERSION_MAJOR}.${SOPT_VERSION_MINOR}") set_target_properties(sopt PROPERTIES VERSION ${version} SOVERSION ${soversion}) target_include_directories(sopt PUBLIC @@ -52,17 +52,9 @@ endif() # Add spdlog as direct dependency if(spdlog_FOUND) target_link_libraries(sopt spdlog::spdlog) - target_include_directories(sopt SYSTEM PUBLIC ${spdlog_INCLUDE_DIR}) endif() -# Add Eigen3 as direct dependency -# On different platforms the CMakeDeps generator in conan seems to install eigen -# as either "eigen" or "Eigen3" because the recipe does not explicitly define the -# name (yet). To work around this we have to check for both. -if(eigen_FOUND) - target_include_directories(sopt SYSTEM PUBLIC ${eigen_INCLUDE_DIR}) -endif() -if(Eigen3_FOUND) - target_include_directories(sopt SYSTEM PUBLIC ${Eigen3_INCLUDE_DIR}) +if(EIGEN3_INCLUDE_DIR) + target_include_directories(sopt SYSTEM PUBLIC ${EIGEN3_INCLUDE_DIR}) endif() if(TARGET openmp::openmp) target_link_libraries(sopt openmp::openmp) @@ -91,9 +83,9 @@ install(FILES ${headers} DESTINATION include/sopt) install(FILES ${wavelet_headers} DESTINATION include/sopt/wavelets) install(FILES ${mpi_headers} DESTINATION include/sopt/mpi) install(TARGETS sopt - EXPORT SoptCPPTargets + EXPORT soptCPPTargets DESTINATION share/cmake/sopt LIBRARY DESTINATION lib ARCHIVE DESTINATION lib INCLUDES DESTINATION include - ) +) diff --git a/cpp/sopt/config.in.h b/cpp/sopt/config.in.h index eb01f0c6d..db07aec76 100644 --- a/cpp/sopt/config.in.h +++ b/cpp/sopt/config.in.h @@ -27,14 +27,14 @@ namespace sopt { //! Returns library version -inline std::string version() { return "@Sopt_VERSION@"; } +inline std::string version() { return "@SOPT_VERSION@"; } //! Returns library version inline std::tuple version_tuple() { return std::tuple( - @Sopt_VERSION_MAJOR@, @Sopt_VERSION_MINOR@, @Sopt_VERSION_PATCH@); + @SOPT_VERSION_MAJOR@, @SOPT_VERSION_MINOR@, @SOPT_VERSION_PATCH@); } //! Returns library git reference, if known -inline std::string gitref() { return "@Sopt_GITREF@"; } +inline std::string gitref() { return "@SOPT_GITREF@"; } //! Default logging level inline std::string default_logging_level() { return "@SOPT_TEST_LOG_LEVEL@"; } //! Default logger name diff --git a/cpp/sopt/logging.disabled.h b/cpp/sopt/logging.disabled.h index b496bc734..309abd20e 100644 --- a/cpp/sopt/logging.disabled.h +++ b/cpp/sopt/logging.disabled.h @@ -19,6 +19,5 @@ inline bool has_level(std::string const &, std::string const &) { return false; } // namespace sopt::logging //! \macro For internal use only -#define SOPT_LOG_(...) - +#define SOPT_LOG_(...) ((void)0) #endif diff --git a/cpp/sopt/logging.enabled.h b/cpp/sopt/logging.enabled.h index dff3f41d4..5780fb584 100644 --- a/cpp/sopt/logging.enabled.h +++ b/cpp/sopt/logging.enabled.h @@ -2,70 +2,84 @@ #define SOPT_LOGGING_ENABLED_H #include "sopt/config.h" -#include // for std::shared_ptr<> -#include // for std::string +#include +#include +#include #include #include #include #include "sopt/exception.h" +using spdlogPtr = std::shared_ptr; + +#if FMT_VERSION >= 90000 + template + struct fmt::formatter< Eigen::Transpose > : fmt::ostream_formatter {}; + + template + struct fmt::formatter> : fmt::ostream_formatter {}; +#endif + namespace sopt::logging { -void set_level(std::string const &level, std::string const &name = ""); -//! \brief Initializes a logger. -//! \details Logger only exists as long as return is kept alive. -inline std::shared_ptr initialize(std::string const &name = "") { - auto const result = spdlog::stdout_logger_mt(default_logger_name() + name); - set_level(default_logging_level(), name); - return result; -} + void set_level(std::string const &level, std::string const &name = ""); + + //! \brief Initializes a logger. + //! \details Logger only exists as long as return is kept alive. + inline spdlogPtr initialize(std::string const &name = "") { + const std::string loggerName = default_logger_name() + name; + const spdlogPtr result = spdlog::stdout_logger_mt(loggerName); + if (!spdlog::get(loggerName)) spdlog::register_logger(result); + set_level(default_logging_level(), name); + return result; + } -//! Returns shared pointer to logger or null if it does not exist -inline std::shared_ptr get(std::string const &name = "") { - return spdlog::get(default_logger_name() + name); -} + //! Returns shared pointer to logger or null if it does not exist + inline spdlogPtr get(std::string const &name = "") { + return spdlog::get(default_logger_name() + name); + } -//! \brief Sets loggin level -//! \details Levels can be one of -//! - "trace" -//! - "debug" -//! - "info" -//! - "warn" -//! - "err" -//! - "critical" -//! - "off" -inline void set_level(std::string const &level, std::string const &name) { - auto const logger = get(name); - if (not logger) SOPT_THROW("No logger by the name of ") << name << ".\n"; -#define SOPT_MACRO(LEVEL) \ - if (level == #LEVEL) logger->set_level(spdlog::level::LEVEL) - SOPT_MACRO(trace); - else SOPT_MACRO(debug); - else SOPT_MACRO(info); - else SOPT_MACRO(warn); - else SOPT_MACRO(err); - else SOPT_MACRO(critical); - else SOPT_MACRO(off); -#undef SOPT_MACRO - else SOPT_THROW("Unknown logging level ") << level << "\n"; -} + //! \brief Sets loggin level + //! \details Levels can be one of + //! - "trace" + //! - "debug" + //! - "info" + //! - "warn" + //! - "err" + //! - "critical" + //! - "off" + inline void set_level(std::string const &level, std::string const &name) { + const spdlogPtr logger = get(name); + if (not logger) SOPT_THROW("No logger by the name of ") << name << ".\n"; + #define SOPT_MACRO(LEVEL) \ + if (level == #LEVEL) logger->set_level(spdlog::level::LEVEL) + SOPT_MACRO(trace); + else SOPT_MACRO(debug); + else SOPT_MACRO(info); + else SOPT_MACRO(warn); + else SOPT_MACRO(err); + else SOPT_MACRO(critical); + else SOPT_MACRO(off); + #undef SOPT_MACRO + else SOPT_THROW("Unknown logging level ") << level << "\n"; + } -inline bool has_level(std::string const &level, std::string const &name = "") { - auto const logger = get(name); - if (not logger) return false; + inline bool has_level(std::string const &level, std::string const &name = "") { + const spdlogPtr logger = get(name); + if (not logger) return false; -#define SOPT_MACRO(LEVEL) \ - if (level == #LEVEL) return logger->level() >= spdlog::level::LEVEL - SOPT_MACRO(trace); - else SOPT_MACRO(debug); - else SOPT_MACRO(info); - else SOPT_MACRO(warn); - else SOPT_MACRO(err); - else SOPT_MACRO(critical); - else SOPT_MACRO(off); -#undef SOPT_MACRO - else SOPT_THROW("Unknown logging level ") << level << "\n"; -} + #define SOPT_MACRO(LEVEL) \ + if (level == #LEVEL) return logger->level() >= spdlog::level::LEVEL + SOPT_MACRO(trace); + else SOPT_MACRO(debug); + else SOPT_MACRO(info); + else SOPT_MACRO(warn); + else SOPT_MACRO(err); + else SOPT_MACRO(critical); + else SOPT_MACRO(off); + #undef SOPT_MACRO + else SOPT_THROW("Unknown logging level ") << level << "\n"; + } } // namespace sopt::logging //! \macro For internal use only diff --git a/cpp/tests/CMakeLists.txt b/cpp/tests/CMakeLists.txt index 5622c5eda..61d06db59 100644 --- a/cpp/tests/CMakeLists.txt +++ b/cpp/tests/CMakeLists.txt @@ -1,10 +1,12 @@ add_library(common_catch_main_object OBJECT "common_catch_main.cc") -if(spdlog_INCLUDE_DIR) +if(spdlog_FOUND) target_link_libraries(common_catch_main_object spdlog::spdlog) - target_include_directories(common_catch_main_object SYSTEM PUBLIC ${spdlog_INCLUDE_DIR}) endif() -if(CATCH_INCLUDE_DIR) - target_include_directories(common_catch_main_object SYSTEM PUBLIC ${CATCH_INCLUDE_DIR}) +if(Catch2_FOUND) + target_link_libraries(common_catch_main_object Catch2::Catch2) +endif() +if(EIGEN3_INCLUDE_DIR) + target_include_directories(common_catch_main_object SYSTEM PUBLIC ${EIGEN3_INCLUDE_DIR}) endif() target_include_directories(common_catch_main_object PUBLIC "${EXTERNAL_ROOT}/include/" @@ -47,12 +49,14 @@ if(SOPT_MPI) add_library(common_mpi_catch_main_object OBJECT common_mpi_catch_main.cc) target_include_directories(common_mpi_catch_main_object PUBLIC ${PROJECT_SOURCE_DIR}/cpp ${PROJECT_BINARY_DIR}/include ${MPI_CXX_INCLUDE_PATH}) - if(spdlog_INCLUDE_DIR) + if(spdlog_FOUND) target_link_libraries(common_mpi_catch_main_object spdlog::spdlog) - target_include_directories(common_mpi_catch_main_object SYSTEM PUBLIC ${spdlog_INCLUDE_DIR}) endif() - if(CATCH_INCLUDE_DIR) - target_include_directories(common_mpi_catch_main_object SYSTEM PUBLIC ${CATCH_INCLUDE_DIR}) + if(Catch2_FOUND) + target_link_libraries(common_mpi_catch_main_object Catch2::Catch2) + endif() + if(EIGEN3_INCLUDE_DIR) + target_include_directories(common_mpi_catch_main_object SYSTEM PUBLIC ${EIGEN3_INCLUDE_DIR}) endif() function(add_mpi_test_from_test testname) diff --git a/cpp/tests/bisection_method.cc b/cpp/tests/bisection_method.cc index 8c005b09e..2fecf6784 100644 --- a/cpp/tests/bisection_method.cc +++ b/cpp/tests/bisection_method.cc @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/cpp/tests/chained_operators.cc b/cpp/tests/chained_operators.cc index 9e4a5a703..de861d005 100644 --- a/cpp/tests/chained_operators.cc +++ b/cpp/tests/chained_operators.cc @@ -1,5 +1,5 @@ -#include +#include #include #include diff --git a/cpp/tests/common_catch_main.cc b/cpp/tests/common_catch_main.cc index 5c409ef2e..722b31d40 100644 --- a/cpp/tests/common_catch_main.cc +++ b/cpp/tests/common_catch_main.cc @@ -1,7 +1,7 @@ #define CATCH_CONFIG_RUNNER #include "sopt/config.h" -#include +#include #include #include #include "sopt/logging.h" diff --git a/cpp/tests/common_mpi_catch_main.cc b/cpp/tests/common_mpi_catch_main.cc index 32f7e460e..da6fd4068 100644 --- a/cpp/tests/common_mpi_catch_main.cc +++ b/cpp/tests/common_mpi_catch_main.cc @@ -1,7 +1,7 @@ #define CATCH_CONFIG_RUNNER #include "sopt/config.h" -#include +#include #include #include #include diff --git a/cpp/tests/communicator.cc b/cpp/tests/communicator.cc index 7f680cc6d..a16de4f14 100644 --- a/cpp/tests/communicator.cc +++ b/cpp/tests/communicator.cc @@ -1,6 +1,6 @@ #include #include -#include "catch.hpp" +#include "catch2/catch_all.hpp" #include "sopt/config.h" #include "sopt/mpi/communicator.h" diff --git a/cpp/tests/conjugate_gradient.cc b/cpp/tests/conjugate_gradient.cc index ccd15b513..bf92db43c 100644 --- a/cpp/tests/conjugate_gradient.cc +++ b/cpp/tests/conjugate_gradient.cc @@ -1,5 +1,5 @@ #include -#include "catch.hpp" +#include "catch2/catch_all.hpp" #include "sopt/conjugate_gradient.h" diff --git a/cpp/tests/cppflow_model.cc b/cpp/tests/cppflow_model.cc index 0db42537d..c1a5722c2 100644 --- a/cpp/tests/cppflow_model.cc +++ b/cpp/tests/cppflow_model.cc @@ -1,6 +1,6 @@ #include #include -#include +#include #include "sopt/logging.h" #include "sopt/types.h" diff --git a/cpp/tests/credible_region.cc b/cpp/tests/credible_region.cc index ad514dc8c..e2e04b6b3 100644 --- a/cpp/tests/credible_region.cc +++ b/cpp/tests/credible_region.cc @@ -1,6 +1,6 @@ #include "sopt/credible_region.h" #include -#include "catch.hpp" +#include "catch2/catch_all.hpp" #include "sopt/objective_functions.h" #include "sopt/types.h" @@ -8,6 +8,7 @@ using namespace sopt; using Scalar = t_complex; using t_Vector = Vector; using t_Image = Image; +using Catch::Approx; t_uint rows = 128; t_uint cols = 128; t_uint N = rows * cols; diff --git a/cpp/tests/forward_backward.cc b/cpp/tests/forward_backward.cc index 192f6b16f..bc7b87c2e 100644 --- a/cpp/tests/forward_backward.cc +++ b/cpp/tests/forward_backward.cc @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/cpp/tests/gradient_operator.cc b/cpp/tests/gradient_operator.cc index f1f0f8517..96c07c593 100644 --- a/cpp/tests/gradient_operator.cc +++ b/cpp/tests/gradient_operator.cc @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -33,13 +33,13 @@ TEST_CASE("Gradient Operator") { CHECK(output.size() == 2 * input.size()); CHECK(output.segment(0, input.size()).isApprox(Vector::Zero(input.size()))); CHECK(output.segment(input.size(), input.size() - 1) - .isApprox(Vector::Constant(0.5, input.size() - 1))); + .isApprox(Vector::Constant((Eigen::Index)0.5, input.size() - 1))); input = Matrix::Ones(image.rows(), image.cols()); for (Eigen::Index i(0); i < image.cols(); i++) input.col(i) *= static_cast(i); output = psi.adjoint() * Vector::Map(input.data(), input.size()); CAPTURE(output.segment(0, 5)); CAPTURE(output.segment(image.size(), 5)); CHECK(output.size() == 2 * input.size()); - CHECK(output.segment(0, input.size() - 1).isApprox(Vector::Constant(0.5, input.size() - 1))); + CHECK(output.segment(0, input.size() - 1).isApprox(Vector::Constant((Eigen::Index)0.5, input.size() - 1))); CHECK(output.segment(input.size(), input.size()).isApprox(Vector::Zero(input.size()))); } diff --git a/cpp/tests/inpainting.cc b/cpp/tests/inpainting.cc index 4a635f7bb..889eab79c 100644 --- a/cpp/tests/inpainting.cc +++ b/cpp/tests/inpainting.cc @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include "sopt/imaging_forward_backward.h" #include "sopt/l1_g_proximal.h" diff --git a/cpp/tests/linear_transform.cc b/cpp/tests/linear_transform.cc index 4e20990ee..d60b558eb 100644 --- a/cpp/tests/linear_transform.cc +++ b/cpp/tests/linear_transform.cc @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/cpp/tests/maths.cc b/cpp/tests/maths.cc index f4db2ea18..6dce2e8c9 100644 --- a/cpp/tests/maths.cc +++ b/cpp/tests/maths.cc @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -8,6 +8,8 @@ #include "sopt/sampling.h" #include "sopt/types.h" +using Catch::Approx; + TEST_CASE("Projector on positive quadrant", "[utility][project]") { using namespace sopt; diff --git a/cpp/tests/mpi_proximals.cc b/cpp/tests/mpi_proximals.cc index 6c28d2e0b..e6e91cb09 100644 --- a/cpp/tests/mpi_proximals.cc +++ b/cpp/tests/mpi_proximals.cc @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/cpp/tests/mpi_session.cc b/cpp/tests/mpi_session.cc index 9e552f9c4..8d2037952 100644 --- a/cpp/tests/mpi_session.cc +++ b/cpp/tests/mpi_session.cc @@ -2,7 +2,7 @@ #include #include #include -#include "catch.hpp" +#include "catch2/catch_all.hpp" #include "sopt/logging.h" #include "sopt/mpi/session.h" using namespace sopt; diff --git a/cpp/tests/mpi_wavelets.cc b/cpp/tests/mpi_wavelets.cc index e8ac8637a..c349bd152 100644 --- a/cpp/tests/mpi_wavelets.cc +++ b/cpp/tests/mpi_wavelets.cc @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/cpp/tests/padmm.cc b/cpp/tests/padmm.cc index 0773f4d20..42132c112 100644 --- a/cpp/tests/padmm.cc +++ b/cpp/tests/padmm.cc @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/cpp/tests/padmm_warm_start.cc b/cpp/tests/padmm_warm_start.cc index 30405df7d..9e17a9d11 100644 --- a/cpp/tests/padmm_warm_start.cc +++ b/cpp/tests/padmm_warm_start.cc @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/cpp/tests/power_method.cc b/cpp/tests/power_method.cc index 549b3c83f..40fb1c4be 100644 --- a/cpp/tests/power_method.cc +++ b/cpp/tests/power_method.cc @@ -1,10 +1,12 @@ #include #include #include -#include "catch.hpp" +#include "catch2/catch_all.hpp" #include "sopt/power_method.h" +using Catch::Approx; + TEST_CASE("Power Method") { using namespace sopt; using Scalar = t_real; diff --git a/cpp/tests/primal_dual.cc b/cpp/tests/primal_dual.cc index 729319023..8de78c6ac 100644 --- a/cpp/tests/primal_dual.cc +++ b/cpp/tests/primal_dual.cc @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -13,6 +13,7 @@ using Scalar = sopt::t_real; using t_Vector = sopt::Vector; using t_Matrix = sopt::Matrix; +using Catch::Approx; auto constexpr N = 5; diff --git a/cpp/tests/proximal.cc b/cpp/tests/proximal.cc index 096f21171..5cfa5fb9e 100644 --- a/cpp/tests/proximal.cc +++ b/cpp/tests/proximal.cc @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -7,6 +7,8 @@ #include "sopt/proximal.h" #include "sopt/types.h" +using Catch::Approx; + template sopt::Matrix concatenated_permutations(sopt::t_uint i, sopt::t_uint j) { extern std::unique_ptr mersenne; diff --git a/cpp/tests/reweighted.cc b/cpp/tests/reweighted.cc index 0ba07375e..b6008f082 100644 --- a/cpp/tests/reweighted.cc +++ b/cpp/tests/reweighted.cc @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/cpp/tests/sara.cc b/cpp/tests/sara.cc index 9d9f0f9ff..b4677e0ba 100644 --- a/cpp/tests/sara.cc +++ b/cpp/tests/sara.cc @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/cpp/tests/sdmm.cc b/cpp/tests/sdmm.cc index 1dbf95e42..37cb672e0 100644 --- a/cpp/tests/sdmm.cc +++ b/cpp/tests/sdmm.cc @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/cpp/tests/sdmm_warm_start.cc b/cpp/tests/sdmm_warm_start.cc index 0c61c0c72..feccd78ae 100644 --- a/cpp/tests/sdmm_warm_start.cc +++ b/cpp/tests/sdmm_warm_start.cc @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/cpp/tests/serial_vs_parallel_padmm.cc b/cpp/tests/serial_vs_parallel_padmm.cc index cfdc63ed1..ad6d4aad0 100644 --- a/cpp/tests/serial_vs_parallel_padmm.cc +++ b/cpp/tests/serial_vs_parallel_padmm.cc @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -18,6 +18,8 @@ #include "tools_for_tests/directories.h" #include "tools_for_tests/tiffwrappers.h" +using Catch::Approx; + TEST_CASE("Parallel vs serial inpainting") { extern std::unique_ptr mersenne; using namespace sopt; diff --git a/cpp/tests/tf_inpainting.cc b/cpp/tests/tf_inpainting.cc index c685ecb0a..0cdfeef0e 100644 --- a/cpp/tests/tf_inpainting.cc +++ b/cpp/tests/tf_inpainting.cc @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include "sopt/imaging_forward_backward.h" #include "sopt/tf_g_proximal.h" diff --git a/cpp/tests/wavelets.cc b/cpp/tests/wavelets.cc index 821cf875c..7d8cc96c4 100644 --- a/cpp/tests/wavelets.cc +++ b/cpp/tests/wavelets.cc @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/cpp/tests/wrapper.cc b/cpp/tests/wrapper.cc index 092da8c53..af6d0b492 100644 --- a/cpp/tests/wrapper.cc +++ b/cpp/tests/wrapper.cc @@ -1,4 +1,4 @@ -#include +#include #include #include "sopt/wrapper.h" diff --git a/cpp/tools_for_tests/CMakeLists.txt b/cpp/tools_for_tests/CMakeLists.txt index d2991f06e..0f64412d4 100644 --- a/cpp/tools_for_tests/CMakeLists.txt +++ b/cpp/tools_for_tests/CMakeLists.txt @@ -1,21 +1,13 @@ add_library(tools_for_tests STATIC tiffwrappers.cc tiffwrappers.h) -target_link_libraries(tools_for_tests ${TIFF_LIBRARY}) +target_link_libraries(tools_for_tests TIFF::TIFF) +target_link_libraries(tools_for_tests sopt) target_include_directories(tools_for_tests PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/.." "${PROJECT_BINARY_DIR}/include/" ) target_include_directories(tools_for_tests SYSTEM PUBLIC ${TIFF_INCLUDE_DIR}) -if(spdlog_INCLUDE_DIR) - target_include_directories(tools_for_tests SYSTEM PUBLIC ${spdlog_INCLUDE_DIR}) -endif() -if(eigen_INCLUDE_DIR) - target_include_directories(tools_for_tests SYSTEM PUBLIC ${eigen_INCLUDE_DIR}) -endif() -# On different platforms the CMakeDeps generator in conan seems to install eigen -# as either "eigen" or "Eigen3" because the recipe does not explicitly define the -# name (yet). To work around this we have to check for both. -if(Eigen3_INCLUDE_DIR) - target_include_directories(tools_for_tests SYSTEM PUBLIC ${Eigen3_INCLUDE_DIR}) +if(EIGEN3_INCLUDE_DIR) + target_include_directories(tools_for_tests SYSTEM PUBLIC ${EIGEN3_INCLUDE_DIR}) endif()