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