utils.cmake 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  1. ################################################################################################
  2. # Exclude and prepend functionalities
  3. function(exclude OUTPUT INPUT)
  4. set(EXCLUDES ${ARGN})
  5. foreach(EXCLUDE ${EXCLUDES})
  6. list(REMOVE_ITEM INPUT "${EXCLUDE}")
  7. endforeach()
  8. set(${OUTPUT} ${INPUT} PARENT_SCOPE)
  9. endfunction(exclude)
  10. function(prepend OUTPUT PREPEND)
  11. set(OUT "")
  12. foreach(ITEM ${ARGN})
  13. list(APPEND OUT "${PREPEND}${ITEM}")
  14. endforeach()
  15. set(${OUTPUT} ${OUT} PARENT_SCOPE)
  16. endfunction(prepend)
  17. ################################################################################################
  18. # Clears variables from list
  19. # Usage:
  20. # caffe_clear_vars(<variables_list>)
  21. macro(caffe_clear_vars)
  22. foreach(_var ${ARGN})
  23. unset(${_var})
  24. endforeach()
  25. endmacro()
  26. ################################################################################################
  27. # Prints list element per line
  28. # Usage:
  29. # caffe_print_list(<list>)
  30. function(caffe_print_list)
  31. foreach(e ${ARGN})
  32. message(STATUS ${e})
  33. endforeach()
  34. endfunction()
  35. ################################################################################################
  36. # Reads set of version defines from the header file
  37. # Usage:
  38. # caffe_parse_header(<file> <define1> <define2> <define3> ..)
  39. macro(caffe_parse_header FILENAME FILE_VAR)
  40. set(vars_regex "")
  41. set(__parnet_scope OFF)
  42. set(__add_cache OFF)
  43. foreach(name ${ARGN})
  44. if("${name}" STREQUAL "PARENT_SCOPE")
  45. set(__parnet_scope ON)
  46. elseif("${name}" STREQUAL "CACHE")
  47. set(__add_cache ON)
  48. elseif(vars_regex)
  49. set(vars_regex "${vars_regex}|${name}")
  50. else()
  51. set(vars_regex "${name}")
  52. endif()
  53. endforeach()
  54. if(EXISTS "${FILENAME}")
  55. file(STRINGS "${FILENAME}" ${FILE_VAR} REGEX "#define[ \t]+(${vars_regex})[ \t]+[0-9]+" )
  56. else()
  57. unset(${FILE_VAR})
  58. endif()
  59. foreach(name ${ARGN})
  60. if(NOT "${name}" STREQUAL "PARENT_SCOPE" AND NOT "${name}" STREQUAL "CACHE")
  61. if(${FILE_VAR})
  62. if(${FILE_VAR} MATCHES ".+[ \t]${name}[ \t]+([0-9]+).*")
  63. string(REGEX REPLACE ".+[ \t]${name}[ \t]+([0-9]+).*" "\\1" ${name} "${${FILE_VAR}}")
  64. else()
  65. set(${name} "")
  66. endif()
  67. if(__add_cache)
  68. set(${name} ${${name}} CACHE INTERNAL "${name} parsed from ${FILENAME}" FORCE)
  69. elseif(__parnet_scope)
  70. set(${name} "${${name}}" PARENT_SCOPE)
  71. endif()
  72. else()
  73. unset(${name} CACHE)
  74. endif()
  75. endif()
  76. endforeach()
  77. endmacro()
  78. ################################################################################################
  79. # Parses a version string that might have values beyond major, minor, and patch
  80. # and set version variables for the library.
  81. # Usage:
  82. # caffe2_parse_version_str(<library_name> <version_string>)
  83. function(caffe2_parse_version_str LIBNAME VERSIONSTR)
  84. string(REGEX REPLACE "^([0-9]+).*$" "\\1" ${LIBNAME}_VERSION_MAJOR "${VERSIONSTR}")
  85. string(REGEX REPLACE "^[0-9]+\\.([0-9]+).*$" "\\1" ${LIBNAME}_VERSION_MINOR "${VERSIONSTR}")
  86. string(REGEX REPLACE "[0-9]+\\.[0-9]+\\.([0-9]+).*$" "\\1" ${LIBNAME}_VERSION_PATCH "${VERSIONSTR}")
  87. set(${LIBNAME}_VERSION_MAJOR ${${LIBNAME}_VERSION_MAJOR} ${ARGN} PARENT_SCOPE)
  88. set(${LIBNAME}_VERSION_MINOR ${${LIBNAME}_VERSION_MINOR} ${ARGN} PARENT_SCOPE)
  89. set(${LIBNAME}_VERSION_PATCH ${${LIBNAME}_VERSION_PATCH} ${ARGN} PARENT_SCOPE)
  90. set(${LIBNAME}_VERSION "${${LIBNAME}_VERSION_MAJOR}.${${LIBNAME}_VERSION_MINOR}.${${LIBNAME}_VERSION_PATCH}" PARENT_SCOPE)
  91. endfunction()
  92. ###
  93. # Removes common indentation from a block of text to produce code suitable for
  94. # setting to `python -c`, or using with pycmd. This allows multiline code to be
  95. # nested nicely in the surrounding code structure.
  96. #
  97. # This function respsects PYTHON_EXECUTABLE if it defined, otherwise it uses
  98. # `python` and hopes for the best. An error will be thrown if it is not found.
  99. #
  100. # Args:
  101. # outvar : variable that will hold the stdout of the python command
  102. # text : text to remove indentation from
  103. #
  104. function(dedent outvar text)
  105. # Use PYTHON_EXECUTABLE if it is defined, otherwise default to python
  106. if("${PYTHON_EXECUTABLE}" STREQUAL "")
  107. set(_python_exe "python")
  108. else()
  109. set(_python_exe "${PYTHON_EXECUTABLE}")
  110. endif()
  111. set(_fixup_cmd "import sys; from textwrap import dedent; print(dedent(sys.stdin.read()))")
  112. file(WRITE "${CMAKE_BINARY_DIR}/indented.txt" "${text}")
  113. execute_process(
  114. COMMAND "${_python_exe}" -c "${_fixup_cmd}"
  115. INPUT_FILE "${CMAKE_BINARY_DIR}/indented.txt"
  116. RESULT_VARIABLE _dedent_exitcode
  117. OUTPUT_VARIABLE _dedent_text)
  118. if(NOT _dedent_exitcode EQUAL 0)
  119. message(ERROR " Failed to remove indentation from: \n\"\"\"\n${text}\n\"\"\"
  120. Python dedent failed with error code: ${_dedent_exitcode}")
  121. message(FATAL_ERROR " Python dedent failed with error code: ${_dedent_exitcode}")
  122. endif()
  123. # Remove supurflous newlines (artifacts of print)
  124. string(STRIP "${_dedent_text}" _dedent_text)
  125. set(${outvar} "${_dedent_text}" PARENT_SCOPE)
  126. endfunction()
  127. function(pycmd_no_exit outvar exitcode cmd)
  128. # Use PYTHON_EXECUTABLE if it is defined, otherwise default to python
  129. if("${PYTHON_EXECUTABLE}" STREQUAL "")
  130. set(_python_exe "python")
  131. else()
  132. set(_python_exe "${PYTHON_EXECUTABLE}")
  133. endif()
  134. # run the actual command
  135. execute_process(
  136. COMMAND "${_python_exe}" -c "${cmd}"
  137. RESULT_VARIABLE _exitcode
  138. OUTPUT_VARIABLE _output)
  139. # Remove supurflous newlines (artifacts of print)
  140. string(STRIP "${_output}" _output)
  141. set(${outvar} "${_output}" PARENT_SCOPE)
  142. set(${exitcode} "${_exitcode}" PARENT_SCOPE)
  143. endfunction()
  144. ###
  145. # Helper function to run `python -c "<cmd>"` and capture the results of stdout
  146. #
  147. # Runs a python command and populates an outvar with the result of stdout.
  148. # Common indentation in the text of `cmd` is removed before the command is
  149. # executed, so the caller does not need to worry about indentation issues.
  150. #
  151. # This function respsects PYTHON_EXECUTABLE if it defined, otherwise it uses
  152. # `python` and hopes for the best. An error will be thrown if it is not found.
  153. #
  154. # Args:
  155. # outvar : variable that will hold the stdout of the python command
  156. # cmd : text representing a (possibly multiline) block of python code
  157. #
  158. function(pycmd outvar cmd)
  159. dedent(_dedent_cmd "${cmd}")
  160. pycmd_no_exit(_output _exitcode "${_dedent_cmd}")
  161. if(NOT _exitcode EQUAL 0)
  162. message(ERROR " Failed when running python code: \"\"\"\n${_dedent_cmd}\n\"\"\"")
  163. message(FATAL_ERROR " Python command failed with error code: ${_exitcode}")
  164. endif()
  165. # Remove supurflous newlines (artifacts of print)
  166. string(STRIP "${_output}" _output)
  167. set(${outvar} "${_output}" PARENT_SCOPE)
  168. endfunction()
  169. ##############################################################################
  170. # Macro to update cached options.
  171. macro(caffe2_update_option variable value)
  172. if(CAFFE2_CMAKE_BUILDING_WITH_MAIN_REPO)
  173. get_property(__help_string CACHE ${variable} PROPERTY HELPSTRING)
  174. set(${variable} ${value} CACHE BOOL ${__help_string} FORCE)
  175. else()
  176. set(${variable} ${value})
  177. endif()
  178. endmacro()
  179. ##############################################################################
  180. # Add an interface library definition that is dependent on the source.
  181. #
  182. # It's probably easiest to explain why this macro exists, by describing
  183. # what things would look like if we didn't have this macro.
  184. #
  185. # Let's suppose we want to statically link against torch. We've defined
  186. # a library in cmake called torch, and we might think that we just
  187. # target_link_libraries(my-app PUBLIC torch). This will result in a
  188. # linker argument 'libtorch.a' getting passed to the linker.
  189. #
  190. # Unfortunately, this link command is wrong! We have static
  191. # initializers in libtorch.a that would get improperly pruned by
  192. # the default link settings. What we actually need is for you
  193. # to do -Wl,--whole-archive,libtorch.a -Wl,--no-whole-archive to ensure
  194. # that we keep all symbols, even if they are (seemingly) not used.
  195. #
  196. # What caffe2_interface_library does is create an interface library
  197. # that indirectly depends on the real library, but sets up the link
  198. # arguments so that you get all of the extra link settings you need.
  199. # The result is not a "real" library, and so we have to manually
  200. # copy over necessary properties from the original target.
  201. #
  202. # (The discussion above is about static libraries, but a similar
  203. # situation occurs for dynamic libraries: if no symbols are used from
  204. # a dynamic library, it will be pruned unless you are --no-as-needed)
  205. macro(caffe2_interface_library SRC DST)
  206. add_library(${DST} INTERFACE)
  207. add_dependencies(${DST} ${SRC})
  208. # Depending on the nature of the source library as well as the compiler,
  209. # determine the needed compilation flags.
  210. get_target_property(__src_target_type ${SRC} TYPE)
  211. # Depending on the type of the source library, we will set up the
  212. # link command for the specific SRC library.
  213. if(${__src_target_type} STREQUAL "STATIC_LIBRARY")
  214. # In the case of static library, we will need to add whole-static flags.
  215. if(APPLE)
  216. target_link_libraries(
  217. ${DST} INTERFACE -Wl,-force_load,\"$<TARGET_FILE:${SRC}>\")
  218. elseif(MSVC)
  219. # In MSVC, we will add whole archive in default.
  220. target_link_libraries(
  221. ${DST} INTERFACE "$<TARGET_FILE:${SRC}>")
  222. target_link_options(
  223. ${DST} INTERFACE "-WHOLEARCHIVE:$<TARGET_FILE:${SRC}>")
  224. else()
  225. # Assume everything else is like gcc
  226. target_link_libraries(${DST} INTERFACE
  227. "-Wl,--whole-archive,\"$<TARGET_FILE:${SRC}>\" -Wl,--no-whole-archive")
  228. endif()
  229. # Link all interface link libraries of the src target as well.
  230. # For static library, we need to explicitly depend on all the libraries
  231. # that are the dependent library of the source library. Note that we cannot
  232. # use the populated INTERFACE_LINK_LIBRARIES property, because if one of the
  233. # dependent library is not a target, cmake creates a $<LINK_ONLY:src> wrapper
  234. # and then one is not able to find target "src". For more discussions, check
  235. # https://gitlab.kitware.com/cmake/cmake/issues/15415
  236. # https://cmake.org/pipermail/cmake-developers/2013-May/019019.html
  237. # Specifically the following quote
  238. #
  239. # """
  240. # For STATIC libraries we can define that the PUBLIC/PRIVATE/INTERFACE keys
  241. # are ignored for linking and that it always populates both LINK_LIBRARIES
  242. # LINK_INTERFACE_LIBRARIES. Note that for STATIC libraries the
  243. # LINK_LIBRARIES property will not be used for anything except build-order
  244. # dependencies.
  245. # """
  246. target_link_libraries(${DST} INTERFACE
  247. $<TARGET_PROPERTY:${SRC},LINK_LIBRARIES>)
  248. elseif(${__src_target_type} STREQUAL "SHARED_LIBRARY")
  249. if("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
  250. target_link_libraries(${DST} INTERFACE
  251. "-Wl,--no-as-needed,\"$<TARGET_FILE:${SRC}>\" -Wl,--as-needed")
  252. else()
  253. target_link_libraries(${DST} INTERFACE ${SRC})
  254. endif()
  255. # Link all interface link libraries of the src target as well.
  256. # For shared libraries, we can simply depend on the INTERFACE_LINK_LIBRARIES
  257. # property of the target.
  258. target_link_libraries(${DST} INTERFACE
  259. $<TARGET_PROPERTY:${SRC},INTERFACE_LINK_LIBRARIES>)
  260. else()
  261. message(FATAL_ERROR
  262. "You made a CMake build file error: target " ${SRC}
  263. " must be of type either STATIC_LIBRARY or SHARED_LIBRARY. However, "
  264. "I got " ${__src_target_type} ".")
  265. endif()
  266. # For all other interface properties, manually inherit from the source target.
  267. set_target_properties(${DST} PROPERTIES
  268. INTERFACE_COMPILE_DEFINITIONS
  269. $<TARGET_PROPERTY:${SRC},INTERFACE_COMPILE_DEFINITIONS>
  270. INTERFACE_COMPILE_OPTIONS
  271. $<TARGET_PROPERTY:${SRC},INTERFACE_COMPILE_OPTIONS>
  272. INTERFACE_INCLUDE_DIRECTORIES
  273. $<TARGET_PROPERTY:${SRC},INTERFACE_INCLUDE_DIRECTORIES>
  274. INTERFACE_SYSTEM_INCLUDE_DIRECTORIES
  275. $<TARGET_PROPERTY:${SRC},INTERFACE_SYSTEM_INCLUDE_DIRECTORIES>)
  276. endmacro()
  277. ##############################################################################
  278. # Creating a Caffe2 binary target with sources specified with relative path.
  279. # Usage:
  280. # caffe2_binary_target(target_name_or_src <src1> [<src2>] [<src3>] ...)
  281. # If only target_name_or_src is specified, this target is build with one single
  282. # source file and the target name is autogen from the filename. Otherwise, the
  283. # target name is given by the first argument and the rest are the source files
  284. # to build the target.
  285. function(caffe2_binary_target target_name_or_src)
  286. # https://cmake.org/cmake/help/latest/command/function.html
  287. # Checking that ARGC is greater than # is the only way to ensure
  288. # that ARGV# was passed to the function as an extra argument.
  289. if(ARGC GREATER 1)
  290. set(__target ${target_name_or_src})
  291. prepend(__srcs "${CMAKE_CURRENT_SOURCE_DIR}/" "${ARGN}")
  292. else()
  293. get_filename_component(__target ${target_name_or_src} NAME_WE)
  294. prepend(__srcs "${CMAKE_CURRENT_SOURCE_DIR}/" "${target_name_or_src}")
  295. endif()
  296. add_executable(${__target} ${__srcs})
  297. target_link_libraries(${__target} torch_library)
  298. # If we have Caffe2_MODULES defined, we will also link with the modules.
  299. if(DEFINED Caffe2_MODULES)
  300. target_link_libraries(${__target} ${Caffe2_MODULES})
  301. endif()
  302. if(USE_TBB AND NOT USE_SYSTEM_TBB)
  303. target_include_directories(${__target} PUBLIC ${TBB_INCLUDE_DIR})
  304. endif()
  305. install(TARGETS ${__target} DESTINATION bin)
  306. endfunction()
  307. function(caffe2_hip_binary_target target_name_or_src)
  308. if(ARGC GREATER 1)
  309. set(__target ${target_name_or_src})
  310. prepend(__srcs "${CMAKE_CURRENT_SOURCE_DIR}/" "${ARGN}")
  311. else()
  312. get_filename_component(__target ${target_name_or_src} NAME_WE)
  313. prepend(__srcs "${CMAKE_CURRENT_SOURCE_DIR}/" "${target_name_or_src}")
  314. endif()
  315. caffe2_binary_target(${target_name_or_src})
  316. target_compile_options(${__target} PRIVATE ${HIP_CXX_FLAGS})
  317. target_include_directories(${__target} PRIVATE ${Caffe2_HIP_INCLUDE})
  318. endfunction()
  319. ##############################################################################
  320. # Multiplex between adding libraries for CUDA versus HIP (AMD Software Stack).
  321. # Usage:
  322. # torch_cuda_based_add_library(cuda_target)
  323. #
  324. macro(torch_cuda_based_add_library cuda_target)
  325. if(USE_ROCM)
  326. hip_add_library(${cuda_target} ${ARGN})
  327. elseif(USE_CUDA)
  328. add_library(${cuda_target} ${ARGN})
  329. else()
  330. endif()
  331. endmacro()
  332. ##############################################################################
  333. # Get the HIP arch flags specified by PYTORCH_ROCM_ARCH.
  334. # Usage:
  335. # torch_hip_get_arch_list(variable_to_store_flags)
  336. #
  337. macro(torch_hip_get_arch_list store_var)
  338. if(DEFINED ENV{PYTORCH_ROCM_ARCH})
  339. set(_TMP $ENV{PYTORCH_ROCM_ARCH})
  340. else()
  341. # Use arch of installed GPUs as default
  342. execute_process(COMMAND "rocm_agent_enumerator" COMMAND bash "-c" "grep -v gfx000 | sort -u | xargs | tr -d '\n'"
  343. RESULT_VARIABLE ROCM_AGENT_ENUMERATOR_RESULT
  344. OUTPUT_VARIABLE ROCM_ARCH_INSTALLED)
  345. if(NOT ROCM_AGENT_ENUMERATOR_RESULT EQUAL 0)
  346. message(FATAL_ERROR " Could not detect ROCm arch for GPUs on machine. Result: '${ROCM_AGENT_ENUMERATOR_RESULT}'")
  347. endif()
  348. set(_TMP ${ROCM_ARCH_INSTALLED})
  349. endif()
  350. string(REPLACE " " ";" ${store_var} "${_TMP}")
  351. endmacro()
  352. ##############################################################################
  353. # Get the NVCC arch flags specified by TORCH_CUDA_ARCH_LIST and CUDA_ARCH_NAME.
  354. # Usage:
  355. # torch_cuda_get_nvcc_gencode_flag(variable_to_store_flags)
  356. #
  357. macro(torch_cuda_get_nvcc_gencode_flag store_var)
  358. # setting nvcc arch flags
  359. if((NOT EXISTS ${TORCH_CUDA_ARCH_LIST}) AND (DEFINED ENV{TORCH_CUDA_ARCH_LIST}))
  360. message(WARNING
  361. "In the future we will require one to explicitly pass "
  362. "TORCH_CUDA_ARCH_LIST to cmake instead of implicitly setting it as an "
  363. "env variable. This will become a FATAL_ERROR in future version of "
  364. "pytorch.")
  365. set(TORCH_CUDA_ARCH_LIST $ENV{TORCH_CUDA_ARCH_LIST})
  366. endif()
  367. if(EXISTS ${CUDA_ARCH_NAME})
  368. message(WARNING
  369. "CUDA_ARCH_NAME is no longer used. Use TORCH_CUDA_ARCH_LIST instead. "
  370. "Right now, CUDA_ARCH_NAME is ${CUDA_ARCH_NAME} and "
  371. "TORCH_CUDA_ARCH_LIST is ${TORCH_CUDA_ARCH_LIST}.")
  372. set(TORCH_CUDA_ARCH_LIST TORCH_CUDA_ARCH_LIST ${CUDA_ARCH_NAME})
  373. endif()
  374. # Invoke cuda_select_nvcc_arch_flags from proper cmake FindCUDA.
  375. cuda_select_nvcc_arch_flags(${store_var} ${TORCH_CUDA_ARCH_LIST})
  376. endmacro()
  377. ##############################################################################
  378. # Add standard compile options.
  379. # Usage:
  380. # torch_compile_options(lib_name)
  381. function(torch_compile_options libname)
  382. set_property(TARGET ${libname} PROPERTY CXX_STANDARD 17)
  383. set(private_compile_options "")
  384. # ---[ Check if warnings should be errors.
  385. if(WERROR)
  386. list(APPEND private_compile_options -Werror)
  387. endif()
  388. # until they can be unified, keep these lists synced with setup.py
  389. if(MSVC)
  390. if(MSVC_Z7_OVERRIDE)
  391. set(MSVC_DEBINFO_OPTION "/Z7")
  392. else()
  393. set(MSVC_DEBINFO_OPTION "/Zi")
  394. endif()
  395. target_compile_options(${libname} PUBLIC
  396. $<$<COMPILE_LANGUAGE:CXX>:
  397. ${MSVC_RUNTIME_LIBRARY_OPTION}
  398. $<$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>:${MSVC_DEBINFO_OPTION}>
  399. /EHsc
  400. /DNOMINMAX
  401. /wd4267
  402. /wd4251
  403. /wd4522
  404. /wd4522
  405. /wd4838
  406. /wd4305
  407. /wd4244
  408. /wd4190
  409. /wd4101
  410. /wd4996
  411. /wd4275
  412. /bigobj>
  413. )
  414. else()
  415. list(APPEND private_compile_options
  416. -Wall
  417. -Wextra
  418. -Wno-unused-parameter
  419. -Wno-unused-function
  420. -Wno-unused-result
  421. -Wno-missing-field-initializers
  422. -Wno-write-strings
  423. -Wno-unknown-pragmas
  424. -Wno-type-limits
  425. -Wno-array-bounds
  426. -Wno-unknown-pragmas
  427. -Wno-sign-compare
  428. -Wno-strict-overflow
  429. -Wno-strict-aliasing
  430. -Wno-error=deprecated-declarations
  431. # Clang has an unfixed bug leading to spurious missing braces
  432. # warnings, see https://bugs.llvm.org/show_bug.cgi?id=21629
  433. -Wno-missing-braces
  434. )
  435. if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
  436. list(APPEND private_compile_options
  437. -Wno-range-loop-analysis)
  438. else()
  439. list(APPEND private_compile_options
  440. # Considered to be flaky. See the discussion at
  441. # https://github.com/pytorch/pytorch/pull/9608
  442. -Wno-maybe-uninitialized)
  443. endif()
  444. endif()
  445. if(MSVC)
  446. elseif(WERROR)
  447. list(APPEND private_compile_options -Wno-strict-overflow)
  448. endif()
  449. target_compile_options(${libname} PRIVATE
  450. $<$<COMPILE_LANGUAGE:CXX>:${private_compile_options}>)
  451. if(USE_CUDA)
  452. string(FIND "${private_compile_options}" " " space_position)
  453. if(NOT space_position EQUAL -1)
  454. message(FATAL_ERROR "Found spaces in private_compile_options='${private_compile_options}'")
  455. endif()
  456. # Convert CMake list to comma-separated list
  457. string(REPLACE ";" "," private_compile_options "${private_compile_options}")
  458. target_compile_options(${libname} PRIVATE
  459. $<$<COMPILE_LANGUAGE:CUDA>:-Xcompiler=${private_compile_options}>)
  460. endif()
  461. if(NOT WIN32 AND NOT USE_ASAN)
  462. # Enable hidden visibility by default to make it easier to debug issues with
  463. # TORCH_API annotations. Hidden visibility with selective default visibility
  464. # behaves close enough to Windows' dllimport/dllexport.
  465. #
  466. # Unfortunately, hidden visibility messes up some ubsan warnings because
  467. # templated classes crossing library boundary get duplicated (but identical)
  468. # definitions. It's easier to just disable it.
  469. target_compile_options(${libname} PRIVATE
  470. $<$<COMPILE_LANGUAGE:CXX>: -fvisibility=hidden>)
  471. endif()
  472. # Use -O2 for release builds (-O3 doesn't improve perf, and -Os results in perf regression)
  473. target_compile_options(${libname} PRIVATE
  474. $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<OR:$<CONFIG:Release>,$<CONFIG:RelWithDebInfo>>>:-O2>)
  475. endfunction()
  476. ##############################################################################
  477. # Set old-style FindCuda.cmake compile flags from modern CMake cuda flags.
  478. # Usage:
  479. # torch_update_find_cuda_flags()
  480. function(torch_update_find_cuda_flags)
  481. # Convert -O2 -Xcompiler="-O2 -Wall" to "-O2;-Xcompiler=-O2,-Wall"
  482. if(USE_CUDA)
  483. separate_arguments(FLAGS UNIX_COMMAND "${CMAKE_CUDA_FLAGS}")
  484. string(REPLACE " " "," FLAGS "${FLAGS}")
  485. set(CUDA_NVCC_FLAGS ${FLAGS} PARENT_SCOPE)
  486. separate_arguments(FLAGS_DEBUG UNIX_COMMAND "${CMAKE_CUDA_FLAGS_DEBUG}")
  487. string(REPLACE " " "," FLAGS_DEBUG "${FLAGS_DEBUG}")
  488. set(CUDA_NVCC_FLAGS_DEBUG "${FLAGS_DEBUG}" PARENT_SCOPE)
  489. separate_arguments(FLAGS_RELEASE UNIX_COMMAND "${CMAKE_CUDA_FLAGS_RELEASE}")
  490. string(REPLACE " " "," FLAGS_RELEASE "${FLAGS_RELEASE}")
  491. set(CUDA_NVCC_FLAGS_RELEASE "${FLAGS_RELEASE}" PARENT_SCOPE)
  492. separate_arguments(FLAGS_MINSIZEREL UNIX_COMMAND "${CMAKE_CUDA_FLAGS_MINSIZEREL}")
  493. string(REPLACE " " "," FLAGS_MINSIZEREL "${FLAGS_MINSIZEREL}")
  494. set(CUDA_NVCC_FLAGS_MINSIZEREL "${FLAGS_MINSIZEREL}" PARENT_SCOPE)
  495. separate_arguments(FLAGS_RELWITHDEBINFO UNIX_COMMAND "${CMAKE_CUDA_FLAGS_RELWITHDEBINFO}")
  496. string(REPLACE " " "," FLAGS_RELWITHDEBINFO "${FLAGS_RELWITHDEBINFO}")
  497. set(CUDA_NVCC_FLAGS_RELWITHDEBINFO "${FLAGS_RELWITHDEBINFO}" PARENT_SCOPE)
  498. message(STATUS "Converting CMAKE_CUDA_FLAGS to CUDA_NVCC_FLAGS:\n"
  499. " CUDA_NVCC_FLAGS = ${FLAGS}\n"
  500. " CUDA_NVCC_FLAGS_DEBUG = ${FLAGS_DEBUG}\n"
  501. " CUDA_NVCC_FLAGS_RELEASE = ${FLAGS_RELEASE}\n"
  502. " CUDA_NVCC_FLAGS_RELWITHDEBINFO = ${FLAGS_RELWITHDEBINFO}\n"
  503. " CUDA_NVCC_FLAGS_MINSIZEREL = ${FLAGS_MINSIZEREL}")
  504. endif()
  505. endfunction()
  506. ##############################################################################
  507. # CHeck if given flag is supported and append it to provided outputvar
  508. # Also define HAS_UPPER_CASE_FLAG_NAME variable
  509. # Usage:
  510. # append_cxx_flag_if_supported("-Werror" CMAKE_CXX_FLAGS)
  511. function(append_cxx_flag_if_supported flag outputvar)
  512. string(TOUPPER "HAS${flag}" _FLAG_NAME)
  513. string(REGEX REPLACE "[=-]" "_" _FLAG_NAME "${_FLAG_NAME}")
  514. check_cxx_compiler_flag("${flag}" ${_FLAG_NAME})
  515. if(${_FLAG_NAME})
  516. string(APPEND ${outputvar} " ${flag}")
  517. set(${outputvar} "${${outputvar}}" PARENT_SCOPE)
  518. endif()
  519. endfunction()
  520. function(target_compile_options_if_supported target flag)
  521. set(_compile_options "")
  522. append_cxx_flag_if_supported("${flag}" _compile_options)
  523. if(NOT "${_compile_options}" STREQUAL "")
  524. target_compile_options(${target} PRIVATE ${flag})
  525. endif()
  526. endfunction()