# Molecular Orbital PACkage (MOPAC) # Copyright 2021 Virginia Polytechnic Institute and State University # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Using Cmake version 3.14 for NumPy support cmake_minimum_required(VERSION 3.14 FATAL_ERROR) # Ensure we are building out-of-source so that the tests work (issue 120) get_filename_component(srcdir "${CMAKE_SOURCE_DIR}" REALPATH) get_filename_component(bindir "${CMAKE_BINARY_DIR}" REALPATH) if("${srcdir}" STREQUAL "${bindir}") message(FATAL_ERROR "MOPAC should not be configured & built in the source directory Please create a separate build directory and rerun cmake from the build directory For example: mkdir build; cd build; cmake ..") endif() # Read version number file(READ "CITATION.cff" CITATION) string(REGEX MATCH "[^-]version: ([0-9\.]*)" _ ${CITATION}) # Code coverage option option(ENABLE_COVERAGE "Code coverage flag" OFF) # Set a safe default build type if there is no user input if(NOT CMAKE_BUILD_TYPE) if (ENABLE_COVERAGE) set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE) else() set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE) endif() else() # otherwise, check conflict with ENABLE_COVERAGE if(ENABLE_COVERAGE AND NOT ${CMAKE_BUILD_TYPE} STREQUAL "Debug") message(FATAL_ERROR "Option ENABLE_COVERAGE requires CMAKE_BUILD_TYPE=Debug") endif() endif() message(STATUS "Build type is ${CMAKE_BUILD_TYPE}") # Specify project name & programming languages project(openmopac VERSION ${CMAKE_MATCH_1} LANGUAGES Fortran) # Enable C language support for MKL? (C is only needed for auto-detection of MKL by find_package) option(ENABLE_MKL "Turn on C language support for MKL" ON) option(USE_C_MALLOC "Turn on C malloc/free for API memory management" OFF) option(FORCE_EXPORT_SYMBOLS "Turn on CMake system to export all symbols in MOPAC shared library" OFF) if(ENABLE_MKL OR USE_C_MALLOC OR FORCE_EXPORT_SYMBOLS) enable_language(C) endif() # Follow GNU conventions for installing directories (languages need to be enabled at this stage) include(GNUInstallDirs) # Failsafe definition of install directories (not guaranteed behavior in some older CMake versions) if(NOT DEFINED CMAKE_INSTALL_BINDIR) set(CMAKE_INSTALL_BINDIR "bin") endif() if(NOT DEFINED CMAKE_INSTALL_LIBDIR) set(CMAKE_INSTALL_LIBDIR "lib") endif() # Static or dynamic build option(STATIC_BUILD "Build a static executable" OFF) if (STATIC_BUILD) message(STATUS "Static executables") message(WARNING "CMake cannot verify the ability to link static executables in the pre-build phase. " "Please verify that you are able to link static executables with a \"-static\" linker flag. " "OpenMP does not support static builds by default, so try THREADS_KEYWORD=OFF if the static build fails to turn off OpenMP.") else() message(STATUS "Shared library and dynamic executables") endif() # location for CMake modules list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") # Set relative RPATH for installation set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) # Install-time options if(APPLE) set(CMAKE_INSTALL_RPATH "\@loader_path/../lib") elseif(UNIX) set(CMAKE_INSTALL_RPATH "\$ORIGIN/../lib") endif() # Define a common library and executables for MOPAC & PARAM if (STATIC_BUILD) # Static build set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX}) add_library(mopac-core STATIC) target_link_options(mopac-core PUBLIC "-static") set(BLA_STATIC ON) else() add_library(mopac-core SHARED) if(FORCE_EXPORT_SYMBOLS) set_target_properties(mopac-core PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS true) endif() endif() set_target_properties(mopac-core PROPERTIES OUTPUT_NAME "mopac") add_executable(mopac) add_executable(mopac-param) add_executable(mopac-makpol) target_link_libraries(mopac mopac-core) target_link_libraries(mopac-param mopac-core) if (STATIC_BUILD) target_link_options(mopac PUBLIC "-static") target_link_options(mopac-param PUBLIC "-static") target_link_options(mopac-makpol PUBLIC "-static") endif() # Add CITATION.cff to source files so that version updates are not ignored target_sources(mopac-core PRIVATE CITATION.cff) # BZ build on Windows w/ the Intel Fortran compiler option(BUILD_BZ "Build BZ with QuickWin GUI (ifort required)" OFF) if(BUILD_BZ) if(NOT (CMAKE_Fortran_COMPILER_ID STREQUAL "Intel")) message(FATAL_ERROR "BZ compilation requires the Intel Fortran compiler (ifort)") endif() if(NOT WIN32) message(FATAL_ERROR "BZ is only available on Windows") endif() add_executable(mopac-bz) target_compile_options(mopac-bz PRIVATE /libs:qwin) target_link_options(mopac-bz PRIVATE /subsystem:windows) if (STATIC_BUILD) target_link_options(mopac-bz PUBLIC "-static") endif() endif() # Use malloc in API w/ Intel Fortran compiler because it can't deallocate Fortran-allocated memory passed through a C interface if(USE_C_MALLOC) target_compile_definitions(mopac-core PRIVATE MOPAC_API_CC) target_link_libraries(mopac-core PUBLIC ${CMAKE_C_STANDARD_LIBRARIES}) elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "Intel") target_compile_definitions(mopac-core PRIVATE MOPAC_API_IFORT) endif() # MOPAC shared library ABI compatibility version set_target_properties(mopac-core PROPERTIES SOVERSION 2) # Adjust legacy PGI compiler behavior: disable C-style backslash characters & warn about CRLF handling if(CMAKE_Fortran_COMPILER_ID MATCHES "PGI|Flang") target_compile_options(mopac-core PUBLIC "-fno-backslash") target_compile_options(mopac-makpol PUBLIC "-fno-backslash") if(UNIX) message(NOTICE "Legacy PGI compiler detected. Set environment variable FORTRANOPT=crlf at compile time to parse Windows-style CRLF endline sequences in MOPAC input files.") endif() endif() # Pass OS information to MOPAC's Fortran source if(APPLE) target_compile_definitions(mopac-core PRIVATE MOPAC_OS="MacOS") elseif(WIN32) target_compile_definitions(mopac-core PRIVATE MOPAC_OS="Windows") target_compile_definitions(mopac-core PRIVATE WIN32) elseif(UNIX) target_compile_definitions(mopac-core PRIVATE MOPAC_OS="Linux") endif() # Pass compiler information to MOPAC's Fortran source if(CMAKE_Fortran_COMPILER_ID MATCHES "Flang") option(F2003_INTRINSICS "Replace non-standard intrinsics w/ Fortran 2003 standards" ON) else() option(F2003_INTRINSICS "Replace non-standard intrinsics w/ Fortran 2003 standards" OFF) endif() if(F2003_INTRINSICS) target_compile_definitions(mopac-core PRIVATE MOPAC_F2003) target_compile_definitions(mopac-makpol PRIVATE MOPAC_F2003) if(BUILD_BZ) target_compile_definitions(mopac-bz PRIVATE MOPAC_F2003) endif() endif() # Pass version & commit information to MOPAC's Fortran source target_compile_definitions(mopac-core PRIVATE MOPAC_VERSION_FULL="${PROJECT_VERSION}") option(GIT_HASH "Show git hash in --version info (git repo only)" ON) if(GIT_HASH) execute_process(COMMAND git rev-parse HEAD OUTPUT_VARIABLE GIT_HASH_VAL) if(GIT_HASH_VAL) string(STRIP ${GIT_HASH_VAL} GIT_HASH_VAL) target_compile_definitions(mopac-core PRIVATE MOPAC_GIT_HASH="${GIT_HASH_VAL}") endif() endif() # Try to use CMake's system of finding BLAS & LAPACK libraries option(AUTO_BLAS "Use find_package to detect BLAS & LAPACK libraries" ON) if(AUTO_BLAS) find_package(BLAS) find_package(LAPACK) if((NOT BLAS_FOUND) OR (NOT LAPACK_FOUND)) message(FATAL_ERROR "find_package failed to find BLAS & LAPACK libraries, adjust environment variables & system paths or set AUTO_BLAS=OFF & manually define a link line with MOPAC_LINK") endif() # Use BLAS/LAPACK information provided by CMake's find_package system target_link_libraries(mopac-core PUBLIC ${BLAS_LIBRARIES} ${LAPACK_LIBRARIES}) target_link_options(mopac PUBLIC ${BLAS_LINKER_FLAGS} ${LAPACK_LINKER_FLAGS}) target_link_options(mopac-param PUBLIC ${BLAS_LINKER_FLAGS} ${LAPACK_LINKER_FLAGS}) else() message(STATUS "AUTO_BLAS=OFF, the user is responsible for linking BLAS & LAPACK libraries (e.g. define compiler link line with MOPAC_LINK)") endif() # Use OpenMP API in MOPAC for "THREADS" keyword option(THREADS_KEYWORD "Enable THREADS keyword using OpenMP API" ON) if(THREADS_KEYWORD) find_package(OpenMP) if(OpenMP_FOUND) target_compile_options(mopac-core PUBLIC ${OpenMP_Fortran_FLAGS}) target_link_options(mopac-core PUBLIC ${OpenMP_Fortran_FLAGS}) endif() endif() # Additional link line set(MOPAC_LINK "" CACHE STRING "Additional link line for MOPAC executable.") set(MOPAC_LINK_PATH "" CACHE STRING "Path of external dependencies to bundle.") separate_arguments(MOPAC_LINK) separate_arguments(MOPAC_LINK_PATH) target_link_libraries(mopac-core PUBLIC ${MOPAC_LINK}) target_link_directories(mopac-core PUBLIC ${MOPAC_LINK_PATH}) # MDI functionality (in development) option(MDI "MDI build flag" OFF) if(MDI) add_definitions(-DBUILD_MDI) find_package(mdi) if(mdi_FOUND) message(STATUS "Found MDI: ${mdi_LIBRARY}") target_link_libraries(mopac-core PUBLIC ${mdi_LIBRARY}) else() message(STATUS "MDI not found, a local version will be downloaded & built") include(MDI) endif() endif() # Add list of source files from src directory add_subdirectory(src) # Set up code coverage set(GCOV_PROGRAM_NAME gcov CACHE STRING "Name of GNU code coverage analysis tool.") set(LCOV_PROGRAM_NAME lcov CACHE STRING "Name of GNU code coverage visualization tool.") if(ENABLE_COVERAGE) if(NOT ("${CMAKE_Fortran_COMPILER_ID}" MATCHES "GNU")) message(FATAL_ERROR "Code coverage requires the GNU Fortran compiler! Aborting...") endif() target_compile_options(mopac-core PUBLIC -fprofile-arcs -ftest-coverage -O0) target_link_options(mopac-core PUBLIC -fprofile-arcs -ftest-coverage) find_program(GCOV_PATH ${GCOV_PROGRAM_NAME}) find_program(LCOV_PATH ${LCOV_PROGRAM_NAME}) if(NOT GCOV_PATH) message(FATAL_ERROR "${GCOV_PROGRAM_NAME} not found! Aborting...") endif() if(NOT LCOV_PATH) message(FATAL_ERROR "${LCOV_PROGRAM_NAME} not found! Aborting...") endif() configure_file("cmake/CTestCustom.cmake" "${CMAKE_BINARY_DIR}/CTestCustom.cmake") endif() # GPU functionality (not functional at the moment) option(GPU "GPU build flag" OFF) if(GPU) add_definitions(-DGPU) endif() # Add tests option(TESTS "Enable tests (needs Python3 and Numpy)" ON) if(TESTS) find_package (Python3 COMPONENTS Interpreter NumPy) if(NOT Python3_FOUND) if(Python3_Interpreter_FOUND AND (NOT Python3_NumPy_FOUND)) message(NOTICE "Python3 found without NumPy at path: ${Python3_EXECUTABLE}\n" "(HINT: install NumPy for this Python3 instance with pip or conda, or give higher priority to an instance with NumPy installed by setting Python3_EXECUTABLE)") endif() message(FATAL_ERROR "Python3 and Numpy are required for MOPAC testing (testing can be disabled with -DTESTS=OFF)") endif() enable_testing() add_executable(mopac-api-test) target_link_libraries(mopac-api-test mopac-core) add_subdirectory(include) add_subdirectory(tests) endif() # CPack options set(CPACK_PACKAGE_NAME "mopac") set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Molecular Orbital PACkage (MOPAC)") set(CPACK_PACKAGE_VENDOR "openmopac GitHub organization") set(CPACK_PACKAGE_CONTACT "openmopac@gmail.com") if(APPLE) set(CPACK_SYSTEM_NAME "mac") elseif(WIN32) set(CPACK_SYSTEM_NAME "win") elseif(UNIX) set(CPACK_SYSTEM_NAME "linux") endif() set(CPACK_PROJECT_CONFIG_FILE "${CMAKE_SOURCE_DIR}/cmake/CPackOptions.cmake") # Package the Intel OpenMP library for the QT installer (hard-coded for each OS) if(CMAKE_Fortran_COMPILER_ID STREQUAL "Intel") if(WIN32) find_file(INTEL_OMP_DLL libiomp5md.dll HINT CMAKE_Fortran_COMPILER PATH_SUFFIXES ../../redist/intel64_win/compiler) if(INTEL_OMP_DLL STREQUAL "INTEL_OMP_DLL-NOTFOUND") message("WARNING: Cannot locate Intel's OpenMP dll for packaging") endif() install(PROGRAMS ${INTEL_OMP_DLL} DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT redist EXCLUDE_FROM_ALL) else() find_library(INTEL_OMP_LIB iomp5 HINT CMAKE_Fortran_COMPILER PATH_SUFFIXES ../../compiler/lib ../../compiler/lib/intel64_lin) if(INTEL_OMP_LIB STREQUAL "INTEL_OMP_LIB-NOTFOUND") message("WARNING: Cannot locate Intel's OpenMP shared library for packaging") endif() # resolve symbolic links get_filename_component(INTEL_OMP_LIB_PATH ${INTEL_OMP_LIB} REALPATH) message(STATUS "OMP packaging: ${INTEL_OMP_LIB} -> ${INTEL_OMP_LIB_PATH}") install(FILES ${INTEL_OMP_LIB_PATH} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT redist EXCLUDE_FROM_ALL) endif() endif() # IFW-specific CPack options set(CPACK_IFW_PACKAGE_NAME "MOPAC") set(CPACK_IFW_PRODUCT_URL "http://openmopac.net") set(CPACK_IFW_PACKAGE_CONTROL_SCRIPT "${CMAKE_SOURCE_DIR}/.github/qtifw_controller.qs") set(CPACK_IFW_PACKAGE_MAINTENANCE_TOOL_NAME "uninstall-mopac") set(CPACK_IFW_VERBOSE ON) if(WIN32) set(CPACK_IFW_TARGET_DIRECTORY "C:/Program Files/MOPAC") else() set(CPACK_IFW_TARGET_DIRECTORY "/opt/mopac") endif() install(FILES "${CMAKE_SOURCE_DIR}/.github/mopac.ico" DESTINATION "." COMPONENT qtifw EXCLUDE_FROM_ALL) install(FILES "${CMAKE_SOURCE_DIR}/CITATION.cff" "${CMAKE_SOURCE_DIR}/LICENSE" DESTINATION "." COMPONENT redist EXCLUDE_FROM_ALL) install(FILES "${CMAKE_SOURCE_DIR}/include/mopac.h" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT main) install(FILES "${CMAKE_SOURCE_DIR}/include/mopac_wrapper_internal.F90" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT redist EXCLUDE_FROM_ALL) install(FILES "${CMAKE_SOURCE_DIR}/include/mopac_wrapper.F90" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT redist EXCLUDE_FROM_ALL) install(FILES "${CMAKE_SOURCE_DIR}/include/LICENSE" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT redist EXCLUDE_FROM_ALL) # Install the executables and library install(TARGETS mopac RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT main) install(TARGETS mopac-param RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT main) install(TARGETS mopac-makpol RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT main) if(WIN32) install(TARGETS mopac-core RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT main) if(BUILD_BZ) install(TARGETS mopac-bz RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT main) endif() else() install(TARGETS mopac-core LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT main) endif() # Add IFW packaging include(CPack) include(CPackIFW) cpack_ifw_configure_component(main DISPLAY_NAME "main program" SORTING_PRIORITY 2 FORCED_INSTALLATION LICENSES "license (Apache-2.0)" "${CMAKE_SOURCE_DIR}/LICENSE" SCRIPT "${CMAKE_SOURCE_DIR}/.github/qtifw_component.qs" USER_INTERFACES "${CMAKE_SOURCE_DIR}/.github/pathcheckboxform.ui" "${CMAKE_SOURCE_DIR}/.github/filecheckboxform.ui" "${CMAKE_SOURCE_DIR}/.github/iconcheckboxform.ui") cpack_ifw_configure_component(qtifw VIRTUAL FORCED_INSTALLATION) cpack_ifw_configure_component(redist VIRTUAL FORCED_INSTALLATION)