diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 1ee42a783..34820bf5e 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -1,9 +1,7 @@ -name: Linux/MacOS Build +name: Build on: [push, pull_request] -#env: - jobs: build_repo: strategy: @@ -17,7 +15,7 @@ jobs: - os: macos-latest cxx: clang++ - name: "${{ matrix.os }}: ${{ matrix.cxx }} ${{ matrix.build_type }}" + name: "Repo • ${{ matrix.os }}: ${{ matrix.cxx }} ${{ matrix.build_type }}" runs-on: ${{ matrix.os }} env: CXX : ${{ matrix.cxx }} @@ -37,11 +35,11 @@ jobs: should_skip: ${{ steps.skip_check.outputs.should_skip }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - id: skip_check name: Check if can skip - uses: fkirc/skip-duplicate-actions@v3.4.0 + uses: fkirc/skip-duplicate-actions@v5 with: cancel_others: 'true' @@ -75,11 +73,11 @@ jobs: shell: cmake -P {0} run: | string(TIMESTAMP current_date "%Y-%m-%d-%H;%M;%S" UTC) - message("::set-output name=timestamp::${current_date}") + message("\"timestamp=${current_date}\" >> $GITHUB_OUTPUT") - name: Setup ccache cache files if: ${{ steps.skip_check.outputs.should_skip != 'true' }} - uses: actions/cache@v1.1.0 + uses: actions/cache@v3 with: path: ${{github.workspace}}/build/.ccache key: ${{ matrix.config.name }}-ccache-${{ steps.ccache_cache_timestamp.outputs.timestamp }} @@ -162,7 +160,7 @@ jobs: # * turn off generator testing (comment out "make check" and "stdtests.pl" lines) # * suppress last two (test library and bindings) steps ("if: false") needs: build_repo - if: always() && (needs.build_repo.steps.skip_check.outputs.should_skip != 'true') + if: always() && (needs.build_repo.outputs.should_skip != 'true') strategy: fail-fast: false matrix: @@ -175,6 +173,20 @@ jobs: # note full paths depend on setup-miniconda: # * Miniforge is miniconda3 vs. Miniconda is miniconda + - 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 + testargs: > + -GNinja + -DCMAKE_BUILD_TYPE=Release + -DCMAKE_CXX_COMPILER=clang-cl + -DCMAKE_C_COMPILER=clang-cl + - runs-on: macos-latest lane: macos-clang libargs: > @@ -185,14 +197,12 @@ jobs: lane: ubuntu-intel libargs: > -DCMAKE_CXX_COMPILER=icpx - -DCMAKE_CXX_FLAGS="--gcc-toolchain=/usr/share/miniconda3/envs/test --sysroot=/usr/share/miniconda3/envs/test/x86_64-conda-linux-gnu/sysroot -target x86_64-conda-linux-gnu" - # flags are long-form of below (envvars not available at spinup) - # -DCMAKE_CXX_FLAGS="--gcc-toolchain=${CONDA_PREFIX} --sysroot=${CONDA_PREFIX}/${HOST}/sysroot -target ${HOST}" + -DCMAKE_CXX_FLAGS="--gcc-toolchain=${CONDA_PREFIX} --sysroot=${CONDA_PREFIX}/${HOST}/sysroot -target ${HOST}" testargs: > -DCMAKE_CXX_COMPILER=icpx - -DCMAKE_CXX_FLAGS="--gcc-toolchain=/usr/share/miniconda3/envs/test --sysroot=/usr/share/miniconda3/envs/test/x86_64-conda-linux-gnu/sysroot -target x86_64-conda-linux-gnu" + -DCMAKE_CXX_FLAGS="--gcc-toolchain=${CONDA_PREFIX} --sysroot=${CONDA_PREFIX}/${HOST}/sysroot -target ${HOST}" - name: "Export • ${{ matrix.cfg.lane }} • ${{ matrix.cfg.libargs }}" + name: "Export • ${{ matrix.cfg.lane }}" runs-on: ${{ matrix.cfg.runs-on }} steps: @@ -217,6 +227,9 @@ jobs: - pybind11 #- dpcpp_linux-64 EOF + if [[ "${{ runner.os }}" == "Windows" ]]; then + sed -i "s/- cxx/#- cxx/g" export.yaml + fi if [[ "${{ matrix.cfg.lane }}" == "ubuntu-intel" ]]; then sed -i "s/#- dpcpp_linux-64/- dpcpp_linux-64/g" export.yaml fi @@ -239,6 +252,12 @@ jobs: conda info conda list + - name: Prepare compiler environment for Windows + if: ${{ runner.os == 'Windows' }} + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: x64 + - uses: actions/download-artifact@v3 with: name: Linux-g++-10 @@ -251,6 +270,7 @@ jobs: cmake \ -S. \ -Bbuild \ + -GNinja \ -DCMAKE_INSTALL_PREFIX="${{github.workspace}}/installed" \ -DCMAKE_CXX_COMPILER=${CXX} \ -DLIBINT2_PYTHON=ON \ @@ -258,14 +278,20 @@ jobs: ${{ matrix.cfg.libargs }} cmake --build build --target install libint2-python-test - - name: Test Installed Libint library + - name: Test Libint library - unit tests + shell: bash -l {0} + working-directory: ${{github.workspace}}/libint/build + run: | + cmake --build . --target check + + - name: Test Libint library - consume installation for SCF shell: bash -l {0} run: | mkdir test_installed_library && cd test_installed_library cat > CMakeLists.txt < 6-31gss.g94. In code, the basis can be accessed through "6-31g**" (longstanding) + or "6-31gss" (new) for all operating systems. + - UNMERGED PR #270: Adapt build system and header imports so that library and Python bindings can build on + Windows (at least with clang-cl compiler atop MSVC). Note that a Linux- or Mac-generated export + builds on Windows; one cannot generate an export on Windows. Note also that only a static library + build, not a shared one, works on Windows (see #237). + - PR #269: minimum CMake bumped to 3.16 + - PR #269: Solid harmonics ordering is runtime switchable in the library. Issue + `libint2::set_solid_harmonics_ordering(libint2::SHGShellOrdering_Gaussian)` or `_Standard` after + initialization. Similarly, prefer new `INT_SOLIDHARMINDEX(sho, l, m)` to usual `(l, m)` version. + - PR #268: Python detection (relevant to Python bindings, Fortran, and some tests) now uses modern + `find_package(Python)`. Specify with `Python_EXECUTABLE` (note change in case) or + https://cmake.org/cmake/help/latest/module/FindPython.html for details . + - PR #268: Python bindings can now use Pybind11 >=2.6 and can use detected installation. - PR #249: Python bindings (HT @asadchev) - PR #246: BasisSet is no longer derived from vector - PR #232: introduced new primitive screening methods diff --git a/export/cmake/CMakeLists.txt.export b/export/cmake/CMakeLists.txt.export index ccc6b2d3d..153f756b3 100644 --- a/export/cmake/CMakeLists.txt.export +++ b/export/cmake/CMakeLists.txt.export @@ -205,12 +205,29 @@ if(BUILD_SHARED_LIBS OR LIBINT2_BUILD_SHARED_AND_STATIC_LIBS OR LIBINT2_PYTHON) set_target_properties(libint2_obj PROPERTIES POSITION_INDEPENDENT_CODE ON) endif() +if (MSVC) + set_target_properties( + libint2_obj + PROPERTIES + # Increase stack size from 1 MB to 4 MB + LINK_FLAGS "/STACK:4194304" + ) +endif() + # shared and static libraries built from the same object files if (LIBINT2_BUILD_SHARED_AND_STATIC_LIBS) add_library(libint2 SHARED $) set_target_properties(libint2 PROPERTIES LIBRARY_OUTPUT_NAME int2) + if(MSVC) + target_compile_definitions(libint2 PUBLIC _USE_MATH_DEFINES) + target_compile_options(libint2 PUBLIC "/EHsc") + endif() add_library(libint2-static STATIC $) set_target_properties(libint2-static PROPERTIES ARCHIVE_OUTPUT_NAME int2) + if(MSVC) + target_compile_definitions(libint2-static PUBLIC _USE_MATH_DEFINES) + target_compile_options(libint2-static PUBLIC "/EHsc") + endif() target_include_directories(libint2-static INTERFACE $ $ $ @@ -265,10 +282,18 @@ else() endif() # install basis set library -install(DIRECTORY ${PROJECT_SOURCE_DIR}/lib/basis +if(MSVC) + install(DIRECTORY ${PROJECT_SOURCE_DIR}/lib/basis + COMPONENT libint2 + DESTINATION "${LIBINT2_INSTALL_DATADIR}" + FILES_MATCHING REGEX "[A-Za-z0-9_\\(\\)-]+\.g94" + ) +else() + install(DIRECTORY ${PROJECT_SOURCE_DIR}/lib/basis COMPONENT libint2 DESTINATION "${LIBINT2_INSTALL_DATADIR}" ) +endif() # LibintCXX library ==================================================================================================== @@ -279,10 +304,40 @@ if (LIBINT_HAS_CXX_API) if (LIBINT_HAS_SYSTEM_BOOST_PREPROCESSOR_VARIADICS) target_link_libraries(libint2_cxx INTERFACE Boost::boost) endif(LIBINT_HAS_SYSTEM_BOOST_PREPROCESSOR_VARIADICS) + if(MSVC) + # MSVC does not include constants, unless _USE_MATH_DEFINES is defined. + # _CRT_* to squash some getenv, strdup, strncpy, ctime, fopen warnings + target_compile_definitions( + libint2_cxx + INTERFACE + _USE_MATH_DEFINES + _CRT_NONSTDC_NO_DEPRECATE + _CRT_NONSTDC_NO_WARNINGS + _CRT_SECURE_NO_WARNINGS + ) + # Set the exception handling model + target_compile_options( + libint2_cxx + INTERFACE + "/EHsc" + ) + endif() get_filename_component(DATADIR_ABSOLUTE "${CMAKE_INSTALL_PREFIX}/${LIBINT2_INSTALL_DATADIR}" ABSOLUTE) target_compile_definitions(libint2_cxx 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 + # * LIBINT2_INSTALL_DATADIR -> LIBINT2_INSTALL_BASISDIR + target_compile_definitions( + libint2_cxx + INTERFACE + $ + ) + endif() # Add library to the list of installed components install(TARGETS libint2_cxx EXPORT libint2 COMPONENT cxx @@ -303,6 +358,11 @@ add_custom_target_subproject(libint2 check USES_TERMINAL COMMAND ${CMAKE_CTEST_C add_executable(eritest-libint2 EXCLUDE_FROM_ALL tests/eri/test.cc) target_link_libraries(eritest-libint2 ${int2_library}) target_include_directories(eritest-libint2 PRIVATE ${PROJECT_SOURCE_DIR}/tests/eri) +if(MSVC) + # TODO on future target pass, def should be added to the L2 target, not added to test + target_compile_definitions(eritest-libint2 PUBLIC _USE_MATH_DEFINES) + target_compile_options(eritest-libint2 PUBLIC "/EHsc") +endif() add_test(libint2/eritest/build "${CMAKE_COMMAND}" --build ${CMAKE_BINARY_DIR} --target eritest-libint2) set_tests_properties(libint2/eritest/build PROPERTIES FIXTURES_SETUP LIBINT2_ERITEST_EXEC) diff --git a/include/libint2/basis.h.in b/include/libint2/basis.h.in index db05f86fa..d3d156ec9 100644 --- a/include/libint2/basis.h.in +++ b/include/libint2/basis.h.in @@ -36,7 +36,14 @@ #include #include +#ifdef _MSC_VER +#include +#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR) +#define PATH_SEPARATOR "\\" +#else #include +#define PATH_SEPARATOR "/" +#endif #include #include @@ -139,7 +146,7 @@ namespace libint2 { // read in ALL basis set components for(const auto& basis_component_name: basis_component_names) { - auto file_dot_g94 = basis_lib_path + "/" + basis_component_name + ".g94"; + auto file_dot_g94 = basis_lib_path + PATH_SEPARATOR + basis_component_name + ".g94"; // use same cartesian_d convention for all components! component_basis_sets.emplace_back(read_g94_basis_library(file_dot_g94, force_cartesian_d, throw_if_no_match)); @@ -161,7 +168,7 @@ namespace libint2 { } else if (throw_if_no_match) { // not found? throw, if needed std::string errmsg(std::string("did not find the basis for this Z in ") + - basis_lib_path + "/" + basis_component_names[comp_idx] + ".g94"); + basis_lib_path + PATH_SEPARATOR + basis_component_names[comp_idx] + ".g94"); throw std::logic_error(errmsg); } } // basis component loop @@ -338,6 +345,9 @@ namespace libint2 { char cc = ::tolower(c); switch (cc) { case '/': cc = 'I'; break; +#ifdef _MSC_VER + case '*': cc = 's'; break; +#endif } return cc; } @@ -411,7 +421,7 @@ namespace libint2 { #endif } // validate basis_path = path + "/basis" - std::string basis_path = path + std::string("/basis"); + std::string basis_path = path + PATH_SEPARATOR + std::string("basis"); bool error = true; std::error_code ec; auto validate_basis_path = [&basis_path, &error, &ec]() -> void { @@ -459,7 +469,12 @@ namespace libint2 { static std::vector> read_g94_basis_library(std::string file_dot_g94, bool force_cartesian_d = false, bool throw_if_missing = true, - std::string locale_name = std::string("POSIX")) { +#ifdef _MSC_VER + std::string locale_name = std::string("en-US") +#else + std::string locale_name = std::string("POSIX") // "en_US" +#endif + ) { std::locale locale(locale_name.c_str()); // TODO omit c_str() with up-to-date stdlib std::vector> ref_shells(118); // 118 = number of chemical elements diff --git a/include/libint2/boys.h b/include/libint2/boys.h index 4521a21f5..8c83ef75a 100644 --- a/include/libint2/boys.h +++ b/include/libint2/boys.h @@ -36,6 +36,13 @@ #include #include +#ifdef _MSC_VER +#define posix_memalign(p, a, s) (((*(p)) = _aligned_malloc((s), (a))), *(p) ?0 :errno) +#define posix_memfree(p) ((_aligned_free((p)))) +#else +#define posix_memfree(p) ((free((p)))) +#endif + // from now on at least C++11 is required by default #include #if LIBINT2_CPLUSPLUS_STD < 2011 @@ -290,7 +297,7 @@ namespace libint2 { } ~FmEval_Chebyshev7() { if (mmax >= 0) { - free(c); + posix_memfree(c); } } @@ -881,7 +888,7 @@ namespace libint2 { ~TennoGmEval() { if (c_ != nullptr) - free(c_); + posix_memfree(c_); } /// Singleton interface allows to manage the lone instance; adjusts max m values as needed in thread-safe fashion @@ -1313,7 +1320,7 @@ namespace libint2 { // get memory void* result; - int status = posix_memalign(&result, std::max(sizeof(Real), 32ul), (mmax_ - mmin_ + 1) * cheb_table_nintervals * ORDERp1 * ORDERp1 * sizeof(Real)); + int status = posix_memalign(&result, std::max(sizeof(Real), (size_t)32), (mmax_ - mmin_ + 1) * cheb_table_nintervals * ORDERp1 * ORDERp1 * sizeof(Real)); if (status != 0) { if (status == EINVAL) throw std::logic_error( diff --git a/include/libint2/util/memory.h b/include/libint2/util/memory.h index e2271fdfb..141180d63 100644 --- a/include/libint2/util/memory.h +++ b/include/libint2/util/memory.h @@ -24,6 +24,10 @@ #include #include +#ifdef _MSC_VER +#define posix_memalign(p, a, s) (((*(p)) = _aligned_malloc((s), (a))), *(p) ?0 :errno) +#endif + namespace libint2 { /// Aligned version of malloc(). diff --git a/include/libint2/util/vector_x86.h b/include/libint2/util/vector_x86.h index 235ff264f..1c0bd09ef 100644 --- a/include/libint2/util/vector_x86.h +++ b/include/libint2/util/vector_x86.h @@ -28,7 +28,9 @@ #include #include -#if defined(__SSE2__) || defined(__SSE__) || defined(__AVX__) +#if defined(_MSC_VER) +# include +#elif defined(__SSE2__) || defined(__SSE__) || defined(__AVX__) # include #endif diff --git a/lib/basis/6-311gss.g94 b/lib/basis/6-311gss.g94 new file mode 120000 index 000000000..dbafb5934 --- /dev/null +++ b/lib/basis/6-311gss.g94 @@ -0,0 +1 @@ +6-311g**.g94 \ No newline at end of file diff --git a/lib/basis/6-31Gs.g94 b/lib/basis/6-31Gs.g94 new file mode 120000 index 000000000..62a7e956a --- /dev/null +++ b/lib/basis/6-31Gs.g94 @@ -0,0 +1 @@ +6-31G*.g94 \ No newline at end of file diff --git a/lib/basis/6-31gs.g94 b/lib/basis/6-31gs.g94 new file mode 120000 index 000000000..c7b036dd7 --- /dev/null +++ b/lib/basis/6-31gs.g94 @@ -0,0 +1 @@ +6-31g*.g94 \ No newline at end of file diff --git a/lib/basis/6-31gss.g94 b/lib/basis/6-31gss.g94 new file mode 120000 index 000000000..1f15651ef --- /dev/null +++ b/lib/basis/6-31gss.g94 @@ -0,0 +1 @@ +6-31g**.g94 \ No newline at end of file diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index a0fc1d2fe..f4f2a7218 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -37,6 +37,16 @@ if (pybind11_VERSION VERSION_LESS_EQUAL 2.5.0) set(CMAKE_CXX_STANDARD 17) endif() +if (pybind11_VERSION VERSION_GREATER_EQUAL 2.11.0) + # ipo/lto triggering changed https://github.com/pybind/pybind11/pull/4643 + if ((CMAKE_CXX_COMPILER_ID STREQUAL "Clang") AND (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")) + # clang-cl + + # this variable needs to be defined, not the property + set(CMAKE_INTERPROCEDURAL_OPTIMIZATION OFF) + endif() +endif() + pybind11_add_module( libint2-python MODULE #EXCLUDE_FROM_ALL @@ -52,7 +62,12 @@ if (pybind11_VERSION VERSION_GREATER_EQUAL 2.7.0) target_compile_definitions(libint2-python PRIVATE NDEBUG=1) endif() -add_compile_options(-Wall) +target_compile_options(libint2-python + PRIVATE + # too many warnings on Windows + # $<$:/W4> + $<$>:-Wall> + ) #find_package(Eigen3 3.3 REQUIRED) @@ -65,6 +80,12 @@ set_target_properties( if (TARGET libint2_obj) set(libint2_python_target libint2_obj) + + 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) else() diff --git a/python/src/libint2/engine.cc b/python/src/libint2/engine.cc index 2aa43add7..1597d739e 100644 --- a/python/src/libint2/engine.cc +++ b/python/src/libint2/engine.cc @@ -6,6 +6,12 @@ #include #include +#if defined(_MSC_VER) +#include +// handles ssize_t in pybind11/numpy.h +typedef SSIZE_T ssize_t; +#endif + #include #include #include diff --git a/python/src/libint2/libint2.cc b/python/src/libint2/libint2.cc index 58bb97019..92408d2e3 100644 --- a/python/src/libint2/libint2.cc +++ b/python/src/libint2/libint2.cc @@ -4,6 +4,12 @@ #include #include +#if defined(_MSC_VER) +#include +// handles ssize_t in pybind11/numpy.h +typedef SSIZE_T ssize_t; +#endif + #include #include #include diff --git a/tests/eri/test.cc b/tests/eri/test.cc index 62937c126..ff4d633ad 100644 --- a/tests/eri/test.cc +++ b/tests/eri/test.cc @@ -23,7 +23,42 @@ #include #include -#include +#ifdef _MSC_VER + // thanks, https://stackoverflow.com/a/26085827 +# define NOMINMAX +# define WIN32_LEAN_AND_MEAN +# include +# include // portable: uint64_t MSVC: __int64 + + // MSVC defines this in winsock2.h!? + typedef struct timeval { + long tv_sec; + long tv_usec; + } timeval; + + int gettimeofday(struct timeval * tp, struct timezone * tzp) + { + // Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's + // This magic number is the number of 100 nanosecond intervals since January 1, 1601 (UTC) + // until 00:00:00 January 1, 1970 + static const uint64_t EPOCH = ((uint64_t) 116444736000000000ULL); + + SYSTEMTIME system_time; + FILETIME file_time; + uint64_t time; + + GetSystemTime( &system_time ); + SystemTimeToFileTime( &system_time, &file_time ); + time = ((uint64_t)file_time.dwLowDateTime ) ; + time += ((uint64_t)file_time.dwHighDateTime) << 32; + + tp->tv_sec = (long) ((time - EPOCH) / 10000000L); + tp->tv_usec = (long) (system_time.wMilliseconds * 1000); + return 0; + } +#else // _MSC_VER +# include +#endif // _MSC_VER #include #include diff --git a/tests/hartree-fock/hartree-fock++-validate.py b/tests/hartree-fock/hartree-fock++-validate.py index 857e8fd13..d42ae0bb6 100644 --- a/tests/hartree-fock/hartree-fock++-validate.py +++ b/tests/hartree-fock/hartree-fock++-validate.py @@ -37,6 +37,8 @@ def validate(label, data, refdata, tolerance, textline): no = False yes = True exec(open(path_to_libfeatures).read()) +else: + sys.exit(2) # ignore test if ERI_MAX_AM is too low if LIBINT_ERI_MAX_AM<2: diff --git a/tests/unit/test-2body.cc b/tests/unit/test-2body.cc index 343adad7c..acfa21c89 100644 --- a/tests/unit/test-2body.cc +++ b/tests/unit/test-2body.cc @@ -9,6 +9,8 @@ # include #endif +typedef unsigned int uint; + TEST_CASE("Slater/Yukawa integrals", "[engine][2-body]") { std::vector obs{ diff --git a/tests/unit/test-basis.cc b/tests/unit/test-basis.cc index 1558564bf..435ff6573 100644 --- a/tests/unit/test-basis.cc +++ b/tests/unit/test-basis.cc @@ -14,6 +14,7 @@ TEST_CASE("Basis", "[basis]") { }; for(auto&& bs_name : {"3-21g", "6-311g**", + "6-311gss", "6-31g", "6-31g*", "6-31g**",