cmake_minimum_required(VERSION 3.15 FATAL_ERROR) # Note that this needs to happen **before** the call to project(...). This is because CMake reads # the CRAYPE_LINK_TYPE environment variable inside the call to project(...) and sets various flags # and properties based on its value. Because we are so early in the CMake processing, we have to # figure out for ourselves whether or not we are running on a Cray system by looking for Cray # environment variables directly. if(DEFINED ENV{CRAYPE_VERSION}) # Older versions of the Cray software prefer static linking by default, which doesn't work with # NEURON with some compilers (GCC and Intel at the time of writing). Note that this variable will # not be set in the compiler and linker runtime environments, so we are relying on CMake baking in # the correct compiler flags based on the value we set here. In more recent versions of the Cray # software the default has changed; CMake knows about this in v3.15.3 and newer, but to support # older CMake versions we still need to set this explicitly. See: # https://github.com/neuronsimulator/nrn/issues/1153 set(ENV{CRAYPE_LINK_TYPE} dynamic) message(STATUS "Cray system detected...setting CRAYPE_LINK_TYPE=dynamic") endif() project( NEURON VERSION 8.2.6 LANGUAGES C CXX HOMEPAGE_URL "https://www.neuron.yale.edu/neuron/") # ============================================================================= # CMake common project settings # ============================================================================= set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) # ============================================================================= # CMake common project settings # ============================================================================= set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) # ============================================================================= # Include default build options # ============================================================================= list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) include(BuildOptionDefaults) # ============================================================================= # Build options (boolean) # ============================================================================= option(NRN_ENABLE_DOCS "Build documentation" ${NRN_ENABLE_DOCS_DEFAULT}) # This is useful for readthedocs-style builds and the documentation CI, where the actual # installation of NEURON comes from an installed binary wheel. option( NRN_ENABLE_DOCS_WITH_EXTERNAL_INSTALLATION "Build documentation without building NEURON. It will be assumed that import neuron works, nrnivmodl is in PATH, etc." ${NRN_ENABLE_DOCS_WITH_EXTERNAL_INSTALLATION_DEFAULT}) mark_as_advanced(NRN_ENABLE_DOCS_WITH_EXTERNAL_INSTALLATION) option(NRN_ENABLE_SHARED "Build shared libraries (otherwise static library)" ${NRN_ENABLE_SHARED_DEFAULT}) option(NRN_ENABLE_INTERVIEWS "Enable GUI with INTERVIEWS" ${NRN_ENABLE_INTERVIEWS_DEFAULT}) option(NRN_ENABLE_MECH_DLL_STYLE "Dynamically load nrnmech shared library" ${NRN_ENABLE_MECH_DLL_STYLE_DEFAULT}) option(NRN_ENABLE_DISCRETE_EVENT_OBSERVER "Enable Observer to be a subclass of DiscreteEvent" ${NRN_ENABLE_DISCRETE_EVENT_OBSERVER_DEFAULT}) option(NRN_ENABLE_PYTHON "Enable Python interpreter support (default python3 fallback to python)" ${NRN_ENABLE_PYTHON_DEFAULT}) option(NRN_ENABLE_THREADS "Allow use of Pthreads" ${NRN_ENABLE_THREADS_DEFAULT}) option(NRN_ENABLE_MPI "Enable MPI support" ${NRN_ENABLE_MPI_DEFAULT}) option(NRN_ENABLE_MUSIC "Enable MUSIC support" ${NRN_ENABLE_MUSIC_DEFAULT}) option(NRN_ENABLE_RX3D "Enable rx3d support" ${NRN_ENABLE_RX3D_DEFAULT}) option(NRN_ENABLE_CORENEURON "Enable CoreNEURON support" ${NRN_ENABLE_CORENEURON_DEFAULT}) option(NRN_ENABLE_BACKTRACE "Enable pretty-printed backtraces" ${NRN_ENABLE_BACKTRACE_DEFAULT}) option(NRN_ENABLE_TESTS "Enable unit tests" ${NRN_ENABLE_TESTS_DEFAULT}) set(NRN_ENABLE_MODEL_TESTS "${NRN_ENABLE_MODEL_TESTS_DEFAULT}" CACHE STRING "Comma-separated list of detailed models to enable tests of.") # parse NRN_ENABLE_MODEL_TESTS as list string(REPLACE "," ";" NRN_ENABLE_MODEL_TESTS "${NRN_ENABLE_MODEL_TESTS}") # This can be helpful in very specific CI build configurations, where ccache is used *and* different # CI builds are built under different directories. option(NRN_AVOID_ABSOLUTE_PATHS "Avoid embedding absolute paths in generated code (ccache optimisation)" ${NRN_AVOID_ABSOLUTE_PATHS_DEFAULT}) mark_as_advanced(NRN_AVOID_ABSOLUTE_PATHS) option(NRN_DYNAMIC_UNITS_USE_LEGACY "Use legacy units as default for dynamic units" ${NRN_DYNAMIC_UNITS_USE_LEGACY_DEFAULT}) # note that if CoreNEURON is enabled then it is not necessary to enable this option option(NRN_ENABLE_MOD_COMPATIBILITY "Enable CoreNEURON compatibility for MOD files" ${NRN_ENABLE_MOD_COMPATIBILITY_DEFAULT}) option(NRN_ENABLE_REL_RPATH "Use relative RPATH in binaries. for relocatable installs/Python" ${NRN_ENABLE_REL_RPATH_DEFAULT}) option(NRN_WHEEL_BUILD ${NRN_WHEEL_BUILD_DEFAULT}) option(NRN_WHEEL_STATIC_READLINE "Use static readline libraries for the wheels." ${NRN_WHEEL_STATIC_READLINE_DEFAULT}) mark_as_advanced(NRN_ENABLE_REL_RPATH) mark_as_advanced(NRN_WHEEL_BUILD) # ============================================================================= # Build options (string) # ============================================================================= # ~~~ # NEURON module installation: # - OFF : do not install # - ON : install in ${CMAKE_INSTALL_PREFIX} (default) # NOTE: When building the wheel, this is set to OFF. # Dynamic Python version support: # - OFF : nrnpython interface is linked into libnrniv.so # - ON : nrnpython interface consistent with default python3 (falling back to python) # is built and loaded dynamically at run time (nrniv still works in the absence # of any Python at all). # - : semicolon (;) separated list of python executable used to create a separate # interface for each. When one of those versions of Python is launched, # "import neuron" will automatically load the appropriate module interface along # with the rest of neuron. Also nrniv -pyexe will work with any # in the list of python executables. # Dynamic MPI support: # - OFF : nrnmpi is linked into libnrniv.so # - ON : nrnmpi interface consistent with default mpi is built and loaded dynamically # at run time (nrniv still works in the absence of any mpi at all). # - : semicolon (;) separated list of MPI's bin directories to create a separate # libnrnmpi_xxx.so interface for each. When nrniv is launched with the -mpi argument, # the first mpi found will determine which interface is dynamically loaded." # Rx3D Cython generated files compiler optimization level. 0 is default. # Specific coverage files: # - OFF : Disable code coverage. # - ON : Collect code coverage for files (default all). # - : semicolon (;) separated list of files to collect coverage. # ~~~ option(NRN_ENABLE_MODULE_INSTALL "Enable installation of NEURON Python module for regular CMake builds" ${NRN_ENABLE_MODULE_INSTALL_DEFAULT}) option(NRN_ENABLE_PYTHON_DYNAMIC "Enable dynamic Python version support" ${NRN_ENABLE_PYTHON_DYNAMIC_DEFAULT}) set(NRN_PYTHON_DYNAMIC "" CACHE STRING "semicolon (;) separated list of python executables to create interface for (default python3)" ) option(NRN_ENABLE_MPI_DYNAMIC "Enable dynamic MPI library support" OFF) set(NRN_MPI_DYNAMIC "" CACHE STRING "semicolon (;) separated list of MPI include directories to build against (default to first found mpi)" ) set(NRN_RX3D_OPT_LEVEL "${NRN_RX3D_OPT_LEVEL_DEFAULT}" CACHE STRING "Optimization level for Cython generated files (non-zero may compile slowly)") option(NRN_ENABLE_COVERAGE "EnableCode Coverage (make cover_begin, make cover_html)" OFF) set(NRN_COVERAGE_FILES "" CACHE STRING "semicolon (;) separated list of files to collect code coverage") set(NRN_NMODL_CXX_FLAGS "${NRN_NMODL_CXX_FLAGS_DEFAULT}" CACHE STRING "space separated list of flags to be added to host tools (nocmodl, modlunit") separate_arguments(NRN_NMODL_CXX_FLAGS UNIX_COMMAND ${NRN_NMODL_CXX_FLAGS}) set(NRN_EXTRA_CXX_FLAGS "" CACHE STRING "Extra compiler flags for NEURON source files") separate_arguments(NRN_EXTRA_CXX_FLAGS) list(APPEND NRN_COMPILE_FLAGS ${NRN_EXTRA_CXX_FLAGS}) set(NRN_EXTRA_MECH_CXX_FLAGS "" CACHE STRING "Extra compiler flags for translated NEURON mechanisms") separate_arguments(NRN_EXTRA_MECH_CXX_FLAGS) option(NRN_ENABLE_PROFILING "Enable profiling" ${NRN_ENABLE_PROFILING_DEFAULT}) set(NRN_PROFILER "${NRN_PROFILER_DEFAULT}" CACHE STRING "Set which profiler to build against ('caliper', 'likwid')") # ============================================================================= # Set Python additional versions earlier (especially for old CMake) # ============================================================================= set(Python_ADDITIONAL_VERSIONS 3 3.9 3.8 3.7 3.6 3.5 3.4 3.3 3.2 3.1 3.0 2.8 2.7 2.6) # ============================================================================= # Include cmake modules # ============================================================================= # sub-directorty containing project submodules set(THIRD_PARTY_DIRECTORY "${PROJECT_SOURCE_DIR}/external") list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/modules) include(cmake/PlatformHelper.cmake) include(cmake/CompilerHelper.cmake) include(cmake/MacroHelper.cmake) include(cmake/RpathHelper.cmake) include(cmake/ExternalProjectHelper.cmake) include(cmake/modules/FindPythonModule.cmake) include(cmake/Coverage.cmake) # set CMAKE_BUILD_TYPE and associated flags using allowableBuildTypes and CMAKE_BUILD_TYPE_DEFAULT set(allowableBuildTypes Custom Debug Release RelWithDebInfo Fast FastDebug) include(ReleaseDebugAutoFlags) # Try and emit an intelligent warning if the version number currently set in the CMake project(...) # call is inconsistent with the output of git describe. include(cmake/CheckGitDescribeCompatibility.cmake) # Save the version information from project(...) to an nrnsemanticversion.h header in the build # directory. This separate from nrnversion.h, which includes information about the latest git # commit, because it should change less frequently, but it is included in many more files. set(NRN_VERSION_MAJOR ${PROJECT_VERSION_MAJOR}) set(NRN_VERSION_MINOR ${PROJECT_VERSION_MINOR}) set(NRN_VERSION_PATCH ${PROJECT_VERSION_PATCH}) configure_file(src/nrnoc/nrnsemanticversion.h.in src/nrnoc/nrnsemanticversion.h @ONLY) # ============================================================================= # Add coding-conventions submodule so we can use helper functions defined there # ============================================================================= set(CODING_CONV_PREFIX "NRN") set(${CODING_CONV_PREFIX}_3RDPARTY_DIR "external") set(${CODING_CONV_PREFIX}_ClangFormat_REQUIRED_VERSION 12.0.1) set(${CODING_CONV_PREFIX}_ClangFormat_EXCLUDES_RE CACHE STRING "") # None needed if(EXISTS "/usr/share/bluebrain-hpc-coding-conventions/cpp/CMakeLists.txt") set(CODING_CONV_CMAKE "/usr/share/bluebrain-hpc-coding-conventions/cpp/cmake") else() set(CODING_CONV_CMAKE "${PROJECT_SOURCE_DIR}/${NRN_3RDPARTY_DIR}/coding-conventions/cpp/cmake") endif() if(NOT EXISTS "${CODING_CONV_CMAKE}/3rdparty.cmake") # Abort with a helpful message if the current source tree lacks .git information, as in that case # we're not going to be able to initialise the submodule. nrn_submodule_file_not_found("3rdparty.cmake") nrn_initialize_submodule(external/coding-conventions) endif() include("${CODING_CONV_CMAKE}/3rdparty.cmake") cpp_cc_git_submodule(Random123) # ============================================================================= # Enable sanitizer support if the NRN_SANITIZERS variable is set # ============================================================================= include(cmake/SanitizerHelper.cmake) # ============================================================================= # Find required packages # ============================================================================= find_package(BISON REQUIRED) find_package(FLEX REQUIRED) # When shipping the wheels we want to link readline libs statically. if(NRN_WHEEL_STATIC_READLINE) # CMake will prefer dynamic libraries over static ones. With the following construct we make sure # we get them. set(ORIGINAL_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") endif() find_package(Readline REQUIRED) if(READLINE_FOUND) # MAC libedit.3.dylib does not have rl_event_hook Readline_LIBRARY may be a binary lib or (on the # MAC) a tbd file that points to the library and mentions all its definitions. this part has to be # prior to adding the nrniv subdirectory. execute_process(COMMAND grep -q rl_event_hook ${Readline_LIBRARY} RESULT_VARIABLE result) if(NOT result EQUAL 0) # define for src/oc/hoc.cpp set(DEF_RL_GETC_FUNCTION use_rl_getc_function) endif() # If we are not using self contained, static readline library created for building wheel then only # look for curses and termcap if(NOT NRN_WHEEL_STATIC_READLINE) find_package(Curses QUIET) find_package(Termcap QUIET) endif() endif() # Reset original CMake library suffixes if(ORIGINAL_CMAKE_FIND_LIBRARY_SUFFIXES) set(CMAKE_FIND_LIBRARY_SUFFIXES ${ORIGINAL_CMAKE_FIND_LIBRARY_SUFFIXES}) endif() if(NRN_ENABLE_RX3D) if(NOT NRN_ENABLE_PYTHON) message(SEND_ERROR "NRN_ENABLE_RX3D requires NRN_ENABLE_PYTHON feature.") else() find_package(Cython REQUIRED) endif() endif() if(MINGW) find_package(Termcap REQUIRED) endif() # ============================================================================= # Enable MPI # ============================================================================= if(NRN_ENABLE_MPI) # find_package(MPI REQUIRED) has a CMAKE_OSX_ARCHITECTURES edge case nrn_mpi_find_package() set(NRNMPI 1) set(PARANEURON 1) # avoid linking to C++ bindings add_definitions("-DMPI_NO_CPPBIND=1") add_definitions("-DOMPI_SKIP_MPICXX=1") add_definitions("-DMPICH_SKIP_MPICXX=1") # Launching mpi executable with full path can mangle different python versions and libraries (see # issue #894). ${MPIEXEC_NAME} would reinsert the full path, but ${CMAKE_COMMAND} -E env # ${MPIEXEC_NAME} does not. get_filename_component(MPIEXEC_NAME ${MPIEXEC_EXECUTABLE} NAME) # Detect if we have an OpenMPI v2 or older. execute_process( COMMAND "${MPIEXEC_EXECUTABLE}" --version RESULT_VARIABLE OPENMPI_TEST_RESULT OUTPUT_VARIABLE OPENMPI_TEST_OUTPUT) set(NRN_HAVE_OPENMPI2_OR_LESS OFF) if(${OPENMPI_TEST_RESULT} EQUAL 0 AND "${OPENMPI_TEST_OUTPUT}" MATCHES "^mpiexec \\(OpenRTE\\) ([0-9\.]+)") set(NRN_OPENMPI_VERSION "${CMAKE_MATCH_1}") message(STATUS "Detected OpenMPI ${NRN_OPENMPI_VERSION}") if("${NRN_OPENMPI_VERSION}" VERSION_LESS 3) set(NRN_HAVE_OPENMPI2_OR_LESS ON) message(STATUS "OpenMPI/share/nrn but for linux it has been . For now we keep # this distinction. # Also, the classic location for shared libraries has been //lib # and for max/linux we have move this to /lib. But windows has classically # expected these shared libraries in /bin (reduces the PATH and expected # by ctypes in the neuron module.) So for now we keep that distinction as # well. Setting these here as setup.py.in needs it. # ~~~ set(CMAKE_INSTALL_BINDIR bin) if(MINGW) set(NRN_INSTALL_SHARE_DIR ${CMAKE_INSTALL_PREFIX}) set(NRN_BUILD_SHARE_DIR ${CMAKE_BINARY_DIR}) set(NRN_INSTALL_SHARE_LIB_DIR ${CMAKE_INSTALL_PREFIX}/lib) else() set(NRN_INSTALL_SHARE_DIR ${CMAKE_INSTALL_PREFIX}/share/nrn) set(NRN_BUILD_SHARE_DIR ${CMAKE_BINARY_DIR}/share/nrn) set(NRN_INSTALL_SHARE_LIB_DIR ${CMAKE_INSTALL_PREFIX}/lib) endif() # ============================================================================= # Add project directories AFTER CMake modules # ============================================================================= add_subdirectory(src/nrniv) add_subdirectory(bin) if(NRN_ENABLE_PYTHON) add_subdirectory(src/nrnpython) endif() if(NRN_MACOS_BUILD) add_subdirectory(src/mac) endif() if(MINGW) add_subdirectory(src/mswin) endif() # ============================================================================= # Collect the environment variables that are needed to execute NEURON from the build directory. This # is used when configuring tests, and when building documentation targets. TODO: be more careful # about trailing colons? # ============================================================================= set(NRN_RUN_FROM_BUILD_DIR_ENV "LD_LIBRARY_PATH=${PROJECT_BINARY_DIR}/lib:$ENV{LD_LIBRARY_PATH}" "NEURONHOME=${PROJECT_BINARY_DIR}/share/nrn" "NRNHOME=${PROJECT_BINARY_DIR}" "PATH=${PROJECT_BINARY_DIR}/bin:$ENV{PATH}") if(NRN_ENABLE_CORENEURON AND NOT coreneuron_FOUND) # CoreNEURON is enabled *and* is being built internally list(APPEND NRN_RUN_FROM_BUILD_DIR_ENV "CORENRNHOME=${PROJECT_BINARY_DIR}") endif() if(NRN_ENABLE_PYTHON) list(APPEND NRN_RUN_FROM_BUILD_DIR_ENV PYTHONPATH=${PROJECT_BINARY_DIR}/lib/python:${PROJECT_SOURCE_DIR}/test/rxd:$ENV{PYTHONPATH}) endif() if(NRN_ENABLE_DOCS) # Do we need to set extra environment variables to find NEURON? set(NRN_DOCS_COMMAND_PREFIX ${CMAKE_COMMAND} -E env) if(NOT NRN_ENABLE_DOCS_WITH_EXTERNAL_INSTALLATION) list(APPEND NRN_DOCS_COMMAND_PREFIX ${NRN_RUN_FROM_BUILD_DIR_ENV}) endif() # Make sure all dependencies are available find_package(Doxygen REQUIRED) find_program(FFMPEG_EXECUTABLE ffmpeg REQUIRED) find_program(JUPYTER_EXECUTABLE jupyter REQUIRED) find_program(PANDOC_EXECUTABLE pandoc REQUIRED) find_package(Sphinx REQUIRED) set(docs_requirements_file "${PROJECT_SOURCE_DIR}/docs/docs_requirements.txt") file(STRINGS "${docs_requirements_file}" docs_requirements) # Make sure CMake reruns if docs_requirements.txt changeds. set_property(GLOBAL APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${docs_requirements_file}") foreach(docs_requirement ${docs_requirements}) if(${skip_next}) set(skip_next FALSE) continue() endif() # This is needed for ipython, which is pip installable but not importable. if("${docs_requirement}" STREQUAL "# do not check import of next line") set(skip_next TRUE) elseif("${docs_requirement}" MATCHES "^([a-zA-Z_][a-zA-Z0-9]*)") nrn_find_python_module(${CMAKE_MATCH_0} REQUIRED) endif() endforeach() # ============================================================================= # Setup Doxygen documentation # ============================================================================= # generate Doxyfile with correct source paths configure_file(${PROJECT_SOURCE_DIR}/docs/Doxyfile.in ${PROJECT_BINARY_DIR}/Doxyfile) add_custom_target( doxygen COMMAND ${NRN_DOCS_COMMAND_PREFIX} ${DOXYGEN_EXECUTABLE} ${PROJECT_BINARY_DIR}/Doxyfile WORKING_DIRECTORY ${PROJECT_BINARY_DIR} COMMENT "Generating API documentation with Doxygen" VERBATIM) # ============================================================================= # Setup Sphinx documentation # ============================================================================= # Target to execute && convert notebooks to html. Note that neuron must be available for python # import, so we use NRN_RUN_FROM_BUILD_DIR_ENV. See docs/README.md. add_custom_target( notebooks COMMAND ${NRN_DOCS_COMMAND_PREFIX} NEURON_MODULE_OPTIONS="-nogui" bash ${PROJECT_SOURCE_DIR}/docs/notebooks.sh WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/docs) if(NRN_ENABLE_DOCS_WITH_EXTERNAL_INSTALLATION) message(STATUS "**Not** making the notebooks target depend on the rest of the NEURON build.") message(STATUS "Documentation building will probably fail if you haven't installed NEURON.") else() # We need NEURON to execute the notebooks. If we're building documentation as part of a normal # build, this means we need to schedule the documenation targets sufficiently late in the build. add_dependencies(notebooks hoc_module rxdmath) endif() add_custom_target( sphinx COMMAND ${NRN_DOCS_COMMAND_PREFIX} ${SPHINX_EXECUTABLE} -b html "${PROJECT_SOURCE_DIR}/docs" "${PROJECT_SOURCE_DIR}/docs/_build" WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/docs COMMENT "Generating documentation with Sphinx") # Executing notebooks will add outputs in-place. We don't want those committed to the repo. This # commands cleans them out. add_custom_target( notebooks-clean COMMAND ${NRN_DOCS_COMMAND_PREFIX} bash ${PROJECT_SOURCE_DIR}/docs/notebooks.sh --clean WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/docs) # ============================================================================= # Build full docs # ============================================================================= add_custom_target( docs COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR} --target doxygen COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR} --target notebooks COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR} --target sphinx COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR} --target notebooks-clean COMMAND echo "The HTML docs are at file://${PROJECT_SOURCE_DIR}/docs/_build/index.html" COMMENT "Generating full documentation") endif() # ============================================================================= # Add coding-conventions submodule if code formatting enabled # ============================================================================= if(NRN_CMAKE_FORMAT OR NRN_CLANG_FORMAT) add_subdirectory(external/coding-conventions/cpp) endif() # ============================================================================= # ~~~ # Update hh.mod for CoreNEURON compatibility # - Replace GLOBAL variable by RANHE # - Comment out TABLE # ~~~ # ============================================================================= if(NRN_ENABLE_CORENEURON OR NRN_ENABLE_MOD_COMPATIBILITY) set(GLOBAL_VAR_TOGGLE_COMMAND "'s/ GLOBAL minf/ RANGE minf/'") set(TABLE_VAR_TOGGLE_COMMAND "'s/ TABLE minf/ :TABLE minf/'") else() set(GLOBAL_VAR_TOGGLE_COMMAND "'s/ RANGE minf/ GLOBAL minf/'") set(TABLE_VAR_TOGGLE_COMMAND "'s/ :TABLE minf/ TABLE minf/'") endif() separate_arguments(GLOBAL_VAR_TOGGLE_COMMAND UNIX_COMMAND "${GLOBAL_VAR_TOGGLE_COMMAND}") separate_arguments(TABLE_VAR_TOGGLE_COMMAND UNIX_COMMAND "${TABLE_VAR_TOGGLE_COMMAND}") add_custom_target( hh_update COMMAND sed ${GLOBAL_VAR_TOGGLE_COMMAND} ${CMAKE_SOURCE_DIR}/src/nrnoc/hh.mod > ${CMAKE_BINARY_DIR}/hh.mod.1 COMMAND sed ${TABLE_VAR_TOGGLE_COMMAND} ${CMAKE_BINARY_DIR}/hh.mod.1 > ${CMAKE_BINARY_DIR}/hh.mod.2 COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_BINARY_DIR}/hh.mod.2 ${CMAKE_SOURCE_DIR}/src/nrnoc/hh.mod COMMAND ${CMAKE_COMMAND} -E remove ${CMAKE_BINARY_DIR}/hh.mod.1 ${CMAKE_BINARY_DIR}/hh.mod.2 COMMENT "Update hh.mod for CoreNEURON compatibility" VERBATIM) add_dependencies(nrniv_lib hh_update) # ============================================================================= # Generate help_data.dat # ============================================================================= if(NRN_ENABLE_PYTHON) add_custom_target( help_data_dat COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/docs/parse_rst.py ${PROJECT_SOURCE_DIR}/docs/python ${PROJECT_SOURCE_DIR}/share/lib/python/neuron/help_data.dat COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_SOURCE_DIR}/share/lib/python/neuron/help_data.dat ${PROJECT_BINARY_DIR}/lib/python/neuron/help_data.dat COMMENT "Generating help_data.dat" VERBATIM) add_dependencies(nrniv_lib help_data_dat) endif() # ============================================================================= # Add tests if enabled # ============================================================================= if(NRN_ENABLE_TESTS) # If CoreNEURON + NMODL are enabled, Catch2 will already have been set up... if(NOT TARGET Catch2::Catch2) nrn_add_external_project(catch2) set(CATCH_DIR ${PROJECT_SOURCE_DIR}/external/catch2) list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/external/catch2/contrib) include(Catch) endif() include(CTest) nrn_find_python_module(pytest) nrn_find_python_module(pytest_cov) if(NRN_ENABLE_PYTHON) if(NOT PYTEST_FOUND) message(SEND_ERROR "pytest Python package is required.") elseif(NOT PYTEST_COV_FOUND) message(WARNING "pytest-cov package not installed. Python coverage will not be generated.") endif() else() # share/demo still required for testing add_custom_target( copy_demo_to_build COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/share/demo ${NRN_BUILD_SHARE_DIR}/demo COMMENT "Copying ${PROJECT_SOURCE_DIR}/share/demo to ${NRN_BUILD_SHARE_DIR}" VERBATIM) add_dependencies(nrniv_lib copy_demo_to_build) endif() # Initialize the submodule *before* including the test/CMakeLists.txt that uses it. This ensures # that the test infrastructure can find the names of the input data files and set up rules to copy # them into the test working directories. set(backup "${${CODING_CONV_PREFIX}_3RDPARTY_DIR}") set(${CODING_CONV_PREFIX}_3RDPARTY_DIR "test") cpp_cc_git_submodule(rxd/testdata) set(${CODING_CONV_PREFIX}_3RDPARTY_DIR "${backup}") add_subdirectory(test) endif() # ============================================================================= # Install targets # ============================================================================= install( DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/share/lib DESTINATION ${NRN_INSTALL_SHARE_DIR} PATTERN "python" EXCLUDE) install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/share/demo DESTINATION ${NRN_INSTALL_SHARE_DIR}) install(FILES ${PROJECT_BINARY_DIR}/share/nrn/lib/nrnunits.lib ${PROJECT_BINARY_DIR}/share/nrn/lib/nrn.defaults DESTINATION ${NRN_INSTALL_SHARE_DIR}/lib) install(PROGRAMS ${CMAKE_CURRENT_SOURCE_DIR}/share/lib/cleanup DESTINATION ${NRN_INSTALL_SHARE_DIR}/lib) # find headers to install nrn_find_project_files(NRN_HEADERS_PATHS ${HEADER_FILES_TO_INSTALL}) file(COPY ${NRN_HEADERS_PATHS} ${PROJECT_BINARY_DIR}/src/nrnoc/nrnsemanticversion.h ${PROJECT_BINARY_DIR}/src/oc/nrnpthread.h DESTINATION ${PROJECT_BINARY_DIR}/include) install(DIRECTORY ${PROJECT_BINARY_DIR}/include DESTINATION ${CMAKE_INSTALL_PREFIX}) if(NRN_MACOS_BUILD) # universal build for neurondemo needs to be after, or at end of, install nrn_macos_after_install() endif() # ============================================================================= # Copy bash executable for windows # ============================================================================= if(MINGW) # ~~~ # nrniv.cpp calls nrnpyenv.sh with absolute path to bash.exe # this is sufficient on the build machine since a full # development environment exists. On the users install machine # using a setup.exe distribution, the setup.ex will contain a # minimal development environment with sufficient mingw programs # to allow nrnpyenv.sh to work. (see nrn/mingw_files/nrnmingwenv.sh) # ~~~ find_file(BASH_EXE bash.exe DOC "DOS path to bash.exe") message(STATUS "Found bash.exe at ${BASH_EXE}") if("${BASH_EXE}" STREQUAL "BASH_EXE-NOTFOUND") set(BASH_EXE "f:/msys64/usr/bin/bash.exe") message(WARNING "Can not find bash.exe, trying to use ${BASH_EXE}") endif() install(PROGRAMS ${BASH_EXE} DESTINATION ${CMAKE_INSTALL_PREFIX}/mingw/usr/bin) endif() # ============================================================================= # Installation steps for backward compatibility # ============================================================================= if(NOT NRN_WINDOWS_BUILD) # create arch folder under prefix with symlink to bin and lib nrn_install_dir_symlink(${CMAKE_INSTALL_BINDIR} ${CMAKE_INSTALL_PREFIX}/${CMAKE_HOST_SYSTEM_PROCESSOR}/bin) nrn_install_dir_symlink(${CMAKE_INSTALL_PREFIX}/lib ${CMAKE_INSTALL_PREFIX}/${CMAKE_HOST_SYSTEM_PROCESSOR}/lib) endif() # ============================================================================= # Print build status # ============================================================================= # just for printing the compiler flags in the build status string(TOUPPER ${CMAKE_BUILD_TYPE} BUILD_TYPE_UPPER) if(BUILD_TYPE_UPPER MATCHES "CUSTOM") set(COMPILER_FLAGS "${CMAKE_CXX_FLAGS}") else() set(COMPILER_FLAGS "${CMAKE_CXX_FLAGS_${BUILD_TYPE_UPPER}}") endif() string(JOIN " " COMPILER_FLAGS "${COMPILER_FLAGS}" ${NRN_COMPILE_FLAGS}) message(STATUS "") message(STATUS "Configured NEURON ${PROJECT_VERSION}") message(STATUS "") message(STATUS "You can now build NEURON using:") message(STATUS " cmake --build . --parallel 8 [--target TARGET]") message(STATUS "You might want to adjust the number of parallel build jobs for your system.") message(STATUS "Some non-default targets you might want to build:") message(STATUS "--------------+--------------------------------------------------------------") message(STATUS " Target | Description") message(STATUS "--------------+--------------------------------------------------------------") message(STATUS "install | Will install NEURON to: ${CMAKE_INSTALL_PREFIX}") message(STATUS " | Change the install location of NEURON using:") message(STATUS " | cmake -DCMAKE_INSTALL_PREFIX=") message( STATUS "docs | Build full docs. Calls targets: doxygen, notebooks, sphinx, notebooks-clean") message(STATUS "uninstall | Removes files installed by make install (todo)") message(STATUS "--------------+--------------------------------------------------------------") message(STATUS " Build option | Status") message(STATUS "--------------+--------------------------------------------------------------") message(STATUS "C COMPILER | ${CMAKE_C_COMPILER}") message(STATUS "CXX COMPILER | ${CMAKE_CXX_COMPILER}") message(STATUS "BUILD_TYPE | ${CMAKE_BUILD_TYPE} (allowed: ${allowableBuildTypes})") message(STATUS "COMPILE FLAGS | ${COMPILER_FLAGS}") message(STATUS "Shared | ${NRN_ENABLE_SHARED}") if(NRN_DYNAMIC_UNITS_USE_LEGACY) message(STATUS "Default units | legacy units") else() message(STATUS "Default units | modern units (2019 nist constants)") endif() message(STATUS "MPI | ${NRN_ENABLE_MPI}") if(NRN_ENABLE_MPI) message(STATUS " DYNAMIC | ${NRN_ENABLE_MPI_DYNAMIC}") if(NRN_ENABLE_MPI_DYNAMIC) list(LENGTH NRN_MPI_LIBNAME_LIST _num_mpi) math(EXPR num_mpi "${_num_mpi} - 1") foreach(val RANGE ${num_mpi}) list(GET NRN_MPI_LIBNAME_LIST ${val} libname) list(GET NRN_MPI_INCLUDE_LIST ${val} include) message(STATUS " LIBNAME | ${libname}") message(STATUS " INC | ${include}") endforeach(val) else() if(NRN_INCLUDE_MPI_HEADERS) message(STATUS " INC | ${MPI_INCLUDE_PATH}") else() message(STATUS " INC | N/A") endif() message(STATUS " LIB | ${MPI_LIBRARY}") endif() endif() if(NRN_ENABLE_MUSIC) message(STATUS "MUSIC | ${MUSIC_LIBDIR}") endif() message(STATUS "Python | ${NRN_ENABLE_PYTHON}") if(NRN_ENABLE_PYTHON) message(STATUS " EXE | ${NRN_DEFAULT_PYTHON_EXECUTABLE}") message(STATUS " INC | ${NRN_DEFAULT_PYTHON_INCLUDE_DIRS}") message(STATUS " LIB | ${NRN_DEFAULT_PYTHON_LIBRARIES}") message(STATUS " MODULE | ${NRN_ENABLE_MODULE_INSTALL}") message(STATUS " DYNAMIC | ${NRN_ENABLE_PYTHON_DYNAMIC}") if(NRN_ENABLE_PYTHON_DYNAMIC) list(LENGTH NRN_PYTHON_EXE_LIST _num_pythons) math(EXPR num_pythons "${_num_pythons} - 1") foreach(val RANGE ${num_pythons}) list(GET NRN_PYTHON_EXE_LIST ${val} exe) list(GET NRN_PYTHON_VER_LIST ${val} version) if(${version} LESS 3) message(SEND_ERROR "Python 3 required. Please upgrade.") endif() list(GET NRN_PYTHON_INCLUDE_LIST ${val} include) list(GET NRN_PYTHON_LIB_LIST ${val} lib) message(STATUS " EXE | ${exe}") message(STATUS " INC | ${include}") message(STATUS " LIB | ${lib}") endforeach(val) endif() endif() if(READLINE_FOUND) message(STATUS "Readline | ${Readline_LIBRARY}") endif() if(CURSES_FOUND) message(STATUS "Curses | ${CURSES_LIBRARIES}") elseif(TERMCAP_FOUND) message(STATUS "Termcap | ${TERMCAP_LIBRARIES}") endif() message(STATUS "RX3D | ${NRN_ENABLE_RX3D}") if(${NRN_ENABLE_RX3D}) message(STATUS " OptLevel | ${NRN_RX3D_OPT_LEVEL}") endif() message(STATUS "Interviews | ${NRN_ENABLE_INTERVIEWS}") if(NRN_ENABLE_INTERVIEWS) message(STATUS " PATH | ${IV_DIR}") message(STATUS " INC | ${IV_INCLUDE_DIR}") message(STATUS " X11 (INC) | ${X11_INCLUDE_DIR}") message(STATUS " (LIBDIR)| ${X11_LIBRARY_DIR}") if(IV_ENABLE_X11_DYNAMIC) message(STATUS " | IV_ENABLE_X11_DYNAMIC ${IV_ENABLE_X11_DYNAMIC}") message(STATUS " | IV_ENABLE_SHARED ${IV_ENABLE_SHARED}") endif() endif() message(STATUS "CoreNEURON | ${NRN_ENABLE_CORENEURON}") if(NRN_ENABLE_CORENEURON) message(STATUS " PATH | ${CORENEURON_DIR}") message(STATUS " LINK FLAGS | ${CORENEURON_LIB_LINK_FLAGS}") if(NOT coreneuron_FOUND) message(STATUS " Legacy Units| ${CORENRN_ENABLE_LEGACY_UNITS}") endif() endif() if(NRN_UNIVERSAL2_BUILD) message(STATUS "CMAKE_OSX_ARCH| ${CMAKE_OSX_ARCHITECTURES}") endif() message(STATUS "Tests | ${NRN_ENABLE_TESTS}") if(NRN_ENABLE_COVERAGE) message(STATUS "Coverage | Enabled") if(NRN_COVERAGE_FILES) message(STATUS " Files | ${NRN_COVERAGE_FILES}") endif() endif() if(NRN_ENABLE_PROFILING) message(STATUS "Profiling | ON") if(NRN_PROFILER STREQUAL "caliper") message(STATUS " Caliper | ${caliper_DIR}") endif() endif() message(STATUS "--------------+--------------------------------------------------------------") message(STATUS " See documentation : https://www.neuron.yale.edu/neuron/") message(STATUS "--------------+--------------------------------------------------------------") message(STATUS "")