# Add directory-level default compiler flags -- these should be added to all NEURON targets, but not # targets from included projects like CoreNEURON and NMODL add_compile_options(${NRN_COMPILE_FLAGS}) add_compile_definitions(${NRN_COMPILE_DEFS}) add_link_options(${NRN_LINK_FLAGS}) # ============================================================================= # Definitions used in setup.py # ============================================================================= set(NRN_SRCDIR ${PROJECT_SOURCE_DIR}) set(NRNPYTHON_DEFINES "") # ~~~ # If NRN_PYTHON_DYNAMIC then the following three will be determined from the # actual pyexe that runs setup.py # ~~~ set(NRNPYTHON_EXEC ${PYTHON_EXECUTABLE}) set(NRNPYTHON_PYVER ${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}) set(npy_pyver10 "") # reset since no " allowed set(PACKAGE_VERSION ${PROJECT_VERSION}) set(NRN_LIBDIR ${CMAKE_INSTALL_PREFIX}/lib) # set by IV's cmake module set(IV_LIBDIR "${IV_INCLUDE_DIR}/../lib") # no suffix for readline set(READLINE_SOSUFFIX "") if(NRN_ENABLE_RX3D) set(BUILD_RX3D "1") else() set(BUILD_RX3D "0") endif() if(NRN_ENABLE_INTERVIEWS) set(IVHINES "interviews") else() set(IVHINES "") endif() # use compiler from CMake set(CC ${CMAKE_C_COMPILER}) set(CXX ${CMAKE_CXX_COMPILER}) # ============================================================================= # Options that get expanded to comments # ============================================================================= set(BUILD_NRNMPI_DYNAMIC_FALSE "#") set(BUILD_NRNPYTHON_DYNAMIC_TRUE "") set(BUILD_NRNPYTHON_DYNAMIC_FALSE "#") if(NRN_ENABLE_PYTHON_DYNAMIC) if("${NRN_PYTHON_DYNAMIC}" STREQUAL "") set(NRN_PYTHON_EXE_LIST ${PYTHON_EXECUTABLE} CACHE INTERNAL "" FORCE) else() set(NRN_PYTHON_EXE_LIST ${NRN_PYTHON_DYNAMIC} CACHE INTERNAL "" FORCE) endif() else() set(BUILD_NRNPYTHON_DYNAMIC_TRUE "#") set(BUILD_NRNPYTHON_DYNAMIC_FALSE "") set(NRN_PYTHON_EXE_LIST ${PYTHON_EXECUTABLE} CACHE INTERNAL "" FORCE) endif() if(NRN_MACOS_BUILD) set(MAC_DARWIN_TRUE "") set(MAC_DARWIN_FALSE "#") else() set(MAC_DARWIN_TRUE "#") set(MAC_DARWIN_FALSE "") endif() if(NRN_WINDOWS_BUILD) set(BUILD_MINGW_TRUE "") set(BUILD_MINGW_FALSE "#") else() set(BUILD_MINGW_TRUE "#") set(BUILD_MINGW_FALSE "") endif() # rxdmath libraries (always build) add_library(rxdmath SHARED ${CMAKE_CURRENT_SOURCE_DIR}/rxdmath.cpp) install(TARGETS rxdmath DESTINATION ${NRN_INSTALL_SHARE_LIB_DIR}) # ============================================================================= # nrnpython libraries (one lib per python) # ============================================================================= set(nrnpython_lib_list) # user has selected dynamic python support (could be multiple versions) if(NRN_ENABLE_PYTHON_DYNAMIC) set(INCLUDE_DIRS . ../oc ../nrnoc ../ivoc ../nrniv ../ivos ../gnu ../mesch ../nrnmpi ${PROJECT_BINARY_DIR}/src/nrnpython ${PROJECT_BINARY_DIR}/src/ivos ${PROJECT_BINARY_DIR}/src/oc ${IV_INCLUDE_DIR}) if(LINK_AGAINST_PYTHON) list(LENGTH NRN_PYTHON_EXE_LIST _num_pythons) math(EXPR num_pythons "${_num_pythons} - 1") foreach(val RANGE ${num_pythons}) list(GET NRN_PYTHON_VER_LIST ${val} pyver) list(GET NRN_PYTHON_INCLUDE_LIST ${val} pyinc) list(GET NRN_PYTHON_LIB_LIST ${val} pylib) add_library(nrnpython${pyver} SHARED ${NRN_NRNPYTHON_SRC_FILES}) target_include_directories(nrnpython${pyver} BEFORE PUBLIC ${pyinc} ${INCLUDE_DIRS}) target_link_libraries(nrnpython${pyver} nrniv_lib ${pylib} ${Readline_LIBRARY}) add_dependencies(nrnpython${pyver} nrniv_lib) list(APPEND nrnpython_lib_list nrnpython${pyver}) install(TARGETS nrnpython${pyver} DESTINATION ${NRN_INSTALL_SHARE_LIB_DIR}) endforeach() else() # build python3 library and install it if(NRNPYTHON_INCLUDE3) add_library(nrnpython3 SHARED ${NRN_NRNPYTHON_SRC_FILES}) add_dependencies(nrnpython3 nrniv_lib) target_include_directories(nrnpython3 PRIVATE "${NRN_OC_GENERATED_SOURCES}") list(APPEND nrnpython_lib_list nrnpython3) target_include_directories(nrnpython3 BEFORE PUBLIC ${NRNPYTHON_INCLUDE3} ${INCLUDE_DIRS}) install(TARGETS nrnpython3 DESTINATION ${NRN_INSTALL_SHARE_LIB_DIR}) endif() endif() endif() # Install package files that were created in build (e.g. .py.in) install( DIRECTORY ${PROJECT_BINARY_DIR}/share/lib/python DESTINATION ${NRN_LIBDIR} FILES_MATCHING PATTERN *.py PATTERN *.so PATTERN *.dylib PATTERN *.dat) # ============================================================================= # If NEURON python module installation is enabled # ============================================================================= if(NRN_ENABLE_MODULE_INSTALL) # All variables are set, prepare setup.py for python module install nrn_configure_file(setup.py src/nrnpython) # Setup MinGW toolchain for setuptools if(MINGW) file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/setup.cfg "[build]\ncompiler=mingw32") # replace windows path of the form C:/msys64 to C:\msys64 string(REPLACE ":/" ":\\\\" module_install_opts "${NRN_MODULE_INSTALL_OPTIONS}") set(NRN_MODULE_INSTALL_OPTIONS "${module_install_opts}" CACHE INTERNAL "" FORCE) endif() # Here and for the neuron/rxd/geometry3d extensions, we build the neuron module in lib/python set(NRN_PYTHON_BUILD_LIB ${PROJECT_BINARY_DIR}/lib/python CACHE INTERNAL "" FORCE) # ~~~ # To tickle setup.py into actually rebuilding if dependencies change, # need to copy inithoc.cpp in from source to binary dir if any module # dependent changes and make a custom target as well. # ~~~ set(binary_dir_filename ${CMAKE_CURRENT_BINARY_DIR}/inithoc.cpp) set(source_dir_filename ${CMAKE_CURRENT_SOURCE_DIR}/inithoc.cpp) set(inithoc_hdeps ${CMAKE_CURRENT_SOURCE_DIR}/../oc/nrnmpi.h ${CMAKE_CURRENT_BINARY_DIR}/../oc/nrnmpiuse.h ${CMAKE_CURRENT_BINARY_DIR}/../oc/nrnpthread.h ${CMAKE_CURRENT_BINARY_DIR}/nrnpython_config.h) add_custom_command( OUTPUT ${binary_dir_filename} COMMAND cp ${source_dir_filename} ${binary_dir_filename} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DEPENDS ${source_dir_filename} ${CMAKE_CURRENT_BINARY_DIR}/setup.py ${inithoc_hdeps}) add_custom_target( hoc_module ALL WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} DEPENDS ${binary_dir_filename}) # ============================================================================= # Copy necessary files to build directory # ============================================================================= add_custom_command( TARGET hoc_module PRE_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/share/lib ${PROJECT_BINARY_DIR}/share/nrn/lib COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/share/demo ${PROJECT_BINARY_DIR}/share/nrn/demo) # Don't do exactly the same copy twice in a row. Presumably it's sometimes important to do both... if(NOT "${NRN_BUILD_SHARE_DIR}/lib" STREQUAL "${PROJECT_BINARY_DIR}/share/nrn/lib") add_custom_command( TARGET hoc_module PRE_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/share/lib ${NRN_BUILD_SHARE_DIR}/lib) endif() # ============================================================================= # Build python module # ============================================================================= # for each python detected / provided by user, install module at install time # Workaround for: https://github.com/neuronsimulator/nrn/issues/1605 See: # https://setuptools.pypa.io/en/latest/deprecated/distutils-legacy.html # https://setuptools.pypa.io/en/latest/history.html#id228 set(extra_env ${CMAKE_COMMAND} -E env "SETUPTOOLS_USE_DISTUTILS=stdlib") if(NRN_SANITIZERS) # Make sure the same compiler (currently always clang in the sanitizer builds) is used to link # as was used to build. By default, Python will try to use the compiler that was used to build # Python, which is often gcc. list(APPEND extra_env "LDCSHARED=${CMAKE_C_COMPILER} ${CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS}" "LDCXXSHARED=${CMAKE_CXX_COMPILER} ${CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS}") endif() foreach(pyexe ${NRN_PYTHON_EXE_LIST}) add_custom_command( TARGET hoc_module POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/inithoc.cpp ${CMAKE_CURRENT_BINARY_DIR}/inithoc.cpp COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_SOURCE_DIR}/share/lib/python/neuron/help_data.dat ${CMAKE_CURRENT_BINARY_DIR}/lib/python/neuron/help_data.dat COMMAND ${extra_env} ${pyexe} setup.py --quiet build --build-lib=${NRN_PYTHON_BUILD_LIB} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT "Building python module with: ${pyexe}") endforeach(pyexe) add_dependencies(hoc_module nrniv_lib ${nrnpython_lib_list}) if(NRN_ENABLE_RX3D) add_dependencies(hoc_module rxd_cython_generated) endif() # ~~~ # neuron module (possibly with multiple extension versions) was built # in NRN_PYTHON_BUILD_LIB. Not a problem if install overwrites multiple # times to same install folder or if each install ends up in different # place. # ~~~ file( WRITE ${CMAKE_CURRENT_BINARY_DIR}/neuron_module_install.sh "\ #!bash\n\ echo 'Installing python module using:'\n\ set -ex\n\ cd ${CMAKE_CURRENT_BINARY_DIR}\n\ export SETUPTOOLS_USE_DISTUTILS=stdlib $1 setup.py --quiet build --build-lib=${NRN_PYTHON_BUILD_LIB} install ${NRN_MODULE_INSTALL_OPTIONS}\n\ ") foreach(pyexe ${NRN_PYTHON_EXE_LIST}) # install(CODE ...) only takes a single CMake code expression, so we can't easily roll our own # check on the return code. Modern CMake versions support the COMMAND_ERROR_IS_FATAL option, # which will cause the installation to abort if the shell script returns an error code. if(${CMAKE_VERSION} VERSION_LESS "3.19") install( CODE "execute_process(COMMAND bash ${CMAKE_CURRENT_BINARY_DIR}/neuron_module_install.sh ${pyexe})" ) else() install( CODE "execute_process(COMMAND bash ${CMAKE_CURRENT_BINARY_DIR}/neuron_module_install.sh ${pyexe} COMMAND_ERROR_IS_FATAL LAST)" ) endif() endforeach(pyexe) endif()