1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
|
# =============================================================================
# Helper functions used in the project
# =============================================================================
include(CheckIncludeFileCXX)
include(CheckIncludeFiles)
include(CheckFunctionExists)
include(CheckSymbolExists)
include(CheckCXXSymbolExists)
include(CMakeParseArguments)
set(CMAKE_REQUIRED_QUIET TRUE)
# =============================================================================
# Check if directory related to DIR exists by compiling code
# =============================================================================
macro(nrn_check_dir_exists HEADER VARIABLE)
# code template to check existence of DIR
string(
CONCAT CONFTEST_DIR_TPL
"#include <sys/types.h>\n"
"#include <@dir_header@>\n"
"int main () {\n"
" if ((DIR *) 0)\n"
" return 0\;\n"
" return 0\;\n"
"}\n")
# first get header file
check_include_files(${HEADER} HAVE_HEADER)
if(${HAVE_HEADER})
# if header is found, create a code from template
string(REPLACE "@dir_header@" ${HEADER} CONFTEST_DIR "${CONFTEST_DIR_TPL}")
file(WRITE "${CMAKE_CURRENT_SOURCE_DIR}/conftest.cpp" ${CONFTEST_DIR})
# try to compile
try_compile(${VARIABLE} "${CMAKE_CURRENT_SOURCE_DIR}"
"${CMAKE_CURRENT_SOURCE_DIR}/conftest.cpp")
file(REMOVE "${CMAKE_CURRENT_SOURCE_DIR}/conftest.cpp")
endif()
endmacro()
# =============================================================================
# Check if given type exists by compiling code
# =============================================================================
macro(nrn_check_type_exists HEADER TYPE DEFAULT_TYPE VARIABLE)
# code template to check existence of specific type
string(
CONCAT CONFTEST_TYPE_TPL
"#include <@header@>\n"
"int main () {\n"
" if (sizeof (@type@))\n"
" return 0\;\n"
" return 0\;\n"
"}\n")
string(REPLACE "@header@" ${HEADER} CONFTEST_TYPE "${CONFTEST_TYPE_TPL}")
string(REPLACE "@type@" ${TYPE} CONFTEST_TYPE "${CONFTEST_TYPE}")
file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/conftest.cpp ${CONFTEST_TYPE})
try_compile(MY_RESULT_VAR ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/conftest.cpp)
if(NOT ${MY_RESULT_VAR})
set(${VARIABLE} ${DEFAULT_TYPE})
endif()
file(REMOVE "conftest.cpp")
endmacro()
# =============================================================================
# Check return type of signal
# =============================================================================
macro(nrn_check_signal_return_type VARIABLE)
# code template to check signal support
string(CONCAT CONFTEST_RETSIGTYPE "#include <sys/types.h>\n" "#include <signal.h>\n"
"int main () {\n" " return *(signal (0, 0)) (0) == 1\;\n" "}\n")
file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/conftest.cpp ${CONFTEST_RETSIGTYPE})
try_compile(MY_RESULT_VAR ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/conftest.cpp)
if(MY_RESULT_VAR)
set(${VARIABLE} int)
else()
set(${VARIABLE} void)
endif()
file(REMOVE "conftest.cpp")
endmacro()
# =============================================================================
# Transform PROJECT_SOURCE_DIR/sdir/sfile.in to PROJECT_BINARY_DIR/bdir/bfile
# =============================================================================
# ~~~
# This 4 arg macro transformsPROJECT_SOURCE_DIR/sdir/sfile.in into
# PROJECT_BINARY_DIR/bdir/bfile .
# THE shorter two arg form transforms PROJECT_SOURCE_DIR/dir/file.in into
# PROJECT_BINARY_DIR/dir/file
# This first copies with some replacement the sfile.in to _cmake_tmp_bfile.in
# so that the normal cmake configure_file command works to make a proper
# cmake_file. Then that is compared to a possibly existing bfile and,
# if different, copies _cmake_tmp_bfile to bfile. This prevents recompilation of
# .o files that depend on unchanged bfile. The sdir arg is the path relative to
# PROJECT_SOURCE_DIR, the bdir arg is the path relative to PROJECT_BINARY_DIR.
# Note that everytime cmake is run, the bfile is compared to a newly created
# _cmake_tmp_bfile consistent with the current cmake args.
# Note that the sfile arg does NOT contain the .in suffix.
# ~~~
macro(nrn_configure_dest_src bfile bdir sfile sdir)
set(infile ${PROJECT_SOURCE_DIR}/${sdir}/${sfile}.in)
set(bin_dir ${PROJECT_BINARY_DIR}/${bdir})
file(MAKE_DIRECTORY ${bin_dir})
execute_process(
COMMAND sed "s/\#undef *\\(.*\\)/\#cmakedefine \\1 @\\1@/"
INPUT_FILE ${infile}
OUTPUT_FILE ${bin_dir}/_cmake_tmp_${bfile}.in)
configure_file(${bin_dir}/_cmake_tmp_${bfile}.in ${bin_dir}/_cmake_tmp_${bfile} @ONLY)
execute_process(COMMAND cmp -s ${bin_dir}/_cmake_tmp_${bfile} ${bin_dir}/${bfile}
RESULT_VARIABLE result)
if(result EQUAL 0)
file(REMOVE ${bin_dir}/_cmake_tmp_${bfile})
else()
file(RENAME ${bin_dir}/_cmake_tmp_${bfile} ${bin_dir}/${bfile})
endif()
file(REMOVE ${bin_dir}/_cmake_tmp_${bfile}.in)
set_property(
DIRECTORY
APPEND
PROPERTY CMAKE_CONFIGURE_DEPENDS ${infile})
endmacro()
macro(nrn_configure_file file dir)
nrn_configure_dest_src(${file} ${dir} ${file} ${dir})
endmacro()
# =============================================================================
# Perform check_include_files and add it to NRN_HEADERS_INCLUDE_LIST if exist Passing an optional
# CXX will call check_include_files_cxx instead.
# =============================================================================
macro(nrn_check_include_files filename variable)
set(options CXX)
cmake_parse_arguments(nrn_check_include_files "${options}" "" "" ${ARGN})
if(${nrn_check_include_files_CXX})
check_include_file_cxx(${filename} ${variable})
else()
check_include_files(${filename} ${variable})
endif()
if(${variable})
list(APPEND NRN_HEADERS_INCLUDE_LIST ${filename})
endif()
endmacro()
# =============================================================================
# Perform check_symbol_exists using NRN_HEADERS_INCLUDE_LIST if empty header_list
# =============================================================================
macro(nrn_check_symbol_exists name header_list variable)
if("${header_list}" STREQUAL "")
check_symbol_exists("${name}" "${NRN_HEADERS_INCLUDE_LIST}" ${variable})
else()
check_symbol_exists("${name}" "${header_list}" ${variable})
endif()
endmacro()
# =============================================================================
# Perform check_cxx_symbol_exists using NRN_HEADERS_INCLUDE_LIST if empty header_list
# =============================================================================
# note that sometimes, though it should have succeeded, cc fails but c++ succeeds
macro(nrn_check_cxx_symbol_exists name header_list variable)
if("${header_list}" STREQUAL "")
check_cxx_symbol_exists("${name}" "${NRN_HEADERS_INCLUDE_LIST}" ${variable})
else()
check_cxx_symbol_exists("${name}" "${header_list}" ${variable})
endif()
endmacro()
# =============================================================================
# Append arguments to given list in the form of prefix/argument
# =============================================================================
macro(nrn_create_file_list list_name prefix)
foreach(name ${ARGN})
list(APPEND ${list_name} ${prefix}/${name})
endforeach(name)
endmacro()
# =============================================================================
# Copy file from source to destination in noclobber mode (i.e. no overwrite)
# =============================================================================
macro(nrn_copy_file_without_overwrite source destination)
execute_process(COMMAND cp -n ${source} ${destination})
endmacro()
# =============================================================================
# Copy file from source to destination only if different
# =============================================================================
macro(nrn_copy_file_if_different source destination)
configure_file(${source} ${destination} COPYONLY)
endmacro()
# =============================================================================
# Set string with double quotes
# =============================================================================
macro(nrn_set_string variable value)
set(${variable} \"${value}\")
endmacro()
# =============================================================================
# Set var to to dos path format
# =============================================================================
macro(dospath path var)
# file(TO_NATIVE_PATH does not convert / to \ for us in msys2.
string(REPLACE "/" "\\" var1 "${path}")
set(${var} ${var1})
endmacro()
# =============================================================================
# Given list of file names, find their path in project source tree
# =============================================================================
macro(nrn_find_project_files list_name)
foreach(name ${ARGN})
file(GLOB_RECURSE filepath "${PROJECT_SOURCE_DIR}/src/*${name}")
if(filepath STREQUAL "")
message(FATAL_ERROR " ${name} not found in ${PROJECT_SOURCE_DIR}/src")
else()
list(APPEND ${list_name} ${filepath})
endif()
endforeach(name)
endmacro()
# =============================================================================
# Utility macro to print all matching CMake variables
# =============================================================================
# example usage : nrn_print_matching_variables("[Mm][Pp][Ii]")
macro(nrn_print_matching_variables prefix_regex)
get_cmake_property(variable_names VARIABLES)
list(SORT variable_names)
foreach(variable ${variable_names})
if(variable MATCHES "^${prefix_regex}")
message(NOTICE " ${variable} ${${variable}}")
endif()
endforeach()
endmacro()
# =============================================================================
# Run nocmodl to convert NMODL to C
# =============================================================================
macro(nocmodl_mod_to_c modfile_basename)
add_custom_command(
OUTPUT ${modfile_basename}.c
COMMAND
${CMAKE_COMMAND} -E env "MODLUNIT=${PROJECT_BINARY_DIR}/share/nrn/lib/nrnunits.lib"
${NRN_NOCMODL_SANITIZER_ENVIRONMENT} ${PROJECT_BINARY_DIR}/bin/nocmodl ${modfile_basename}.mod
COMMAND sed "'s/_reg()/_reg_()/'" ${modfile_basename}.c > ${modfile_basename}.c.tmp
COMMAND mv ${modfile_basename}.c.tmp ${modfile_basename}.c
DEPENDS nocmodl ${modfile_basename}.mod
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/src/nrniv)
endmacro()
# =============================================================================
# Create symbolic links
# =============================================================================
macro(nrn_install_dir_symlink source_dir symlink_dir)
# make sure to have directory path exist upto parent dir
get_filename_component(parent_symlink_dir ${symlink_dir} DIRECTORY)
install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${parent_symlink_dir})")
# create symbolic link
install(
CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink ${source_dir} ${symlink_dir})")
endmacro(nrn_install_dir_symlink)
# ========================================================================
# There is an edge case to 'find_package(MPI REQUIRED)' in that we can still build a universal2
# macos package on an arm64 architecture even if the mpi library has no slice for x86_64.
# ========================================================================
macro(nrn_mpi_find_package)
if("arm64" IN_LIST CMAKE_OSX_ARCHITECTURES
AND "x86_64" IN_LIST CMAKE_OSX_ARCHITECTURES
AND NRN_ENABLE_MPI_DYNAMIC)
set(_temp ${CMAKE_OSX_ARCHITECTURES})
unset(CMAKE_OSX_ARCHITECTURES CACHE)
find_package(MPI REQUIRED)
set(CMAKE_OSX_ARCHITECTURES
${_temp}
CACHE INTERNAL "" FORCE)
set(NRN_UNIVERSAL2_BUILD ON)
else()
find_package(MPI REQUIRED)
endif()
endmacro()
|