Skip to content

Commit

Permalink
cmake: export targets, allow to build models via CMake
Browse files Browse the repository at this point in the history
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‥
  • Loading branch information
matz-e committed May 17, 2024
1 parent 30b42a1 commit c210d77
Show file tree
Hide file tree
Showing 9 changed files with 236 additions and 23 deletions.
21 changes: 21 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,9 @@ endif()
# initialize CLI11 submodule
cpp_cc_git_submodule(CLI11 BUILD PACKAGE CLI11 REQUIRED)

# coreneuron targets will get appended here
set(NRN_INSTALL_TARGETS nrniv_lib)

# =============================================================================
# Enable CoreNEURON support
# =============================================================================
Expand Down Expand Up @@ -896,6 +899,24 @@ 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/mod_reg_nrn.cpp.in
${CMAKE_CURRENT_SOURCE_DIR}/cmake/mod_reg_corenrn.cpp.in DESTINATION share/nrn)

# =============================================================================
# Copy bash executable for windows
# =============================================================================
Expand Down
16 changes: 16 additions & 0 deletions cmake/mod_reg_corenrn.cpp.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#include <cstdio>
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
16 changes: 16 additions & 0 deletions cmake/mod_reg_nrn.cpp.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#include <stdio.h>
#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@
}

128 changes: 128 additions & 0 deletions cmake/neuronConfig.cmake.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
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(NOCMODL nocmodl REQUIRED)
find_program(NMODL nmodl REQUIRED)

function(merge_modfile_lists)
cmake_parse_arguments(MERGE_MODS "" "" "MOD_FILES" ${ARGN})
endfunction()

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(CORE "")
set(INPUT_MAIN ${_NEURON_MAIN})
set(INPUT_MECH_REG ${_NEURON_MECH_REG})
set(RETURN_TYPE "\"C\" void")
set(TRANSPILER "${NOCMODL}")

if(NRN_MECH_CORENEURON)
if(NOT NRN_ENABLE_CORENEURON)
message(FATAL_ERROR "CoreNEURON support not enabled")
endif()
set(CORE "core")
set(INPUT_MAIN ${_CORENEURON_MAIN})
set(INPUT_MECH_REG ${_CORENEURON_MECH_REG})
set(RETURN_TYPE "int")
set(TRANSPILER "${NMODL}")
endif()

set(OUTDIR "${CORE}neuron")
set(LIBNAME "${CORE}nrnmech")
set(EXENAME "${CORE}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()

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()
endif()

foreach(MOD_FILE IN LISTS MOD_FILES)
# set(MOD_FILE common/mod/DetAMPANMDA.mod)
get_filename_component(MOD_STUB "${MOD_FILE}" NAME_WLE)
set(CPP_FILE "cpp/${OUTDIR}/${MOD_STUB}.cpp")

list(APPEND L_MECH_DECLARE "extern ${RETURN_TYPE} _${MOD_STUB}_reg(void)\;")
list(APPEND L_MECH_PRINT "fprintf(stderr, \" \\\"${MOD_FILE}\\\"\")\;")
list(APPEND L_MECH_REGISTRE "_${MOD_STUB}_reg()\;")

add_custom_command(COMMAND "${TRANSPILER}" -o "${CMAKE_CURRENT_BINARY_DIR}/cpp/${OUTDIR}"
"${MOD_FILE}" OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${CPP_FILE}")

list(APPEND L_SOURCES "${CMAKE_CURRENT_BINARY_DIR}/${CPP_FILE}")
endforeach()

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 "${INPUT_MECH_REG}" NAME_WLE)
configure_file(${INPUT_MECH_REG} ${MECH_REG} @ONLY)

if(NRN_MECH_CORENEURON)
add_library(${LIBNAME} SHARED ${_CORENEURON_MECH_ENG} ${L_SOURCES})
target_include_directories(${LIBNAME} PRIVATE ${_CORENEURON_RANDOM_INCLUDE})
target_compile_definitions(${LIBNAME} PRIVATE ADDITIONAL_MECHS NRN_PRCELLSTATE=0
CORENEURON_BUILD)
target_compile_definitions(${LIBNAME} PRIVATE "${_CORENEURON_FLAGS}")
target_link_libraries(${LIBNAME} PUBLIC neuron::corenrn)
else()
add_library(${LIBNAME} SHARED ${L_SOURCES})
target_link_libraries(${LIBNAME} PUBLIC neuron::nrniv)
endif()

if(NRN_MECH_INSTALL_CPP)
install(FILES ${L_SOURCES} DESTINATION "share/${LIBNAME}$<$<BOOL:${NRN_MECH_MECHANISM_NAME}>:_${NRN_MECH_MECHANISM_NAME}>/cpp")
endif()

if(NRN_MECH_INSTALL_MOD)
install(FILES ${MOD_FILES} DESTINATION "share/${LIBNAME}$<$<BOOL:${NRN_MECH_MECHANISM_NAME}>:_${NRN_MECH_MECHANISM_NAME}>/mod")
endif()

install(TARGETS ${LIBNAME} DESTINATION lib)
set_target_properties(${LIBNAME} PROPERTIES OUTPUT_NAME "${LIBNAME}$<$<BOOL:${NRN_MECH_MECHANISM_NAME}>:_${NRN_MECH_MECHANISM_NAME}>")

if(NRN_MECH_SPECIAL)
add_executable(${EXENAME} ${INPUT_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$<$<BOOL:${NRN_MECH_CORENEURON}>:-core>")
install(TARGETS ${EXENAME} DESTINATION bin)
endif()
endfunction()
9 changes: 9 additions & 0 deletions src/coreneuron/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -479,10 +479,16 @@ 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(APPEND CORENRN_INSTALL_TARGETS coreneuron-cuda)
endif()

foreach(target coreneuron-core ${coreneuron_cuda_target})
Expand Down Expand Up @@ -561,6 +567,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 $<INSTALL_INTERFACE:include>)

# 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.
Expand Down
2 changes: 1 addition & 1 deletion src/ivoc/nrnmain.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include "nrnconf.h"
#include "nrnmpi.h"
#include "../nrncvode/nrnneosm.h"
#include "nrnneosm.h"

#include <errno.h>
#include <stdio.h>
Expand Down
45 changes: 25 additions & 20 deletions src/nrniv/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -399,43 +399,48 @@ 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_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)
# 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 $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/${NRN_3RDPARTY_DIR}/eigen>)
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 PRIVATE "${NRN_OC_GEN}")
target_include_directories(nrniv_lib INTERFACE $<INSTALL_INTERFACE:include>)
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
Expand Down Expand Up @@ -480,16 +485,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 PRIVATE ${NRN_IVOS_SRC_DIR})
endif()

if(IV_ENABLE_X11_DYNAMIC)
Expand Down Expand Up @@ -520,11 +525,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()
Expand All @@ -542,7 +547,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
Expand Down
4 changes: 2 additions & 2 deletions src/nrnoc/hh.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down Expand Up @@ -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)
Expand Down
18 changes: 18 additions & 0 deletions src/nrnpython/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,24 @@ 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)
Expand Down

0 comments on commit c210d77

Please sign in to comment.