From 09618991ea8e39ba73c3ec7b0038cb90abef81b0 Mon Sep 17 00:00:00 2001 From: "Lori A. Burns" Date: Sun, 7 Jan 2024 14:00:39 -0500 Subject: [PATCH] add subproject, c++ ho, fortran, python, c++ compiled take 2 take 3 c++ ho testing take 2 try 3 take 4 take 5 take 6 take 7 take 8 take 8 take 9 fortran try 2 try 3 try 4 try 5 python try 2 try 3 try 4 try 5 try 6 try 7 try 8 try 9 try 10 try 11 try 12 try 13 try 14 try 15 try 16 try 17 helps to spell var correctly try 18 try 19 try 20 try 21 try 22 try 22 try 24 --- .github/workflows/ci_cmake.yml | 145 +++++---- .github/workflows/cmake.yml | 2 +- CMakeLists.txt | 16 +- INSTALL.md | 54 +++- cmake/modules/DynamicVersion.cmake | 280 ++++++++++++---- cmake/modules/int_computed.cmake.in | 64 ++-- cmake/modules/int_versions.cmake | 18 +- export/cmake/CMakeLists.txt.export | 2 +- include/libint2/config.h.cmake.in | 8 +- python/CMakeLists.txt | 79 ++++- src/bin/CMakeLists.txt | 1 + src/bin/libint/CMakeLists.txt | 6 +- src/lib/libint/CMakeLists.txt | 118 +++++-- src/lib/libint/CMakeLists.txt.export | 464 ++++++++++++++++++++++++--- src/lib/libint/engine.cpp | 30 ++ src/lib/libint/populate.cmake | 181 ++++++++++- tests/CMakeLists.txt | 259 ++++++++++++++- tests/hartree-fock/hftest.cmake | 44 +++ 18 files changed, 1468 insertions(+), 303 deletions(-) create mode 100644 src/lib/libint/engine.cpp create mode 100644 tests/hartree-fock/hftest.cmake diff --git a/.github/workflows/ci_cmake.yml b/.github/workflows/ci_cmake.yml index 961012401..41aa64c46 100644 --- a/.github/workflows/ci_cmake.yml +++ b/.github/workflows/ci_cmake.yml @@ -13,19 +13,35 @@ jobs: matrix: build_type : [ Release, Debug ] os : [ macos-latest, ubuntu-20.04 ] + subproject : [ ON, OFF ] + exclude: + - build_type: Release + subproject: ON include: - os: ubuntu-20.04 cxx: g++-10 cc: gcc-10 + compressor: gzip - os: macos-latest cxx: clang++ cc: clang - - build_type: Release - build_shared_libs: ON + compressor: bzip2 - build_type: Debug build_shared_libs: OFF + do_fortran: ON + - build_type: Release + build_shared_libs: ON + os: ubuntu-20.04 + do_fortran: ON + - build_type: Release + build_shared_libs: ON + os: macos-latest + do_fortran: OFF + # someday when mac+fortran+shared is fixed (plus universal do_fortran: ON) + #- build_type: Release + # build_shared_libs: ON - name: "Repo • ${{ matrix.os }}: ${{ matrix.cxx }} ${{ matrix.build_type }}" + name: "Repo • ${{ matrix.os }}: ${{ matrix.cxx }} ${{ matrix.build_type }} shared=${{ matrix.build_shared_libs }} fetch=${{ matrix.subproject }}" runs-on: ${{ matrix.os }} env: CC: ${{ matrix.cc }} @@ -35,19 +51,23 @@ jobs: CCACHE_COMPRESSLEVEL : 6 BUILD_CONFIG : > -G Ninja - -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} - -DBUILD_SHARED_LIBS=${{ matrix.build_shared_libs }} - -DMPIEXEC_PREFLAGS='--bind-to;none;--allow-run-as-root' - -DCMAKE_INSTALL_PREFIX=${{github.workspace}}/build/library - -DWITH_MAX_AM=2;2 - -DWITH_ERI_MAX_AM=2;2 - -DWITH_ERI3_MAX_AM=3;2 - -DENABLE_ERI=1 - -DENABLE_ERI3=1 - -DENABLE_ONEBODY=1 - -DDISABLE_ONEBODY_PROPERTY_DERIVS=ON - -DMULTIPOLE_MAX_ORDER=2 - -DLIBINT2_ENABLE_PYTHON=ON + -D CMAKE_BUILD_TYPE=${{ matrix.build_type }} + -D BUILD_SHARED_LIBS=${{ matrix.build_shared_libs }} + -D LIBINT_BUILD_LIBRARY_AS_SUBPROJECT=${{ matrix.subproject }} + -D CMAKE_INSTALL_PREFIX=${{github.workspace}}/build/library + -D WITH_MAX_AM=2;2 + -D WITH_ERI_MAX_AM=2;2 + -D WITH_ERI3_MAX_AM=3;2 + -D ENABLE_ERI=1 + -D ENABLE_ERI3=1 + -D ENABLE_ONEBODY=1 + -D DISABLE_ONEBODY_PROPERTY_DERIVS=ON + -D MULTIPOLE_MAX_ORDER=2 + -D LIBINT2_REQUIRE_CXX_API_COMPILED=ON + -D LIBINT2_ENABLE_FORTRAN=${{ matrix.do_fortran }} + -D LIBINT2_ENABLE_PYTHON=ON + -D Python_EXECUTABLE=${{ matrix.os == 'macos-latest' && '/usr/local/Frameworks/Python.framework/Versions/3.11/bin/python3.11' || '/usr/bin/python3.8' }} + -D EXPORT_COMPRESSOR=${{ matrix.compressor }} outputs: should_skip: ${{ steps.skip_check.outputs.should_skip }} @@ -66,8 +86,6 @@ jobs: - name: Create Build Environment if: ${{ steps.skip_check.outputs.should_skip != 'true' }} - # Some projects don't allow in-source building, so create a separate build directory - # We'll use this as our working directory for all subsequent commands run: | cmake -E make_directory ${{github.workspace}}/build/compiler cmake -E make_directory ${{github.workspace}}/build/library @@ -105,7 +123,7 @@ jobs: restore-keys: | ${{ matrix.config.name }}-ccache- - - name: Generate Libint generator + - name: Build Libint generator if: ${{ steps.skip_check.outputs.should_skip != 'true' }} # Use a bash shell so we can use the same syntax for environment variable # access regardless of the host operating system @@ -116,16 +134,16 @@ jobs: cmake -S ../.. -B build $BUILD_CONFIG --log-level=DEBUG cmake --build build --target check-libint2compiler - - name: Generate Libint export + - name: Generate Libint library tarball if: ${{ steps.skip_check.outputs.should_skip != 'true' }} shell: bash working-directory: ${{github.workspace}}/build/compiler run: | cmake --build build --target export - cd build && echo "ARTIFACT=`ls -1 libint*tgz`" >> $GITHUB_ENV + cd build && echo "ARTIFACT=`ls -1 libint*z*`" >> $GITHUB_ENV - - name: Archive Library Tarball - if: ${{ steps.skip_check.outputs.should_skip != 'true' && matrix.build_type == 'Release'}} + - name: Archive Libint library tarball + if: ${{ steps.skip_check.outputs.should_skip != 'true' && matrix.build_type == 'Release' }} uses: actions/upload-artifact@v3 with: if-no-files-found: error @@ -133,17 +151,28 @@ jobs: path: ${{github.workspace}}/build/compiler/build/${{ env.ARTIFACT }} retention-days: 1 - - name: Generate Libint library + - name: Build Libint library (FetchContent=${{ matrix.subproject }}) + if: ${{ steps.skip_check.outputs.should_skip }} + shell: bash + working-directory: ${{github.workspace}}/build/compiler + run: cmake --build build + + - name: Test Libint library - unit tests if: ${{ steps.skip_check.outputs.should_skip != 'true' }} shell: bash working-directory: ${{github.workspace}}/build/compiler - run: | - cmake --build build --target library check-libint2 - cd build && echo "ARTIFACT=`ls -1 libint*tgz`" >> $GITHUB_ENV + run: CTEST_PARALLEL_LEVEL=2 cmake --build build --target check-libint2 -#rm -rf buildcm/ && cmake -S. -Bbuildcm -GNinja -DEXPORT_COMPRESSOR=bzip2 -DWITH_MAX_AM="2;2" -DWITH_ERI_MAX_AM="2;2" -DWITH_ERI3_MAX_AM="3;2" -DENABLE_ERI=1 -DENABLE_ERI3=1 -DMULTIPOLE_MAX_ORDER=2 -DBUILD_SHARED_LIBS=ON && time cmake --build buildcm --target check-libint2 + - name: Build & Test Python bindings + if: ${{ steps.skip_check.outputs.should_skip != 'true' }} + shell: bash + working-directory: ${{github.workspace}}/build/compiler + run: cmake --build build --target check-python build_export: + # to debug the second stage, it is handy to short-circuit the first stage: + # * suppress steps beyond "Archive Library Tarball" with "if: false" + # * for further reduction, run mostly Linux lanes with "os : [ ubuntu-20.04 ]" needs: build_repo if: always() && (needs.build_repo.outputs.should_skip != 'true') strategy: @@ -153,37 +182,40 @@ jobs: - runs-on: ubuntu-latest lane: ubuntu-gnu libargs: > - -DBUILD_SHARED_LIBS=ON + -D BUILD_SHARED_LIBS=ON + -D LIBINT2_ENABLE_FORTRAN=ON testargs: "" - runs-on: windows-latest lane: windows-clang-cl libargs: > - -GNinja - -DCMAKE_BUILD_TYPE=Release - -DBUILD_SHARED_LIBS=OFF - -DCMAKE_CXX_COMPILER=clang-cl - -DCMAKE_C_COMPILER=clang-cl + -G Ninja + -D CMAKE_BUILD_TYPE=Release + -D BUILD_SHARED_LIBS=OFF + -D CMAKE_CXX_COMPILER=clang-cl + -D CMAKE_C_COMPILER=clang-cl testargs: > - -GNinja - -DCMAKE_BUILD_TYPE=Release - -DCMAKE_CXX_COMPILER=clang-cl - -DCMAKE_C_COMPILER=clang-cl + -G Ninja + -D CMAKE_BUILD_TYPE=Release + -D CMAKE_CXX_COMPILER=clang-cl + -D CMAKE_C_COMPILER=clang-cl - runs-on: macos-latest lane: macos-clang libargs: > - -DBUILD_SHARED_LIBS=ON + -D BUILD_SHARED_LIBS=OFF + -D LIBINT2_ENABLE_FORTRAN=ON + # return to shared when mac+fortran+shared is fixed testargs: "" - runs-on: ubuntu-latest lane: ubuntu-intel libargs: > - -DCMAKE_CXX_COMPILER=icpx - -DCMAKE_CXX_FLAGS="--gcc-toolchain=${CONDA_PREFIX} --sysroot=${CONDA_PREFIX}/${HOST}/sysroot -target ${HOST}" + -D CMAKE_CXX_COMPILER=icpx + -D CMAKE_CXX_FLAGS="--gcc-toolchain=${CONDA_PREFIX} --sysroot=${CONDA_PREFIX}/${HOST}/sysroot -target ${HOST}" testargs: > - -DCMAKE_CXX_COMPILER=icpx - -DCMAKE_CXX_FLAGS="--gcc-toolchain=${CONDA_PREFIX} --sysroot=${CONDA_PREFIX}/${HOST}/sysroot -target ${HOST}" + -D CMAKE_CXX_COMPILER=icpx + -D CMAKE_CXX_FLAGS="--gcc-toolchain=${CONDA_PREFIX} --sysroot=${CONDA_PREFIX}/${HOST}/sysroot -target ${HOST}" name: "Export • ${{ matrix.cfg.lane }}" runs-on: ${{ matrix.cfg.runs-on }} @@ -191,6 +223,10 @@ jobs: steps: # Note we're not checking out the repo. All src from Linux tarball generated above. + - uses: actions/download-artifact@v3 + with: + name: Linux-g++-10 + - name: Write a Conda Env File shell: bash -l {0} run: | @@ -202,6 +238,7 @@ jobs: - cmake - ninja - cxx-compiler + - fortran-compiler - python - boost - eigen @@ -212,6 +249,7 @@ jobs: EOF if [[ "${{ runner.os }}" == "Windows" ]]; then sed -i "s/- cxx/#- cxx/g" export.yaml + sed -i "s/- fortran/#- fortran/g" export.yaml fi if [[ "${{ matrix.cfg.lane }}" == "ubuntu-intel" ]]; then sed -i "s/#- dpcpp_linux-64/- dpcpp_linux-64/g" export.yaml @@ -241,25 +279,22 @@ jobs: with: arch: x64 - - uses: actions/download-artifact@v3 - with: - name: Linux-g++-10 - - name: Extract, Build, Install Libint Library shell: bash -l {0} run: | tar -zxf libint*tgz mkdir libint && mv libint-2*/* libint/ && cd libint/ cmake \ - -S. \ - -Bbuild \ - -GNinja \ - -DCMAKE_INSTALL_PREFIX="${{github.workspace}}/installed" \ - -DCMAKE_CXX_COMPILER=${CXX} \ - -DLIBINT2_PYTHON=OFF \ - -DCMAKE_PREFIX_PATH="${CONDA_PREFIX}" \ + -S . \ + -B build \ + -G Ninja \ + -D CMAKE_INSTALL_PREFIX="${{github.workspace}}/installed" \ + -D CMAKE_CXX_COMPILER=${CXX} \ + -D LIBINT2_REQUIRE_CXX_API_COMPILED=ON \ + -D LIBINT2_ENABLE_PYTHON=ON \ + -D CMAKE_PREFIX_PATH="${CONDA_PREFIX}" \ ${{ matrix.cfg.libargs }} - cmake --build build --target install + cmake --build build --target install libint2-python-test - name: Test Libint library - unit tests shell: bash -l {0} diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index d313421ea..ce187abc9 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -4,7 +4,7 @@ on: push: branches: - master - #pull_request: + pull_request: jobs: build_repo: diff --git a/CMakeLists.txt b/CMakeLists.txt index 80a00f777..57bccfc58 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,10 +13,13 @@ include(DynamicVersion) dynamic_version( PROJECT_PREFIX Libint2Compiler_ GIT_ARCHIVAL_FILE ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/.git_archival.txt + VERSION_FULL_MODE POST OUTPUT_COMMIT LibintRepository_COMMIT OUTPUT_VERSION LibintRepository_VERSION OUTPUT_DESCRIBE LibintRepository_DESCRIBE OUTPUT_DISTANCE LibintRepository_DISTANCE + OUTPUT_SHORT_HASH LibintRepository_SHORT_HASH + OUTPUT_VERSION_FULL LibintRepository_VERSION_FULL ) set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build.") # foil Ninja Debug on Windows @@ -100,13 +103,20 @@ message(STATUS "Building using CMake ${CMAKE_VERSION} Generator ${CMAKE_GENERATO option_with_default(CMAKE_BUILD_TYPE "Build type (Release or Debug)" Release) ### compiler-only +option_with_print(LIBINT_BUILD_LIBRARY_AS_SUBPROJECT + "[EXPERT] Build generated library as a subproject: if FALSE will configure and build separately" OFF) ### library-only -option_with_default(LIBINT2_ENABLE_PYTHON +option_with_print(LIBINT2_REQUIRE_CXX_API + "C++11 Libint API: define library targets + test (requires Eigen3, Boost is optional but strongly recommended)" ON) +option_with_print(LIBINT2_REQUIRE_CXX_API_COMPILED + "Build C++11 Compiled (not just header-only) targets (requires Eigen3, Boost strongly recommended)" ON) +option_with_print(LIBINT2_ENABLE_FORTRAN + "Build Fortran03+ Libint interface (requires Fortran)" OFF) +option_with_print(LIBINT2_ENABLE_PYTHON "Build Python bindings (requires Python and Pybind11 and Eigen3)" OFF) -option_with_default(LIBINT2_PREFIX_PYTHON_INSTALL +option_with_print(LIBINT2_PREFIX_PYTHON_INSTALL "For LIBINT2_ENABLE_PYTHON=ON, whether to install the Python module in the Linux manner to CMAKE_INSTALL_PREFIX or to not install it. See target libint2-python-wheel for alternate installation in the Python manner to Python_EXECUTABLE's site-packages." OFF) - option_with_print(BUILD_SHARED_LIBS "Build Libint library as shared, not static" OFF) option_with_print(LIBINT2_BUILD_SHARED_AND_STATIC_LIBS diff --git a/INSTALL.md b/INSTALL.md index 529ae3e9c..28389d2b1 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -73,13 +73,21 @@ cmake/ COPYING src/ tests/ ... ### Build Targets -| `--target ...` | incl. | steps | ( | see | above | ) | | (TARBALL) `--target ...` [^25] | -| -------------- | ----- | ----- | ----- | ----- | ----- | ----- | ----- | ------------------------------ | +| `--target ...` [^27] | incl. | steps | ( | see | above | ) | | (TARBALL) `--target ...` [^25] | +| -------------------- | ----- | ----- | ----- | ----- | ----- | ----- | ----- | ------------------------------ | | `build_libint` | 1 | - | - | - | - | - | - | n/a | | `check-libint2compiler` | 1 | 2 | - | - | - | - | - | n/a | +| `export` | 1 | - | 3 | - | - | - | - | n/a | +| `library` (default) [^26] | 1 | - | 3 | 4 | - | - | - | (default) [^26] | +| `check` | 1 | 2 | 3 | 4 | 5 | - | - | `check` | + +Use combined targets like `cmake --target check install` to avoid some unnecessary rebuilding (esp. of build_libint) that occurs with successive targets. The CMake dependency structure is imperfect. [^25]: (TARBALL) targets can include steps 4 onwards; the starting tarball itself is the product of step 3. +[^26]: See [see "Internal Targets" column in table](#consumption-targets) for individual library targets. + +[^27]: For FetchContent/`LIBINT_BUILD_LIBRARY_AS_SUBPROJECT=ON`, build target `export` aka `libint-library-export`. Then, as a separate command, build further targets like `check` or `install`; target plain `library` is not available. ----------------------------------------------------------------------------- @@ -259,6 +267,9 @@ Note that options, docs, and CMake components are focused on the C++ interface, ### Build Library What (L) (TARBALL) +* `LIBINT2_REQUIRE_CXX_API` — L — Build C++11 Libint API. Define header-only library target and check target (requires Eigen3; Boost recommended; [see prereq line](#prerequisites)). [Default=ON] +* `LIBINT2_REQUIRE_CXX_API_COMPILED` — L — Build C++11 Libint API. Define compiled (not just header-only) targets (requires Eigen3; Boost recommended). [Default=ON] +* `LIBINT2_ENABLE_FORTRAN` — L — Build Fortran03+ module/bindings (requires C and Fortran compilers and Python). [Default=OFF] * `LIBINT2_ENABLE_MPFR` — L — Use MPFR library to test Libint integrals in high precision (requires MPFR; experts only). [Default=OFF] * `LIBINT2_LOCAL_Eigen3_INSTALL` — L — Install an exported target with hard-coded Eigen3 dependency paths. This is potentially useful and important when consuming the compiled C++11 interface library so that the Libint library build and Libint consumer build use the same Eigen3 installation & ABI. This is at most a convenience when consuming the header-only C++11 interface library. See `LIBINT2_LOCAL_Eigen3_FIND`. [Default=OFF] * `LIBINT2_ENABLE_PYTHON` — L — Build Python bindings (requires Python and Eigen3; Boost and pybind11 recommended; [see prereq line](#prerequisites)). Can instead be enabled and built through separate CMake configuration after library build. [Default=OFF] @@ -269,6 +280,7 @@ Note that options, docs, and CMake components are focused on the C++ interface, * `CMAKE_BUILD_TYPE` — G L — [Standard CMake variable](https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html) [Default=Release] * `BUILD_SHARED_LIBS` — L — Build Libint library as shared, not static. [Standard CMake variable](https://cmake.org/cmake/help/latest/variable/BUILD_SHARED_LIBS.html) [Default=OFF] * `LIBINT2_BUILD_SHARED_AND_STATIC_LIBS` — L — Build both shared and static Libint libraries in one shot. Uses `-fPIC`. [Default=OFF] +* `LIBINT_BUILD_LIBRARY_AS_SUBPROJECT` — G — If building compiler and library in continuous command, build generated library as a subproject (FetchContent); if OFF will configure and build separately (ExternalProject) (expert only). [Default=OFF] ### Detecting Dependencies (G L C) (TARBALL) @@ -352,6 +364,35 @@ Note that options, docs, and CMake components are focused on the C++ interface, * `LIBINT_FLOP_COUNT` — G — Support (approximate) FLOP counting by the library. (Generated code will require C++11!). [Default=OFF] * `LIBINT_PROFILE` — G — Turn on profiling instrumentation of the library. (Generated code will require C++11!). [Default=OFF] +----------------------------------------------------------------------------- + +# Consuming Libint + + +### Programming to Access Integrals + +* if you use C++11 or later (strongly recommended): read the [Libint Wiki](https://github.com/evaleev/libint/wiki/using-modern-CPlusPlus-API) +* if you use pre-2011 C++, C, Fortran, or any other language, refer to the [Libint Programmer's Manual](https://sourceforge.net/projects/libint/files/libint-for-beginners/progman-2.0.3-stable.pdf/download) for brief information on how to use the library in your code. + + +### Consumption Targets + +| Namespaced Target[^15] | CMake[^16] Component | Built by Default | Ensure Built | Ensure Excluded | Internal Target(s)[^17] | Alias[^18] | +| ---------------------- | -------------------- | ---------------- | ------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | ----------------------------------- | ------------ | +| | | yes | always | impossible | `int-obj` | | +| `Libint2::int2` | `C` | yes | always | impossible | `int-{static,shared}` | `libint2` | +| `Libint2::cxx` | `CXX_ho` | yes | `LIBINT2_REQUIRE_CXX_API=ON` | `LIBINT2_REQUIRE_CXX_API=OFF` & withhold Eigen3 & `LIBINT2_REQUIRE_CXX_API_COMPILED=OFF` & `LIBINT2_ENABLE_PYTHON=OFF` | `int-cxx-headeronly-{static,shared}` | `libint2_cxx` | +| `Libint2::int2-cxx` | `CXX` | yes | `LIBINT2_REQUIRE_CXX_API_COMPILED=ON` | `LIBINT2_REQUIRE_CXX_API_COMPILED=OFF` | `int-cxx-{static,shared}` | | +| Fortran local[^19] | (NYI) | no | `LIBINT2_ENABLE_FORTRAN=ON` | `LIBINT2_ENABLE_FORTRAN=OFF` | `libint_f` | | + +[^15]: Targets for library consumer use. These are available after `find_package(Libint2)` or `add_subdirectory()`. +[^16]: Ensure target found in installation after `find_package(Libint2 COMPONENTS ...)`. +[^17]: Targets in src/lib/libint/CMakeLists.txt.export . Names subject to change. Use namespaced target names in any consuming code. +[^18]: Deprecated legacy aliases. Update any uses to namespaced target. +[^19]: The `libint_f` internal target defines the Fortran interface to Libint2. One must also link to `Libint2::int2` or `Libint2::cxx`. At present, it is not exported, and a namespaced target is not defined. + + +----------------------------------------------------------------------------- # GNU Autotools Update Guide @@ -407,14 +448,21 @@ Note that options, docs, and CMake components are focused on the C++ interface, * `--disable-1body-property-derivs` --> `-D DISABLE_ONEBODY_PROPERTY_DERIVS=ON` - +* `--enable-shared` --> `-D BUILD_SHARED=ON` --> `-D BUILD_SHARED_LIBS=ON` (standard CMake variable) +* `--enable-static` --> `-D BUILD_STATIC=ON` --> `-D BUILD_SHARED_LIBS=OFF` (standard CMake variable) +* `--enable-shared --enable-static` --> `-D BUILD_SHARED=ON -D BUILD_STATIC=ON` --> `-D LIBINT2_BUILD_SHARED_AND_STATIC_LIBS=ON` +* `-D REQUIRE_CXX_API=ON` --> `-D ENABLE_CXX11API=ON` --> `-D LIBINT2_REQUIRE_CXX_API=ON` * `--enable-mpfr` --> assumed present --> `-D ENABLE_MPFR=ON` --> `-D LIBINT2_ENABLE_MPFR=ON` +* (target) `libint2` --> `Libint2::int2` +* (target) `libint2_cxx` --> `Libint2::cxx` + * `ENV(CPPFLAGS)=-I/path/to/boost/includes` --> `-D BOOST_ROOT=/path/to/boost/prefix` * `-D LIBINT2_PYTHON=ON` --> `-D LIBINT2_ENABLE_PYTHON=ON` * `-D LIBINT_USE_BUNDLED_BOOST=ON` --> `-D CMAKE_DISABLE_FIND_PACKAGE_Boost=ON` (standard CMake variable) * `--with-boost` & `--with-boost-libdir` --> see `BOOST_ROOT` & `Boost_DIR` +* `-D ENABLE_FORTRAN=ON` --> `-D LIBINT2_ENABLE_FORTRAN=ON` * `-D LIBINT_LOCAL_Eigen3_INSTALL` --> `-D LIBINT2_LOCAL_Eigen3_INSTALL` * `-D LIBINT_LOCAL_Eigen3_FIND` --> `-D LIBINT2_LOCAL_Eigen3_FIND` diff --git a/cmake/modules/DynamicVersion.cmake b/cmake/modules/DynamicVersion.cmake index c50be9de4..4c62477fa 100644 --- a/cmake/modules/DynamicVersion.cmake +++ b/cmake/modules/DynamicVersion.cmake @@ -1,5 +1,4 @@ -# copied from https://github.com/LecrisUT/CMakeExtraUtils/blob/main/cmake/DynamicVersion.md ~20 Dec 2023 -# * modified to add distance field and return +# copied from https://github.com/LecrisUT/CMakeExtraUtils/blob/main/cmake/DynamicVersion.md 15 Jan 2023 #[===[.md: # DynamicVersion @@ -16,9 +15,9 @@ Helper module to get the project's version dynamically. Format is compatible wit include_guard() list(APPEND CMAKE_MESSAGE_CONTEXT DynamicVersion) if (POLICY CMP0140) - # Enable using return(PROPAGATE) - # TODO: Remove when cmake 3.25 is commonly distributed - cmake_policy(SET CMP0140 NEW) + # Enable using return(PROPAGATE) + # TODO: Remove when cmake 3.25 is commonly distributed + cmake_policy(SET CMP0140 NEW) endif () #[==============================================================================================[ @@ -42,8 +41,12 @@ function(dynamic_version) Main interface dynamic_version(PROJECT_PREFIX ) dynamic_version(PROJECT_PREFIX - [OUTPUT_VERSION ] [OUTPUT_DESCRIBE ] [OUTPUT_COMMIT ] - [OUTPUT_DISTANCE ] [PROJECT_SOURCE ] [GIT_ARCHIVAL_FILE ]) + [OUTPUT_VERSION ] [OUTPUT_VERSION_FULL ] + [OUTPUT_DESCRIBE ] [OUTPUT_COMMIT ] + [OUTPUT_DISTANCE ] [OUTPUT_SHORT_HASH ] + [VERSION_FULL_MODE ] + [PROJECT_SOURCE ] [GIT_ARCHIVAL_FILE ] + ) Fallbacks dynamic_version(... @@ -61,6 +64,12 @@ function(dynamic_version) `OUTPUT_VERSION` [Default: PROJECT_VERSION] Variable where to save the calculated version + `OUTPUT_VERSION_FULL` [Default: PROJECT_VERSION_FULL] + Variable where to save the full version in the format + + `VERSION_FULL_MODE` [Default: DEV] + Format of the `OUTPUT_VERSION_FULL`. Must be one of [`DEV`, `POST`] + `OUTPUT_DESCRIBE` [Default: GIT_DESCRIBE] Variable where to save the pure `git describe` output @@ -70,6 +79,9 @@ function(dynamic_version) `OUTPUT_DISTANCE` [Default: GIT_DISTANCE] Variable where to save the distance from git tag + `OUTPUT_SHORT_HASH` [Default: GIT_SHORT_HASH] + Variable where to save the shortened git commit hash + `PROJECT_SOURCE` [Default: `${CMAKE_CURRENT_SOURCE_DIR}`] Location of the project source. Has to be either an extracted git archive or a git clone @@ -135,9 +147,12 @@ function(dynamic_version) set(ARGS_OneValue PROJECT_PREFIX OUTPUT_VERSION + OUTPUT_VERSION_FULL + VERSION_FULL_MODE OUTPUT_DESCRIBE OUTPUT_COMMIT OUTPUT_DISTANCE + OUTPUT_SHORT_HASH PROJECT_SOURCE GIT_ARCHIVAL_FILE FALLBACK_VERSION @@ -156,6 +171,14 @@ function(dynamic_version) if (NOT DEFINED ARGS_OUTPUT_VERSION) set(ARGS_OUTPUT_VERSION PROJECT_VERSION) endif () + if (NOT DEFINED ARGS_OUTPUT_VERSION_FULL) + set(ARGS_OUTPUT_VERSION_FULL PROJECT_VERSION_FULL) + endif () + if (NOT DEFINED ARGS_VERSION_FULL_MODE) + set(ARGS_VERSION_FULL_MODE DEV) + elseif (NOT ARGS_VERSION_FULL_MODE MATCHES "(DEV|POST)") + message(FATAL_ERROR "Unsupported VERSION_FULL_MODE = ${ARGS_VERSION_FULL_MODE}") + endif () if (NOT DEFINED ARGS_OUTPUT_DESCRIBE) set(ARGS_OUTPUT_DESCRIBE GIT_DESCRIBE) endif () @@ -165,6 +188,9 @@ function(dynamic_version) if (NOT DEFINED ARGS_OUTPUT_DISTANCE) set(ARGS_OUTPUT_DISTANCE GIT_DISTANCE) endif () + if (NOT DEFINED ARGS_OUTPUT_SHORT_HASH) + set(ARGS_OUTPUT_SHORT_HASH GIT_SHORT_HASH) + endif () if (NOT DEFINED ARGS_PROJECT_SOURCE) set(ARGS_PROJECT_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}) endif () @@ -205,6 +231,7 @@ function(dynamic_version) PROJECT_SOURCE ${ARGS_PROJECT_SOURCE} GIT_ARCHIVAL_FILE ${ARGS_GIT_ARCHIVAL_FILE} TMP_FOLDER ${ARGS_TMP_FOLDER} + VERSION_FULL_MODE ${ARGS_VERSION_FULL_MODE} ) if (DEFINED ARGS_FALLBACK_VERSION) list(APPEND DynamicVersion_ARGS @@ -236,16 +263,22 @@ function(dynamic_version) else () file(COPY ${ARGS_TMP_FOLDER}/${file} DESTINATION ${ARGS_OUTPUT_FOLDER}/) endif () - endif () + endif () endforeach () # Check configuration state file(READ ${ARGS_TMP_FOLDER}/.DynamicVersion.json data) + # failed, mode, and version are always set if get_dynamic_version did not exit with failure string(JSON failed GET ${data} failed) - string(JSON ${ARGS_OUTPUT_VERSION} ERROR_VARIABLE _ GET ${data} version) - string(JSON ${ARGS_OUTPUT_DESCRIBE} ERROR_VARIABLE _ GET ${data} describe) - string(JSON ${ARGS_OUTPUT_COMMIT} ERROR_VARIABLE _ GET ${data} commit) + string(JSON ${ARGS_OUTPUT_VERSION} GET ${data} version) + string(JSON ${ARGS_OUTPUT_VERSION_FULL} GET ${data} version-full) + # Other outputs are optional, populate the variables if found + # These are populated if failed = false + string(JSON ${ARGS_OUTPUT_SHORT_HASH} ERROR_VARIABLE _ GET ${data} short-hash) string(JSON ${ARGS_OUTPUT_DISTANCE} ERROR_VARIABLE _ GET ${data} distance) + # These may not be populated depending on mode + string(JSON ${ARGS_OUTPUT_COMMIT} ERROR_VARIABLE _ GET ${data} commit) + string(JSON ${ARGS_OUTPUT_DESCRIBE} ERROR_VARIABLE _ GET ${data} describe) # Configure targets if (failed) @@ -265,15 +298,28 @@ function(dynamic_version) -P ${CMAKE_CURRENT_FUNCTION_LIST_FILE} COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ARGS_TMP_FOLDER}/.DynamicVersion.json ${ARGS_OUTPUT_FOLDER}/.DynamicVersion.json ) + set(extra_version_args) + # .git_describe might not be generated, e.g. if it's an sdist. Make it optional + if (EXISTS ${ARGS_OUTPUT_FOLDER}/.git_describe) + list(APPEND extra_version_args + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ARGS_TMP_FOLDER}/.git_describe ${ARGS_OUTPUT_FOLDER}/.git_describe + ) + endif () add_custom_target(${ARGS_PROJECT_PREFIX}Version ALL DEPENDS ${ARGS_PROJECT_PREFIX}DynamicVersion - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ARGS_TMP_FOLDER}/.git_describe ${ARGS_OUTPUT_FOLDER}/.git_describe COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ARGS_TMP_FOLDER}/.version ${ARGS_OUTPUT_FOLDER}/.version + ${extra_version_args} ) - add_custom_target(${ARGS_PROJECT_PREFIX}GitHash - DEPENDS ${ARGS_PROJECT_PREFIX}DynamicVersion - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ARGS_TMP_FOLDER}/.git_commit ${ARGS_OUTPUT_FOLDER}/.git_commit - ) + # .git_commit might not exist, make the target a no-op in that case + if (NOT EXISTS ${ARGS_OUTPUT_FOLDER}/.git_commit) + add_custom_target(${ARGS_PROJECT_PREFIX}GitHash + COMMAND ${CMAKE_COMMAND} -E true) + else () + add_custom_target(${ARGS_PROJECT_PREFIX}GitHash + DEPENDS ${ARGS_PROJECT_PREFIX}DynamicVersion + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ARGS_TMP_FOLDER}/.git_commit ${ARGS_OUTPUT_FOLDER}/.git_commit + ) + endif () endif () # This ensures that the project is reconfigured (at least at second run) whenever the version changes @@ -288,14 +334,18 @@ function(dynamic_version) # TODO: Remove when cmake 3.25 is commonly distributed set(${ARGS_OUTPUT_DESCRIBE} ${${ARGS_OUTPUT_DESCRIBE}} PARENT_SCOPE) set(${ARGS_OUTPUT_VERSION} ${${ARGS_OUTPUT_VERSION}} PARENT_SCOPE) + set(${ARGS_OUTPUT_VERSION_FULL} ${${ARGS_OUTPUT_VERSION_FULL}} PARENT_SCOPE) set(${ARGS_OUTPUT_COMMIT} ${${ARGS_OUTPUT_COMMIT}} PARENT_SCOPE) set(${ARGS_OUTPUT_DISTANCE} ${${ARGS_OUTPUT_DISTANCE}} PARENT_SCOPE) + set(${ARGS_OUTPUT_SHORT_HASH} ${${ARGS_OUTPUT_SHORT_HASH}} PARENT_SCOPE) endif () return(PROPAGATE ${ARGS_OUTPUT_DESCRIBE} ${ARGS_OUTPUT_VERSION} + ${ARGS_OUTPUT_VERSION_FULL} ${ARGS_OUTPUT_COMMIT} ${ARGS_OUTPUT_DISTANCE} + ${ARGS_OUTPUT_SHORT_HASH} ) endfunction() @@ -316,8 +366,8 @@ function(get_dynamic_version) ## Synopsis ```cmake get_dynamic_version(PROJECT_SOURCE GIT_ARCHIVAL_FILE - TMP_FOLDER - [FALLBACK_VERSION ] [FALLBACK_HASH ] + TMP_FOLDER VERSION_FULL_MODE + [FALLBACK_VERSION ] [FALLBACK_HASH ] ) ``` @@ -335,6 +385,7 @@ function(get_dynamic_version) ) set(ARGS_OneValue PROJECT_SOURCE + VERSION_FULL_MODE GIT_ARCHIVAL_FILE FALLBACK_VERSION FALLBACK_HASH @@ -366,17 +417,19 @@ function(get_dynamic_version) if (DEFINED ARGS_FALLBACK_VERSION) string(JSON data SET ${data} version \"${ARGS_FALLBACK_VERSION}\") - file(WRITE ${ARGS_TMP_FOLDER}/.DynamicVersion.json ${data}) + string(JSON data SET + ${data} version-full \"${ARGS_FALLBACK_VERSION}\") file(WRITE ${ARGS_TMP_FOLDER}/.version ${ARGS_FALLBACK_VERSION}) endif () if (DEFINED ARGS_FALLBACK_HASH) string(JSON data SET ${data} commit \"${ARGS_FALLBACK_HASH}\") - file(WRITE ${ARGS_TMP_FOLDER}/.DynamicVersion.json ${data}) file(WRITE ${ARGS_TMP_FOLDER}/.git_commit ${ARGS_FALLBACK_HASH}) endif () + file(WRITE ${ARGS_TMP_FOLDER}/.DynamicVersion.json ${data}) + # Check git_archival.txt file is present and properly written if (NOT EXISTS ${ARGS_GIT_ARCHIVAL_FILE}) # If git_archival.txt is missing, project is ill-formed message(${error_message_type} @@ -385,8 +438,6 @@ function(get_dynamic_version) ) return() endif () - - # Get version dynamically from git_archival.txt file(STRINGS ${ARGS_GIT_ARCHIVAL_FILE} describe-name REGEX "^describe-name:.*") if (NOT describe-name) @@ -398,30 +449,65 @@ function(get_dynamic_version) return() endif () - # Try to get the version tag of the form `vX.Y.Z` or `X.Y.Z` (with arbitrary suffix) - if (describe-name MATCHES "^describe-name:[ ]?([v]?([0-9\\.]+).*)") - # First matched group is the full `git describe` of the latest tag - # Second matched group is only the version, i.e. `X.Y.Z` - string(JSON data SET - ${data} describe \"${CMAKE_MATCH_1}\") - file(WRITE ${ARGS_TMP_FOLDER}/.git_describe ${CMAKE_MATCH_1}) - string(JSON data SET - ${data} version \"${CMAKE_MATCH_2}\") - file(WRITE ${ARGS_TMP_FOLDER}/.version ${CMAKE_MATCH_2}) - # Get commit hash + # Try to get the version statically, and if it fails, get it from VCS + if (EXISTS ${ARGS_PROJECT_SOURCE}/PKG-INFO) + # Case1: Python sdist archive. Get everything from PKG-INFO file + set(mode pkg-info) + file(STRINGS ${ARGS_PROJECT_SOURCE}/PKG-INFO version + REGEX "^Version:[ ]?(([0-9\\.]+)([a-zA-Z0-9]*)?(\\.(dev|post)([0-9]+)\\+g([a-f0-9]+))?)$") # Cannot use Regex match from here, need to run string(REGEX MATCH) again # https://gitlab.kitware.com/cmake/cmake/-/issues/23770 + string(REGEX MATCH "^Version:[ ]?(([0-9\\.]+)([a-zA-Z0-9]*)?(\\.(dev|post)([0-9]+)\\+g([a-f0-9]+))?)$" version "${version}") + # Regex match groups: https://regex101.com/r/G4Ox4X/5 + # 1: Full version string + # 2: Version string + # 3: Version suffix (e.g. rc, alpha, etc.) + # 4: Development suffix + # 5: dev/post + # 6: git distance + # 7: short_hash + set(version-full ${CMAKE_MATCH_1}) + set(version ${CMAKE_MATCH_2}) + set(version-suffix ${CMAKE_MATCH_3}) + if (CMAKE_MATCH_4) + set(distance ${CMAKE_MATCH_6}) + set(short-hash ${CMAKE_MATCH_7}) + string(JSON data SET + ${data} dev-type \"${CMAKE_MATCH_5}\") + else () + set(distance 0) + endif () + message(DEBUG "Found version in PKG-INFO") + elseif (describe-name MATCHES "^describe-name:[ ]?(v?([0-9\\.]+)(-?[a-zA-z0-9]*)?(-([0-9]+)-g([a-f0-9]+))?)$") + # Case2: Git archive. Get everything from git_archival.txt file + set(mode git-archive) + # Regex match groups: https://regex101.com/r/osVZpm/4 + # 1: Git describe + # 2: Version string + # 3: Version suffix (e.g. rc, alpha, etc.) + # 4: Development suffix + # 5: git distance + # 6: short_hash + set(describe ${CMAKE_MATCH_1}) + set(version ${CMAKE_MATCH_2}) + set(version-suffix ${CMAKE_MATCH_3}) + if (CMAKE_MATCH_4) + set(distance ${CMAKE_MATCH_5}) + set(short-hash ${CMAKE_MATCH_6}) + else () + set(distance 0) + endif () + # Get commit hash file(STRINGS ${ARGS_GIT_ARCHIVAL_FILE} node REGEX "^node:[ ]?(.*)") + # Cannot use Regex match from here, need to run string(REGEX MATCH) again + # https://gitlab.kitware.com/cmake/cmake/-/issues/23770 string(REGEX MATCH "^node:[ ]?(.*)" node "${node}") - string(JSON data SET - ${data} commit \"${CMAKE_MATCH_1}\") - file(WRITE ${ARGS_TMP_FOLDER}/.git_commit ${CMAKE_MATCH_1}) - message(DEBUG - "Found appropriate tag in .git_archival.txt file" - ) + set(commit ${CMAKE_MATCH_1}) + message(DEBUG "Found version in git-archival.txt") else () - # If not it has to be computed from the git archive + # Default: Git repository. Call git commands + set(mode git) find_package(Git REQUIRED) # Test if project is a git repository execute_process(COMMAND ${GIT_EXECUTABLE} status @@ -435,41 +521,109 @@ function(get_dynamic_version) ) return() endif () - # Get most recent commit hash - execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse HEAD - WORKING_DIRECTORY ${ARGS_PROJECT_SOURCE} - OUTPUT_VARIABLE git-hash - OUTPUT_STRIP_TRAILING_WHITESPACE - COMMAND_ERROR_IS_FATAL ANY) # Get version and describe-name - execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags --long --abbrev=8 --match=?[0-9.]* + execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags --long --match=?[0-9.]* WORKING_DIRECTORY ${ARGS_PROJECT_SOURCE} OUTPUT_VARIABLE describe-name OUTPUT_STRIP_TRAILING_WHITESPACE COMMAND_ERROR_IS_FATAL ANY) # Match any part containing digits and periods (strips out rc and so on) - if (NOT describe-name MATCHES "^([v]?([0-9\\.]+)-([0-9]+)-g(.*))") + if (NOT describe-name MATCHES "^(v?([0-9\\.]+)(-?[a-zA-z0-9]*)?(-([0-9]+)-g([a-f0-9]+))?)$") message(${error_message_type} "Version tag is ill-formatted\n" " Describe-name: ${describe-name}" ) return() endif () - string(JSON data SET - ${data} describe \"${CMAKE_MATCH_1}\") - file(WRITE ${ARGS_TMP_FOLDER}/.git_describe ${CMAKE_MATCH_1}) - string(JSON data SET - ${data} version \"${CMAKE_MATCH_2}\") - file(WRITE ${ARGS_TMP_FOLDER}/.version ${CMAKE_MATCH_2}) - string(JSON data SET - ${data} distance \"${CMAKE_MATCH_3}\") - string(JSON data SET - ${data} short_sha \"${CMAKE_MATCH_4}\") - string(JSON data SET - ${data} commit \"${git-hash}\") - file(WRITE ${ARGS_TMP_FOLDER}/.git_commit ${git-hash}) - message(DEBUG - "Found appropriate tag from git" + # Regex match groups: https://regex101.com/r/GIfYI1/2 + # 1: Git describe + # 2: Version string + # 3: Version suffix (e.g. rc, alpha, etc.) + # 4: Development suffix + # 5: git distance + # 6: short_hash + set(describe ${CMAKE_MATCH_1}) + set(version ${CMAKE_MATCH_2}) + set(version-suffix ${CMAKE_MATCH_3}) + if (CMAKE_MATCH_4) + set(distance ${CMAKE_MATCH_5}) + set(short-hash ${CMAKE_MATCH_6}) + else () + set(distance 0) + endif () + # Get commit hash + execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse HEAD + WORKING_DIRECTORY ${ARGS_PROJECT_SOURCE} + OUTPUT_VARIABLE commit + OUTPUT_STRIP_TRAILING_WHITESPACE + COMMAND_ERROR_IS_FATAL ANY) + message(DEBUG "Found version git repo") + endif () + + # Construct the version_full if it was not already provided + if (NOT version-full) + string(REGEX REPLACE "[-_]" "" version-suffix-sanitized "${version-suffix}") + if (distance EQUAL 0) + # If the distance is 0, just use the original tag version with sanitized suffix + set(version-full "${version}${version-suffix-sanitized}") + else () + # Otherwise construct it according to VERSION_FULL_MODE + if (ARGS_VERSION_FULL_MODE STREQUAL DEV) + # In DEV mode, we bump the last digit of the version. If this is in version-suffix, like `-rcX`, then + # this must be bumped instead + if (version-suffix-sanitized MATCHES "([a-zA-Z]*)([0-9]+)") + math(EXPR bumped_number "${CMAKE_MATCH_2} + 1") + set(version-suffix-sanitized "${CMAKE_MATCH_1}${bumped_number}") + elseif (version MATCHES "([0-9\\.]*\\.)([0-9]+)") + math(EXPR bumped_number "${CMAKE_MATCH_2} + 1") + set(version "${CMAKE_MATCH_1}${bumped_number}") + else () + message(FATAL_ERROR "Assert False: version = ${version}") + endif () + set(version-full "${version}${version-suffix-sanitized}.dev${distance}+g${short-hash}") + elseif (ARGS_VERSION_FULL_MODE STREQUAL POST) + set(version-full "${version}${version-suffix-sanitized}.post${distance}+g${short-hash}") + else () + message(FATAL_ERROR "Assert False: VERSION_FULL_MODE = ${ARGS_VERSION_FULL_MODE}") + endif () + endif () + endif () + + # Construct the JSON data + string(JSON data SET ${data} + mode \"${mode}\" + ) + string(JSON data SET ${data} + version \"${version}\" + ) + file(WRITE ${ARGS_TMP_FOLDER}/.version ${version}) + string(JSON data SET ${data} + version-full \"${version-full}\" + ) + if (describe) + string(JSON data SET ${data} + describe \"${describe}\" + ) + file(WRITE ${ARGS_TMP_FOLDER}/.git_describe ${describe}) + endif () + if (commit) + string(JSON data SET ${data} + commit \"${commit}\" + ) + file(WRITE ${ARGS_TMP_FOLDER}/.git_commit ${commit}) + endif () + set(JSON data SET ${data} + version-full \"${version-full}\" + ) + string(JSON data SET ${data} + version-suffix \"${version-suffix}\" + ) + string(JSON data SET ${data} + distance ${distance} + ) + if (short-hash) + string(JSON data SET ${data} + short-hash \"${short-hash}\" ) endif () diff --git a/cmake/modules/int_computed.cmake.in b/cmake/modules/int_computed.cmake.in index 1511d08bb..51d79d527 100644 --- a/cmake/modules/int_computed.cmake.in +++ b/cmake/modules/int_computed.cmake.in @@ -28,6 +28,8 @@ set(LIBINT_MINOR_VERSION "@LIBINT_MINOR_VERSION@") set(LIBINT_MICRO_VERSION "@LIBINT_MICRO_VERSION@") set(LIBINT_VERSION ${LIBINT_MAJOR_VERSION}.${LIBINT_MINOR_VERSION}.${LIBINT_MICRO_VERSION}) +# for macros.tex +set(LIBINT_MMM_VERSION "${LIBINT_VERSION}") # <<< Dev Version >>> @@ -54,53 +56,31 @@ set(LIBINT2_SHELL_SET "@LIBINT2_SHELL_SET@") # <<< Features List >>> -if ((@LIBINT_CGSHELL_ORDERING@ EQUAL 1) AND (@LIBINT_SHELL_SET@ EQUAL 1)) - set(_ordering "ss") -elseif((@LIBINT_CGSHELL_ORDERING@ EQUAL 1) AND (@LIBINT_SHELL_SET@ EQUAL 2)) - set(_ordering "so") -elseif((@LIBINT_CGSHELL_ORDERING@ EQUAL 2) AND (@LIBINT_SHELL_SET@ EQUAL 1)) - set(_ordering "is") -elseif((@LIBINT_CGSHELL_ORDERING@ EQUAL 2) AND (@LIBINT_SHELL_SET@ EQUAL 2)) - set(_ordering "io") -elseif((@LIBINT_CGSHELL_ORDERING@ EQUAL 3) AND (@LIBINT_SHELL_SET@ EQUAL 1)) - set(_ordering "gs") -elseif((@LIBINT_CGSHELL_ORDERING@ EQUAL 3) AND (@LIBINT_SHELL_SET@ EQUAL 2)) - set(_ordering "go") -elseif((@LIBINT_CGSHELL_ORDERING@ EQUAL 4) AND (@LIBINT_SHELL_SET@ EQUAL 1)) - set(_ordering "os") -elseif((@LIBINT_CGSHELL_ORDERING@ EQUAL 4) AND (@LIBINT_SHELL_SET@ EQUAL 2)) - set(_ordering "oo") -elseif((@LIBINT_CGSHELL_ORDERING@ EQUAL 5) AND (@LIBINT_SHELL_SET@ EQUAL 1)) - set(_ordering "bs") -elseif((@LIBINT_CGSHELL_ORDERING@ EQUAL 5) AND (@LIBINT_SHELL_SET@ EQUAL 2)) - set(_ordering "bo") -elseif((@LIBINT_CGSHELL_ORDERING@ EQUAL 1) AND (@LIBINT_SHELL_SET@ EQUAL 1)) - set(_ordering "ss") -elseif((@LIBINT_CGSHELL_ORDERING@ EQUAL 1) AND (@LIBINT_SHELL_SET@ EQUAL 2)) - set(_ordering "so") -elseif((@LIBINT_CGSHELL_ORDERING@ EQUAL 2) AND (@LIBINT_SHELL_SET@ EQUAL 1)) - set(_ordering "is") -elseif((@LIBINT_CGSHELL_ORDERING@ EQUAL 2) AND (@LIBINT_SHELL_SET@ EQUAL 2)) - set(_ordering "io") -elseif((@LIBINT_CGSHELL_ORDERING@ EQUAL 3) AND (@LIBINT_SHELL_SET@ EQUAL 1)) - set(_ordering "gs") -elseif((@LIBINT_CGSHELL_ORDERING@ EQUAL 3) AND (@LIBINT_SHELL_SET@ EQUAL 2)) - set(_ordering "go") -elseif((@LIBINT_CGSHELL_ORDERING@ EQUAL 4) AND (@LIBINT_SHELL_SET@ EQUAL 1)) - set(_ordering "os") -elseif((@LIBINT_CGSHELL_ORDERING@ EQUAL 4) AND (@LIBINT_SHELL_SET@ EQUAL 2)) - set(_ordering "oo") -elseif((@LIBINT_CGSHELL_ORDERING@ EQUAL 5) AND (@LIBINT_SHELL_SET@ EQUAL 1)) - set(_ordering "bs") -elseif((@LIBINT_CGSHELL_ORDERING@ EQUAL 5) AND (@LIBINT_SHELL_SET@ EQUAL 2)) - set(_ordering "bo") +if (@LIBINT_CGSHELL_ORDERING@ EQUAL 1) + set(_o1st "s") +elseif(@LIBINT_CGSHELL_ORDERING@ EQUAL 2) + set(_o1st "i") +elseif(@LIBINT_CGSHELL_ORDERING@ EQUAL 3) + set(_o1st "g") +elseif(@LIBINT_CGSHELL_ORDERING@ EQUAL 4) + set(_o1st "o") +elseif(@LIBINT_CGSHELL_ORDERING@ EQUAL 5) + set(_o1st "b") else() - message(STATUS "int_computed.cmake: indeterminate orderings") + message(STATUS "int_computed.cmake: indeterminate orderings: cgshell") +endif() + +if (@LIBINT_SHELL_SET@ EQUAL 1) + set(_o2nd "s") +elseif(@LIBINT_SHELL_SET@ EQUAL 2) + set(_o2nd "o") +else() + message(STATUS "int_computed.cmake: indeterminate orderings: shell_set") endif() # for configuration.cc and libint2-config.cmake files set(Libint2_CONFIG_COMPONENTS "@Libint2_ERI_COMPONENTS@") -list(PREPEND Libint2_CONFIG_COMPONENTS "${_ordering}") +list(PREPEND Libint2_CONFIG_COMPONENTS "${_o1st}${_o2nd}") # <<< AM Components >>> diff --git a/cmake/modules/int_versions.cmake b/cmake/modules/int_versions.cmake index 35c6e9d13..460fd7ef9 100644 --- a/cmake/modules/int_versions.cmake +++ b/cmake/modules/int_versions.cmake @@ -13,10 +13,12 @@ # <<< Sortable Version >>> -message(DEBUG "LibintRepository_VERSION ${LibintRepository_VERSION}") -message(DEBUG "LibintRepository_COMMIT ${LibintRepository_COMMIT}") -message(DEBUG "LibintRepository_DISTANCE ${LibintRepository_DISTANCE}") -message(DEBUG "LibintRepository_DESCRIBE ${LibintRepository_DESCRIBE}") +message(DEBUG "LibintRepository_VERSION ${LibintRepository_VERSION}") +message(DEBUG "LibintRepository_VERSION_FULL ${LibintRepository_VERSION_FULL}") +message(DEBUG "LibintRepository_COMMIT ${LibintRepository_COMMIT}") +message(DEBUG "LibintRepository_SHORT_HASH ${LibintRepository_SHORT_HASH}") +message(DEBUG "LibintRepository_DISTANCE ${LibintRepository_DISTANCE}") +message(DEBUG "LibintRepository_DESCRIBE ${LibintRepository_DESCRIBE}") if (LibintRepository_DISTANCE STREQUAL "0") set(LIBINT_SORTABLE_VERSION "${LibintRepository_VERSION}") @@ -24,8 +26,10 @@ else() set(LIBINT_SORTABLE_VERSION "${LibintRepository_VERSION}.post${LibintRepository_DISTANCE}") endif() -string(SUBSTRING ${LibintRepository_COMMIT} 0 7 LIBINT_GIT_COMMIT) -message(DEBUG "LIBINT_GIT_COMMIT ${LIBINT_GIT_COMMIT}") +# short hash from DynVer is variable length from `git describe`. +# * use below for fixed length +# string(SUBSTRING ${LibintRepository_COMMIT} 0 7 LIBINT_GIT_COMMIT) +message(DEBUG "LIBINT_GIT_COMMIT ${LibintRepository_SHORT_HASH}") # Below goes into BibTeX citation. Currently year of export. For year of tag, parse: # `git show -s --no-notes --date=short --pretty='%cd' v2.7.2` responds: 2022-06-20 @@ -52,7 +56,7 @@ else() set(LIBINT_EXT_VERSION ${LIBINT_VERSION}) endif() -message(STATUS "Version: Full ${LIBINT_EXT_VERSION} Numeric ${LIBINT_VERSION} Sortable ${LIBINT_SORTABLE_VERSION}") +message(STATUS "Version: Full ${LIBINT_EXT_VERSION} Numeric ${LIBINT_VERSION} Sortable ${LIBINT_SORTABLE_VERSION} SCM ${LibintRepository_VERSION_FULL}") if (NOT(LibintRepository_VERSION STREQUAL LIBINT_VERSION)) message(AUTHOR_WARNING diff --git a/export/cmake/CMakeLists.txt.export b/export/cmake/CMakeLists.txt.export index 1908ff32f..6e8c0631a 100644 --- a/export/cmake/CMakeLists.txt.export +++ b/export/cmake/CMakeLists.txt.export @@ -8,7 +8,7 @@ project(Libint LANGUAGES CXX C) # Set Libint version =================================================================================================== set(LIBINT_MAJOR_VERSION 2) set(LIBINT_MINOR_VERSION 8) -set(LIBINT_MICRO_VERSION 1) +set(LIBINT_MICRO_VERSION 1) # Sync this with python/CMakeLists.txt set(LIBINT_BUILDID ) set(LIBINT_VERSION "${LIBINT_MAJOR_VERSION}.${LIBINT_MINOR_VERSION}.${LIBINT_MICRO_VERSION}") if (LIBINT_BUILDID) diff --git a/include/libint2/config.h.cmake.in b/include/libint2/config.h.cmake.in index 723f28cb2..d88b5a1e7 100644 --- a/include/libint2/config.h.cmake.in +++ b/include/libint2/config.h.cmake.in @@ -330,15 +330,15 @@ #if __has_cpp_attribute(maybe_unused) #define LIBINT_MAYBE_UNUSED [[maybe_unused]] #endif -#endif // __has_cpp_attribute +#endif /* __has_cpp_attribute */ #ifndef LIBINT_MAYBE_UNUSED #if defined __has_attribute # if __has_attribute (unused) # define LIBINT_MAYBE_UNUSED __attribute__ ((unused)) # endif -#endif // __has_attribute -#endif // LIBINT_MAYBE_UNUSED -#ifndef LIBINT_MAYBE_UNUSED // fallback +#endif /* __has_attribute */ +#endif /* LIBINT_MAYBE_UNUSED */ +#ifndef LIBINT_MAYBE_UNUSED /* fallback */ #define LIBINT_MAYBE_UNUSED #endif diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 5511d99d5..ba0bf421f 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -5,7 +5,20 @@ else() endif() cmake_policy(SET CMP0079 NEW) -project(libint2-python) +if(NOT DEFINED LIBINT_VERSION) + # for indep bld of project(libint2-python), version (for setup.py) not available from project(Libint2) + list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules) + include(int_computed OPTIONAL) # cmake+cmake + + if(NOT DEFINED LIBINT_VERSION) + set(LIBINT_VERSION "2.8.1") # libtool+cmake + endif() +endif() + +project( + libint2-python + VERSION ${LIBINT_VERSION} + ) if (NOT TARGET Python::Module) find_package(Python COMPONENTS Interpreter Development REQUIRED) @@ -23,6 +36,7 @@ if (NOT TARGET pybind11::pybind11) pybind11 GIT_REPOSITORY https://github.com/ValeevGroup/pybind11.git GIT_TAG ValeevGroup/v2.11 + # FIND_PACKAGE_ARGS 2.6.0 CONFIG # CMake 3.24 integrates find_package() call above into FC_Declare ) FetchContent_MakeAvailable(pybind11) @@ -40,10 +54,10 @@ if (pybind11_VERSION VERSION_GREATER_EQUAL 2.11.0) endif() pybind11_add_module( - libint2-python MODULE - #EXCLUDE_FROM_ALL - src/libint2/libint2.cc - src/libint2/engine.cc + libint2-python + MODULE + src/libint2/libint2.cc + src/libint2/engine.cc ) target_compile_features(libint2-python PRIVATE "cxx_std_17") @@ -56,9 +70,8 @@ endif() target_compile_options(libint2-python PRIVATE - # too many warnings on Windows - # $<$:/W4> - $<$>:-Wall> + #$<$:/W4> + $<$>:-Wall> ) #find_package(Eigen3 3.3 REQUIRED) @@ -66,23 +79,28 @@ target_compile_options(libint2-python set_target_properties( libint2-python PROPERTIES - #PREFIX "" - OUTPUT_NAME libint2 + #PREFIX "" + OUTPUT_NAME libint2 ) -if (TARGET libint2_obj) - set(libint2_python_target libint2_obj) +# future note: this whole block could likely be replaced by the below, but perhaps explicit better for now +# * `if(TARGET Libint2::cxx)\n target_link_libraries(libint2-python PRIVATE Libint2::cxx)\nelse()\n find_package(Libint2 ...` +if (TARGET Libint2::cxx) - if(MSVC) + + if (MSVC) target_compile_definitions(libint2-python PUBLIC _USE_MATH_DEFINES) target_compile_options(libint2-python PUBLIC "/EHsc") endif() - target_link_libraries(libint2-python PRIVATE libint2_obj) - target_link_libraries(libint2-python PRIVATE Boost::boost) + target_link_libraries( + libint2-python + PRIVATE + Libint2::cxx + ) else() - find_package(Libint2 REQUIRED) - target_link_libraries(libint2-python PRIVATE Libint2::cxx) + find_package(Libint2 COMPONENTS CXX_ho REQUIRED) + target_link_libraries(libint2-python PRIVATE Libint2::cxx) endif() # if (Eigen3::Eigen) @@ -93,12 +111,39 @@ endif() configure_file(setup.py.in ${PROJECT_BINARY_DIR}/setup.py) +# <<< Install >>> + +if (LIBINT2_PREFIX_PYTHON_INSTALL) + # * Note that this block is *Linux-style* install to `CMAKE_INSTALL_PREFIX`. + # * For *Python-style* install to `Python_EXECUTABLE`'s site-packages, use + # wheel target below from python/ directory. + # > make libint2-python-wheel + # > pip3 install dist/libint2-*.whl + + execute_process( + COMMAND ${Python_EXECUTABLE} -c + "import os, sys, sysconfig as s; spdir = s.get_path('platlib'); print(spdir.replace(os.path.commonpath([sys.prefix, spdir]), '').lstrip(os.path.sep));" + OUTPUT_VARIABLE LIBINT2_INSTALL_PYMODDIR + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + message(STATUS "Showing option LIBINT2_INSTALL_PYMODDIR: ${LIBINT2_INSTALL_PYMODDIR} (non-user-configurable until wanted)") + + install( + FILES $ + COMPONENT ${L2}_Python + DESTINATION ${LIBINT2_INSTALL_PYMODDIR} + ) +endif() + +# <<< Python Tooling >>> + add_custom_target( libint2-python-test DEPENDS libint2-python COMMAND ${Python_EXECUTABLE} -m setup test WORKING_DIRECTORY ${PROJECT_BINARY_DIR} ) +add_custom_target(check-python DEPENDS libint2-python-test) add_custom_target( libint2-python-wheel diff --git a/src/bin/CMakeLists.txt b/src/bin/CMakeLists.txt index 7de67d430..58d0a77bb 100644 --- a/src/bin/CMakeLists.txt +++ b/src/bin/CMakeLists.txt @@ -6,6 +6,7 @@ add_custom_target_subproject( USES_TERMINAL COMMAND ${CMAKE_CTEST_COMMAND} -V -R "libint2/compiler" ) +add_dependencies(check-libint2compiler build_libint) if (BUILD_TESTING) add_subdirectory(test_eri) diff --git a/src/bin/libint/CMakeLists.txt b/src/bin/libint/CMakeLists.txt index 532a6da97..ebb7983b7 100644 --- a/src/bin/libint/CMakeLists.txt +++ b/src/bin/libint/CMakeLists.txt @@ -38,7 +38,6 @@ add_library( target_compile_definitions( libint-libcompiler PUBLIC - __COMPILING_LIBINT2=1 $<$:_USE_MATH_DEFINES> # MSVC does not include constants, unless _USE_MATH_DEFINES is defined. ) @@ -85,7 +84,10 @@ add_executable( EXCLUDE_FROM_ALL build_libint.cc ) -target_link_libraries(build_libint libint-libcompiler) +target_link_libraries( + build_libint + libint-libcompiler + ) if(MSVC) # Increase stack size from 1 MB to 4 MB diff --git a/src/lib/libint/CMakeLists.txt b/src/lib/libint/CMakeLists.txt index e652bdccb..7de6dbf74 100644 --- a/src/lib/libint/CMakeLists.txt +++ b/src/lib/libint/CMakeLists.txt @@ -1,44 +1,69 @@ list(APPEND CMAKE_MODULE_PATH ${PROJECT_BINARY_DIR}/cmake/modules) +include(GNUInstallDirs) include(int_computed) # for macros.tex and features # <<< Generate Library Source >>> -file(MAKE_DIRECTORY "${EXPORT_STAGE_DIR}/src") +file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/generated") add_custom_command( OUTPUT - "${EXPORT_STAGE_DIR}/src/libint2_params.h" + "${PROJECT_BINARY_DIR}/generated/libint2_params.h" + "${PROJECT_BINARY_DIR}/generated/HRRPart0bra0ket0pp.h" + "${PROJECT_BINARY_DIR}/generated/HRRPart0bra0ket0pp.cc" COMMAND $ - WORKING_DIRECTORY "${EXPORT_STAGE_DIR}/src" DEPENDS build_libint + WORKING_DIRECTORY "${PROJECT_BINARY_DIR}/generated" COMMENT "Generating Libint2 library source" ) -add_custom_target(libint-library-generate DEPENDS "${EXPORT_STAGE_DIR}/src/libint2_params.h") +add_custom_target(libint-library-generate DEPENDS "${PROJECT_BINARY_DIR}/generated/libint2_params.h") + # <<< Add Metadata To The Library Source >>> +# the library source to be tarballed is mainly assembled through populate.cmake. +# These following configure_file's need a few extra substitution variables that +# aren't passed to populate. + configure_file( "features.cmake.in" "${EXPORT_STAGE_DIR}/features" @ONLY) configure_file( - "${PROJECT_SOURCE_DIR}/include/libint2/basis.h.in" # TODO could move to basis.h.cmake.in when libtool retires + "${PROJECT_SOURCE_DIR}/doc/progman/macros.tex.in" + "${EXPORT_STAGE_DIR}/doc/macros.tex" + @ONLY) + +# position basis.h for local buildtree. +# * gets re-configured (CMakeLists.txt.export) for library export with its own +# CMAKE_INSTALL_PREFIX +# * gets re-re-positioned (end of this file) for case of continuous generator + +# library build (through EP) with outer CMAKE_INSTALL_PREFIX +set(DATADIR_ABSOLUTE ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/libint/${LIBINT_VERSION}) +configure_file( + "${PROJECT_SOURCE_DIR}/include/libint2/basis.h.in" # TODO basis.h.cmake.in after libtool retires "include/libint2/basis.h" @ONLY) add_custom_command( OUTPUT ${EXPORT_STAGE_DIR}/CMakeLists.txt + ${EXPORT_STAGE_DIR}/include/libint2_params.h + ${EXPORT_STAGE_DIR}/include/HRRPart0bra0ket0pp.h + ${EXPORT_STAGE_DIR}/src/HRRPart0bra0ket0pp.cc + COMMAND ${CMAKE_COMMAND} + "-DPROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR}" + "-DPROJECT_BINARY_DIR=${PROJECT_BINARY_DIR}" + "-DEXPORT_STAGE_DIR=${EXPORT_STAGE_DIR}" + -P ${CMAKE_CURRENT_SOURCE_DIR}/populate.cmake DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/populate.cmake" + "${PROJECT_BINARY_DIR}/generated/libint2_params.h" + "${PROJECT_BINARY_DIR}/generated/HRRPart0bra0ket0pp.h" + "${PROJECT_BINARY_DIR}/generated/HRRPart0bra0ket0pp.cc" libint-library-generate - COMMAND ${CMAKE_COMMAND} - "-DPROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR}" - "-DPROJECT_BINARY_DIR=${PROJECT_BINARY_DIR}" - "-DEXPORT_STAGE_DIR=${EXPORT_STAGE_DIR}" - -P ${CMAKE_CURRENT_SOURCE_DIR}/populate.cmake COMMENT "Populating Libint2 library" ) add_custom_target(libint-library-populate DEPENDS ${EXPORT_STAGE_DIR}/CMakeLists.txt) @@ -46,21 +71,25 @@ add_custom_target(libint-library-populate DEPENDS ${EXPORT_STAGE_DIR}/CMakeLists # <<< Export The Library Source >>> +set(EXPORT_TARBALL "${EXPORT_STAGE_DIR}.${EXPORT_COMPRESSOR_EXT}") add_custom_command( OUTPUT - "${EXPORT_STAGE_DIR}.${EXPORT_COMPRESSOR_EXT}" - COMMAND ${CMAKE_COMMAND} -E tar ${EXPORT_COMPRESSOR_CMD} "${EXPORT_STAGE_DIR}.${EXPORT_COMPRESSOR_EXT}" "${EXPORT_STAGE_DIR}" + "${EXPORT_TARBALL}" + COMMAND ${CMAKE_COMMAND} -E tar ${EXPORT_COMPRESSOR_CMD} "${EXPORT_TARBALL}" "${EXPORT_STAGE_DIR}" DEPENDS libint-library-generate libint-library-populate + ${EXPORT_STAGE_DIR}/CMakeLists.txt WORKING_DIRECTORY "${EXPORT_STAGE_DIR}/.." - COMMENT "Exporting tarball of Libint2 library source" + COMMENT "Exporting tarball of Libint2 library source: ${EXPORT_TARBALL}" ) - add_custom_target( - libint-library-export - DEPENDS - "${EXPORT_STAGE_DIR}.${EXPORT_COMPRESSOR_EXT}" - ) +if (LIBINT_BUILD_LIBRARY_AS_SUBPROJECT) + # rerun cmake if building as subproject to unpack and consume the library as subproject + add_custom_target(libint-library-export DEPENDS "${EXPORT_TARBALL}" + COMMAND ${CMAKE_COMMAND} -S "${CMAKE_SOURCE_DIR}" -B "${CMAKE_BINARY_DIR}") +else() + add_custom_target(libint-library-export DEPENDS "${EXPORT_TARBALL}") +endif() add_custom_target(export DEPENDS libint-library-export) @@ -74,13 +103,32 @@ else() message(FATAL_ERROR "No C language support; invoke CMake with -D CMAKE_C_COMPILER=/path/to/C/compiler to resolve") endif() +if (LIBINT_BUILD_LIBRARY_AS_SUBPROJECT) + include(FetchContent) + + if (EXISTS "${EXPORT_TARBALL}") + message("Unpacking ${EXPORT_TARBALL} and setting up as a subproject") + FetchContent_Declare( + libint-library + URL "${EXPORT_TARBALL}" + ) + FetchContent_MakeAvailable(libint-library) + else() + message(WARNING "LIBINT_BUILD_LIBRARY_AS_SUBPROJECT=ON but library has not been exported yet; build target 'libint-library-export' first, this will make library build/test targets ('check', 'install') available. Don't run 'check' with CTEST_PARALLEL_LEVEL as this will build the library multiple times.") + endif() + +else() include(ExternalProject) list(APPEND library_CMAKE_ARGS + -G${CMAKE_GENERATOR} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DBUILD_TESTING=${BUILD_TESTING} -DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS} -DLIBINT2_BUILD_SHARED_AND_STATIC_LIBS=${LIBINT2_BUILD_SHARED_AND_STATIC_LIBS} + -DLIBINT2_REQUIRE_CXX_API=${LIBINT2_REQUIRE_CXX_API} + -DLIBINT2_REQUIRE_CXX_API_COMPILED=${LIBINT2_REQUIRE_CXX_API_COMPILED} + -DLIBINT2_ENABLE_FORTRAN=${LIBINT2_ENABLE_FORTRAN} -DLIBINT2_ALIGN_SIZE=${LIBINT_ALIGN_SIZE} -DLIBINT2_REALTYPE=${LIBINT2_REALTYPE} -DLIBINT2_ENABLE_MPFR=${LIBINT2_ENABLE_MPFR} @@ -108,10 +156,13 @@ endif() if (LIBINT2_LOCAL_Eigen3_INSTALL) list(APPEND library_CMAKE_ARGS "-DLIBINT2_LOCAL_Eigen3_INSTALL=${LIBINT2_LOCAL_Eigen3_INSTALL}") endif() - - - - + if (Python_EXECUTABLE) + list(APPEND library_CMAKE_ARGS "-DPython_EXECUTABLE=${Python_EXECUTABLE}") + endif() + if (LIBINT2_ENABLE_FORTRAN AND CMAKE_Fortran_COMPILER) + # Note: not handling CMAKE_Fortran_COMPILER_ARG1 + list(APPEND library_CMAKE_ARGS "-DCMAKE_Fortran_COMPILER=${CMAKE_Fortran_COMPILER}") + endif() ExternalProject_Add( library @@ -120,7 +171,7 @@ endif() BUILD_ALWAYS 1 # download generalized to generating source by unpacking source tarball # * DOWNLOAD_DIR is tidier but fails on Windows - URL "${EXPORT_STAGE_DIR}.${EXPORT_COMPRESSOR_EXT}" + URL "${EXPORT_TARBALL}" LOG_DOWNLOAD 1 CMAKE_ARGS "${library_CMAKE_ARGS}" CMAKE_CACHE_ARGS @@ -130,10 +181,17 @@ endif() -DCMAKE_C_COMPILER_ARG1:STRING=${CMAKE_C_COMPILER_ARG1} -DCMAKE_PREFIX_PATH:STRING=${CMAKE_PREFIX_PATH} TEST_COMMAND "" - STEP_TARGETS build + USES_TERMINAL_CONFIGURE TRUE + USES_TERMINAL_BUILD TRUE + USES_TERMINAL_INSTALL TRUE + STEP_TARGETS + build + install ) ExternalProject_Get_property(library BINARY_DIR) + # instead of running tests by default, replicate check-libint2 target here + # and use it to invoke library's check-libint2 target if (BUILD_TESTING) include(AddCustomTargetSubproject) add_custom_target_subproject( @@ -144,6 +202,17 @@ endif() DEPENDS "library-build" ) + + if (LIBINT2_ENABLE_PYTHON) + find_package(Python COMPONENTS Interpreter REQUIRED) + add_custom_target_subproject( + libint2 check-python + COMMAND ${Python_EXECUTABLE} -m setup test + WORKING_DIRECTORY ${BINARY_DIR}/python + DEPENDS + "library-install" + ) + endif() endif() install( @@ -151,3 +220,4 @@ endif() "${CMAKE_CURRENT_BINARY_DIR}/include/libint2/basis.h" DESTINATION "${STAGED_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}/libint2" ) +endif() diff --git a/src/lib/libint/CMakeLists.txt.export b/src/lib/libint/CMakeLists.txt.export index 48c42d0eb..73c946647 100644 --- a/src/lib/libint/CMakeLists.txt.export +++ b/src/lib/libint/CMakeLists.txt.export @@ -29,6 +29,7 @@ set(pnv libint2) # projectnameversion # See "TARBALL" labels in INSTALL.md for elaboration of options, dependencies, & targets. ################################### Options #################################### +include(GNUInstallDirs) include(CTest) include(options) include(CheckFunctionExists) @@ -41,6 +42,12 @@ option_with_print(BUILD_SHARED_LIBS "Build Libint library as shared, not static" OFF) option_with_print(LIBINT2_BUILD_SHARED_AND_STATIC_LIBS "Build both shared and static Libint libraries in one shot. Uses -fPIC." OFF) +option_with_print(LIBINT2_REQUIRE_CXX_API + "C++11 Libint API: define library targets + test (requires Eigen3, Boost is optional but strongly recommended)" ON) +option_with_print(LIBINT2_REQUIRE_CXX_API_COMPILED + "Build C++11 Compiled (not just header-only) targets (requires Eigen3)" OFF) +option_with_print(LIBINT2_ENABLE_FORTRAN + "Build Fortran03+ Libint interface (requires C and Fortran and Python)" OFF) option_with_print(LIBINT2_ENABLE_MPFR "Use GNU MPFR library for high-precision testing (requires MPFR. EXPERTS ONLY)" OFF) option_with_print(LIBINT2_ENABLE_PYTHON @@ -52,21 +59,37 @@ option_with_print(LIBINT2_LOCAL_Eigen3_INSTALL option_with_print(CMAKE_DISABLE_FIND_PACKAGE_Boost "When Boost required for C++11 API, disable its detection, thereby forcing use of bundled Boost (Standard CMake variable: https://cmake.org/cmake/help/latest/variable/CMAKE_DISABLE_FIND_PACKAGE_PackageName.html)" OFF) - check_function_exists(posix_memalign HAVE_POSIX_MEMALIGN) if (HAVE_POSIX_MEMALIGN) option_with_default(LIBINT2_ALIGN_SIZE "(EXPERT) if posix_memalign is available, this will specify alignment of Libint data, in units of sizeof(LIBINT2_REALTYPE). Default is to use built-in heuristics." 0) mark_as_advanced(LIBINT2_ALIGN_SIZE) elseif (MSVC) - set(HAVE_POSIX_MEMALIGN 1) # aliased in memory.h + # works for Windows in memory.h set(LIBINT2_ALIGN_SIZE "0" CACHE STRING "") endif() option_with_default(LIBINT2_REALTYPE "Specifies the floating-point data type used by the library." double) +option_with_print(LIBINT_USER_DEFINED_REAL_INCLUDES + "UNTESTED Additional #includes necessary to use the real type." OFF) include(int_userreal) +if ((LIBINT2_REQUIRE_CXX_API_COMPILED OR LIBINT2_ENABLE_PYTHON) AND NOT LIBINT2_REQUIRE_CXX_API) + set(LIBINT2_REQUIRE_CXX_API 1) + message(STATUS "Setting option LIBINT2_REQUIRE_CXX_API=ON as needed by LIBINT2_REQUIRE_CXX_API_COMPILED=${LIBINT2_REQUIRE_CXX_API_COMPILED} and/or LIBINT2_ENABLE_PYTHON=${LIBINT2_ENABLE_PYTHON}.") +endif() + +if (LIBINT2_ENABLE_FORTRAN) + include(CheckLanguage) + check_language(Fortran) + if (CMAKE_Fortran_COMPILER) + enable_language(Fortran) + else() + message(FATAL_ERROR "Given LIBINT2_ENABLE_FORTRAN=ON but could not find Fortran compiler. Provide via CMAKE_Fortran_COMPILER") + endif() +endif() + # <<< Miscellaneous >>> # next one defined by `include(CTest)` @@ -106,7 +129,7 @@ if (LIBINT2_ENABLE_MPFR) message(VERBOSE "${Cyan}Found MPFR${ColourReset}: ${_loc} (found version ${MPFR_VERSION})") endif() -#if (LIBINT2_REQUIRE_CXX_API) +if (LIBINT2_REQUIRE_CXX_API) if (NOT TARGET Boost::headers) find_package(Boost 1.57) endif() @@ -129,16 +152,15 @@ endif() message(FATAL_ERROR "Failed to unpack the bundled Boost! The tar command output:\n${UNPACK_BOOST_OUTPUT}") endif() endif() -#endif() +endif() find_package(Eigen3 MODULE) if (TARGET Eigen3::Eigen) set(LIBINT_HAS_EIGEN 1) endif() -#if (LIBINT2_REQUIRE_CXX_API AND NOT ${LIBINT_HAS_CXX_API}) -if (NOT LIBINT_HAS_EIGEN) # TODO tmp wrong logic - message(FATAL_ERROR "C++ API cannot be built without Eigen3; configure (via CMake) and install Eigen3 and add the install prefix to CMAKE_PREFIX_PATH, or add -DLIBINT2_REQUIRE_CXX_API=OFF to the CMake command line if the C++ API is not required") +if (LIBINT2_REQUIRE_CXX_API AND NOT ${LIBINT_HAS_EIGEN}) + message(FATAL_ERROR "C++ API cannot be built without Eigen3; configure (via CMake) and install Eigen3 and add the install prefix to CMAKE_PREFIX_PATH, or add -D LIBINT2_REQUIRE_CXX_API=OFF to the CMake command line if the C++ API is not required") endif() # Python is optionally used for testing. @@ -168,47 +190,46 @@ configure_file( src/configuration.cc @ONLY) +set(DATADIR_ABSOLUTE ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/libint/${LIBINT_VERSION}) +configure_file( + include/libint2/basis.h.in # temp until libtool dropped and moved to basis.h.cmake.in + include/libint2/basis.h + @ONLY) + include(srclist.cmake) list(LENGTH LIBINT2_LIBRARY_CXX_SRC _source_count) message(STATUS "Loading ${_source_count} library source files from LIBINT2_LIBRARY_CXX_SRC") message(DEBUG "LIBINT2_LIBRARY_CXX_SRC=${LIBINT2_LIBRARY_CXX_SRC}") -# Notes +# Notes: # * __COMPILING_LIBINT2 is needed whenever using libint targets in the build tree # * MSVC does not include constants, unless _USE_MATH_DEFINES is defined # * /EHsc sets the exception handling model (allows "throw") +# * _CRT_* squashs some getenv, strdup, strncpy, ctime, fopen warnings + +# ==== pre-user-targets: plain/C++(compiled) ================================== add_library( int-obj OBJECT "${LIBINT2_LIBRARY_CXX_SRC}" - "src/configuration.cc" - ) -target_compile_definitions( - int-obj - PRIVATE - -D__COMPILING_LIBINT2=1 + src/configuration.cc ) target_compile_features( int-obj PUBLIC - "cxx_std_11" - # N.B. PUBLIC to make int-{static/shared} require C++11? + "cxx_std_11" # N.B. PUBLIC to make int-{static/shared} require C++11 + ) +target_compile_definitions( + int-obj + PRIVATE + __COMPILING_LIBINT2=1 ) set_target_properties( int-obj PROPERTIES UNITY_BUILD TRUE # always use unity build for int-obj ) -target_include_directories( - int-obj - PRIVATE - ${PROJECT_BINARY_DIR}/include/ - ${PROJECT_SOURCE_DIR}/src/ - ${PROJECT_SOURCE_DIR}/include/ - ${PROJECT_SOURCE_DIR}/include/libint2/ - ) - if (MSVC) set_target_properties( int-obj @@ -217,21 +238,76 @@ if (MSVC) # Increase stack size from 1 MB to 4 MB ) endif() +target_include_directories( + int-obj + PRIVATE + ${PROJECT_SOURCE_DIR}/include/ + ${PROJECT_BINARY_DIR}/include/ + ) + +if (LIBINT2_REQUIRE_CXX_API_COMPILED) + + add_library( + int-cxx-obj + OBJECT + src/engine.cpp + ) + target_compile_features( + int-cxx-obj + PUBLIC + "cxx_std_11" + ) + target_compile_definitions( + int-cxx-obj + PRIVATE + __COMPILING_LIBINT2=1 + LIBINT2_DOES_NOT_INLINE_ENGINE=1 + $<$:_USE_MATH_DEFINES> + $<$:_CRT_NONSTDC_NO_DEPRECATE> + $<$:_CRT_NONSTDC_NO_WARNINGS> + $<$:_CRT_SECURE_NO_WARNINGS> + ) + target_include_directories( + int-cxx-obj + PRIVATE + ${PROJECT_SOURCE_DIR}/include/ + ${PROJECT_BINARY_DIR}/include/ + ) + target_link_libraries ( + int-cxx-obj + PRIVATE + Eigen3::Eigen + $<$:Boost::headers> + ) + +endif() + +# plan shared, static, or both, then set fpic accordingly +if (LIBINT2_BUILD_SHARED_AND_STATIC_LIBS OR BUILD_SHARED_LIBS) + set(L2_BUILD_SHARED_LIBS 1) +endif() +if (LIBINT2_BUILD_SHARED_AND_STATIC_LIBS OR (NOT BUILD_SHARED_LIBS)) + set(L2_BUILD_STATIC_LIBS 1) +endif() +if (L2_BUILD_SHARED_LIBS OR (LIBINT2_ENABLE_PYTHON AND NOT MSVC)) + if (TARGET int-cxx-obj) + set(tgts int-obj int-cxx-obj) + else() + set(tgts int-obj) + endif() -if (BUILD_SHARED_LIBS OR LIBINT2_BUILD_SHARED_AND_STATIC_LIBS) - set(BUILD_SHARED_LIBS 1) set_target_properties( - int-obj + ${tgts} PROPERTIES POSITION_INDEPENDENT_CODE 1 ) endif() -if (NOT BUILD_SHARED_LIBS OR LIBINT2_BUILD_SHARED_AND_STATIC_LIBS) - set(BUILD_STATIC_LIBS 1) -endif() -if (BUILD_SHARED_LIBS) + +# ==== 6 user targets: plain/C++(headers)/C++(compiled) shared/static ========= + +if (L2_BUILD_SHARED_LIBS) add_library( int-shared @@ -249,28 +325,115 @@ if (BUILD_SHARED_LIBS) $ PUBLIC $<$:_USE_MATH_DEFINES> - ) + $<$:_CRT_NONSTDC_NO_DEPRECATE> + $<$:_CRT_NONSTDC_NO_WARNINGS> + $<$:_CRT_SECURE_NO_WARNINGS> + ) target_compile_options( int-shared PUBLIC $<$:/EHsc> ) + set_target_properties( + int-shared + PROPERTIES + OUTPUT_NAME "int2" + ) + if (APPLE) + set_target_properties( + int-shared + PROPERTIES + LINK_FLAGS "-undefined dynamic_lookup" + ) + endif() target_include_directories( int-shared INTERFACE $ - $ $ - $ ) - set_target_properties( - int-shared - PROPERTIES - OUTPUT_NAME "int2" - ) -endif() -if (BUILD_STATIC_LIBS) + if (LIBINT2_REQUIRE_CXX_API) + + add_library( + int-cxx-headeronly-shared + INTERFACE + ) + target_compile_features( + int-cxx-headeronly-shared + INTERFACE + "cxx_std_11" + ) + target_compile_definitions( + int-cxx-headeronly-shared + INTERFACE + $ + ) + if (NOT MSVC) + # TODO fix the DATADIR define escaping on Windows + # * below works fine in tests + # * but fails in Psi4 compile + # * prefix replacement in conda used instead on Windows + target_compile_definitions( + int-cxx-headeronly-shared + INTERFACE + $ + ) + endif() + target_link_libraries( + int-cxx-headeronly-shared + INTERFACE + int-shared + Eigen3::Eigen + $<$:Boost::headers> + ) + + if (LIBINT2_REQUIRE_CXX_API_COMPILED) + + add_library( + int-cxx-shared + SHARED + $ + ) + target_compile_definitions( + int-cxx-shared + INTERFACE + $ + PUBLIC + LIBINT2_DOES_NOT_INLINE_ENGINE=1 + LIBINT2_CONSTEXPR_STATICS=1 # LAB: needed for tests, but correct in general, EFV? + $<$:_USE_MATH_DEFINES> + ) + target_compile_options( + int-cxx-shared + PUBLIC + $<$:/EHsc> + ) + set_target_properties( + int-cxx-shared + PROPERTIES + #SOVERSION ${LIBINT_MAJOR_SOVERSION} + MACOSX_RPATH ON + OUTPUT_NAME "int2-cxx" + ) + if (APPLE) + set_target_properties( + int-cxx-shared + PROPERTIES + LINK_FLAGS "-undefined dynamic_lookup" + ) + endif() + target_link_libraries( + int-cxx-shared + INTERFACE + int-cxx-headeronly-shared + ) + + endif (LIBINT2_REQUIRE_CXX_API_COMPILED) + endif (LIBINT2_REQUIRE_CXX_API) +endif (L2_BUILD_SHARED_LIBS) + +if (L2_BUILD_STATIC_LIBS) add_library( int-static @@ -288,36 +451,231 @@ if (BUILD_STATIC_LIBS) $ PUBLIC $<$:_USE_MATH_DEFINES> + $<$:_CRT_NONSTDC_NO_DEPRECATE> + $<$:_CRT_NONSTDC_NO_WARNINGS> + $<$:_CRT_SECURE_NO_WARNINGS> ) target_compile_options( int-static PUBLIC $<$:/EHsc> ) + set_target_properties( + int-static + PROPERTIES + OUTPUT_NAME "int2" + ) target_include_directories( int-static INTERFACE $ - $ $ - $ ) - set_target_properties( - int-static - PROPERTIES - OUTPUT_NAME "int2" - ) -endif() -# Permanent aliases ============================================================= + if (LIBINT2_REQUIRE_CXX_API) + + add_library( + int-cxx-headeronly-static + INTERFACE + ) + target_compile_features( + int-cxx-headeronly-static + INTERFACE + "cxx_std_11" + ) + target_compile_definitions( + int-cxx-headeronly-static + INTERFACE + $ + ) + target_link_libraries( + int-cxx-headeronly-static + INTERFACE + int-static + Eigen3::Eigen + $<$:Boost::headers> + ) + + if (LIBINT2_REQUIRE_CXX_API_COMPILED) + + add_library( + int-cxx-static + STATIC + $ + ) + target_compile_definitions( + int-cxx-static + INTERFACE + $ + PUBLIC + LIBINT2_DOES_NOT_INLINE_ENGINE=1 + LIBINT2_CONSTEXPR_STATICS=1 # LAB: needed for tests, but correct in general, EFV? + $<$:_USE_MATH_DEFINES> + ) + target_compile_options( + int-cxx-static + PUBLIC + $<$:/EHsc> + ) + set_target_properties( + int-cxx-static + PROPERTIES + OUTPUT_NAME "int2-cxx" + #EXPORT_NAME "int2-cxx" + ) + target_link_libraries( + int-cxx-static + INTERFACE + int-cxx-headeronly-static + ) + + endif (LIBINT2_REQUIRE_CXX_API_COMPILED) + endif (LIBINT2_REQUIRE_CXX_API) +endif (L2_BUILD_STATIC_LIBS) + + +# ==== aliases ================================================================ + +# permanent aliases # * used for tests -if (BUILD_SHARED_LIBS) +if (L2_BUILD_SHARED_LIBS) add_library(${L2}::int2 ALIAS int-shared) -elseif (BUILD_STATIC_LIBS) + if (LIBINT2_REQUIRE_CXX_API) + add_library(${L2}::cxx ALIAS int-cxx-headeronly-shared) + if (LIBINT2_REQUIRE_CXX_API_COMPILED) + add_library(${L2}::int2-cxx ALIAS int-cxx-shared) + endif() + endif() +elseif (L2_BUILD_STATIC_LIBS) add_library(${L2}::int2 ALIAS int-static) + if (LIBINT2_REQUIRE_CXX_API) + add_library(${L2}::cxx ALIAS int-cxx-headeronly-static) + if (LIBINT2_REQUIRE_CXX_API_COMPILED) + add_library(${L2}::int2-cxx ALIAS int-cxx-static) + endif() + endif() endif() +# legacy (pre-2.9.0) aliases + +if (L2_BUILD_SHARED_LIBS) + add_library(libint2 ALIAS int-shared) + if (LIBINT2_REQUIRE_CXX_API) + add_library(libint2_cxx ALIAS int-cxx-headeronly-shared) + endif() +elseif (L2_BUILD_STATIC_LIBS) + add_library(libint2 ALIAS int-static) + if (LIBINT2_REQUIRE_CXX_API) + add_library(libint2_cxx ALIAS int-cxx-headeronly-static) + endif() +endif() + + +# ==== Fortran bindings ======================================================= + +if (LIBINT2_ENABLE_FORTRAN) + # specify the location of modules + set(BUILDTREE_FMODDIR "fortran/modules") + + # preprocess libint2.h ... this is a guess for UNIX systems only + # N.B. Requires C compiler! + if (UNIX) + file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/fortran) + + include(CheckLanguage) + check_language(C) + if (CMAKE_C_COMPILER) + enable_language(C) + else() + message(FATAL_ERROR "Given LIBINT2_ENABLE_FORTRAN=ON but could not find C compiler needed to generate Fortran bindings, provide via CMAKE_C_COMPILER") + endif() + + # preprocessed libint.h + add_custom_command( + OUTPUT + ${PROJECT_BINARY_DIR}/fortran/libint2.h.i + COMMAND ${CMAKE_C_COMPILER} -E + -D__COMPILING_LIBINT2 + -I${PROJECT_SOURCE_DIR}/include + -I${PROJECT_SOURCE_DIR}/src + -I${PROJECT_BINARY_DIR}/include + -I${PROJECT_BINARY_DIR}/include/libint2 + ${PROJECT_SOURCE_DIR}/include/libint2.h + -o ${PROJECT_BINARY_DIR}/fortran/libint2.h.i + DEPENDS + ${PROJECT_SOURCE_DIR}/include/libint2.h + COMMENT "Generating libint2.h.i" + ) + else() + message(FATAL_ERROR "Cannot run preprocessor on non-Unix systems, disable Fortran to proceed") + endif() + + # translated Libint_t + add_custom_command( + OUTPUT + ${PROJECT_BINARY_DIR}/fortran/libint2_types_f.h + COMMAND ${Python_EXECUTABLE} ${PROJECT_SOURCE_DIR}/fortran/c_to_f.py ${PROJECT_BINARY_DIR}/fortran/libint2.h.i ${PROJECT_BINARY_DIR}/fortran/libint2_types_f.h Libint_t + DEPENDS + ${PROJECT_BINARY_DIR}/fortran/libint2.h.i + COMMENT "Generating libint2_types_f.h" + ) + + # extracted defines from libint2_types.h + add_custom_command( + OUTPUT + ${PROJECT_BINARY_DIR}/fortran/fortran_incldefs.h + COMMAND ${Python_EXECUTABLE} ${PROJECT_SOURCE_DIR}/fortran/make_defs.py ${PROJECT_SOURCE_DIR}/include/libint2_types.h ${PROJECT_BINARY_DIR}/fortran/fortran_incldefs.h + DEPENDS + ${PROJECT_SOURCE_DIR}/include/libint2_types.h + COMMENT "Generating fortran_incldefs.h" + ) + + # build module + add_library( + libint_f + OBJECT + fortran/libint_f.F90 + ) + set_source_files_properties( + fortran/libint_f.F90 + PROPERTIES + OBJECT_DEPENDS "${PROJECT_BINARY_DIR}/fortran/libint2_types_f.h;${PROJECT_BINARY_DIR}/fortran/fortran_incldefs.h" + ) + target_compile_definitions( + libint_f + PRIVATE + __COMPILING_LIBINT2 + ) + set_target_properties( + libint_f + PROPERTIES + Fortran_MODULE_DIRECTORY ${PROJECT_BINARY_DIR}/${BUILDTREE_FMODDIR} + ) + if (BUILD_SHARED_LIBS) + set_target_properties(libint_f PROPERTIES POSITION_INDEPENDENT_CODE 1) + endif() + target_include_directories( + libint_f + PUBLIC + $ + $ + $ + $ + ) + + # Fortran tests merged into rest of tests + +endif (LIBINT2_ENABLE_FORTRAN) + + +# ==== Python bindings ======================================================== + +if (LIBINT2_ENABLE_PYTHON) + add_subdirectory(python EXCLUDE_FROM_ALL) +endif() + + if (BUILD_TESTING) add_subdirectory(tests) endif() diff --git a/src/lib/libint/engine.cpp b/src/lib/libint/engine.cpp new file mode 100644 index 000000000..b6d4735b1 --- /dev/null +++ b/src/lib/libint/engine.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2022-2024 Edward F. Valeev + * + * This file is part of Libint. + * + * Libint 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. + * + * Libint 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 Libint. If not, see . + * + */ + +#include + +// need to instantiate this just in case user constructs a libint2::Engine using +// default operator params +template __libint2_engine_inline libint2::any +libint2::Engine::enforce_params_type< + libint2::detail::default_operator_traits::oper_params_type>( + libint2::Operator oper, + const libint2::detail::default_operator_traits::oper_params_type& params, + bool throw_if_wrong_type); diff --git a/src/lib/libint/populate.cmake b/src/lib/libint/populate.cmake index 8e2b59ad5..38daa14de 100644 --- a/src/lib/libint/populate.cmake +++ b/src/lib/libint/populate.cmake @@ -1,19 +1,58 @@ set(LIBRARY_SOURCE_DIR ${PROJECT_SOURCE_DIR}/src/lib/libint) +# ==== /doc =================================================================== + file( INSTALL - "${LIBRARY_SOURCE_DIR}/../../../tests/" + "${PROJECT_SOURCE_DIR}/doc/progman/progman.tex" + "${PROJECT_SOURCE_DIR}/doc/progman/refs.bib" + "${PROJECT_SOURCE_DIR}/doc/Libint_Logo3_alt.pdf" + "${PROJECT_SOURCE_DIR}/doc/Libint_Logo3_alt.eps" + DESTINATION "${EXPORT_STAGE_DIR}/doc" + ) + +file( + INSTALL + "${PROJECT_SOURCE_DIR}/doc/progman/" + DESTINATION "${EXPORT_STAGE_DIR}/doc" + FILES_MATCHING + PATTERN "*.cc" + ) + +# ==== /tests ================================================================= + +file( + INSTALL + "${PROJECT_SOURCE_DIR}/tests/" DESTINATION "${EXPORT_STAGE_DIR}/tests" FILES_MATCHING PATTERN "*.c" PATTERN "*.cc" PATTERN "*.h" PATTERN "*.hpp" + PATTERN "*.F90" PATTERN "*.py" PATTERN "*.xyz" + PATTERN "hftest.cmake" PATTERN "CMakeLists.txt" + # PATTERN "ssss.nb" ) +file( + INSTALL + "${PROJECT_SOURCE_DIR}/export/fortran/fortran_example.F90" + DESTINATION "${EXPORT_STAGE_DIR}/tests/fortran" + ) + +file(READ "${PROJECT_SOURCE_DIR}/export/fortran/test.cc" _file_contents) +string(REPLACE "tests/unit" "unit" _file_contents "${_file_contents}") +file(WRITE "${EXPORT_STAGE_DIR}/tests/fortran/test.cc" "${_file_contents}") + +file(READ "${PROJECT_SOURCE_DIR}/export/fortran/test-eri.cc" _file_contents) +string(REPLACE "tests/unit" "unit" _file_contents "${_file_contents}") +string(REPLACE "tests/eri" "eri" _file_contents "${_file_contents}") +file(WRITE "${EXPORT_STAGE_DIR}/tests/fortran/test-eri.cc" "${_file_contents}") + file( INSTALL "${PROJECT_SOURCE_DIR}/src/bin/test_eri/eri.h" @@ -21,6 +60,70 @@ file( DESTINATION "${EXPORT_STAGE_DIR}/tests/eri" ) +# ==== /lib/basis ============================================================= + +file( + INSTALL + "${PROJECT_SOURCE_DIR}/lib/basis/" + DESTINATION "${EXPORT_STAGE_DIR}/lib/basis" + FILES_MATCHING + PATTERN "*.g94" + ) + +# file(INSTALL) preserves symlinks, and tar -xf fails on them on Windows (either +# the symlink extracted before the target file or problems with the stars in +# filenames themselves). To make export tarballs broadly usable, we'll copy +# the symlinked files into real files, which is what libtool effectively did. +file( + COPY_FILE + "${PROJECT_SOURCE_DIR}/lib/basis/6-31gs.g94" + "${EXPORT_STAGE_DIR}/lib/basis/6-31gs.g94" + ) +file( + COPY_FILE + "${PROJECT_SOURCE_DIR}/lib/basis/6-31gss.g94" + "${EXPORT_STAGE_DIR}/lib/basis/6-31gss.g94" + ) +file( + COPY_FILE + "${PROJECT_SOURCE_DIR}/lib/basis/6-311gss.g94" + "${EXPORT_STAGE_DIR}/lib/basis/6-311gss.g94" + ) + +# ==== /fortran =============================================================== + +file( + INSTALL + "${PROJECT_SOURCE_DIR}/export/fortran/c_to_f.py" + "${PROJECT_SOURCE_DIR}/export/fortran/make_defs.py" + "${PROJECT_SOURCE_DIR}/export/fortran/libint_f.F90" + DESTINATION "${EXPORT_STAGE_DIR}/fortran" + ) + +# ==== /python ================================================================ + +file( + INSTALL + "${PROJECT_SOURCE_DIR}/python/" + DESTINATION "${EXPORT_STAGE_DIR}/python" + FILES_MATCHING + PATTERN "*.h" + PATTERN "*.cc" + PATTERN "*.py" + PATTERN "*.py.in" + PATTERN "CMakeLists.txt" + ) + +# ==== /external ============================================================== + +file( + INSTALL + "${PROJECT_SOURCE_DIR}/external/boost.tar.gz" + DESTINATION "${EXPORT_STAGE_DIR}/external" + ) + +# ==== /cmake ================================================================= + file( INSTALL "${PROJECT_SOURCE_DIR}/cmake/modules/autocmake_safeguards.cmake" @@ -41,13 +144,7 @@ file( DESTINATION "${EXPORT_STAGE_DIR}/cmake" ) -configure_file( - "${LIBRARY_SOURCE_DIR}/CMakeLists.txt.export" - "${EXPORT_STAGE_DIR}/CMakeLists.txt" - COPYONLY) - - -# <<< Headers >>> +# ==== /include =============================================================== file( INSTALL @@ -55,30 +152,88 @@ file( "${PROJECT_SOURCE_DIR}/include/libint2.hpp" DESTINATION "${EXPORT_STAGE_DIR}/include" ) + +# Note that libint2_iface.h, libint2_params.h, libint2_types.h shift around. +# They're generated along with the integrals .h/.cc library src, then get +# exported to include/ (along with the integrals .h), then are finally +# installed (not with the integrals .h) into include/libint2/ . The +# __COMPILING_LIBINT define and the include/libint2/util/generated/libint2_*.h +# redirection headers take care of the "build tree"/"export" setup. +# In a cmake+cmake buildsystem, one could probably install these three headers +# to both locations and forego the define. file( INSTALL - "${PROJECT_SOURCE_DIR}/include/libint2/" - DESTINATION "${EXPORT_STAGE_DIR}/include/libint2" + "${PROJECT_BINARY_DIR}/generated/" + DESTINATION "${EXPORT_STAGE_DIR}/include" FILES_MATCHING PATTERN "*.h" - PATTERN "*.h.cmake.in" ) + +file( + INSTALL + "${PROJECT_SOURCE_DIR}/src/bin/libint/util_types.h" + DESTINATION "${EXPORT_STAGE_DIR}/include" + ) + file( INSTALL "${LIBRARY_SOURCE_DIR}/" - DESTINATION "${EXPORT_STAGE_DIR}/include/libint2" + DESTINATION "${EXPORT_STAGE_DIR}/include" FILES_MATCHING PATTERN "*.h" ) +# ==== /include/libint2 ======================================================= + +file( + INSTALL + "${PROJECT_SOURCE_DIR}/include/libint2/" + DESTINATION "${EXPORT_STAGE_DIR}/include/libint2" + FILES_MATCHING + PATTERN "*.h" + PATTERN "*.h.cmake.in" + PATTERN "basis.h.in" # TODO basis.h.cmake.in after libtool retires + ) -# <<< Source >>> +# ==== /src =================================================================== file( INSTALL + "${PROJECT_SOURCE_DIR}/src/lib/libint/engine.cpp" "${PROJECT_SOURCE_DIR}/src/lib/libint/configuration.cc.cmake.in" DESTINATION "${EXPORT_STAGE_DIR}/src" ) +file( + INSTALL + "${PROJECT_BINARY_DIR}/generated/" + DESTINATION "${EXPORT_STAGE_DIR}/src" + FILES_MATCHING + PATTERN "*.cc" + ) + file(GLOB generated_sources_list RELATIVE "${EXPORT_STAGE_DIR}" "${EXPORT_STAGE_DIR}/src/*.cc") file(WRITE ${EXPORT_STAGE_DIR}/srclist.cmake "set(LIBINT2_LIBRARY_CXX_SRC \"${generated_sources_list}\" )") + +# ==== / ====================================================================== + +configure_file( + "${PROJECT_SOURCE_DIR}/export/LICENSE.export" + "${EXPORT_STAGE_DIR}/LICENSE" + COPYONLY) + +file( + INSTALL + "${PROJECT_SOURCE_DIR}/INSTALL" + "${PROJECT_SOURCE_DIR}/INSTALL.md" + "${PROJECT_SOURCE_DIR}/COPYING" + "${PROJECT_SOURCE_DIR}/COPYING.LESSER" + "${PROJECT_SOURCE_DIR}/CITATION" + "${PROJECT_SOURCE_DIR}/README.md" + DESTINATION "${EXPORT_STAGE_DIR}" + ) + +configure_file( + "${LIBRARY_SOURCE_DIR}/CMakeLists.txt.export" + "${EXPORT_STAGE_DIR}/CMakeLists.txt" + COPYONLY) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 45a7c2ea7..ca2b48249 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,7 +1,7 @@ include(AddCustomTargetSubproject) add_custom_target_subproject( libint2 check # target check-libint2 - USES_TERMINAL + USES_TERMINAL COMMAND ${CMAKE_CTEST_COMMAND} -V -R "libint2/" ) @@ -13,27 +13,35 @@ add_custom_target_subproject( ## Tests ======================================================================== add_executable( - eritest-libint2 - EXCLUDE_FROM_ALL + eritest-libint2 + EXCLUDE_FROM_ALL eri/test.cc ) target_include_directories( - eritest-libint2 - PRIVATE + eritest-libint2 + PRIVATE eri # src/bin/test_eri/eri.h + # see note on eri.h at unit_tests-libint2 + ) +target_compile_definitions( + eritest-libint2 + PRIVATE + $<$:LIBINT_HAS_MPFR=1> ) target_link_libraries( - eritest-libint2 - Libint2::int2 # N.B. plain library + eritest-libint2 + PRIVATE + Libint2::int2 # N.B. plain library + $<$:Multiprecision::mpfr> + $<$:Multiprecision::gmpxx> ) - add_test( # Test #1 - NAME libint2/eritest/build + NAME libint2/eritest/build COMMAND "${CMAKE_COMMAND}" --build ${CMAKE_BINARY_DIR} --target eritest-libint2 ) set_tests_properties( - libint2/eritest/build - PROPERTIES + libint2/eritest/build + PROPERTIES FIXTURES_SETUP LIBINT2_ERITEST_EXEC ) add_test( # Test #2 @@ -62,10 +70,15 @@ set_tests_properties( libint2/eritest/run2 libint2/eritest/run3 libint2/eritest/run4 - PROPERTIES + PROPERTIES FIXTURES_REQUIRED LIBINT2_ERITEST_EXEC ) + +if (LIBINT2_REQUIRE_CXX_API) + set(utests_src + unit/catch.hpp + unit/fixture.h unit/test-1body.cc unit/test-2body.cc unit/test-basis.cc @@ -76,11 +89,227 @@ set_tests_properties( unit/test-shell-order.cc unit/test-util.cc ) + # if have C, also test C bindings + include(CheckLanguage) + check_language(C) + if (CMAKE_C_COMPILER) + enable_language(C) + list(APPEND unit_tests-src + unit/c-api.c + unit/c-api-util.cc + unit/test-c-api.cc + ) + endif() add_executable( - unit_tests-libint2 - EXCLUDE_FROM_ALL - unit/test.cc + unit_tests-libint2 + EXCLUDE_FROM_ALL + unit/test.cc ${utests_src} ) + target_compile_definitions( + unit_tests-libint2 + PRIVATE + NO_LIBINT_COMPILER_CODE # src/bin/test_eri/eri.h + # note there's two ways to use eri.h, depending on the test src. eritest-libint2 uses the other. + $<$:LIBINT_HAS_MPFR=1> + ) + target_link_libraries( + unit_tests-libint2 + PRIVATE + $,Libint2::int2-cxx,Libint2::cxx> + # N.B. cxx compiled library if LIBINT2_REQUIRE_CXX_API_COMPILED=ON else header-only library + $<$:Multiprecision::mpfr> + $<$:Multiprecision::gmpxx> + $<$:Multiprecision::gmp> + # MPFR: numeric.h:175:23: error: cannot convert 'const char*' to 'double' in initialization: To to(ss.str().c_str()); + ) + add_test( # Test #7 + NAME libint2/unit/build + COMMAND "${CMAKE_COMMAND}" --build ${CMAKE_BINARY_DIR} --target unit_tests-libint2 + ) + set_tests_properties( + libint2/unit/build + PROPERTIES + FIXTURES_SETUP LIBINT2_UNIT_TESTS_EXEC + ) + add_test( # Test #8 + NAME libint2/unit/run + COMMAND $ + ) + add_test( # Test #9 + NAME libint2/unit/sho=gaussian/run + COMMAND $ --shgshell-order=gaussian + ) + set_tests_properties( + libint2/unit/run + libint2/unit/sho=gaussian/run + PROPERTIES + FIXTURES_REQUIRED LIBINT2_UNIT_TESTS_EXEC + ) + + add_executable( + hf-libint2 + EXCLUDE_FROM_ALL + hartree-fock/hartree-fock.cc + ) + target_link_libraries( + hf-libint2 + PRIVATE + $,Libint2::int2-cxx,Libint2::cxx> + # N.B. cxx compiled library if LIBINT2_REQUIRE_CXX_API_COMPILED=ON else header-only library + ) + add_test( # Test #10 + NAME libint2/hf/build + COMMAND "${CMAKE_COMMAND}" --build ${CMAKE_BINARY_DIR} --target hf-libint2 + ) + set_tests_properties( + libint2/hf/build + PROPERTIES + FIXTURES_SETUP LIBINT2_HFTEST_EXEC + ) + if (Python_Interpreter_FOUND) + add_test( # Test #11 + NAME libint2/hf/run + COMMAND ${CMAKE_COMMAND} + -DexecName=hf-libint2 + -DtestName=hartree-fock + -DtestArgs=${PROJECT_SOURCE_DIR}/tests/hartree-fock/h2o.xyz + -DPROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR} + -DPROJECT_BINARY_DIR=${PROJECT_BINARY_DIR} + -DpythonExec=${Python_EXECUTABLE} + -P ${PROJECT_SOURCE_DIR}/tests/hartree-fock/hftest.cmake + ) + else() + add_test( # Test #11 alt. + NAME libint2/hf/run + COMMAND $ ${PROJECT_SOURCE_DIR}/tests/hartree-fock/h2o.xyz + ) + endif() + set_tests_properties( + libint2/hf/run + PROPERTIES + FIXTURES_REQUIRED LIBINT2_HFTEST_EXEC + ) + + add_executable( + hf++-libint2 + EXCLUDE_FROM_ALL + hartree-fock/hartree-fock++.cc + ) + find_package(Threads) # for some reason clang does not link in threading support even though we are using C++ threads + target_link_libraries( + hf++-libint2 + PRIVATE + Libint2::cxx + Threads::Threads + # mostly errors for int2-cxx (excpet some Linux configurations) + # $,Libint2::int2-cxx,Libint2::cxx> + ) + add_test( # Test #12 + NAME libint2/hf++/build + COMMAND "${CMAKE_COMMAND}" --build ${CMAKE_BINARY_DIR} --target hf++-libint2 + ) + set_tests_properties( + libint2/hf++/build + PROPERTIES + FIXTURES_SETUP LIBINT2_HFXXTEST_EXEC + ) + if (Python_Interpreter_FOUND) + add_test( # Test #13 + NAME libint2/hf++/run + COMMAND ${CMAKE_COMMAND} + -DexecName=hf++-libint2 + -DtestName=hartree-fock++ + -DtestArgs=${PROJECT_SOURCE_DIR}/tests/hartree-fock/h2o_rotated.xyz + -DPROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR} + -DPROJECT_BINARY_DIR=${PROJECT_BINARY_DIR} + -DpythonExec=${Python_EXECUTABLE} + -P ${PROJECT_SOURCE_DIR}/tests/hartree-fock/hftest.cmake + ) + else() + add_test( # Test #13 alt. + NAME libint2/hf++/run + COMMAND $ ${PROJECT_SOURCE_DIR}/tests/hartree-fock/h2o_rotated.xyz + ) + endif() + set_tests_properties( + libint2/hf++/run + PROPERTIES + FIXTURES_REQUIRED LIBINT2_HFXXTEST_EXEC + ) + +endif (LIBINT2_REQUIRE_CXX_API) + +if (LIBINT2_ENABLE_FORTRAN) + + # Note: if forming compile line by hand rather than using targets, you'll + # need to include the Fortran module file directory: + # `target_include_directories(... PRIVATE $)` + + add_executable( + fortran_example-libint2 + EXCLUDE_FROM_ALL + fortran/fortran_example.F90 + ) + target_link_libraries( + fortran_example-libint2 + PRIVATE + Libint2::int2 + libint_f + ) + add_test( # Test #14 + NAME libint2/fortran_example/build + COMMAND "${CMAKE_COMMAND}" --build ${CMAKE_BINARY_DIR} --target fortran_example-libint2 + ) + set_tests_properties( + libint2/fortran_example/build + PROPERTIES + FIXTURES_SETUP LIBINT2_FORTRAN_EXAMPLE_EXEC + ) + add_test( # Test #15 + NAME libint2/fortran_example/run + COMMAND $ + ) + set_tests_properties( + libint2/fortran_example/run + PROPERTIES + FIXTURES_REQUIRED LIBINT2_FORTRAN_EXAMPLE_EXEC + ) + + if (LIBINT2_REQUIRE_CXX_API) + add_executable( + fortran_test-libint2 + EXCLUDE_FROM_ALL + fortran/test.cc + fortran/test-eri.cc + $ + ) + target_link_libraries( + fortran_test-libint2 + PRIVATE + $,Libint2::int2-cxx,Libint2::cxx> + # N.B. cxx compiled library if LIBINT2_REQUIRE_CXX_API_COMPILED=ON else header-only library + libint_f + ) + add_test( # Test #16 + NAME libint2/fortran_test/build + COMMAND "${CMAKE_COMMAND}" --build ${CMAKE_BINARY_DIR} --target fortran_test-libint2 + ) + set_tests_properties( + libint2/fortran_test/build + PROPERTIES + FIXTURES_SETUP LIBINT2_FORTRAN_TEST_EXEC + ) + add_test( # Test #17 + NAME libint2/fortran_test/run + COMMAND $ + ) + set_tests_properties( + libint2/fortran_test/run + PROPERTIES + FIXTURES_REQUIRED LIBINT2_FORTRAN_TEST_EXEC + ) + endif (LIBINT2_REQUIRE_CXX_API) +endif (LIBINT2_ENABLE_FORTRAN) diff --git a/tests/hartree-fock/hftest.cmake b/tests/hartree-fock/hftest.cmake new file mode 100644 index 000000000..92442cd0e --- /dev/null +++ b/tests/hartree-fock/hftest.cmake @@ -0,0 +1,44 @@ + +macro(runtest) + + set(OUTPUT_FILE_NAME "${PROJECT_BINARY_DIR}/tests/${testName}.out") + + set(CHECK_CMD "${pythonExec}" "${PROJECT_SOURCE_DIR}/tests/hartree-fock/${testName}-validate.py") + if (testName STREQUAL "hartree-fock++") + set(CHECK_ARGS "${PROJECT_SOURCE_DIR}/features") + endif() + + execute_process(COMMAND + ${PROJECT_BINARY_DIR}/tests/${execName} ${testArgs} + OUTPUT_FILE "${OUTPUT_FILE_NAME}" + RESULT_VARIABLE TEST_RESULT) + + if(TEST_RESULT) + message(STATUS "\nOUTPUT of " ${PROJECT_BINARY_DIR}/tests/${execName} " with args " ${testArgs}) + execute_process(COMMAND + cat + ${OUTPUT_FILE_NAME} + RESULT_VARIABLE + CAT_RESULT + ) + message(FATAL_ERROR "Error running ${PROJECT_BINARY_DIR}/tests/${execName}") + endif(TEST_RESULT) + + execute_process(COMMAND + ${CHECK_CMD} ${CHECK_ARGS} ${OUTPUT_FILE_NAME} + RESULT_VARIABLE CHECK_RESULT) + + if(CHECK_RESULT) + message(STATUS "\nOUTPUT of " ${CHECK_CMD}) + execute_process(COMMAND + cat + ${OUTPUT_FILE_NAME} + RESULT_VARIABLE + CAT_RESULT + ) + message(FATAL_ERROR "Error running ${CHECK_CMD} with args " ${CHECK_ARGS} " " ${OUTPUT_FILE_NAME}) + endif(CHECK_RESULT) + +endmacro(runtest) + +runtest()