You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

utils.cmake 23 kB

5 years ago
8 years ago
5 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. # Functions to help with the OpenBLAS build
  2. # Reads string from getarch into CMake vars. Format of getarch vars is VARNAME=VALUE
  3. function(ParseGetArchVars GETARCH_IN)
  4. string(REGEX MATCHALL "[0-9_a-zA-Z]+=[0-9_a-zA-Z]+" GETARCH_RESULT_LIST "${GETARCH_IN}")
  5. foreach (GETARCH_LINE ${GETARCH_RESULT_LIST})
  6. # split the line into var and value, then assign the value to a CMake var
  7. string(REGEX MATCHALL "[0-9_a-zA-Z]+" SPLIT_VAR "${GETARCH_LINE}")
  8. list(GET SPLIT_VAR 0 VAR_NAME)
  9. list(GET SPLIT_VAR 1 VAR_VALUE)
  10. set(${VAR_NAME} ${VAR_VALUE} PARENT_SCOPE)
  11. endforeach ()
  12. endfunction ()
  13. # Reads a Makefile into CMake vars.
  14. macro(ParseMakefileVars MAKEFILE_IN)
  15. message(STATUS "Reading vars from ${MAKEFILE_IN}...")
  16. set (C_COMPILER ${CMAKE_C_COMPILER_ID})
  17. set (OSNAME ${CMAKE_SYSTEM_NAME})
  18. if (${C_COMPILER} MATCHES Clang)
  19. set (C_COMPILER CLANG)
  20. endif ()
  21. if (${OSNAME} STREQUAL Windows)
  22. set (OSNAME WINNT)
  23. endif ()
  24. message(STATUS OS ${OSNAME} COMPILER ${C_COMPILER})
  25. set (IfElse 0)
  26. set (ElseSeen 0)
  27. set (SkipIfs 0)
  28. set (SkipElse 0)
  29. file(STRINGS ${MAKEFILE_IN} makefile_contents)
  30. foreach (makefile_line ${makefile_contents})
  31. #message(STATUS "parsing ${makefile_line}")
  32. # Skip the entire scope of the else statement given that the if statement that precedes it has the valid condition.
  33. # The variable SkipIfs is used to identify which endif statement closes the scope of the else statement.
  34. if (${SkipElse} EQUAL 1)
  35. #message(STATUS "skipping ${makefile_line}")
  36. string(REGEX MATCH "(ifeq|ifneq|ifdef|ifndef) .*$" line_match "${makefile_line}")
  37. if (NOT "${line_match}" STREQUAL "")
  38. MATH(EXPR SkipIfs "${SkipIfs}+1")
  39. endif ()
  40. string(REGEX MATCH "endif[ \t]*" line_match "${makefile_line}")
  41. if (NOT "${line_match}" STREQUAL "")
  42. if (${SkipIfs} EQUAL 0)
  43. set (SkipElse 0)
  44. else ()
  45. MATH(EXPR SkipIfs "${SkipIfs}-1")
  46. endif ()
  47. endif ()
  48. continue ()
  49. endif ()
  50. # The variable IfElse is greater than 0 if and only if the previously parsed line is an if statement.
  51. if (${IfElse} GREATER 0)
  52. # If the current scope is the one that has to be skipped, the if/endif/else statements
  53. # along with it till the endif that closes the current scope have to be ignored as well.
  54. string(REGEX MATCH "(ifeq|ifneq|ifdef|ifndef) .*$" line_match "${makefile_line}")
  55. if (NOT "${line_match}" STREQUAL "")
  56. if ((${IfElse} EQUAL 2 AND ${ElseSeen} EQUAL 0) OR (${IfElse} EQUAL 1 AND ${ElseSeen} EQUAL 1))
  57. #message(STATUS "skipping ${makefile_line}")
  58. MATH(EXPR SkipIfs "${SkipIfs}+1")
  59. continue ()
  60. endif ()
  61. endif ()
  62. string(REGEX MATCH "endif[ \t]*" line_match "${makefile_line}")
  63. if (NOT "${line_match}" STREQUAL "")
  64. if (${SkipIfs} EQUAL 0)
  65. #message(STATUS "ENDIF ${makefile_line}")
  66. set (IfElse 0)
  67. set (ElseSeen 0)
  68. else ()
  69. #message(STATUS "skipping ${makefile_line}")
  70. MATH(EXPR SkipIfs "${SkipIfs}-1")
  71. endif ()
  72. continue ()
  73. endif ()
  74. string(REGEX MATCH "else[ \t]*" line_match "${makefile_line}")
  75. if (NOT "${line_match}" STREQUAL "")
  76. if (${SkipIfs} EQUAL 0)
  77. #message(STATUS "ELSE ${makefile_line}")
  78. set (ElseSeen 1)
  79. else ()
  80. #message(STATUS "skipping ${makefile_line}")
  81. endif ()
  82. continue ()
  83. endif()
  84. # Skip the lines that are not part of the path that has to be taken.
  85. if ((${IfElse} EQUAL 2 AND ${ElseSeen} EQUAL 0) OR (${IfElse} EQUAL 1 AND ${ElseSeen} EQUAL 1) OR (${SkipIfs} GREATER 0))
  86. #message(STATUS "skipping ${makefile_line}")
  87. continue ()
  88. endif ()
  89. endif ()
  90. # Skip commented lines (the ones that start with '#')
  91. string(REGEX MATCH "[ \t]*\\#.*$" line_match "${makefile_line}")
  92. if (NOT "${line_match}" STREQUAL "")
  93. #message(STATUS "skipping ${makefile_line}")
  94. continue ()
  95. endif ()
  96. # Example 1: SBGEMM_SMALL_M_PERMIT =
  97. # Unset the variable
  98. string(REGEX MATCH "([0-9_a-zA-Z]+)[ \t]*=[ \t]*$" line_match "${makefile_line}")
  99. if (NOT "${line_match}" STREQUAL "")
  100. set(var_name ${CMAKE_MATCH_1})
  101. unset(${var_name})
  102. endif()
  103. string(REGEX MATCH "([0-9_a-zA-Z]+)[ \t]*=[ \t]*(.+)$" line_match "${makefile_line}")
  104. if (NOT "${line_match}" STREQUAL "")
  105. #message(STATUS "match on ${line_match}")
  106. set(var_name ${CMAKE_MATCH_1})
  107. #set(var_value ${CMAKE_MATCH_2})
  108. string(STRIP ${CMAKE_MATCH_2} var_value)
  109. # check for Makefile variables in the string, e.g. $(TSUFFIX)
  110. string(REGEX MATCHALL "\\$\\(([0-9_a-zA-Z]+)\\)" make_var_matches ${var_value})
  111. foreach (make_var ${make_var_matches})
  112. # strip out Makefile $() markup
  113. string(REGEX REPLACE "\\$\\(([0-9_a-zA-Z]+)\\)" "\\1" make_var ${make_var})
  114. # now replace the instance of the Makefile variable with the value of the CMake variable (note the double quote)
  115. string(REPLACE "$(${make_var})" "${${make_var}}" var_value ${var_value})
  116. endforeach ()
  117. set(${var_name} ${var_value})
  118. continue ()
  119. endif ()
  120. # Include a new file to be parsed
  121. string(REGEX MATCH "include \\$\\(KERNELDIR\\)/(.+)$" line_match "${makefile_line}")
  122. if (NOT "${line_match}" STREQUAL "")
  123. #message(STATUS "match on include ${line_match}")
  124. ParseMakefileVars(${KERNELDIR}/${CMAKE_MATCH_1})
  125. continue ()
  126. endif ()
  127. # The if statement that precedes this else has the path taken
  128. # Thus, this else statement has to be skipped.
  129. string(REGEX MATCH "else[ \t]*" line_match "${makefile_line}")
  130. if (NOT "${line_match}" STREQUAL "")
  131. #message(STATUS "skipping ${makefile_line}")
  132. set (SkipElse 1)
  133. continue()
  134. endif()
  135. # Example 1: ifdef HAVE_MSA
  136. # Example 2: ifndef ZNRM2KERNEL
  137. string(REGEX MATCH "(ifdef|ifndef) ([0-9_A-Z]+)" line_match "${makefile_line}")
  138. if (NOT "${line_match}" STREQUAL "")
  139. #message(STATUS "${CMAKE_MATCH_1} first: ${CMAKE_MATCH_2}")
  140. set (ElseSeen 0)
  141. if (${CMAKE_MATCH_2})
  142. if (${CMAKE_MATCH_1} STREQUAL "ifdef")
  143. #message (STATUS "condition is true")
  144. set (IfElse 1)
  145. else ()
  146. set (IfElse 2)
  147. endif ()
  148. else ()
  149. if (${CMAKE_MATCH_1} STREQUAL "ifdef")
  150. set (IfElse 2)
  151. else ()
  152. #message (STATUS "condition is true")
  153. set (IfElse 1)
  154. endif ()
  155. endif ()
  156. continue ()
  157. endif ()
  158. # Example 1: ifeq ($(SGEMM_UNROLL_M), 16)
  159. # Example 2: ifeq ($(SGEMM_UNROLL_M)x$(SGEMM_UNROLL_N), 8x8)
  160. # Example 3: ifeq ($(__BYTE_ORDER__)$(ELF_VERSION),__ORDER_BIG_ENDIAN__2)
  161. # Ignore the second group since (?:...) does not work on cmake
  162. string(REGEX MATCH "ifeq \\(\\$\\(([0-9_A-Z]+)\\)(([0-9_A-Za-z]*)\\$\\(([0-9_A-Z]+)\\))?,[ \t]*([0-9_A-Za-z]+)\\)" line_match "${makefile_line}")
  163. if (NOT "${line_match}" STREQUAL "")
  164. #message(STATUS "IFEQ: ${line_match} first: ${CMAKE_MATCH_1} second: ${CMAKE_MATCH_3} third: ${CMAKE_MATCH_4} fourth: ${CMAKE_MATCH_5}")
  165. if (DEFINED ${CMAKE_MATCH_1})
  166. if (DEFINED ${CMAKE_MATCH_4})
  167. set (STR ${${CMAKE_MATCH_1}}${CMAKE_MATCH_3}${${CMAKE_MATCH_4}})
  168. else ()
  169. set (STR ${${CMAKE_MATCH_1}})
  170. endif ()
  171. if (${STR} STREQUAL ${CMAKE_MATCH_5})
  172. #message (STATUS "condition is true")
  173. set (IfElse 1)
  174. continue ()
  175. endif ()
  176. endif ()
  177. set (IfElse 2)
  178. continue ()
  179. endif ()
  180. # Example 1 (Group 3): ifneq ($(SGEMM_UNROLL_M), $(SGEMM_UNROLL_N))
  181. # Example 2 (Group 4): ifneq ($(C_COMPILER), PGI)
  182. string(REGEX MATCH "ifneq \\(\\$\\(([0-9_A-Z]+)\\),[ \t]*(\\$\\(([0-9_A-Z]+)\\)|([0-9_A-Z]+))\\)" line_match "${makefile_line}")
  183. if (NOT "${line_match}" STREQUAL "")
  184. #message(STATUS "IFNEQ: ${line_match} first: ${CMAKE_MATCH_1} second: ${CMAKE_MATCH_3} third: ${CMAKE_MATCH_4}")
  185. set (ElseSeen 0)
  186. set (HasValidGroup 0)
  187. if (DEFINED ${CMAKE_MATCH_3})
  188. set (HasValidGroup 1)
  189. set (STR ${${CMAKE_MATCH_3}})
  190. elseif (NOT ${CMAKE_MATCH_4} STREQUAL "")
  191. set (HasValidGroup 1)
  192. set (STR ${CMAKE_MATCH_4})
  193. endif ()
  194. if (DEFINED CMAKE_MATCH_1 AND ${HasValidGroup} EQUAL 1)
  195. if (NOT (CMAKE_MATCH_1 STREQUAL ${STR}))
  196. #message (STATUS "condition is true")
  197. set (IfElse 1)
  198. continue ()
  199. endif ()
  200. endif ()
  201. set (IfElse 2)
  202. continue ()
  203. endif ()
  204. #message(STATUS "unmatched line ${line_match}")
  205. endforeach ()
  206. endmacro ()
  207. # Returns all combinations of the input list, as a list with colon-separated combinations
  208. # E.g. input of A B C returns A B C A:B A:C B:C
  209. # N.B. The input is meant to be a list, and to past a list to a function in CMake you must quote it (e.g. AllCombinations("${LIST_VAR}")).
  210. # #param absent_codes codes to use when an element is absent from a combination. For example, if you have TRANS;UNIT;UPPER you may want the code to be NNL when nothing is present.
  211. # @returns LIST_OUT a list of combinations
  212. # CODES_OUT a list of codes corresponding to each combination, with N meaning the item is not present, and the first letter of the list item meaning it is presen
  213. function(AllCombinations list_in absent_codes_in)
  214. list(LENGTH list_in list_count)
  215. set(num_combos 1)
  216. # subtract 1 since we will iterate from 0 to num_combos
  217. math(EXPR num_combos "(${num_combos} << ${list_count}) - 1")
  218. set(LIST_OUT "")
  219. set(CODES_OUT "")
  220. foreach (c RANGE 0 ${num_combos})
  221. set(current_combo "")
  222. set(current_code "")
  223. # this is a little ridiculous just to iterate through a list w/ indices
  224. math(EXPR last_list_index "${list_count} - 1")
  225. foreach (list_index RANGE 0 ${last_list_index})
  226. math(EXPR bit "1 << ${list_index}")
  227. math(EXPR combo_has_bit "${c} & ${bit}")
  228. list(GET list_in ${list_index} list_elem)
  229. if (combo_has_bit)
  230. if (current_combo)
  231. set(current_combo "${current_combo}:${list_elem}")
  232. else ()
  233. set(current_combo ${list_elem})
  234. endif ()
  235. string(SUBSTRING ${list_elem} 0 1 code_char)
  236. else ()
  237. list(GET absent_codes_in ${list_index} code_char)
  238. endif ()
  239. set(current_code "${current_code}${code_char}")
  240. endforeach ()
  241. if (current_combo STREQUAL "")
  242. list(APPEND LIST_OUT " ") # Empty set is a valid combination, but CMake isn't appending the empty string for some reason, use a space
  243. else ()
  244. list(APPEND LIST_OUT ${current_combo})
  245. endif ()
  246. list(APPEND CODES_OUT ${current_code})
  247. endforeach ()
  248. set(LIST_OUT ${LIST_OUT} PARENT_SCOPE)
  249. set(CODES_OUT ${CODES_OUT} PARENT_SCOPE)
  250. endfunction ()
  251. # generates object files for each of the sources, using the BLAS naming scheme to pass the function name as a preprocessor definition
  252. # @param sources_in the source files to build from
  253. # @param defines_in (optional) preprocessor definitions that will be applied to all objects
  254. # @param name_in (optional) if this is set this name will be used instead of the filename. Use a * to indicate where the float character should go, if no star the character will be prepended.
  255. # e.g. with DOUBLE set, "i*max" will generate the name "idmax", and "max" will be "dmax"
  256. # @param replace_last_with replaces the last character in the filename with this string (e.g. symm_k should be symm_TU)
  257. # @param append_with appends the filename with this string (e.g. trmm_R should be trmm_RTUU or some other combination of characters)
  258. # @param no_float_type turns off the float type define for this build (e.g. SINGLE/DOUBLE/etc)
  259. # @param complex_filename_scheme some routines have separate source files for complex and non-complex float types.
  260. # 0 - compiles for all types
  261. # 1 - compiles the sources for non-complex types only (SINGLE/DOUBLE)
  262. # 2 - compiles for complex types only (COMPLEX/DOUBLE COMPLEX)
  263. # 3 - compiles for all types, but changes source names for complex by prepending z (e.g. axpy.c becomes zaxpy.c)
  264. # 4 - compiles for complex types only, but changes source names for complex by prepending z (e.g. hemv.c becomes zhemv.c)
  265. # STRING - compiles only the given type (e.g. DOUBLE)
  266. function(GenerateNamedObjects sources_in)
  267. if (${ARGC} GREATER 1)
  268. set(defines_in ${ARGV1})
  269. endif ()
  270. if (${ARGC} GREATER 2 AND NOT "${ARGV2}" STREQUAL "")
  271. set(name_in ${ARGV2})
  272. # strip off extension for kernel files that pass in the object name.
  273. get_filename_component(name_in ${name_in} NAME_WE)
  274. endif ()
  275. if (${ARGC} GREATER 3)
  276. set(use_cblas ${ARGV3})
  277. else ()
  278. set(use_cblas false)
  279. endif ()
  280. if (${ARGC} GREATER 4)
  281. set(replace_last_with ${ARGV4})
  282. endif ()
  283. if (${ARGC} GREATER 5)
  284. set(append_with ${ARGV5})
  285. endif ()
  286. if (${ARGC} GREATER 6)
  287. set(no_float_type ${ARGV6})
  288. else ()
  289. set(no_float_type false)
  290. endif ()
  291. if (no_float_type)
  292. set(float_list "DUMMY") # still need to loop once
  293. else ()
  294. set(float_list "${FLOAT_TYPES}")
  295. endif ()
  296. set(real_only false)
  297. set(complex_only false)
  298. set(mangle_complex_sources false)
  299. if (${ARGC} GREATER 7 AND NOT "${ARGV7}" STREQUAL "")
  300. if (${ARGV7} EQUAL 1)
  301. set(real_only true)
  302. elseif (${ARGV7} EQUAL 2)
  303. set(complex_only true)
  304. elseif (${ARGV7} EQUAL 3)
  305. set(mangle_complex_sources true)
  306. elseif (${ARGV7} EQUAL 4)
  307. set(mangle_complex_sources true)
  308. set(complex_only true)
  309. elseif (NOT ${ARGV7} EQUAL 0)
  310. set(float_list ${ARGV7})
  311. endif ()
  312. endif ()
  313. if (complex_only)
  314. list(REMOVE_ITEM float_list "SINGLE")
  315. list(REMOVE_ITEM float_list "DOUBLE")
  316. list(REMOVE_ITEM float_list "BFLOAT16")
  317. elseif (real_only)
  318. list(REMOVE_ITEM float_list "COMPLEX")
  319. list(REMOVE_ITEM float_list "ZCOMPLEX")
  320. endif ()
  321. set(float_char "")
  322. set(OBJ_LIST_OUT "")
  323. foreach (float_type ${float_list})
  324. foreach (source_file ${sources_in})
  325. if (NOT no_float_type)
  326. string(SUBSTRING ${float_type} 0 1 float_char)
  327. string(TOLOWER ${float_char} float_char)
  328. if (${float_type} STREQUAL "BFLOAT16")
  329. set (float_char "sb")
  330. endif ()
  331. endif ()
  332. if (NOT name_in)
  333. get_filename_component(source_name ${source_file} NAME_WE)
  334. set(obj_name "${float_char}${source_name}")
  335. else ()
  336. # replace * with float_char
  337. if (${name_in} MATCHES "\\*")
  338. string(REPLACE "*" ${float_char} obj_name ${name_in})
  339. else ()
  340. set(obj_name "${float_char}${name_in}")
  341. endif ()
  342. endif ()
  343. if (replace_last_with)
  344. string(REGEX REPLACE ".$" ${replace_last_with} obj_name ${obj_name})
  345. else ()
  346. set(obj_name "${obj_name}${append_with}")
  347. endif ()
  348. # now add the object and set the defines
  349. set(obj_defines ${defines_in})
  350. list(FIND obj_defines "RC" def_idx)
  351. if (${def_idx} GREATER -1)
  352. # list(REMOVE_AT ${obj_defines} ${def_idx})
  353. list (REMOVE_ITEM obj_defines "RC")
  354. list(APPEND obj_defines "RC=RC")
  355. endif ()
  356. list(FIND obj_defines "CR" def_idx)
  357. if (${def_idx} GREATER -1)
  358. # list(REMOVE_AT ${obj_defines} ${def_idx})
  359. list (REMOVE_ITEM obj_defines "CR")
  360. list(APPEND obj_defines "CR=CR")
  361. endif ()
  362. if (use_cblas)
  363. set(obj_name "cblas_${obj_name}")
  364. list(APPEND obj_defines "CBLAS")
  365. elseif (NOT "${obj_name}" MATCHES "${ARCH_SUFFIX}")
  366. set(obj_name "${obj_name}${ARCH_SUFFIX}")
  367. endif ()
  368. list(APPEND obj_defines "ASMNAME=${FU}${obj_name};ASMFNAME=${FU}${obj_name}${BU};NAME=${obj_name}${BU};CNAME=${obj_name};CHAR_NAME=\"${obj_name}${BU}\";CHAR_CNAME=\"${obj_name}\"")
  369. if (${float_type} STREQUAL "DOUBLE" OR ${float_type} STREQUAL "ZCOMPLEX")
  370. list(APPEND obj_defines "DOUBLE")
  371. endif ()
  372. if (${float_type} STREQUAL "BFLOAT16")
  373. list(APPEND obj_defines "BFLOAT16")
  374. endif ()
  375. if (${float_type} STREQUAL "COMPLEX" OR ${float_type} STREQUAL "ZCOMPLEX")
  376. list(APPEND obj_defines "COMPLEX")
  377. if (mangle_complex_sources)
  378. # add a z to the filename
  379. get_filename_component(source_name ${source_file} NAME)
  380. get_filename_component(source_dir ${source_file} DIRECTORY)
  381. string(REPLACE ${source_name} "z${source_name}" source_file ${source_file})
  382. endif ()
  383. endif ()
  384. if (VERBOSE_GEN)
  385. message(STATUS "${obj_name}:${source_file}")
  386. message(STATUS "${obj_defines}")
  387. endif ()
  388. # create a copy of the source to avoid duplicate obj filename problem with ar.exe
  389. get_filename_component(source_extension ${source_file} EXT)
  390. set(new_source_file "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${obj_name}${source_extension}")
  391. if (IS_ABSOLUTE ${source_file})
  392. set(old_source_file ${source_file})
  393. else ()
  394. set(old_source_file "${CMAKE_CURRENT_LIST_DIR}/${source_file}")
  395. endif ()
  396. string(REPLACE ";" "\n#define " define_source "${obj_defines}")
  397. string(REPLACE "=" " " define_source "${define_source}")
  398. file(WRITE ${new_source_file}.tmp "#define ${define_source}\n#include \"${old_source_file}\"")
  399. configure_file(${new_source_file}.tmp ${new_source_file} COPYONLY)
  400. file(REMOVE ${new_source_file}.tmp)
  401. list(APPEND SRC_LIST_OUT ${new_source_file})
  402. message (STATUS ${new_source_file})
  403. if (DEFINED HAVE_FMA3)
  404. if ( ${new_source_file} MATCHES "(s|d?)rot_k.*c")
  405. set_source_files_properties(${new_source_file} PROPERTIES COMPILE_OPTIONS "-mfma")
  406. endif ()
  407. if ( ${new_source_file} MATCHES "dgemv_t_k.*c")
  408. set_source_files_properties(${new_source_file} PROPERTIES COMPILE_OPTIONS "-mfma")
  409. endif ()
  410. endif ()
  411. endforeach ()
  412. endforeach ()
  413. list(APPEND OPENBLAS_SRC ${SRC_LIST_OUT})
  414. set(OPENBLAS_SRC ${OPENBLAS_SRC} PARENT_SCOPE)
  415. endfunction ()
  416. # generates object files for each of the sources for each of the combinations of the preprocessor definitions passed in
  417. # @param sources_in the source files to build from
  418. # @param defines_in the preprocessor definitions that will be combined to create the object files
  419. # @param all_defines_in (optional) preprocessor definitions that will be applied to all objects
  420. # @param replace_scheme If 1, replace the "k" in the filename with the define combo letters. E.g. symm_k.c with TRANS and UNIT defined will be symm_TU.
  421. # If 0, it will simply append the code, e.g. symm_L.c with TRANS and UNIT will be symm_LTU.
  422. # If 2, it will append the code with an underscore, e.g. symm.c with TRANS and UNIT will be symm_TU.
  423. # If 3, it will insert the code *around* the last character with an underscore, e.g. symm_L.c with TRANS and UNIT will be symm_TLU (required by BLAS level2 objects).
  424. # If 4, it will insert the code before the last underscore. E.g. trtri_U_parallel with TRANS will be trtri_UT_parallel
  425. # @param alternate_name replaces the source name as the object name (define codes are still appended)
  426. # @param no_float_type turns off the float type define for this build (e.g. SINGLE/DOUBLE/etc)
  427. # @param complex_filename_scheme see GenerateNamedObjects
  428. function(GenerateCombinationObjects sources_in defines_in absent_codes_in all_defines_in replace_scheme)
  429. set(alternate_name_in "")
  430. if (${ARGC} GREATER 5)
  431. set(alternate_name_in ${ARGV5})
  432. endif ()
  433. set(no_float_type false)
  434. if (${ARGC} GREATER 6)
  435. set(no_float_type ${ARGV6})
  436. endif ()
  437. set(complex_filename_scheme "")
  438. if (${ARGC} GREATER 7)
  439. set(complex_filename_scheme ${ARGV7})
  440. endif ()
  441. AllCombinations("${defines_in}" "${absent_codes_in}")
  442. set(define_combos ${LIST_OUT})
  443. set(define_codes ${CODES_OUT})
  444. list(LENGTH define_combos num_combos)
  445. math(EXPR num_combos "${num_combos} - 1")
  446. foreach (c RANGE 0 ${num_combos})
  447. list(GET define_combos ${c} define_combo)
  448. list(GET define_codes ${c} define_code)
  449. foreach (source_file ${sources_in})
  450. set(alternate_name ${alternate_name_in})
  451. # replace colon separated list with semicolons, this turns it into a CMake list that we can use foreach with
  452. string(REPLACE ":" ";" define_combo ${define_combo})
  453. # now add the object and set the defines
  454. set(cur_defines ${define_combo})
  455. if ("${cur_defines}" STREQUAL " ")
  456. set(cur_defines ${all_defines_in})
  457. else ()
  458. list(APPEND cur_defines ${all_defines_in})
  459. endif ()
  460. set(replace_code "")
  461. set(append_code "")
  462. if (replace_scheme EQUAL 1)
  463. set(replace_code ${define_code})
  464. else ()
  465. if (replace_scheme EQUAL 2)
  466. set(append_code "_${define_code}")
  467. elseif (replace_scheme EQUAL 3)
  468. if ("${alternate_name}" STREQUAL "")
  469. string(REGEX MATCH "[a-zA-Z]\\." last_letter ${source_file})
  470. else ()
  471. string(REGEX MATCH "[a-zA-Z]$" last_letter ${alternate_name})
  472. endif ()
  473. # first extract the last letter
  474. string(SUBSTRING ${last_letter} 0 1 last_letter) # remove period from match
  475. # break the code up into the first letter and the remaining (should only be 2 anyway)
  476. string(SUBSTRING ${define_code} 0 1 define_code_first)
  477. string(SUBSTRING ${define_code} 1 -1 define_code_second)
  478. set(replace_code "${define_code_first}${last_letter}${define_code_second}")
  479. elseif (replace_scheme EQUAL 4)
  480. # insert code before the last underscore and pass that in as the alternate_name
  481. if ("${alternate_name}" STREQUAL "")
  482. get_filename_component(alternate_name ${source_file} NAME_WE)
  483. endif ()
  484. set(extra_underscore "")
  485. # check if filename has two underscores, insert another if not (e.g. getrs_parallel needs to become getrs_U_parallel not getrsU_parallel)
  486. string(REGEX MATCH "_[a-zA-Z]+_" underscores ${alternate_name})
  487. string(LENGTH "${underscores}" underscores)
  488. if (underscores EQUAL 0)
  489. set(extra_underscore "_")
  490. endif ()
  491. string(REGEX REPLACE "(.+)(_[^_]+)$" "\\1${extra_underscore}${define_code}\\2" alternate_name ${alternate_name})
  492. else()
  493. set(append_code ${define_code}) # replace_scheme should be 0
  494. endif ()
  495. endif ()
  496. GenerateNamedObjects("${source_file}" "${cur_defines}" "${alternate_name}" false "${replace_code}" "${append_code}" "${no_float_type}" "${complex_filename_scheme}")
  497. endforeach ()
  498. endforeach ()
  499. set(OPENBLAS_SRC ${OPENBLAS_SRC} PARENT_SCOPE)
  500. endfunction ()