From 744864a80e4a31c8233e209c32a37e4fca9f9485 Mon Sep 17 00:00:00 2001 From: Matthias Wolf Date: Sat, 17 Feb 2024 20:10:00 +0100 Subject: [PATCH 01/23] cmake: export targets, allow to build models via CMake MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR aims to allow dependent projects to build their models via CMake rather than a combination of shell scripts and Makefiles. In the long term, this may help facilitate building natively on Windows. To try: ``` git clone -b imported-main https://github.com/BlueBrain/neurodamus-models.git cd neurodamus-models ``` Create a `CMakeLists.txt` with contents like: ```cmake cmake_minimum_required(VERSION 3.28) project(newrodamus) find_package(neuron REQUIRED) create_libnrnmech(MOD_FILES neocortex/mod/v6/CaDynamics_DC0.mod neocortex/mod/v6/Ca_HVA2.mod neocortex/mod/v6/Ca_LVAst.mod neocortex/mod/v6/DetAMPANMDA.mod neocortex/mod/v6/DetGABAAB.mod neocortex/mod/v6/GluSynapse.mod neocortex/mod/v6/Ih.mod neocortex/mod/v6/K_Pst.mod neocortex/mod/v6/K_Tst.mod neocortex/mod/v6/KdShu2007.mod neocortex/mod/v6/NaTg.mod neocortex/mod/v6/Nap_Et2.mod neocortex/mod/v6/ProbAMPANMDA_EMS.mod neocortex/mod/v6/ProbGABAAB_EMS.mod neocortex/mod/v6/SK_E2.mod neocortex/mod/v6/SKv3_1.mod neocortex/mod/v6/StochKv3.mod neocortex/mod/v6/TTXDynamicsSwitch.mod neocortex/mod/v6/VecStim.mod neocortex/mod/v6/gap.mod neocortex/mod/v6/netstim_inhpoisson.mod ) ``` Then build and install: ``` cmake -B build -S . -GNinja -DCMAKE_INSTALL_PREFIX=x86_64 cmake --build build cmake --install build ``` To be continued  --- CMakeLists.txt | 22 ++++++ cmake/mod_reg_corenrn.cpp.in | 16 +++++ cmake/mod_reg_nrn.cpp.in | 16 +++++ cmake/neuronConfig.cmake.in | 25 +++++++ cmake/neuronMechMaker.cmake | 131 ++++++++++++++++++++++++++++++++++ src/coreneuron/CMakeLists.txt | 15 ++++ src/ivoc/nrnmain.cpp | 2 +- src/nrniv/CMakeLists.txt | 47 ++++++------ src/nrnoc/hh.mod | 4 +- src/nrnpython/CMakeLists.txt | 4 ++ 10 files changed, 258 insertions(+), 24 deletions(-) create mode 100644 cmake/mod_reg_corenrn.cpp.in create mode 100644 cmake/mod_reg_nrn.cpp.in create mode 100644 cmake/neuronConfig.cmake.in create mode 100644 cmake/neuronMechMaker.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 1b74dbc9a4..1b0735c166 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -495,6 +495,9 @@ endif() # initialize CLI11 submodule cpp_cc_git_submodule(CLI11 BUILD PACKAGE CLI11 REQUIRED) +# coreneuron targets will get propagated down from the subdirectory +set(NRN_INSTALL_TARGETS nrniv_lib nocmodl) + # ============================================================================= # Enable CoreNEURON support # ============================================================================= @@ -904,6 +907,25 @@ if(NRN_MACOS_BUILD) nrn_macos_after_install() endif() +# ============================================================================= +# Install CMake glue +# ============================================================================= +install(TARGETS ${NRN_INSTALL_TARGETS} ${CORENRN_INSTALL_TARGETS} EXPORT NeuronTargets) +install( + EXPORT NeuronTargets + FILE neuronTargets.cmake + NAMESPACE neuron:: + DESTINATION lib/cmake/neuron) + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/neuronConfig.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/neuronConfig.cmake @ONLY) + +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/neuronConfig.cmake DESTINATION lib/cmake/neuron) +install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/cmake/neuronMechMaker.cmake DESTINATION lib/cmake/neuron) + +install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/cmake/mod_reg_nrn.cpp.in + ${CMAKE_CURRENT_SOURCE_DIR}/cmake/mod_reg_corenrn.cpp.in DESTINATION share/nrn) + # ============================================================================= # Copy bash executable for windows # ============================================================================= diff --git a/cmake/mod_reg_corenrn.cpp.in b/cmake/mod_reg_corenrn.cpp.in new file mode 100644 index 0000000000..ff71d4e6c8 --- /dev/null +++ b/cmake/mod_reg_corenrn.cpp.in @@ -0,0 +1,16 @@ +#include +namespace coreneuron { +extern int nrnmpi_myid; +extern int nrn_nobanner_; + +@MECH_DECLARE@ + +void modl_reg() { + if (!nrn_nobanner_) if (nrnmpi_myid < 1) { + fprintf(stderr, " Additional mechanisms from files\n"); + @MECH_PRINT@ + fprintf(stderr, "\n\n"); + } + @MECH_REGISTRE@ +} +} //namespace coreneuron diff --git a/cmake/mod_reg_nrn.cpp.in b/cmake/mod_reg_nrn.cpp.in new file mode 100644 index 0000000000..ae9fda03d4 --- /dev/null +++ b/cmake/mod_reg_nrn.cpp.in @@ -0,0 +1,16 @@ +#include +#include "hocdec.h" +extern int nrnmpi_myid; +extern int nrn_nobanner_; + +@MECH_DECLARE@ + +extern "C" void modl_reg() { + if (!nrn_nobanner_) if (nrnmpi_myid < 1) { + fprintf(stderr, "Additional mechanisms from files\n"); + @MECH_PRINT@ + fprintf(stderr, "\n"); + } + @MECH_REGISTRE@ +} + diff --git a/cmake/neuronConfig.cmake.in b/cmake/neuronConfig.cmake.in new file mode 100644 index 0000000000..2375f0d608 --- /dev/null +++ b/cmake/neuronConfig.cmake.in @@ -0,0 +1,25 @@ +include(CMakeFindDependencyMacro) + +find_dependency(Threads) + +include("${CMAKE_CURRENT_LIST_DIR}/neuronTargets.cmake") + +get_filename_component(_dir "${CMAKE_CURRENT_LIST_FILE}" PATH) +get_filename_component(_prefix "${_dir}/../../.." ABSOLUTE) + +set(NRN_ENABLE_CORENEURON @NRN_ENABLE_CORENEURON@) + +set(_NEURON_MAIN "${_prefix}/share/nrn/nrnmain.cpp") +set(_NEURON_MAIN_INCLUDE_DIR "${_prefix}/include/nrncvode") +set(_NEURON_MECH_REG "${_prefix}/share/nrn/mod_reg_nrn.cpp.in") + +set(_CORENEURON_BASE_MOD "${_prefix}/share/modfile") +set(_CORENEURON_MAIN "${_prefix}/share/coreneuron/coreneuron.cpp") +set(_CORENEURON_MECH_REG "${_prefix}/share/nrn/mod_reg_corenrn.cpp.in") +set(_CORENEURON_MECH_ENG "${_prefix}/share/coreneuron/enginemech.cpp") +set(_CORENEURON_RANDOM_INCLUDE "${_prefix}/include/coreneuron/utils/randoms") +set(_CORENEURON_FLAGS @CORENRN_CXX_FLAGS@) + +find_program(NMODL nmodl REQUIRED) + +include(${CMAKE_CURRENT_LIST_DIR}/neuronMechMaker.cmake) diff --git a/cmake/neuronMechMaker.cmake b/cmake/neuronMechMaker.cmake new file mode 100644 index 0000000000..a0897eb41a --- /dev/null +++ b/cmake/neuronMechMaker.cmake @@ -0,0 +1,131 @@ +# ~~~ +# +function(create_nrnmech) + set(options CORENEURON INSTALL_CPP INSTALL_MOD SPECIAL) + set(oneValueArgs MECHANISM_NAME) + cmake_parse_arguments(NRN_MECH "${options}" "${oneValueArgs}" "MOD_FILES" ${ARGN}) + + if(NRN_MECH_CORENEURON) + if(NOT NRN_ENABLE_CORENEURON) + message(FATAL_ERROR "CoreNEURON support not enabled") + endif() + endif() + + if(NOT MECHANISM_NAME) + set(MECHANISM_NAME neuron) + endif() + + set(LIBNAME "nrnmech") + set(EXENAME "special") + + foreach(MOD_FILE IN LISTS NRN_MECH_MOD_FILES) + get_filename_component(MOD_STUB "${MOD_FILE}" NAME_WLE) + list(APPEND INPUT_STUBS "${MOD_STUB}") + list(APPEND MOD_FILES "${MOD_FILE}") + endforeach() + + foreach(MOD_FILE IN LISTS MOD_FILES) + get_filename_component(MOD_STUB "${MOD_FILE}" NAME_WLE) + set(CPP_FILE "cpp/${MOD_STUB}.cpp") + file(RELATIVE_PATH MOD_SHORT "${CMAKE_SOURCE_DIR}" "${MOD_FILE}") + + list(APPEND L_MECH_DECLARE "extern \"C\" void _${MOD_STUB}_reg(void)\;") + list(APPEND L_MECH_PRINT "fprintf(stderr, \" \\\"${MOD_SHORT}\\\"\")\;") + list(APPEND L_MECH_REGISTRE "_${MOD_STUB}_reg()\;") + + add_custom_command( + COMMAND neuron::nocmodl -o "${CMAKE_CURRENT_BINARY_DIR}/cpp" "${MOD_FILE}" + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${CPP_FILE}" + DEPENDS neuron::nocmodl) + + list(APPEND L_SOURCES "${CMAKE_CURRENT_BINARY_DIR}/${CPP_FILE}") + endforeach() + + if(NRN_MECH_CORENEURON) + # CoreNEURON requires additional mod files. Only append them to the input list if similar named + # mods are _not yet present_ + file(GLOB BASE_MOD_FILES "${_CORENEURON_BASE_MOD}/*.mod") + foreach(MOD_FILE IN LISTS BASE_MOD_FILES) + get_filename_component(MOD_STUB "${MOD_FILE}" NAME_WLE) + if("${MOD_STUB}" IN_LIST INPUT_STUBS) + + else() + list(APPEND MOD_FILES "${MOD_FILE}") + endif() + endforeach() + + foreach(MOD_FILE IN LISTS MOD_FILES) + get_filename_component(MOD_STUB "${MOD_FILE}" NAME_WLE) + set(CPP_FILE "cpp_core/${MOD_STUB}.cpp") + file(RELATIVE_PATH MOD_SHORT "${CMAKE_SOURCE_DIR}" "${MOD_FILE}") + + list(APPEND L_CORE_MECH_DECLARE "extern int void _${MOD_STUB}_reg(void)\;") + list(APPEND L_CORE_MECH_PRINT "fprintf(stderr, \" \\\"${MOD_SHORT}\\\"\")\;") + list(APPEND L_CORE_MECH_REGISTRE "_${MOD_STUB}_reg()\;") + + add_custom_command( + COMMAND "${NMODL}" -o "${CMAKE_CURRENT_BINARY_DIR}/cpp_core" "${MOD_FILE}" + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${CPP_FILE}" + DEPENDS "${NMODL}") + + list(APPEND L_CORE_SOURCES "${CMAKE_CURRENT_BINARY_DIR}/${CPP_FILE}") + endforeach() + endif() + + add_library(${LIBNAME} SHARED ${L_SOURCES}) + target_link_libraries(${LIBNAME} PUBLIC neuron::nrniv) + # set_target_properties(${LIBNAME} PROPERTIES OUTPUT_NAME + # "${LIBNAME}$<$:_${NRN_MECH_MECHANISM_NAME}>") + install(TARGETS ${LIBNAME} DESTINATION lib) + + if(NRN_MECH_CORENEURON) + add_library(core${LIBNAME} SHARED ${_CORENEURON_MECH_ENG} ${L_CORE_SOURCES}) + target_include_directories(core${LIBNAME} PRIVATE ${_CORENEURON_RANDOM_INCLUDE}) + target_compile_options(core${LIBNAME} PRIVATE ${_CORENEURON_FLAGS}) + target_link_libraries(core${LIBNAME} PUBLIC neuron::corenrn) + # set_target_properties(${LIBNAME} PROPERTIES OUTPUT_NAME + # "${LIBNAME}$<$:_${NRN_MECH_MECHANISM_NAME}>") + install(TARGETS core${LIBNAME} DESTINATION lib) + endif() + + if(NRN_MECH_INSTALL_CPP) + install(FILES ${L_SOURCES} DESTINATION "share/${NRN_MECH_MECHANISM_NAME}/cpp") + if(NRN_ENABLE_CORENEURON) + install(FILES ${L_CORE_SOURCES} DESTINATION "share/${NRN_MECH_MECHANISM_NAME}/cpp_core") + endif() + endif() + + if(NRN_MECH_INSTALL_MOD) + install(FILES ${MOD_FILES} DESTINATION "share/${NRN_MECH_MECHANISM_NAME}/mod") + endif() + + if(NRN_MECH_SPECIAL) + list(JOIN L_MECH_DECLARE "\n" MECH_DECLARE) + list(JOIN L_MECH_PRINT " \n" MECH_PRINT) + list(JOIN L_MECH_REGISTRE " \n" MECH_REGISTRE) + + get_filename_component(MECH_REG "${_NEURON_MECH_REG}" NAME_WLE) + configure_file(${_NEURON_MECH_REG} ${MECH_REG} @ONLY) + + add_executable(${EXENAME} ${_NEURON_MAIN} ${MECH_REG}) + target_include_directories(${EXENAME} PUBLIC ${_NEURON_MAIN_INCLUDE_DIR}) + target_link_libraries(${EXENAME} ${LIBNAME}) + set_target_properties(${EXENAME} PROPERTIES OUTPUT_NAME "special") + install(TARGETS ${EXENAME} DESTINATION bin) + + if(NRN_MECH_CORENEURON) + list(JOIN L_CORE_MECH_DECLARE "\n" MECH_DECLARE) + list(JOIN L_CORE_MECH_PRINT " \n" MECH_PRINT) + list(JOIN L_CORE_MECH_REGISTRE " \n" MECH_REGISTRE) + + get_filename_component(CORE_MECH_REG "${_NEURON_COREMECH_REG}" NAME_WLE) + configure_file(${_NEURON_MECH_REG} core${CORE_MECH_REG} @ONLY) + + add_executable(core${EXENAME} ${_CORENEURON_MAIN} core${CORE_MECH_REG}) + target_include_directories(core${EXENAME} PUBLIC ${_NEURON_MAIN_INCLUDE_DIR}) + target_link_libraries(core${EXENAME} core${LIBNAME}) + set_target_properties(core${EXENAME} PROPERTIES OUTPUT_NAME "special-core") + install(TARGETS core${EXENAME} DESTINATION bin) + endif() + endif() +endfunction() diff --git a/src/coreneuron/CMakeLists.txt b/src/coreneuron/CMakeLists.txt index cf4fdf4903..56bf4b6018 100644 --- a/src/coreneuron/CMakeLists.txt +++ b/src/coreneuron/CMakeLists.txt @@ -444,10 +444,19 @@ endif() # https://forums.developer.nvidia.com/t/cannot-dynamically-load-a-shared-library-containing-both-openacc-and-cuda-code/210972 add_library(coreneuron-core STATIC ${CORENEURON_CODE_FILES} ${CORENRN_MPI_OBJ}) add_dependencies(coreneuron-core coreneuron-copy-nrnivmodl-core-dependencies) +set_target_properties(coreneuron-core PROPERTIES EXPORT_NAME corenrn) +set(CORENRN_INSTALL_TARGETS + coreneuron-core + PARENT_SCOPE) if(CORENRN_ENABLE_GPU) set(coreneuron_cuda_target coreneuron-cuda) add_library(coreneuron-cuda ${COMPILE_LIBRARY_TYPE} ${CORENEURON_CUDA_FILES}) + set_target_properties(coreneuron-cuda PROPERTIES EXPORT_NAME corenrn-cuda) target_link_libraries(coreneuron-core PUBLIC coreneuron-cuda) + # list() commands don't propagate to parent scope + set(CORENRN_INSTALL_TARGETS + "coreneuron-core;coreneuron-cuda" + PARENT_SCOPE) endif() foreach(target coreneuron-core ${coreneuron_cuda_target}) @@ -526,6 +535,9 @@ endif() target_compile_options(coreneuron-core PRIVATE ${CORENEURON_CXX_WARNING_SUPPRESSIONS}) target_link_libraries(coreneuron-core PUBLIC ${sonatareport_LIBRARY} ${CORENRN_CALIPER_LIB} ${CORENRN_LIKWID_LIB}) +set_target_properties(coreneuron-core PROPERTIES EXPORT_NAME corenrn) +target_compile_features(coreneuron-core PUBLIC cxx_std_17) +target_include_directories(coreneuron-core INTERFACE $) # TODO: fix adding a dependency of coreneuron-core on CLI11::CLI11 when CLI11 is a submodule. Right # now this doesn't work because the CLI11 targets are not exported/installed but coreneuron-core is. @@ -626,6 +638,9 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/utils/profile/profiler_interface.h # CORENRN_LIB_LINK_FLAGS, which contains the arguments that must be added to the link line for # `special` to link against `libcorenrnmech_internal.{a,so}` include(MakefileBuildOptions) +set(CORENRN_CXX_FLAGS + "${CORENRN_CXX_FLAGS}" + PARENT_SCOPE) # ============================================================================= # CoreNEURON related configuration diff --git a/src/ivoc/nrnmain.cpp b/src/ivoc/nrnmain.cpp index 153e9d4559..4e734e6a85 100644 --- a/src/ivoc/nrnmain.cpp +++ b/src/ivoc/nrnmain.cpp @@ -1,6 +1,6 @@ #include "nrnconf.h" #include "nrnmpi.h" -#include "../nrncvode/nrnneosm.h" +#include "nrnneosm.h" #include #include diff --git a/src/nrniv/CMakeLists.txt b/src/nrniv/CMakeLists.txt index 07aa0a7624..b010afa138 100644 --- a/src/nrniv/CMakeLists.txt +++ b/src/nrniv/CMakeLists.txt @@ -399,44 +399,49 @@ include_directories(${NRN_INCLUDE_DIRS}) # All source directories to include # ============================================================================= add_library(nrniv_lib ${NRN_LIBRARY_TYPE} ${NRN_NRNIV_LIB_SRC_FILES}) -target_link_libraries(nrniv_lib nrngnu) -target_link_libraries(nrniv_lib sparse13) -target_link_libraries(nrniv_lib fmt::fmt) -target_include_directories(nrniv_lib SYSTEM PUBLIC ${PROJECT_SOURCE_DIR}/${NRN_3RDPARTY_DIR}/eigen) +target_link_libraries(nrniv_lib PRIVATE nrngnu) +target_link_libraries(nrniv_lib PRIVATE sparse13) +target_link_libraries(nrniv_lib PRIVATE fmt::fmt) +# We feel at liberty to include across various subdirectories without clear interfaces, thus this +# should be public at _build_ time, but not at install time. +target_include_directories( + nrniv_lib SYSTEM PUBLIC $) cpp_cc_configure_sanitizers(TARGET nrniv_lib) # Source-directory .cpp needs to find generated .hpp. -target_include_directories(nrniv_lib PUBLIC "${NRN_OC_GEN}") +target_include_directories(nrniv_lib PUBLIC $) +target_include_directories(nrniv_lib INTERFACE $) if(NRN_ENABLE_PYTHON AND NOT NRN_ENABLE_PYTHON_DYNAMIC) - target_link_libraries(nrniv_lib nrnpython) + target_link_libraries(nrniv_lib PRIVATE nrnpython) endif() if(NRN_ENABLE_THREADS) - target_link_libraries(nrniv_lib Threads::Threads) + target_link_libraries(nrniv_lib PUBLIC Threads::Threads) endif() if(NRN_WINDOWS_BUILD) - target_link_libraries(nrniv_lib ${TERMCAP_LIBRARIES} ${Readline_LIBRARY}) + target_link_libraries(nrniv_lib PUBLIC ${TERMCAP_LIBRARIES} ${Readline_LIBRARY}) else() if(READLINE_FOUND) - target_link_libraries(nrniv_lib ${Readline_LIBRARY}) + target_link_libraries(nrniv_lib PUBLIC ${Readline_LIBRARY}) else() - target_link_libraries(nrniv_lib readline) + target_link_libraries(nrniv_lib PUBLIC readline) endif() if(CURSES_FOUND) - target_link_libraries(nrniv_lib ${CURSES_LIBRARIES}) + target_link_libraries(nrniv_lib PUBLIC ${CURSES_LIBRARIES}) elseif(TERMCAP_FOUND) - target_link_libraries(nrniv_lib ${TERMCAP_LIBRARIES}) + target_link_libraries(nrniv_lib PUBLIC ${TERMCAP_LIBRARIES}) endif() endif() if(NRN_ENABLE_MUSIC AND NOT NRN_ENABLE_MPI_DYNAMIC) - target_link_libraries(nrniv_lib ${MUSIC_LIBRARY}) + target_link_libraries(nrniv_lib PUBLIC ${MUSIC_LIBRARY}) endif() if(NRN_ENABLE_PROFILING) - target_link_libraries(nrniv_lib ${likwid_LIBRARIES} ${CALIPER_LIB} ${LIKWID_LIB}) + target_link_libraries(nrniv_lib PUBLIC ${likwid_LIBRARIES} ${CALIPER_LIB} ${LIKWID_LIB}) endif() -set_property(TARGET nrniv_lib PROPERTY OUTPUT_NAME nrniv) +set_target_properties(nrniv_lib PROPERTIES EXPORT_NAME nrniv OUTPUT_NAME nrniv) +target_compile_features(nrniv_lib PUBLIC cxx_std_17) # ============================================================================= # Link with backward-cpp if enabled @@ -482,16 +487,16 @@ if(NRN_ENABLE_MPI) install(TARGETS ${libnrnmusic}_lib DESTINATION ${NRN_INSTALL_SHARE_LIB_DIR}) endif() else() - target_link_libraries(nrniv_lib ${MPI_C_LIBRARIES}) + target_link_libraries(nrniv_lib PUBLIC ${MPI_C_LIBRARIES}) target_include_directories(nrniv_lib PUBLIC ${MPI_INCLUDE_PATH}) endif() endif() if(NRN_ENABLE_INTERVIEWS) include_directories(${IV_INCLUDE_DIR}) - target_link_libraries(nrniv_lib interviews) + target_link_libraries(nrniv_lib PRIVATE interviews) else() - target_include_directories(nrniv_lib PUBLIC ${NRN_IVOS_SRC_DIR}) + target_include_directories(nrniv_lib PUBLIC $) endif() if(IV_ENABLE_X11_DYNAMIC) @@ -522,11 +527,11 @@ if(IV_ENABLE_X11_DYNAMIC) ${PROJECT_BINARY_DIR}/lib/${LIBIVX11DYNAM_NAME}) endif() else() - target_link_libraries(nrniv_lib ${X11_LIBRARIES}) + target_link_libraries(nrniv_lib PRIVATE ${X11_LIBRARIES}) endif() if(NRN_COVERAGE_FILES) - target_link_libraries(nrniv_lib ${NRN_COVERAGE_LIB}) + target_link_libraries(nrniv_lib PRIVATE ${NRN_COVERAGE_LIB}) target_link_libraries(modlunit ${NRN_COVERAGE_LIB}) target_link_libraries(nocmodl ${NRN_COVERAGE_LIB}) endif() @@ -544,7 +549,7 @@ if(NRN_ENABLE_THREADS) target_link_libraries(nrniv Threads::Threads) endif() if(NOT MINGW) - target_link_libraries(nrniv_lib ${CMAKE_DL_LIBS}) + target_link_libraries(nrniv_lib PUBLIC ${CMAKE_DL_LIBS}) endif() # TODO: unset in top level CMake is not working diff --git a/src/nrnoc/hh.mod b/src/nrnoc/hh.mod index 0c7305ee1b..12c22f0aab 100644 --- a/src/nrnoc/hh.mod +++ b/src/nrnoc/hh.mod @@ -30,7 +30,7 @@ NEURON { NONSPECIFIC_CURRENT il RANGE gnabar, gkbar, gl, el, gna, gk : `GLOBAL minf` will be replaced with `RANGE minf` if CoreNEURON enabled - GLOBAL minf, hinf, ninf, mtau, htau, ntau + RANGE minf, hinf, ninf, mtau, htau, ntau THREADSAFE : assigned GLOBALs will be per thread } @@ -94,7 +94,7 @@ PROCEDURE rates(v(mV)) { :Computes rate and other constants at current v. :Call once from HOC to initialize inf at resting v. LOCAL alpha, beta, sum, q10 : `TABLE minf` will be replaced with `:TABLE minf` if CoreNEURON enabled) - TABLE minf, mtau, hinf, htau, ninf, ntau DEPEND celsius FROM -100 TO 100 WITH 200 + :TABLE minf, mtau, hinf, htau, ninf, ntau DEPEND celsius FROM -100 TO 100 WITH 200 UNITSOFF q10 = 3^((celsius - 6.3)/10) diff --git a/src/nrnpython/CMakeLists.txt b/src/nrnpython/CMakeLists.txt index c1e16afbff..5bd8e8a278 100644 --- a/src/nrnpython/CMakeLists.txt +++ b/src/nrnpython/CMakeLists.txt @@ -45,6 +45,10 @@ endif() # user has selected dynamic python support (could be multiple versions) if(NRN_ENABLE_PYTHON_DYNAMIC) + # set(INCLUDE_DIRS . .. ../oc ../nrnoc ../ivoc ../nrniv ../gnu ../nrnmpi + # ${PROJECT_BINARY_DIR}/src/nrnpython ${PROJECT_BINARY_DIR}/src/ivos ${PROJECT_BINARY_DIR}/src/oc + # ${NRN_OC_GENERATED_SOURCES}) if(NRN_ENABLE_INTERVIEWS) list(APPEND INCLUDE_DIRS + # ${IV_INCLUDE_DIR}) else() list(APPEND INCLUDE_DIRS ../ivos) endif() foreach(val RANGE ${NRN_PYTHON_ITERATION_LIMIT}) list(GET NRN_PYTHON_VERSIONS ${val} pyver) list(GET NRN_PYTHON_INCLUDES ${val} pyinc) From 2df21034aa195459d5d59a49345e15da2c4f2ed0 Mon Sep 17 00:00:00 2001 From: Matthias Wolf Date: Thu, 15 Aug 2024 11:04:45 +0200 Subject: [PATCH 02/23] Bump stuff. --- cmake/coreneuron/packages/Findnmodl.cmake | 42 ----------------------- external/nmodl | 2 +- src/coreneuron/CMakeLists.txt | 14 ++++---- 3 files changed, 8 insertions(+), 50 deletions(-) delete mode 100644 cmake/coreneuron/packages/Findnmodl.cmake diff --git a/cmake/coreneuron/packages/Findnmodl.cmake b/cmake/coreneuron/packages/Findnmodl.cmake deleted file mode 100644 index aa483c889e..0000000000 --- a/cmake/coreneuron/packages/Findnmodl.cmake +++ /dev/null @@ -1,42 +0,0 @@ -# ============================================================================= -# Copyright (C) 2016-2021 Blue Brain Project -# -# See top-level LICENSE file for details. -# ============================================================================= - -# ~~~ -# Findnmodl -# ------------- -# -# Find nmodl -# -# Find the nmodl Blue Brain HPC utils library -# -# Using nmodl: -# -# :: -# set(CORENRN_NMODL_DIR "" CACHE PATH "Path to nmodl source-to-source compiler installation") -# find_package(nmodl REQUIRED) -# target_link_libraries(foo ${nmodl_LIBRARIES}) -# -# This module sets the following variables: -# -# :: -# -# nmodl_FOUND - set to true if the library is found -# nmodl_BINARY - the nmodl binary -# ~~~ - -# UNIX paths are standard, no need to write. -find_program( - nmodl_BINARY - NAMES nmodl${CMAKE_EXECUTABLE_SUFFIX} - HINTS "${CORENRN_NMODL_DIR}/bin" QUIET) - -# Checks 'REQUIRED', 'QUIET' and versions. -include(FindPackageHandleStandardArgs) - -find_package_handle_standard_args( - nmodl - FOUND_VAR nmodl_FOUND - REQUIRED_VARS nmodl_BINARY) diff --git a/external/nmodl b/external/nmodl index 7910146791..08735d544b 160000 --- a/external/nmodl +++ b/external/nmodl @@ -1 +1 @@ -Subproject commit 79101467912f9690b6c40a1d3eed7315e3ea9bc4 +Subproject commit 08735d544b68aee54016e88231e2706dc71762b0 diff --git a/src/coreneuron/CMakeLists.txt b/src/coreneuron/CMakeLists.txt index 56bf4b6018..cf7d6ad748 100644 --- a/src/coreneuron/CMakeLists.txt +++ b/src/coreneuron/CMakeLists.txt @@ -255,13 +255,13 @@ endif() if(nmodl_FOUND) set(CORENRN_NMODL_BINARY ${nmodl_BINARY}) else() + message(FATAL_ERROR "BLARGH") set(NMODL_ENABLE_PYTHON_BINDINGS OFF CACHE BOOL "Enable NMODL python bindings") nrn_add_external_project(nmodl DISABLE_ADD) add_subdirectory(${PROJECT_SOURCE_DIR}/external/nmodl ${CMAKE_BINARY_DIR}/external/nmodl) set(CORENRN_NMODL_BINARY ${CMAKE_BINARY_DIR}/bin/nmodl${CMAKE_EXECUTABLE_SUFFIX}) - set(NMODL_TARGET_TO_DEPEND nmodl) set(NMODL_PROJECT_BINARY_DIR ${CMAKE_BINARY_DIR}/external/nmodl) # install nrnunits.lib and libpywrapper.so from external/nmodl install( @@ -576,7 +576,7 @@ set(output_binaries "${nrniv_core_prefix}/special-core" "${corenrn_mech_library} add_custom_command( OUTPUT ${output_binaries} - DEPENDS coreneuron-core ${NMODL_TARGET_TO_DEPEND} ${CORENEURON_BUILTIN_MODFILES} + DEPENDS coreneuron-core nmodl::nmodl ${CORENEURON_BUILTIN_MODFILES} COMMAND ${CMAKE_COMMAND} -E env NMODLHOME=${NMODL_PROJECT_BINARY_DIR} ${CMAKE_BINARY_DIR}/bin/nrnivmodl-core -b ${COMPILE_LIBRARY_TYPE} -m ${CORENRN_NMODL_BINARY} -n @@ -600,7 +600,7 @@ endif() # tests will depend on this, so it must in turn depend on everything that is needed to run nrnivmodl # -coreneuron. add_custom_target(coreneuron-for-tests) -add_dependencies(coreneuron-for-tests coreneuron-core ${NMODL_TARGET_TO_DEPEND}) +add_dependencies(coreneuron-for-tests coreneuron-core nmodl::nmodl) # Create an extra target for internal use that unit tests and so on can depend on. # ${corenrn_mech_library} is libcorenrnmech_internal.{a,so}, which contains both the compiled # default mechanisms and the content of libcoreneuron-core.a. @@ -653,13 +653,13 @@ configure_file(${PROJECT_SOURCE_DIR}/bin/nrnivmodl_core_makefile.in ${CMAKE_BINARY_DIR}/share/coreneuron/nrnivmodl_core_makefile @ONLY) configure_file(${PROJECT_SOURCE_DIR}/bin/nrnivmodl-core.in ${CMAKE_BINARY_DIR}/bin/nrnivmodl-core @ONLY) -# nrnivmodl-core depends on the building of NMODL_TARGET_TO_DEPEND and the configuration of the -# nrnivmodl-core and nrnivmodl_core_makefile this doesn't imply that whenever there is a change in -# one of those files then the prebuilt mod files are going to be rebuilt +# nrnivmodl-core depends on the building of nmodl::nmodl and the configuration of the +# nrnivmodl-core and nrnivmodl_core_makefile this doesn't imply that whenever there is a +# change in one of those files then the prebuilt mod files are going to be rebuilt add_custom_target( nrnivmodl-core ALL DEPENDS ${CMAKE_BINARY_DIR}/bin/nrnivmodl-core - ${CMAKE_BINARY_DIR}/share/coreneuron/nrnivmodl_core_makefile ${NMODL_TARGET_TO_DEPEND}) + ${CMAKE_BINARY_DIR}/share/coreneuron/nrnivmodl_core_makefile nmodl::nmodl) if(CORENRN_ENABLE_UNIT_TESTS) add_subdirectory(${PROJECT_SOURCE_DIR}/test/coreneuron/unit From 87cc65bf89123ee62008beea797c8b2b143c8ca3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 15 Aug 2024 09:07:53 +0000 Subject: [PATCH 03/23] Fix formatting --- src/coreneuron/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/coreneuron/CMakeLists.txt b/src/coreneuron/CMakeLists.txt index cf7d6ad748..c32a8dda7b 100644 --- a/src/coreneuron/CMakeLists.txt +++ b/src/coreneuron/CMakeLists.txt @@ -653,9 +653,9 @@ configure_file(${PROJECT_SOURCE_DIR}/bin/nrnivmodl_core_makefile.in ${CMAKE_BINARY_DIR}/share/coreneuron/nrnivmodl_core_makefile @ONLY) configure_file(${PROJECT_SOURCE_DIR}/bin/nrnivmodl-core.in ${CMAKE_BINARY_DIR}/bin/nrnivmodl-core @ONLY) -# nrnivmodl-core depends on the building of nmodl::nmodl and the configuration of the -# nrnivmodl-core and nrnivmodl_core_makefile this doesn't imply that whenever there is a -# change in one of those files then the prebuilt mod files are going to be rebuilt +# nrnivmodl-core depends on the building of nmodl::nmodl and the configuration of the nrnivmodl-core +# and nrnivmodl_core_makefile this doesn't imply that whenever there is a change in one of those +# files then the prebuilt mod files are going to be rebuilt add_custom_target( nrnivmodl-core ALL DEPENDS ${CMAKE_BINARY_DIR}/bin/nrnivmodl-core From 489c39021fcf71852fbaf70a2bdc1d14e289f7b1 Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Thu, 16 Jan 2025 14:46:58 +0100 Subject: [PATCH 04/23] Add fmt to linked libs for testing --- test/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6555a87b23..2e5572c1a0 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -34,7 +34,7 @@ if(NRN_ENABLE_THREADS) endif() foreach(target ${catch2_targets}) cpp_cc_configure_sanitizers(TARGET ${target}) - target_link_libraries(${target} Catch2::Catch2 nrniv_lib) + target_link_libraries(${target} Catch2::Catch2 fmt::fmt nrniv_lib) if(NOT MINGW) target_link_libraries(${target} ${CMAKE_DL_LIBS}) endif() From 65fc1ee57b57e220749f7e219ca2e6d9beb7e656 Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Thu, 16 Jan 2025 15:13:16 +0100 Subject: [PATCH 05/23] Also link fmt in Python build --- src/nrnpython/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nrnpython/CMakeLists.txt b/src/nrnpython/CMakeLists.txt index 613ed3b038..4f508301da 100644 --- a/src/nrnpython/CMakeLists.txt +++ b/src/nrnpython/CMakeLists.txt @@ -60,7 +60,7 @@ if(NRN_ENABLE_PYTHON_DYNAMIC) add_library(nrnpython${pyver} SHARED ${NRNPYTHON_FILES_LIST}) target_include_directories(nrnpython${pyver} BEFORE PUBLIC ${pyinc} ${INCLUDE_DIRS}) target_link_libraries(nrnpython${pyver} PUBLIC nrniv_lib) - target_link_libraries(nrnpython${pyver} PRIVATE ${Readline_LIBRARY} ${nanobind_target}) + target_link_libraries(nrnpython${pyver} PRIVATE fmt::fmt ${Readline_LIBRARY} ${nanobind_target}) if(NRN_LINK_AGAINST_PYTHON) target_link_libraries(nrnpython${pyver} PUBLIC ${pylib}) endif() From 047732db2fa12657a09f8f29db0854045027638f Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Thu, 16 Jan 2025 16:00:15 +0100 Subject: [PATCH 06/23] Put back the original `hh.mod` --- src/nrnoc/hh.mod | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nrnoc/hh.mod b/src/nrnoc/hh.mod index 12c22f0aab..0c7305ee1b 100644 --- a/src/nrnoc/hh.mod +++ b/src/nrnoc/hh.mod @@ -30,7 +30,7 @@ NEURON { NONSPECIFIC_CURRENT il RANGE gnabar, gkbar, gl, el, gna, gk : `GLOBAL minf` will be replaced with `RANGE minf` if CoreNEURON enabled - RANGE minf, hinf, ninf, mtau, htau, ntau + GLOBAL minf, hinf, ninf, mtau, htau, ntau THREADSAFE : assigned GLOBALs will be per thread } @@ -94,7 +94,7 @@ PROCEDURE rates(v(mV)) { :Computes rate and other constants at current v. :Call once from HOC to initialize inf at resting v. LOCAL alpha, beta, sum, q10 : `TABLE minf` will be replaced with `:TABLE minf` if CoreNEURON enabled) - :TABLE minf, mtau, hinf, htau, ninf, ntau DEPEND celsius FROM -100 TO 100 WITH 200 + TABLE minf, mtau, hinf, htau, ninf, ntau DEPEND celsius FROM -100 TO 100 WITH 200 UNITSOFF q10 = 3^((celsius - 6.3)/10) From 86895cbeb9a35284cabc7f70bc214d37a6b13381 Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Mon, 20 Jan 2025 20:48:33 +0100 Subject: [PATCH 07/23] Fix issue with corenrn target --- src/coreneuron/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/coreneuron/CMakeLists.txt b/src/coreneuron/CMakeLists.txt index 3f938742d2..04f6cc626d 100644 --- a/src/coreneuron/CMakeLists.txt +++ b/src/coreneuron/CMakeLists.txt @@ -421,6 +421,11 @@ if(CORENRN_ENABLE_GPU) set(CORENRN_INSTALL_TARGETS "coreneuron-core;coreneuron-cuda" PARENT_SCOPE) +else() + set_target_properties(coreneuron-core PROPERTIES EXPORT_NAME corenrn) + set(CORENRN_INSTALL_TARGETS + coreneuron-core + PARENT_SCOPE) endif() foreach(target coreneuron-core ${coreneuron_cuda_target}) From 6a8c83b2cee2c67e4e7a808a54cf01a509f3d985 Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Thu, 17 Apr 2025 15:55:53 +0200 Subject: [PATCH 08/23] Fix issues with paths Always use resolved absolute paths in CMake since nocmodl has some trouble with symlinks. --- cmake/neuronMechMaker.cmake | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/cmake/neuronMechMaker.cmake b/cmake/neuronMechMaker.cmake index a0897eb41a..f8a310e3dc 100644 --- a/cmake/neuronMechMaker.cmake +++ b/cmake/neuronMechMaker.cmake @@ -26,15 +26,17 @@ function(create_nrnmech) foreach(MOD_FILE IN LISTS MOD_FILES) get_filename_component(MOD_STUB "${MOD_FILE}" NAME_WLE) + # nocmodl has trouble with symlinks, so we always use the real path + get_filename_component(MOD_ABSPATH "${MOD_FILE}" REALPATH) set(CPP_FILE "cpp/${MOD_STUB}.cpp") - file(RELATIVE_PATH MOD_SHORT "${CMAKE_SOURCE_DIR}" "${MOD_FILE}") + file(RELATIVE_PATH MOD_SHORT "${CMAKE_SOURCE_DIR}" "${MOD_ABSPATH}") list(APPEND L_MECH_DECLARE "extern \"C\" void _${MOD_STUB}_reg(void)\;") list(APPEND L_MECH_PRINT "fprintf(stderr, \" \\\"${MOD_SHORT}\\\"\")\;") list(APPEND L_MECH_REGISTRE "_${MOD_STUB}_reg()\;") add_custom_command( - COMMAND neuron::nocmodl -o "${CMAKE_CURRENT_BINARY_DIR}/cpp" "${MOD_FILE}" + COMMAND neuron::nocmodl -o "${CMAKE_CURRENT_BINARY_DIR}/cpp" "${MOD_ABSPATH}" OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${CPP_FILE}" DEPENDS neuron::nocmodl) @@ -56,15 +58,17 @@ function(create_nrnmech) foreach(MOD_FILE IN LISTS MOD_FILES) get_filename_component(MOD_STUB "${MOD_FILE}" NAME_WLE) + # nmodl _may_ have trouble with symlinks, so we always use the real path + get_filename_component(MOD_ABSPATH "${MOD_FILE}" REALPATH) set(CPP_FILE "cpp_core/${MOD_STUB}.cpp") - file(RELATIVE_PATH MOD_SHORT "${CMAKE_SOURCE_DIR}" "${MOD_FILE}") + file(RELATIVE_PATH MOD_SHORT "${CMAKE_SOURCE_DIR}" "${MOD_ABSPATH}") list(APPEND L_CORE_MECH_DECLARE "extern int void _${MOD_STUB}_reg(void)\;") list(APPEND L_CORE_MECH_PRINT "fprintf(stderr, \" \\\"${MOD_SHORT}\\\"\")\;") list(APPEND L_CORE_MECH_REGISTRE "_${MOD_STUB}_reg()\;") add_custom_command( - COMMAND "${NMODL}" -o "${CMAKE_CURRENT_BINARY_DIR}/cpp_core" "${MOD_FILE}" + COMMAND "${NMODL}" -o "${CMAKE_CURRENT_BINARY_DIR}/cpp_core" "${MOD_ABSPATH}" OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${CPP_FILE}" DEPENDS "${NMODL}") From 58a380f5a7128ad55a0732088333338a302617ad Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Tue, 3 Jun 2025 16:37:36 +0200 Subject: [PATCH 09/23] Update create_nrnmech * add docs and various args --- cmake/neuronMechMaker.cmake | 366 ++++++++++++++++++++++++++++-------- 1 file changed, 285 insertions(+), 81 deletions(-) diff --git a/cmake/neuronMechMaker.cmake b/cmake/neuronMechMaker.cmake index f8a310e3dc..6e41878e5c 100644 --- a/cmake/neuronMechMaker.cmake +++ b/cmake/neuronMechMaker.cmake @@ -1,9 +1,79 @@ # ~~~ +# Helper functions for generating (core)NEURON mechanism libraries directly in CMake +# The basic idea is to replicate all of the previous functionality of the Makefiles, +# but without having to deal with reading Makefiles or having to worry about dependencies. +# What `nrnivmodl` and `nrnivmodl -coreneuron` were doing was essentially: +# - create a subdir equivalent to `CMAKE_HOST_SYSTEM_PROCESSOR` in the current working directory +# - translate a given list of mod files to cpp files (using either NOCMODL or NMODL) +# - create a file `mod_func.cpp` which dynamically (that is, upon running `nrniv` or similar) registers the mechanisms in NEURON +# - create a `nrnmech` library in the `CMAKE_HOST_SYSTEM_PROCESSOR` subdirectory from all of the above listed cpp files +# - create a `special` executable in the `CMAKE_HOST_SYSTEM_PROCESSOR` subdirectory from the `nrnmain.cpp` file +# - link the above executable to the `nrnmech` library +# In case the `-coreneuron` option is given, it additionally does the following: +# - create a `corenrnmech` library in the `CMAKE_HOST_SYSTEM_PROCESSOR` subdirectory from all of the above listed cpp files, except with a different `mod_func.cpp` which correctly registers it under the `coreneuron` cpp namespace +# - create a `special-core` executable in the `CMAKE_HOST_SYSTEM_PROCESSOR` subdirectory from the `coreneuron.cpp` file +# - link the above executable to the `corenrnmech` library +# Note that any other files created are basically noise. +# create_nrnmech( +# [NEURON] +# [CORENEURON] +# [SPECIAL] +# [NMODL_NEURON_CODEGEN] +# [TARGET_LIBRARY_NAME lib_tgt] +# [TARGET_EXECUTABLE_NAME exe_tgt] +# [LIBRARY_OUTPUT_DIR lib_outdir] +# [EXECUTABLE_OUTPUT_DIR exe_outdir] +# [ARTIFACTS_OUTPUT_DIR art_outdir] +# [LIBRARY_TYPE type] +# [NOCMODL_EXECUTABLE path/to/nocmodl] +# [NMODL_EXECUTABLE path/to/nmodl] +# [MOD_FILES mod1 mod2 ...] +# [NMODL_EXTRA_ARGS arg1 arg2 ...] +# [EXTRA_ENV KEY1=VAL1 KEY2=VAL2 ...] +# ) # +# Create a suitable mechanism for loading into NEURON. +# +# NEURON - (optional) whether a library compatible with NEURON should be created. +# CORENEURON - (optional) whether a library compatible with coreNEURON should be created. At least one of NEURON or CORENEURON must be specified. +# SPECIAL - (optional) whether a `special` (or `special-core` in case of coreNEURON) executable should be created. +# NMODL_NEURON_CODEGEN - (optional) whether to use NMODL to generate files compatible with NEURON. +# TARGET_LIBRARY_NAME - (optional, default: nrnmech) the name of the CMake target for the library. Note that `core` is prepended to the coreNEURON target. +# TARGET_EXECUTABLE_NAME - (optional, default: special) the name of the CMake target for the executable. Note that `-core` is appended to the coreNEURON target. +# ARTIFACTS_OUTPUT_DIR - (optional) the path where the CPP files will be placed at build-time. +# NOCMODL_EXECUTABLE - (optional) the path to the NOCMODL executable. If not specified, attempts to find deduce the location of the executable from the NEURON CMake configuration. +# NMODL_EXECUTABLE - (optional) the path to the NMODL executable. If not specified, attempts to find deduce the location of the executable from the NEURON CMake configuration. +# MOD_FILES - list of mod files to convert. +# NMODL_EXTRA_ARGS - (optional, default: None) list of additional arguments to pass to NMODL. +# EXTRA_ENV - (optional, default: None) list of additional environmental variables to pass when building the targets. +# TODO figure out why we get missing symbols when testing +# ~~~ function(create_nrnmech) - set(options CORENEURON INSTALL_CPP INSTALL_MOD SPECIAL) - set(oneValueArgs MECHANISM_NAME) - cmake_parse_arguments(NRN_MECH "${options}" "${oneValueArgs}" "MOD_FILES" ${ARGN}) + set(options NEURON CORENEURON SPECIAL NMODL_NEURON_CODEGEN) + set(oneValueArgs + MECHANISM_NAME + TARGET_LIBRARY_NAME + TARGET_EXECUTABLE_NAME + LIBRARY_OUTPUT_DIR + EXECUTABLE_OUTPUT_DIR + ARTIFACTS_OUTPUT_DIR + LIBRARY_TYPE + NOCMODL_EXECUTABLE + NMODL_EXECUTABLE) + set(multiValueArgs MOD_FILES NMODL_EXTRA_ARGS EXTRA_ENV) + cmake_parse_arguments(NRN_MECH "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + # The name of the output library + set(LIBNAME "nrnmech") + # The name of the output executable + set(EXENAME "special") + # The default type of the output library. Note that `nrnmech` and `corenrnmech` are actually + # module libraries (since they are loaded via `dlopen`-like functionality), but a module library + # cannot be linked to, and since `special` must link to `nrnmech`, so to avoid having to compile + # the source files twice, we use a shared library instead. + set(DEFAULT_LIBRARY_TYPE "SHARED") + # The default name of the mechanism + set(DEFAULT_MECHANISM_NAME "neuron") if(NRN_MECH_CORENEURON) if(NOT NRN_ENABLE_CORENEURON) @@ -11,51 +81,204 @@ function(create_nrnmech) endif() endif() - if(NOT MECHANISM_NAME) - set(MECHANISM_NAME neuron) + if(NOT NRN_MECH_NEURON AND NOT NRN_MECH_CORENEURON) + message( + FATAL_ERROR + "No output specified for mod files, please specify at least one of `NEURON` or `CORENEURON` outputs" + ) endif() - set(LIBNAME "nrnmech") - set(EXENAME "special") + if(NOT NRN_MECH_MOD_FILES) + message(FATAL_ERROR "No input mod files specified!") + endif() + + if(NRN_MECH_MECHANISM_NAME) + set(MECHANISM_NAME "${NRN_MECH_MECHANISM_NAME}") + else() + set(MECHANISM_NAME "${DEFAULT_MECHANISM_NAME}") + endif() + + # the `nmodl` and `nocmodl` executables are usually found through `find_program` on the user's + # system, but we allow overrides (for testing purposes only) + if(NRN_MECH_NMODL_EXECUTABLE) + set(NMODL_EXECUTABLE "${NRN_MECH_NMODL_EXECUTABLE}") + else() + set(NMODL_EXECUTABLE "${NMODL}") + endif() + + if(NRN_MECH_NOCMODL_EXECUTABLE) + set(NOCMODL_EXECUTABLE "${NRN_MECH_NOCMODL_EXECUTABLE}") + else() + set(NOCMODL_EXECUTABLE $) + endif() + + # the option `CORENRN_ENABLE_SHARED` toggles the kind of library we want to build, so we respect + # it here + if(NRN_MECH_LIBRARY_TYPE) + set(LIBRARY_TYPE "${NRN_MECH_LIBRARY_TYPE}") + else() + set(LIBRARY_TYPE "${DEFAULT_LIBRARY_TYPE}") + endif() + + # nmodl by default generates code for coreNEURON, so we toggle this via an option + if(NRN_MECH_NMODL_NEURON_CODEGEN) + set(NEURON_TRANSPILER_LAUNCHER ${NMODL_EXECUTABLE} --neuron) + else() + set(NEURON_TRANSPILER_LAUNCHER ${NOCMODL_EXECUTABLE}) + endif() + + # raise warning that NMODL extra args will be ignored if we use NEURON codegen with NOCMODL + if(NRN_MECH_NEURON + AND NOT NRN_MECH_NMODL_NEURON_CODEGEN + AND NRN_MECH_NMODL_EXTRA_ARGS) + message( + WARNING + "create_nrmech: requested NEURON library with NOCMODL codegen, but NMODL_EXTRA_ARGS is not empty; " + "will ignore NMODL_EXTRA_ARGS when building NEURON library.\n" + "Hint: if you want to use NMODL for codegen, add the NMODL_NEURON_CODEGEN option when calling this function." + ) + set(NRN_MECH_NMODL_EXTRA_ARGS) + endif() + + # any extra environment variables that need to be passed (for testing purposes only). Because + # CMake likes to escape and quote things, we need to do it the roundabout way... + if(NRN_MECH_EXTRA_ENV) + set(ENV_COMMAND "${CMAKE_COMMAND}" -E env ${NRN_MECH_EXTRA_ENV}) + else() + set(ENV_COMMAND) + endif() + + # Override the _target_ name, but not the library name. This is useful when we are using this + # function for building NEURON components, since we may experience collisions in the target names + if(NRN_MECH_TARGET_LIBRARY_NAME) + set(TARGET_LIBRARY_NAME "${NRN_MECH_TARGET_LIBRARY_NAME}") + else() + set(TARGET_LIBRARY_NAME "${LIBNAME}") + endif() + + # Override the _target_ name, but not the executable name. This is useful when we are using this + # function for building NEURON components, since we may experience collisions in the target names + if(NRN_MECH_TARGET_EXECUTABLE_NAME) + set(TARGET_EXECUTABLE_NAME "${NRN_MECH_TARGET_EXECUTABLE_NAME}") + else() + set(TARGET_EXECUTABLE_NAME "${EXENAME}") + endif() + + # Where to output the library (during build) + if(NRN_MECH_LIBRARY_OUTPUT_DIR) + set(LIBRARY_OUTPUT_DIR "${NRN_MECH_LIBRARY_OUTPUT_DIR}") + else() + set(LIBRARY_OUTPUT_DIR "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}") + endif() + + # Where to output the executable (during build) + if(NRN_MECH_EXECUTABLE_OUTPUT_DIR) + set(EXECUTABLE_OUTPUT_DIR "${NRN_MECH_EXECUTABLE_OUTPUT_DIR}") + else() + set(EXECUTABLE_OUTPUT_DIR "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}") + endif() + + # Where the intermediate CPP files will be placed + if(NRN_MECH_ARTIFACTS_OUTPUT_DIR) + set(ARTIFACTS_OUTPUT_DIR "${NRN_MECH_ARTIFACTS_OUTPUT_DIR}") + else() + set(ARTIFACTS_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}") + endif() + # Collect mod files, output any warnings + set(MOD_FILES "") foreach(MOD_FILE IN LISTS NRN_MECH_MOD_FILES) + if(NOT MOD_FILE MATCHES ".*mod$") + message(WARNING "File ${MOD_FILE} has an extension that is not .mod, compilation may fail") + endif() get_filename_component(MOD_STUB "${MOD_FILE}" NAME_WLE) list(APPEND INPUT_STUBS "${MOD_STUB}") list(APPEND MOD_FILES "${MOD_FILE}") endforeach() - foreach(MOD_FILE IN LISTS MOD_FILES) - get_filename_component(MOD_STUB "${MOD_FILE}" NAME_WLE) - # nocmodl has trouble with symlinks, so we always use the real path - get_filename_component(MOD_ABSPATH "${MOD_FILE}" REALPATH) - set(CPP_FILE "cpp/${MOD_STUB}.cpp") - file(RELATIVE_PATH MOD_SHORT "${CMAKE_SOURCE_DIR}" "${MOD_ABSPATH}") + # We later include the directories where the mod files in case people add headers in VERBATIM + # blocks + set(MOD_DIRECTORIES) - list(APPEND L_MECH_DECLARE "extern \"C\" void _${MOD_STUB}_reg(void)\;") - list(APPEND L_MECH_PRINT "fprintf(stderr, \" \\\"${MOD_SHORT}\\\"\")\;") - list(APPEND L_MECH_REGISTRE "_${MOD_STUB}_reg()\;") + # Convert mod files for use with NEURON + if(NRN_MECH_NEURON) + # Convert to CPP files + foreach(MOD_FILE IN LISTS MOD_FILES) + get_filename_component(MOD_STUB "${MOD_FILE}" NAME_WLE) + # nocmodl has trouble with symlinks, so we always use the real path + get_filename_component(MOD_ABSPATH "${MOD_FILE}" REALPATH) + get_filename_component(MOD_DIRECTORY "${MOD_ABSPATH}" DIRECTORY) + if(NOT MOD_DIRECTORY IN_LIST MOD_DIRECTORIES) + list(APPEND MOD_DIRECTORIES "${MOD_DIRECTORY}") + endif() + set(CPP_FILE "cpp/${MOD_STUB}.cpp") + file(RELATIVE_PATH MOD_SHORT "${CMAKE_SOURCE_DIR}" "${MOD_ABSPATH}") - add_custom_command( - COMMAND neuron::nocmodl -o "${CMAKE_CURRENT_BINARY_DIR}/cpp" "${MOD_ABSPATH}" - OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${CPP_FILE}" - DEPENDS neuron::nocmodl) + list(APPEND L_MECH_DECLARE "extern \"C\" void _${MOD_STUB}_reg(void)\;") + list(APPEND L_MECH_PRINT "fprintf(stderr, \" \\\"${MOD_SHORT}\\\"\")\;") + list(APPEND L_MECH_REGISTRE "_${MOD_STUB}_reg()\;") - list(APPEND L_SOURCES "${CMAKE_CURRENT_BINARY_DIR}/${CPP_FILE}") - endforeach() + add_custom_command( + COMMAND ${ENV_COMMAND} ${NEURON_TRANSPILER_LAUNCHER} -o "${ARTIFACTS_OUTPUT_DIR}/cpp" + "${MOD_ABSPATH}" ${NRN_MECH_NMODL_EXTRA_ARGS} + OUTPUT "${ARTIFACTS_OUTPUT_DIR}/${CPP_FILE}" + COMMENT "Converting ${MOD_ABSPATH} to ${ARTIFACTS_OUTPUT_DIR}/${CPP_FILE}" + # TODO some mod files may include other files, and NMODL can get the AST of a given file in + # JSON form, which we could potentially parse with CMake and get the full list of + # dependencies + DEPENDS "${MOD_ABSPATH}" + VERBATIM) + + list(APPEND L_SOURCES "${ARTIFACTS_OUTPUT_DIR}/${CPP_FILE}") + endforeach() + + # add the nrnmech library + add_library(${TARGET_LIBRARY_NAME} ${LIBRARY_TYPE} ${L_SOURCES}) + set_target_properties( + ${TARGET_LIBRARY_NAME} PROPERTIES OUTPUT_NAME "${LIBNAME}" LIBRARY_OUTPUT_DIRECTORY + "${LIBRARY_OUTPUT_DIR}") + target_link_libraries(${TARGET_LIBRARY_NAME} PUBLIC neuron::nrniv) + # we need to add the `mech_func.cpp` file as well since it handles registration of mechanisms + list(JOIN L_MECH_DECLARE "\n" MECH_DECLARE) + list(JOIN L_MECH_PRINT " \n" MECH_PRINT) + list(JOIN L_MECH_REGISTRE " \n" MECH_REGISTRE) + get_filename_component(MECH_REG "${_NEURON_MECH_REG}" NAME_WLE) + configure_file(${_NEURON_MECH_REG} "${ARTIFACTS_OUTPUT_DIR}/${MECH_REG}" @ONLY) + target_sources(${TARGET_LIBRARY_NAME} PRIVATE "${ARTIFACTS_OUTPUT_DIR}/${MECH_REG}") + target_compile_definitions(${TARGET_LIBRARY_NAME} PUBLIC AUTO_DLOPEN_NRNMECH=0) + target_include_directories(${TARGET_LIBRARY_NAME} BEFORE PUBLIC ${_NEURON_MAIN_INCLUDE_DIR}) + # sometimes people will add `#include`s in VERBATIM blocks; usually those are in the same + # directory as the mod file, so let's add that as well + target_include_directories(${TARGET_LIBRARY_NAME} PRIVATE "${MOD_DIRECTORIES}") + + # add the special executable + if(NRN_MECH_SPECIAL) + add_executable(${TARGET_EXECUTABLE_NAME} ${_NEURON_MAIN} + "${ARTIFACTS_OUTPUT_DIR}/${MECH_REG}") + target_include_directories(${TARGET_EXECUTABLE_NAME} BEFORE + PUBLIC ${_NEURON_MAIN_INCLUDE_DIR}) + target_link_libraries(${TARGET_EXECUTABLE_NAME} PUBLIC ${TARGET_LIBRARY_NAME}) + set_target_properties( + ${TARGET_EXECUTABLE_NAME} PROPERTIES OUTPUT_NAME "special" RUNTIME_OUTPUT_DIRECTORY + "${EXECUTABLE_OUTPUT_DIR}") + endif() + + endif() + + # Convert mod files for use with coreNEURON if(NRN_MECH_CORENEURON) # CoreNEURON requires additional mod files. Only append them to the input list if similar named # mods are _not yet present_ file(GLOB BASE_MOD_FILES "${_CORENEURON_BASE_MOD}/*.mod") foreach(MOD_FILE IN LISTS BASE_MOD_FILES) get_filename_component(MOD_STUB "${MOD_FILE}" NAME_WLE) - if("${MOD_STUB}" IN_LIST INPUT_STUBS) - - else() + if(NOT "${MOD_STUB}" IN_LIST INPUT_STUBS) list(APPEND MOD_FILES "${MOD_FILE}") endif() endforeach() + # Convert to CPP files foreach(MOD_FILE IN LISTS MOD_FILES) get_filename_component(MOD_STUB "${MOD_FILE}" NAME_WLE) # nmodl _may_ have trouble with symlinks, so we always use the real path @@ -63,73 +286,54 @@ function(create_nrnmech) set(CPP_FILE "cpp_core/${MOD_STUB}.cpp") file(RELATIVE_PATH MOD_SHORT "${CMAKE_SOURCE_DIR}" "${MOD_ABSPATH}") - list(APPEND L_CORE_MECH_DECLARE "extern int void _${MOD_STUB}_reg(void)\;") + list(APPEND L_CORE_MECH_DECLARE "extern int _${MOD_STUB}_reg(void)\;") list(APPEND L_CORE_MECH_PRINT "fprintf(stderr, \" \\\"${MOD_SHORT}\\\"\")\;") list(APPEND L_CORE_MECH_REGISTRE "_${MOD_STUB}_reg()\;") add_custom_command( - COMMAND "${NMODL}" -o "${CMAKE_CURRENT_BINARY_DIR}/cpp_core" "${MOD_ABSPATH}" - OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${CPP_FILE}" - DEPENDS "${NMODL}") + COMMAND ${ENV_COMMAND} ${NMODL_EXECUTABLE} -o "${ARTIFACTS_OUTPUT_DIR}/cpp_core" + "${MOD_ABSPATH}" ${NRN_MECH_NMODL_EXTRA_ARGS} + OUTPUT "${ARTIFACTS_OUTPUT_DIR}/${CPP_FILE}" + COMMENT "Converting ${MOD_ABSPATH} to ${ARTIFACTS_OUTPUT_DIR}/${CPP_FILE}" + DEPENDS "${MOD_ABSPATH}" + VERBATIM) - list(APPEND L_CORE_SOURCES "${CMAKE_CURRENT_BINARY_DIR}/${CPP_FILE}") + list(APPEND L_CORE_SOURCES "${ARTIFACTS_OUTPUT_DIR}/${CPP_FILE}") endforeach() - endif() - add_library(${LIBNAME} SHARED ${L_SOURCES}) - target_link_libraries(${LIBNAME} PUBLIC neuron::nrniv) - # set_target_properties(${LIBNAME} PROPERTIES OUTPUT_NAME - # "${LIBNAME}$<$:_${NRN_MECH_MECHANISM_NAME}>") - install(TARGETS ${LIBNAME} DESTINATION lib) + add_library(core${TARGET_LIBRARY_NAME} ${LIBRARY_TYPE} ${_CORENEURON_MECH_ENG} + ${L_CORE_SOURCES}) + set_target_properties( + core${TARGET_LIBRARY_NAME} PROPERTIES OUTPUT_NAME "core${LIBNAME}" LIBRARY_OUTPUT_DIRECTORY + "${LIBRARY_OUTPUT_DIR}") + target_include_directories(core${TARGET_LIBRARY_NAME} BEFORE + PUBLIC ${_CORENEURON_RANDOM_INCLUDE}) + target_compile_options(core${TARGET_LIBRARY_NAME} BEFORE PRIVATE ${_CORENEURON_FLAGS}) + target_link_libraries(core${TARGET_LIBRARY_NAME} PUBLIC neuron::corenrn) + target_compile_definitions(core${TARGET_LIBRARY_NAME} PUBLIC ADDITIONAL_MECHS) + # Random123 does not play nicely with NVHPC + target_compile_definitions(core${TARGET_LIBRARY_NAME} PUBLIC R123_USE_INTRIN_H=0) - if(NRN_MECH_CORENEURON) - add_library(core${LIBNAME} SHARED ${_CORENEURON_MECH_ENG} ${L_CORE_SOURCES}) - target_include_directories(core${LIBNAME} PRIVATE ${_CORENEURON_RANDOM_INCLUDE}) - target_compile_options(core${LIBNAME} PRIVATE ${_CORENEURON_FLAGS}) - target_link_libraries(core${LIBNAME} PUBLIC neuron::corenrn) - # set_target_properties(${LIBNAME} PROPERTIES OUTPUT_NAME - # "${LIBNAME}$<$:_${NRN_MECH_MECHANISM_NAME}>") - install(TARGETS core${LIBNAME} DESTINATION lib) - endif() - - if(NRN_MECH_INSTALL_CPP) - install(FILES ${L_SOURCES} DESTINATION "share/${NRN_MECH_MECHANISM_NAME}/cpp") - if(NRN_ENABLE_CORENEURON) - install(FILES ${L_CORE_SOURCES} DESTINATION "share/${NRN_MECH_MECHANISM_NAME}/cpp_core") - endif() - endif() + list(JOIN L_CORE_MECH_DECLARE "\n" MECH_DECLARE) + list(JOIN L_CORE_MECH_PRINT " \n" MECH_PRINT) + list(JOIN L_CORE_MECH_REGISTRE " \n" MECH_REGISTRE) - if(NRN_MECH_INSTALL_MOD) - install(FILES ${MOD_FILES} DESTINATION "share/${NRN_MECH_MECHANISM_NAME}/mod") - endif() + get_filename_component(CORE_MECH_REG "${_CORENEURON_MECH_REG}" NAME_WLE) + configure_file(${_CORENEURON_MECH_REG} "${ARTIFACTS_OUTPUT_DIR}/core${CORE_MECH_REG}" @ONLY) - if(NRN_MECH_SPECIAL) - list(JOIN L_MECH_DECLARE "\n" MECH_DECLARE) - list(JOIN L_MECH_PRINT " \n" MECH_PRINT) - list(JOIN L_MECH_REGISTRE " \n" MECH_REGISTRE) + target_sources(core${TARGET_LIBRARY_NAME} + PRIVATE "${ARTIFACTS_OUTPUT_DIR}/core${CORE_MECH_REG}") - get_filename_component(MECH_REG "${_NEURON_MECH_REG}" NAME_WLE) - configure_file(${_NEURON_MECH_REG} ${MECH_REG} @ONLY) - - add_executable(${EXENAME} ${_NEURON_MAIN} ${MECH_REG}) - target_include_directories(${EXENAME} PUBLIC ${_NEURON_MAIN_INCLUDE_DIR}) - target_link_libraries(${EXENAME} ${LIBNAME}) - set_target_properties(${EXENAME} PROPERTIES OUTPUT_NAME "special") - install(TARGETS ${EXENAME} DESTINATION bin) - - if(NRN_MECH_CORENEURON) - list(JOIN L_CORE_MECH_DECLARE "\n" MECH_DECLARE) - list(JOIN L_CORE_MECH_PRINT " \n" MECH_PRINT) - list(JOIN L_CORE_MECH_REGISTRE " \n" MECH_REGISTRE) - - get_filename_component(CORE_MECH_REG "${_NEURON_COREMECH_REG}" NAME_WLE) - configure_file(${_NEURON_MECH_REG} core${CORE_MECH_REG} @ONLY) - - add_executable(core${EXENAME} ${_CORENEURON_MAIN} core${CORE_MECH_REG}) - target_include_directories(core${EXENAME} PUBLIC ${_NEURON_MAIN_INCLUDE_DIR}) - target_link_libraries(core${EXENAME} core${LIBNAME}) - set_target_properties(core${EXENAME} PROPERTIES OUTPUT_NAME "special-core") - install(TARGETS core${EXENAME} DESTINATION bin) + if(NRN_MECH_SPECIAL) + add_executable(core${TARGET_EXECUTABLE_NAME} ${_CORENEURON_MAIN} + "${ARTIFACTS_OUTPUT_DIR}/core${CORE_MECH_REG}") + target_include_directories(core${TARGET_EXECUTABLE_NAME} BEFORE + PUBLIC ${_NEURON_MAIN_INCLUDE_DIR}) + target_link_libraries(core${TARGET_EXECUTABLE_NAME} PUBLIC core${TARGET_LIBRARY_NAME}) + target_compile_definitions(core${TARGET_EXECUTABLE_NAME} PUBLIC ADDITIONAL_MECHS) + set_target_properties( + core${TARGET_EXECUTABLE_NAME} + PROPERTIES OUTPUT_NAME "special-core" RUNTIME_OUTPUT_DIRECTORY "${EXECUTABLE_OUTPUT_DIR}") endif() endif() endfunction() From f0eaccc135e2e88c67e4e8e9659b73c37aaed9d6 Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Tue, 3 Jun 2025 16:39:30 +0200 Subject: [PATCH 10/23] Remove comments --- src/nrnpython/CMakeLists.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/nrnpython/CMakeLists.txt b/src/nrnpython/CMakeLists.txt index f1d9100256..ae091104b7 100644 --- a/src/nrnpython/CMakeLists.txt +++ b/src/nrnpython/CMakeLists.txt @@ -57,10 +57,6 @@ endif() # user has selected dynamic python support (could be multiple versions) if(NRN_ENABLE_PYTHON_DYNAMIC) - # set(INCLUDE_DIRS . .. ../oc ../nrnoc ../ivoc ../nrniv ../gnu ../nrnmpi - # ${PROJECT_BINARY_DIR}/src/nrnpython ${PROJECT_BINARY_DIR}/src/ivos ${PROJECT_BINARY_DIR}/src/oc - # ${NRN_OC_GENERATED_SOURCES}) if(NRN_ENABLE_INTERVIEWS) list(APPEND INCLUDE_DIRS - # ${IV_INCLUDE_DIR}) else() list(APPEND INCLUDE_DIRS ../ivos) endif() foreach(val RANGE ${NRN_PYTHON_ITERATION_LIMIT}) # the NEURON Python library (with nanobind) From c0f168afed2a79955112e434dcf2782c043c0c6c Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Wed, 4 Jun 2025 13:30:01 +0200 Subject: [PATCH 11/23] Add tentative test --- test/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3af9cf9ae2..43dad54b22 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -826,3 +826,8 @@ if((NRN_ENABLE_NMODL OR NRN_ENABLE_CORENEURON) AND NRN_ENABLE_TESTS) add_subdirectory(nmodl/transpiler/usecases) endif() endif() + +# Test nrnivmodl-cmake +if(NRN_ENABLE_CORENEURON AND NRN_ENABLE_TESTS) + add_subdirectory(nrnivmodl-cmake) +endif() From 758142c7e3eb2f75bd541f0c5ef2c14419c31000 Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Wed, 4 Jun 2025 13:41:34 +0200 Subject: [PATCH 12/23] Neuron config --- CMakeLists.txt | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ac634fbae8..b2348de183 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1110,7 +1110,18 @@ endif() # ============================================================================= # Install CMake glue # ============================================================================= +configure_file(cmake/neuronMechMaker.cmake + "${PROJECT_BINARY_DIR}/lib/cmake/neuron/neuronMechMaker.cmake" COPYONLY) +configure_file(cmake/mod_reg_nrn.cpp.in "${PROJECT_BINARY_DIR}/share/nrn/mod_reg_nrn.cpp.in" + COPYONLY) +configure_file(cmake/mod_reg_corenrn.cpp.in + "${PROJECT_BINARY_DIR}/share/nrn/mod_reg_corenrn.cpp.in" COPYONLY) install(TARGETS ${NRN_INSTALL_TARGETS} ${CORENRN_INSTALL_TARGETS} EXPORT NeuronTargets) +export( + EXPORT NeuronTargets + FILE ${PROJECT_BINARY_DIR}/lib/cmake/neuron/neuronTargets.cmake + NAMESPACE neuron::) + install( EXPORT NeuronTargets FILE neuronTargets.cmake @@ -1118,7 +1129,7 @@ install( DESTINATION lib/cmake/neuron) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/neuronConfig.cmake.in - ${CMAKE_CURRENT_BINARY_DIR}/neuronConfig.cmake @ONLY) + ${CMAKE_CURRENT_BINARY_DIR}/lib/cmake/neuron/neuronConfig.cmake @ONLY) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/neuronConfig.cmake DESTINATION lib/cmake/neuron) install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/cmake/neuronMechMaker.cmake DESTINATION lib/cmake/neuron) From 32c2cc17bd217530f23da2160bae9ac3e9927a16 Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Wed, 4 Jun 2025 14:07:57 +0200 Subject: [PATCH 13/23] Fix include paths Also finally add (hacky) test --- cmake/neuronConfig.cmake.in | 4 ++-- test/nrnivmodl-cmake/CMakeLists.txt | 20 +++++++++++++++++++ .../build_cmake/CMakeLists.txt | 6 ++++++ 3 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 test/nrnivmodl-cmake/CMakeLists.txt create mode 100644 test/nrnivmodl-cmake/build_cmake/CMakeLists.txt diff --git a/cmake/neuronConfig.cmake.in b/cmake/neuronConfig.cmake.in index 2375f0d608..68c6252459 100644 --- a/cmake/neuronConfig.cmake.in +++ b/cmake/neuronConfig.cmake.in @@ -10,14 +10,14 @@ get_filename_component(_prefix "${_dir}/../../.." ABSOLUTE) set(NRN_ENABLE_CORENEURON @NRN_ENABLE_CORENEURON@) set(_NEURON_MAIN "${_prefix}/share/nrn/nrnmain.cpp") -set(_NEURON_MAIN_INCLUDE_DIR "${_prefix}/include/nrncvode") +set(_NEURON_MAIN_INCLUDE_DIR "${_prefix}/include/nrncvode" "${_prefix}/include") set(_NEURON_MECH_REG "${_prefix}/share/nrn/mod_reg_nrn.cpp.in") set(_CORENEURON_BASE_MOD "${_prefix}/share/modfile") set(_CORENEURON_MAIN "${_prefix}/share/coreneuron/coreneuron.cpp") set(_CORENEURON_MECH_REG "${_prefix}/share/nrn/mod_reg_corenrn.cpp.in") set(_CORENEURON_MECH_ENG "${_prefix}/share/coreneuron/enginemech.cpp") -set(_CORENEURON_RANDOM_INCLUDE "${_prefix}/include/coreneuron/utils/randoms") +set(_CORENEURON_RANDOM_INCLUDE "${_prefix}/include/coreneuron/utils/randoms" "${_prefix}/include") set(_CORENEURON_FLAGS @CORENRN_CXX_FLAGS@) find_program(NMODL nmodl REQUIRED) diff --git a/test/nrnivmodl-cmake/CMakeLists.txt b/test/nrnivmodl-cmake/CMakeLists.txt new file mode 100644 index 0000000000..5cbe720a8f --- /dev/null +++ b/test/nrnivmodl-cmake/CMakeLists.txt @@ -0,0 +1,20 @@ +# ~~~ +# Test for `create_nrnmech` as if it was already installed +# ~~~ +set(TEST_NAMESPACE "nrnivmodl-cmake") +set(TEST_DIR "${CMAKE_CURRENT_BINARY_DIR}/build_cmake") +file(GLOB MOD_FILES "${PROJECT_SOURCE_DIR}/test/coreneuron/mod files/*.mod") + +# This is admittedly a bit hacky, but we are launching CMake inside of CMake, and we cannot use any +# of the set variables, either via CMake itself, or through the env. The only thing that must be +# available is the NEURON CMake config file, and NMODL must be in PATH at CMake configure time. +add_test( + NAME "${TEST_NAMESPACE}::modfiles" + COMMAND + sh -c + "CMAKE_PREFIX_PATH='${PROJECT_BINARY_DIR}/lib/cmake' PATH='${PROJECT_BINARY_DIR}/bin:$ENV{PATH}' \ + ${CMAKE_COMMAND} -S '${CMAKE_CURRENT_SOURCE_DIR}/build_cmake' -B '${TEST_DIR}' -DMOD_FILES='${MOD_FILES}' \ + && \ + ${CMAKE_COMMAND} --build '${TEST_DIR}' -v --parallel \ + && \ + rm -fr '${TEST_DIR}'") diff --git a/test/nrnivmodl-cmake/build_cmake/CMakeLists.txt b/test/nrnivmodl-cmake/build_cmake/CMakeLists.txt new file mode 100644 index 0000000000..b71dffea71 --- /dev/null +++ b/test/nrnivmodl-cmake/build_cmake/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.15) +project(modfile_test CXX) + +find_package(neuron REQUIRED) + +create_nrnmech(CORENEURON MOD_FILES ${MOD_FILES}) From 6a8ed75579371b02d29d7dcf4f28a659969e11b8 Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Wed, 4 Jun 2025 14:21:52 +0200 Subject: [PATCH 14/23] Add NEURON and special --- test/nrnivmodl-cmake/CMakeLists.txt | 1 + test/nrnivmodl-cmake/build_cmake/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/test/nrnivmodl-cmake/CMakeLists.txt b/test/nrnivmodl-cmake/CMakeLists.txt index 5cbe720a8f..a62657a21b 100644 --- a/test/nrnivmodl-cmake/CMakeLists.txt +++ b/test/nrnivmodl-cmake/CMakeLists.txt @@ -17,4 +17,5 @@ add_test( && \ ${CMAKE_COMMAND} --build '${TEST_DIR}' -v --parallel \ && \ + '${TEST_DIR}/special' -nobanner -nogui -c 'quit()' \ rm -fr '${TEST_DIR}'") diff --git a/test/nrnivmodl-cmake/build_cmake/CMakeLists.txt b/test/nrnivmodl-cmake/build_cmake/CMakeLists.txt index b71dffea71..da4f2733bd 100644 --- a/test/nrnivmodl-cmake/build_cmake/CMakeLists.txt +++ b/test/nrnivmodl-cmake/build_cmake/CMakeLists.txt @@ -3,4 +3,4 @@ project(modfile_test CXX) find_package(neuron REQUIRED) -create_nrnmech(CORENEURON MOD_FILES ${MOD_FILES}) +create_nrnmech(NEURON CORENEURON SPECIAL MOD_FILES ${MOD_FILES}) From 6988505682a244b4665c3ac6e0663683920bb434 Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Wed, 4 Jun 2025 14:41:03 +0200 Subject: [PATCH 15/23] Formatting --- test/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 43dad54b22..e6f37005c9 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -829,5 +829,5 @@ endif() # Test nrnivmodl-cmake if(NRN_ENABLE_CORENEURON AND NRN_ENABLE_TESTS) - add_subdirectory(nrnivmodl-cmake) + add_subdirectory(nrnivmodl-cmake) endif() From b00f3dcefeb828b262cd63102d19e8c172fb24ed Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Wed, 4 Jun 2025 14:46:40 +0200 Subject: [PATCH 16/23] Better config --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b2348de183..15d05c0829 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1131,7 +1131,7 @@ install( configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/neuronConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/lib/cmake/neuron/neuronConfig.cmake @ONLY) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/neuronConfig.cmake DESTINATION lib/cmake/neuron) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/lib/cmake/neuron/neuronConfig.cmake DESTINATION lib/cmake/neuron) install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/cmake/neuronMechMaker.cmake DESTINATION lib/cmake/neuron) install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/cmake/mod_reg_nrn.cpp.in From 535bb1c57bdbdb8c7e942351d859b89ff901621e Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Wed, 4 Jun 2025 14:56:14 +0200 Subject: [PATCH 17/23] Formatting --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 15d05c0829..1a347aa497 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1131,7 +1131,8 @@ install( configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/neuronConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/lib/cmake/neuron/neuronConfig.cmake @ONLY) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/lib/cmake/neuron/neuronConfig.cmake DESTINATION lib/cmake/neuron) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/lib/cmake/neuron/neuronConfig.cmake + DESTINATION lib/cmake/neuron) install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/cmake/neuronMechMaker.cmake DESTINATION lib/cmake/neuron) install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/cmake/mod_reg_nrn.cpp.in From 3a7bb988b220c4ed4f8421d6c0f747f81c7a28d3 Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Wed, 4 Jun 2025 16:01:11 +0200 Subject: [PATCH 18/23] Appease MODLUNIT --- test/CMakeLists.txt | 2 +- test/nrnivmodl-cmake/CMakeLists.txt | 11 ++++++++--- test/nrnivmodl-cmake/build_cmake/CMakeLists.txt | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index e6f37005c9..a95667bdd6 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -828,6 +828,6 @@ if((NRN_ENABLE_NMODL OR NRN_ENABLE_CORENEURON) AND NRN_ENABLE_TESTS) endif() # Test nrnivmodl-cmake -if(NRN_ENABLE_CORENEURON AND NRN_ENABLE_TESTS) +if(NRN_ENABLE_TESTS) add_subdirectory(nrnivmodl-cmake) endif() diff --git a/test/nrnivmodl-cmake/CMakeLists.txt b/test/nrnivmodl-cmake/CMakeLists.txt index a62657a21b..f66e1e99ff 100644 --- a/test/nrnivmodl-cmake/CMakeLists.txt +++ b/test/nrnivmodl-cmake/CMakeLists.txt @@ -2,18 +2,23 @@ # Test for `create_nrnmech` as if it was already installed # ~~~ set(TEST_NAMESPACE "nrnivmodl-cmake") -set(TEST_DIR "${CMAKE_CURRENT_BINARY_DIR}/build_cmake") file(GLOB MOD_FILES "${PROJECT_SOURCE_DIR}/test/coreneuron/mod files/*.mod") # This is admittedly a bit hacky, but we are launching CMake inside of CMake, and we cannot use any # of the set variables, either via CMake itself, or through the env. The only thing that must be # available is the NEURON CMake config file, and NMODL must be in PATH at CMake configure time. +set(TEST_DIR "${CMAKE_CURRENT_BINARY_DIR}/build_cmake") +if(NRN_ENABLE_CORENEURON) + set(CORENEURON CORENEURON) +endif() add_test( NAME "${TEST_NAMESPACE}::modfiles" COMMAND sh -c - "CMAKE_PREFIX_PATH='${PROJECT_BINARY_DIR}/lib/cmake' PATH='${PROJECT_BINARY_DIR}/bin:$ENV{PATH}' \ - ${CMAKE_COMMAND} -S '${CMAKE_CURRENT_SOURCE_DIR}/build_cmake' -B '${TEST_DIR}' -DMOD_FILES='${MOD_FILES}' \ + "CMAKE_PREFIX_PATH='${PROJECT_BINARY_DIR}/lib/cmake' \ + PATH='${PROJECT_BINARY_DIR}/bin:$ENV{PATH}' \ + MODLUNIT='${PROJECT_BINARY_DIR}/share/nrn/lib/nrnunits.lib' \ + ${CMAKE_COMMAND} -S '${CMAKE_CURRENT_SOURCE_DIR}/build_cmake' -B '${TEST_DIR}' -DMOD_FILES='${MOD_FILES}' -DCORENEURON=${CORENEURON} \ && \ ${CMAKE_COMMAND} --build '${TEST_DIR}' -v --parallel \ && \ diff --git a/test/nrnivmodl-cmake/build_cmake/CMakeLists.txt b/test/nrnivmodl-cmake/build_cmake/CMakeLists.txt index da4f2733bd..737abf33fb 100644 --- a/test/nrnivmodl-cmake/build_cmake/CMakeLists.txt +++ b/test/nrnivmodl-cmake/build_cmake/CMakeLists.txt @@ -3,4 +3,4 @@ project(modfile_test CXX) find_package(neuron REQUIRED) -create_nrnmech(NEURON CORENEURON SPECIAL MOD_FILES ${MOD_FILES}) +create_nrnmech(NEURON ${CORENEURON} SPECIAL MOD_FILES ${MOD_FILES}) From 908dc4e3dbcfe2372bf1b3b4760f48eb7af5dd65 Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Wed, 4 Jun 2025 18:09:01 +0200 Subject: [PATCH 19/23] Workaround for NOCMODL --- cmake/neuronMechMaker.cmake | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cmake/neuronMechMaker.cmake b/cmake/neuronMechMaker.cmake index 6e41878e5c..3c94c76a01 100644 --- a/cmake/neuronMechMaker.cmake +++ b/cmake/neuronMechMaker.cmake @@ -148,6 +148,12 @@ function(create_nrnmech) set(ENV_COMMAND) endif() + # nocmodl sometimes does not work due to lack of MODLUNIT, see: + # https://github.com/neuronsimulator/nrn/issues/3470 + if(DEFINED ENV{MODLUNIT}) + list(APPEND ENV_COMMAND "MODLUNIT=$ENV{MODLUNIT}") + endif() + # Override the _target_ name, but not the library name. This is useful when we are using this # function for building NEURON components, since we may experience collisions in the target names if(NRN_MECH_TARGET_LIBRARY_NAME) From 1462039e1fccd94e174bef6e4a6674c3cf35f28b Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Thu, 5 Jun 2025 12:09:52 +0200 Subject: [PATCH 20/23] Use same compiler as used by system --- test/nrnivmodl-cmake/CMakeLists.txt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/test/nrnivmodl-cmake/CMakeLists.txt b/test/nrnivmodl-cmake/CMakeLists.txt index f66e1e99ff..773408aa57 100644 --- a/test/nrnivmodl-cmake/CMakeLists.txt +++ b/test/nrnivmodl-cmake/CMakeLists.txt @@ -14,11 +14,15 @@ endif() add_test( NAME "${TEST_NAMESPACE}::modfiles" COMMAND - sh -c - "CMAKE_PREFIX_PATH='${PROJECT_BINARY_DIR}/lib/cmake' \ + sh -c "CMAKE_PREFIX_PATH='${PROJECT_BINARY_DIR}/lib/cmake' \ PATH='${PROJECT_BINARY_DIR}/bin:$ENV{PATH}' \ MODLUNIT='${PROJECT_BINARY_DIR}/share/nrn/lib/nrnunits.lib' \ - ${CMAKE_COMMAND} -S '${CMAKE_CURRENT_SOURCE_DIR}/build_cmake' -B '${TEST_DIR}' -DMOD_FILES='${MOD_FILES}' -DCORENEURON=${CORENEURON} \ + ${CMAKE_COMMAND} \ + -S '${CMAKE_CURRENT_SOURCE_DIR}/build_cmake' -B '${TEST_DIR}' \ + -DMOD_FILES='${MOD_FILES}' \ + -DCORENEURON=${CORENEURON} \ + -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} \ + -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} \ && \ ${CMAKE_COMMAND} --build '${TEST_DIR}' -v --parallel \ && \ From 446fb4836ad5d84fbdf865fa8b745e89913759bd Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Thu, 5 Jun 2025 13:13:45 +0200 Subject: [PATCH 21/23] Disable CMake mechanism test if using sanitizers --- test/CMakeLists.txt | 5 +++-- test/nrnivmodl-cmake/build_cmake/CMakeLists.txt | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a95667bdd6..4fde4a072f 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -827,7 +827,8 @@ if((NRN_ENABLE_NMODL OR NRN_ENABLE_CORENEURON) AND NRN_ENABLE_TESTS) endif() endif() -# Test nrnivmodl-cmake -if(NRN_ENABLE_TESTS) +# Test nrnivmodl-cmake, but only without sanitizers since those cause issues, and end-users won't +# get builds with sanitizer builds anyway +if(NRN_ENABLE_TESTS AND NOT NRN_SANITIZERS) add_subdirectory(nrnivmodl-cmake) endif() diff --git a/test/nrnivmodl-cmake/build_cmake/CMakeLists.txt b/test/nrnivmodl-cmake/build_cmake/CMakeLists.txt index 737abf33fb..836884d5cc 100644 --- a/test/nrnivmodl-cmake/build_cmake/CMakeLists.txt +++ b/test/nrnivmodl-cmake/build_cmake/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.15) -project(modfile_test CXX) +project(modfile_test LANGUAGES C CXX) find_package(neuron REQUIRED) From ebbe6f5000399884f273ac38134a62664de4cac4 Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Thu, 5 Jun 2025 14:59:42 +0200 Subject: [PATCH 22/23] Use `-nopython` when launching `special` --- test/nrnivmodl-cmake/CMakeLists.txt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/test/nrnivmodl-cmake/CMakeLists.txt b/test/nrnivmodl-cmake/CMakeLists.txt index 773408aa57..f3cb8be679 100644 --- a/test/nrnivmodl-cmake/CMakeLists.txt +++ b/test/nrnivmodl-cmake/CMakeLists.txt @@ -6,7 +6,9 @@ file(GLOB MOD_FILES "${PROJECT_SOURCE_DIR}/test/coreneuron/mod files/*.mod") # This is admittedly a bit hacky, but we are launching CMake inside of CMake, and we cannot use any # of the set variables, either via CMake itself, or through the env. The only thing that must be -# available is the NEURON CMake config file, and NMODL must be in PATH at CMake configure time. +# available is the NEURON CMake config file, and NMODL must be in PATH at CMake configure time. Note +# that we do not try to use Python abilities of `special`, since those require setting env +# variables, which the user may not be aware of. set(TEST_DIR "${CMAKE_CURRENT_BINARY_DIR}/build_cmake") if(NRN_ENABLE_CORENEURON) set(CORENEURON CORENEURON) @@ -20,11 +22,12 @@ add_test( ${CMAKE_COMMAND} \ -S '${CMAKE_CURRENT_SOURCE_DIR}/build_cmake' -B '${TEST_DIR}' \ -DMOD_FILES='${MOD_FILES}' \ + -DCMAKE_BUILD_TYPE=Debug \ -DCORENEURON=${CORENEURON} \ -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} \ -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} \ && \ ${CMAKE_COMMAND} --build '${TEST_DIR}' -v --parallel \ && \ - '${TEST_DIR}/special' -nobanner -nogui -c 'quit()' \ + '${TEST_DIR}/special' -nopython -nobanner -nogui -c 'quit()' \ rm -fr '${TEST_DIR}'") From 81c1d1f326b3a02a66c4b3c6fad0a679b0b4c81e Mon Sep 17 00:00:00 2001 From: Goran Jelic-Cizmek Date: Thu, 5 Jun 2025 16:14:50 +0200 Subject: [PATCH 23/23] Disable test on coverage as well --- test/CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 4fde4a072f..809bc84722 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -828,7 +828,9 @@ if((NRN_ENABLE_NMODL OR NRN_ENABLE_CORENEURON) AND NRN_ENABLE_TESTS) endif() # Test nrnivmodl-cmake, but only without sanitizers since those cause issues, and end-users won't -# get builds with sanitizer builds anyway -if(NRN_ENABLE_TESTS AND NOT NRN_SANITIZERS) +# get builds with sanitizer builds anyway. The same reasoning applies to coverage. +if(NRN_ENABLE_TESTS + AND NOT NRN_SANITIZERS + AND NOT NRN_ENABLE_COVERAGE) add_subdirectory(nrnivmodl-cmake) endif()