cmake_minimum_required(VERSION 3.10 FATAL_ERROR) project(openmc C CXX) # Set version numbers set(OPENMC_VERSION_MAJOR 0) set(OPENMC_VERSION_MINOR 14) set(OPENMC_VERSION_RELEASE 1) set(OPENMC_VERSION ${OPENMC_VERSION_MAJOR}.${OPENMC_VERSION_MINOR}.${OPENMC_VERSION_RELEASE}) configure_file(include/openmc/version.h.in "${CMAKE_BINARY_DIR}/include/openmc/version.h" @ONLY) # Setup output directories set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) # Set module path set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules) # Allow user to specify _ROOT variables if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.12) cmake_policy(SET CMP0074 NEW) endif() # Enable correct usage of CXX_EXTENSIONS if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.22) cmake_policy(SET CMP0128 NEW) endif() #=============================================================================== # Command line options #=============================================================================== option(OPENMC_USE_OPENMP "Enable shared-memory parallelism with OpenMP" ON) option(OPENMC_BUILD_TESTS "Build tests" ON) option(OPENMC_ENABLE_PROFILE "Compile with profiling flags" OFF) option(OPENMC_ENABLE_COVERAGE "Compile with coverage analysis flags" OFF) option(OPENMC_USE_DAGMC "Enable support for DAGMC (CAD) geometry" OFF) option(OPENMC_USE_LIBMESH "Enable support for libMesh unstructured mesh tallies" OFF) option(OPENMC_USE_MPI "Enable MPI" OFF) option(OPENMC_USE_MCPL "Enable MCPL" OFF) option(OPENMC_USE_NCRYSTAL "Enable support for NCrystal scattering" OFF) # Warnings for deprecated options foreach(OLD_OPT IN ITEMS "openmp" "profile" "coverage" "dagmc" "libmesh") if(DEFINED ${OLD_OPT}) string(TOUPPER ${OLD_OPT} OPT_UPPER) if ("${OLD_OPT}" STREQUAL "profile" OR "${OLD_OPT}" STREQUAL "coverage") set(NEW_OPT_PREFIX "OPENMC_ENABLE") else() set(NEW_OPT_PREFIX "OPENMC_USE") endif() message(WARNING "The OpenMC CMake option '${OLD_OPT}' has been deprecated. " "Its value will be ignored. " "Please use '-D${NEW_OPT_PREFIX}_${OPT_UPPER}=${${OLD_OPT}}' instead.") unset(${OLD_OPT} CACHE) endif() endforeach() foreach(OLD_BLD in ITEMS "debug" "optimize") if(DEFINED ${OLD_BLD}) if("${OLD_BLD}" STREQUAL "debug") set(BLD_VAR "Debug") else() set(BLD_VAR "Release") endif() message(WARNING "The OpenMC CMake option '${OLD_BLD}' has been deprecated. " "Its value will be ignored. " "OpenMC now uses the CMAKE_BUILD_TYPE variable to set the build mode. " "Please use '-DCMAKE_BUILD_TYPE=${BLD_VAR}' instead.") unset(${OLD_BLD} CACHE) endif() endforeach() #=============================================================================== # Set a default build configuration if not explicitly specified #=============================================================================== if(NOT CMAKE_BUILD_TYPE) message(STATUS "No build type selected, defaulting to RelWithDebInfo") set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build" FORCE) endif() #=============================================================================== # MPI for distributed-memory parallelism #=============================================================================== if(OPENMC_USE_MPI) find_package(MPI REQUIRED) endif() #=============================================================================== # Helper macro for finding a dependency #=============================================================================== macro(find_package_write_status pkg) find_package(${pkg} QUIET NO_SYSTEM_ENVIRONMENT_PATH) if(${pkg}_FOUND) message(STATUS "Found ${pkg}: ${${pkg}_DIR} (version ${${pkg}_VERSION})") else() message(STATUS "Did not find ${pkg}, will use submodule instead") endif() endmacro() #=============================================================================== # NCrystal Scattering Support #=============================================================================== if(OPENMC_USE_NCRYSTAL) find_package(NCrystal REQUIRED) message(STATUS "Found NCrystal: ${NCrystal_DIR} (version ${NCrystal_VERSION})") endif() #=============================================================================== # DAGMC Geometry Support - need DAGMC/MOAB #=============================================================================== if(OPENMC_USE_DAGMC) find_package(DAGMC REQUIRED PATH_SUFFIXES lib/cmake) if (${DAGMC_VERSION} VERSION_LESS 3.2.0) message(FATAL_ERROR "Discovered DAGMC Version: ${DAGMC_VERSION}. \ Please update DAGMC to version 3.2.0 or greater.") endif() message(STATUS "Found DAGMC: ${DAGMC_DIR} (version ${DAGMC_VERSION})") endif() #=============================================================================== # libMesh Unstructured Mesh Support #=============================================================================== if(OPENMC_USE_LIBMESH) find_package(LIBMESH REQUIRED) endif() #=============================================================================== # libpng #=============================================================================== find_package(PNG) #=============================================================================== # HDF5 for binary output #=============================================================================== # Unfortunately FindHDF5.cmake will always prefer a serial HDF5 installation # over a parallel installation if both appear on the user's PATH. To get around # this, we check for the environment variable HDF5_ROOT and if it exists, use it # to check whether its a parallel version. if(NOT DEFINED HDF5_PREFER_PARALLEL) if(DEFINED ENV{HDF5_ROOT} AND EXISTS $ENV{HDF5_ROOT}/bin/h5pcc) set(HDF5_PREFER_PARALLEL TRUE) else() set(HDF5_PREFER_PARALLEL FALSE) endif() endif() find_package(HDF5 REQUIRED COMPONENTS C HL) # Remove HDF5 transitive dependencies that are system libraries list(FILTER HDF5_LIBRARIES EXCLUDE REGEX ".*lib(pthread|dl|m).*") message(STATUS "HDF5 Libraries: ${HDF5_LIBRARIES}") if(HDF5_IS_PARALLEL) if(NOT OPENMC_USE_MPI) message(FATAL_ERROR "Parallel HDF5 was detected, but MPI was not enabled.\ To use parallel HDF5, OpenMC needs to be built with MPI support by passing\ -DOPENMC_USE_MPI=ON when calling cmake.") endif() message(STATUS "Using parallel HDF5") endif() # Version 1.12 of HDF5 deprecates the H5Oget_info_by_idx() interface. # Thus, we give these flags to allow usage of the old interface in newer # versions of HDF5. if(${HDF5_VERSION} VERSION_GREATER_EQUAL 1.12.0) list(APPEND cxxflags -DH5Oget_info_by_idx_vers=1 -DH5O_info_t_vers=1) endif() #=============================================================================== # MCPL #=============================================================================== if (OPENMC_USE_MCPL) find_package(MCPL REQUIRED) message(STATUS "Found MCPL: ${MCPL_DIR} (found version \"${MCPL_VERSION}\")") endif() #=============================================================================== # Set compile/link flags based on which compiler is being used #=============================================================================== # Skip for Visual Studio which has its own configurations through GUI if(NOT MSVC) if(OPENMC_USE_OPENMP) find_package(OpenMP REQUIRED) # In CMake 3.9+, can use the OpenMP::OpenMP_CXX imported target list(APPEND cxxflags ${OpenMP_CXX_FLAGS}) list(APPEND ldflags ${OpenMP_CXX_FLAGS}) endif() set(CMAKE_POSITION_INDEPENDENT_CODE ON) if(OPENMC_ENABLE_PROFILE) list(APPEND cxxflags -g -fno-omit-frame-pointer) endif() if(OPENMC_ENABLE_COVERAGE) list(APPEND cxxflags --coverage) list(APPEND ldflags --coverage) endif() # Show flags being used message(STATUS "OpenMC C++ flags: ${cxxflags}") message(STATUS "OpenMC Linker flags: ${ldflags}") endif() #=============================================================================== # Update git submodules as needed #=============================================================================== find_package(Git) if(GIT_FOUND AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.git") option(GIT_SUBMODULE "Check submodules during build" ON) if(GIT_SUBMODULE) message(STATUS "Submodule update") execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} RESULT_VARIABLE GIT_SUBMOD_RESULT) if(NOT GIT_SUBMOD_RESULT EQUAL 0) message(FATAL_ERROR "git submodule update --init failed with \ ${GIT_SUBMOD_RESULT}, please checkout submodules") endif() endif() endif() # Check to see if submodules exist (by checking one) if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/vendor/pugixml/CMakeLists.txt") message(FATAL_ERROR "The git submodules were not downloaded! GIT_SUBMODULE was \ turned off or failed. Please update submodules and try again.") endif() #=============================================================================== # pugixml library #=============================================================================== find_package_write_status(pugixml) if (NOT pugixml_FOUND) add_subdirectory(vendor/pugixml) set_target_properties(pugixml PROPERTIES CXX_STANDARD 14 CXX_EXTENSIONS OFF) endif() #=============================================================================== # {fmt} library #=============================================================================== find_package_write_status(fmt) if (NOT fmt_FOUND) set(FMT_INSTALL ON CACHE BOOL "Generate the install target.") add_subdirectory(vendor/fmt) endif() #=============================================================================== # xtensor header-only library #=============================================================================== # CMake 3.13+ will complain about policy CMP0079 unless it is set explicitly if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.13) cmake_policy(SET CMP0079 NEW) endif() find_package_write_status(xtensor) if (NOT xtensor_FOUND) add_subdirectory(vendor/xtl) set(xtl_DIR ${CMAKE_CURRENT_BINARY_DIR}/vendor/xtl) add_subdirectory(vendor/xtensor) endif() #=============================================================================== # GSL header-only library #=============================================================================== find_package_write_status(gsl-lite) if (NOT gsl-lite_FOUND) add_subdirectory(vendor/gsl-lite) # Make sure contract violations throw exceptions target_compile_definitions(gsl-lite-v1 INTERFACE GSL_THROW_ON_CONTRACT_VIOLATION) target_compile_definitions(gsl-lite-v1 INTERFACE gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON=1) endif() #=============================================================================== # Catch2 library #=============================================================================== if(OPENMC_BUILD_TESTS) find_package_write_status(Catch2) if (NOT Catch2_FOUND) add_subdirectory(vendor/Catch2) endif() endif() #=============================================================================== # RPATH information #=============================================================================== # Provide install directory variables as defined by GNU coding standards include(GNUInstallDirs) # This block of code ensures that dynamic libraries can be found via the RPATH # whether the executable is the original one from the build directory or the # installed one in CMAKE_INSTALL_PREFIX. Ref: # https://gitlab.kitware.com/cmake/community/wikis/doc/cmake/RPATH-handling # use, i.e. don't skip the full RPATH for the build tree set(CMAKE_SKIP_BUILD_RPATH FALSE) # when building, don't use the install RPATH already # (but later on when installing) set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) # add the automatically determined parts of the RPATH # which point to directories outside the build tree to the install RPATH set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) # the RPATH to be used when installing, but only if it's not a system directory list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_FULL_LIBDIR}" isSystemDir) if("${isSystemDir}" STREQUAL "-1") set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}") endif() #=============================================================================== # libopenmc #=============================================================================== list(APPEND libopenmc_SOURCES src/bank.cpp src/boundary_condition.cpp src/bremsstrahlung.cpp src/cell.cpp src/cmfd_solver.cpp src/cross_sections.cpp src/dagmc.cpp src/distribution.cpp src/distribution_angle.cpp src/distribution_energy.cpp src/distribution_multi.cpp src/distribution_spatial.cpp src/eigenvalue.cpp src/endf.cpp src/error.cpp src/event.cpp src/file_utils.cpp src/finalize.cpp src/geometry.cpp src/geometry_aux.cpp src/hdf5_interface.cpp src/initialize.cpp src/lattice.cpp src/material.cpp src/math_functions.cpp src/mcpl_interface.cpp src/mesh.cpp src/message_passing.cpp src/mgxs.cpp src/mgxs_interface.cpp src/ncrystal_interface.cpp src/nuclide.cpp src/output.cpp src/particle.cpp src/particle_data.cpp src/particle_restart.cpp src/photon.cpp src/physics.cpp src/physics_common.cpp src/physics_mg.cpp src/plot.cpp src/position.cpp src/progress_bar.cpp src/random_dist.cpp src/random_lcg.cpp src/reaction.cpp src/reaction_product.cpp src/scattdata.cpp src/secondary_correlated.cpp src/secondary_kalbach.cpp src/secondary_nbody.cpp src/secondary_thermal.cpp src/secondary_uncorrelated.cpp src/settings.cpp src/simulation.cpp src/source.cpp src/state_point.cpp src/string_utils.cpp src/summary.cpp src/surface.cpp src/tallies/derivative.cpp src/tallies/filter.cpp src/tallies/filter_azimuthal.cpp src/tallies/filter_cell.cpp src/tallies/filter_cell_instance.cpp src/tallies/filter_cellborn.cpp src/tallies/filter_cellfrom.cpp src/tallies/filter_collision.cpp src/tallies/filter_delayedgroup.cpp src/tallies/filter_distribcell.cpp src/tallies/filter_energy.cpp src/tallies/filter_energyfunc.cpp src/tallies/filter_legendre.cpp src/tallies/filter_material.cpp src/tallies/filter_materialfrom.cpp src/tallies/filter_mesh.cpp src/tallies/filter_meshsurface.cpp src/tallies/filter_mu.cpp src/tallies/filter_particle.cpp src/tallies/filter_polar.cpp src/tallies/filter_sph_harm.cpp src/tallies/filter_sptl_legendre.cpp src/tallies/filter_surface.cpp src/tallies/filter_time.cpp src/tallies/filter_universe.cpp src/tallies/filter_zernike.cpp src/tallies/tally.cpp src/tallies/tally_scoring.cpp src/tallies/trigger.cpp src/thermal.cpp src/timer.cpp src/track_output.cpp src/universe.cpp src/urr.cpp src/volume_calc.cpp src/weight_windows.cpp src/wmp.cpp src/xml_interface.cpp src/xsdata.cpp) # Add bundled external dependencies list(APPEND libopenmc_SOURCES src/external/quartic_solver.cpp src/external/Faddeeva.cc) # For Visual Studio compilers if(MSVC) # Use static library (otherwise explicit symbol portings are needed) add_library(libopenmc STATIC ${libopenmc_SOURCES}) # To use the shared HDF5 libraries on Windows, the H5_BUILT_AS_DYNAMIC_LIB # compile definition must be specified. target_compile_definitions(libopenmc PRIVATE -DH5_BUILT_AS_DYNAMIC_LIB) else() add_library(libopenmc SHARED ${libopenmc_SOURCES}) endif() add_library(OpenMC::libopenmc ALIAS libopenmc) # Avoid vs error lnk1149 :output filename matches input filename if(NOT MSVC) set_target_properties(libopenmc PROPERTIES OUTPUT_NAME openmc) endif() target_include_directories(libopenmc PUBLIC $ $ ${HDF5_INCLUDE_DIRS} ) # Set compile flags target_compile_options(libopenmc PRIVATE ${cxxflags}) # Add include directory for configured version file target_include_directories(libopenmc PUBLIC $) if (HDF5_IS_PARALLEL) target_compile_definitions(libopenmc PRIVATE -DPHDF5) endif() if (OPENMC_USE_MPI) target_compile_definitions(libopenmc PUBLIC -DOPENMC_MPI) endif() # Set git SHA1 hash as a compile definition if(GIT_FOUND) execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse HEAD WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} RESULT_VARIABLE GIT_SHA1_SUCCESS OUTPUT_VARIABLE GIT_SHA1 ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) if(GIT_SHA1_SUCCESS EQUAL 0) target_compile_definitions(libopenmc PRIVATE -DGIT_SHA1="${GIT_SHA1}") endif() endif() # target_link_libraries treats any arguments starting with - but not -l as # linker flags. Thus, we can pass both linker flags and libraries together. target_link_libraries(libopenmc ${ldflags} ${HDF5_LIBRARIES} ${HDF5_HL_LIBRARIES} xtensor gsl::gsl-lite-v1 fmt::fmt ${CMAKE_DL_LIBS}) if(TARGET pugixml::pugixml) target_link_libraries(libopenmc pugixml::pugixml) else() target_link_libraries(libopenmc pugixml) endif() if(OPENMC_USE_DAGMC) target_compile_definitions(libopenmc PRIVATE DAGMC) target_link_libraries(libopenmc dagmc-shared uwuw-shared) endif() if(OPENMC_USE_LIBMESH) target_compile_definitions(libopenmc PRIVATE LIBMESH) target_link_libraries(libopenmc PkgConfig::LIBMESH) endif() if (PNG_FOUND) target_compile_definitions(libopenmc PRIVATE USE_LIBPNG) target_link_libraries(libopenmc PNG::PNG) endif() if (OPENMC_USE_MPI) target_link_libraries(libopenmc MPI::MPI_CXX) endif() if (OPENMC_BUILD_TESTS) # Add cpp tests directory include(CTest) add_subdirectory(tests/cpp_unit_tests) endif() if (OPENMC_USE_MCPL) target_compile_definitions(libopenmc PUBLIC OPENMC_MCPL) target_link_libraries(libopenmc MCPL::mcpl) endif() if(OPENMC_USE_NCRYSTAL) target_compile_definitions(libopenmc PRIVATE NCRYSTAL) target_link_libraries(libopenmc NCrystal::NCrystal) endif() #=============================================================================== # Log build info that this executable can report later #=============================================================================== target_compile_definitions(libopenmc PRIVATE BUILD_TYPE=${CMAKE_BUILD_TYPE}) target_compile_definitions(libopenmc PRIVATE COMPILER_ID=${CMAKE_CXX_COMPILER_ID}) target_compile_definitions(libopenmc PRIVATE COMPILER_VERSION=${CMAKE_CXX_COMPILER_VERSION}) if (OPENMC_ENABLE_PROFILE) target_compile_definitions(libopenmc PRIVATE PROFILINGBUILD) endif() if (OPENMC_ENABLE_COVERAGE) target_compile_definitions(libopenmc PRIVATE COVERAGEBUILD) endif() #=============================================================================== # openmc executable #=============================================================================== add_executable(openmc src/main.cpp) add_executable(OpenMC::openmc ALIAS openmc) target_compile_options(openmc PRIVATE ${cxxflags}) target_include_directories(openmc PRIVATE ${CMAKE_BINARY_DIR}/include) target_link_libraries(openmc libopenmc) # Ensure C++14 standard is used and turn off GNU extensions target_compile_features(openmc PUBLIC cxx_std_14) target_compile_features(libopenmc PUBLIC cxx_std_14) set_target_properties(openmc libopenmc PROPERTIES CXX_EXTENSIONS OFF) #=============================================================================== # Python package #=============================================================================== add_custom_command(TARGET libopenmc POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $ ${CMAKE_CURRENT_SOURCE_DIR}/openmc/lib/$ COMMENT "Copying libopenmc to Python module directory") #=============================================================================== # Install executable, scripts, manpage, license #=============================================================================== configure_file(cmake/OpenMCConfig.cmake.in "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/OpenMCConfig.cmake" @ONLY) configure_file(cmake/OpenMCConfigVersion.cmake.in "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/OpenMCConfigVersion.cmake" @ONLY) set(INSTALL_CONFIGDIR ${CMAKE_INSTALL_LIBDIR}/cmake/OpenMC) install(TARGETS openmc libopenmc EXPORT openmc-targets RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) install(EXPORT openmc-targets FILE OpenMCTargets.cmake NAMESPACE OpenMC:: DESTINATION ${INSTALL_CONFIGDIR}) install(FILES "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/OpenMCConfig.cmake" "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/OpenMCConfigVersion.cmake" DESTINATION ${INSTALL_CONFIGDIR}) install(FILES man/man1/openmc.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) install(FILES LICENSE DESTINATION "${CMAKE_INSTALL_DOCDIR}" RENAME copyright) install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) install(FILES "${CMAKE_BINARY_DIR}/include/openmc/version.h" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/openmc)