summaryrefslogtreecommitdiffstats
path: root/Modules/CMakeDetermineHIPCompiler.cmake
blob: e667099c9c0dd3d8d44875dea89cfa75198fe926 (plain)
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
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.

include(${CMAKE_ROOT}/Modules/CMakeDetermineCompiler.cmake)
include(${CMAKE_ROOT}/Modules/CMakeParseImplicitLinkInfo.cmake)
include(${CMAKE_ROOT}/Modules/CMakeParseLibraryArchitecture.cmake)

if(NOT ((CMAKE_GENERATOR MATCHES "Make") OR
        (CMAKE_GENERATOR MATCHES "Ninja")))
  message(FATAL_ERROR "HIP language not currently supported by \"${CMAKE_GENERATOR}\" generator")
endif()

if(NOT CMAKE_HIP_PLATFORM)
  execute_process(COMMAND hipconfig --platform
    OUTPUT_VARIABLE _CMAKE_HIPCONFIG_PLATFORM OUTPUT_STRIP_TRAILING_WHITESPACE
    RESULT_VARIABLE _CMAKE_HIPCONFIG_RESULT
    )
  if(_CMAKE_HIPCONFIG_RESULT EQUAL 0 AND _CMAKE_HIPCONFIG_PLATFORM MATCHES "^(nvidia|nvcc)$")
    set(CMAKE_HIP_PLATFORM "nvidia" CACHE STRING "HIP platform" FORCE)
  else()
    set(CMAKE_HIP_PLATFORM "amd" CACHE STRING "HIP platform" FORCE)
  endif()
endif()
if(NOT CMAKE_HIP_PLATFORM MATCHES "^(amd|nvidia)$")
  message(FATAL_ERROR
    "The CMAKE_HIP_PLATFORM has unsupported value:\n"
    " '${CMAKE_HIP_PLATFORM}'\n"
    "It must be 'amd' or 'nvidia'."
    )
endif()

if(NOT CMAKE_HIP_COMPILER)
  set(CMAKE_HIP_COMPILER_INIT NOTFOUND)

  # prefer the environment variable HIPCXX
  if(NOT $ENV{HIPCXX} STREQUAL "")
    if("$ENV{HIPCXX}" MATCHES "hipcc")
      message(FATAL_ERROR
        "The HIPCXX environment variable is set to the hipcc wrapper:\n"
        " $ENV{HIPCXX}\n"
        "This is not supported.  Use Clang directly, or let CMake pick a default."
        )
    endif()
    get_filename_component(CMAKE_HIP_COMPILER_INIT $ENV{HIPCXX} PROGRAM PROGRAM_ARGS CMAKE_HIP_FLAGS_ENV_INIT)
    if(CMAKE_HIP_FLAGS_ENV_INIT)
      set(CMAKE_HIP_COMPILER_ARG1 "${CMAKE_HIP_FLAGS_ENV_INIT}" CACHE STRING "Arguments to CXX compiler")
    endif()
    if(NOT EXISTS ${CMAKE_HIP_COMPILER_INIT})
      message(FATAL_ERROR "Could not find compiler set in environment variable HIPCXX:\n$ENV{HIPCXX}.\n${CMAKE_HIP_COMPILER_INIT}")
    endif()
  endif()

  # finally list compilers to try
  if(NOT CMAKE_HIP_COMPILER_INIT)
    if(CMAKE_HIP_PLATFORM STREQUAL "nvidia")
      set(CMAKE_HIP_COMPILER_LIST nvcc)
    elseif(CMAKE_HIP_PLATFORM STREQUAL "amd")
      set(CMAKE_HIP_COMPILER_LIST clang++)

      # Look for the Clang coming with ROCm to support HIP.
      execute_process(COMMAND hipconfig --hipclangpath
        OUTPUT_VARIABLE _CMAKE_HIPCONFIG_CLANGPATH
        RESULT_VARIABLE _CMAKE_HIPCONFIG_RESULT
      )
      if(_CMAKE_HIPCONFIG_RESULT EQUAL 0 AND EXISTS "${_CMAKE_HIPCONFIG_CLANGPATH}")
        set(CMAKE_HIP_COMPILER_HINTS "${_CMAKE_HIPCONFIG_CLANGPATH}")
      endif()
    endif()
  endif()

  _cmake_find_compiler(HIP)
elseif(CMAKE_HIP_COMPILER MATCHES "hipcc")
  message(FATAL_ERROR
    "CMAKE_HIP_COMPILER is set to the hipcc wrapper:\n"
    " ${CMAKE_HIP_COMPILER}\n"
    "This is not supported.  Use Clang directly, or let CMake pick a default."
    )
else()
  _cmake_find_compiler_path(HIP)
endif()

mark_as_advanced(CMAKE_HIP_COMPILER)

# Build a small source file to identify the compiler.
if(NOT CMAKE_HIP_COMPILER_ID_RUN)
  set(CMAKE_HIP_COMPILER_ID_RUN 1)

  include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerId.cmake)

  # We determine the vendor to use the right flags for detection right away.
  # The main compiler identification is still needed below to extract other information.
  list(APPEND CMAKE_HIP_COMPILER_ID_VENDORS NVIDIA Clang)
  set(CMAKE_HIP_COMPILER_ID_VENDOR_REGEX_NVIDIA "nvcc: NVIDIA \\(R\\) Cuda compiler driver")
  set(CMAKE_HIP_COMPILER_ID_VENDOR_REGEX_Clang "(clang version)")
  CMAKE_DETERMINE_COMPILER_ID_VENDOR(HIP "--version")

  if(CMAKE_HIP_COMPILER_ID STREQUAL "NVIDIA")
    # Find the CUDA toolkit to get:
    # - CMAKE_HIP_COMPILER_CUDA_TOOLKIT_VERSION
    # - CMAKE_HIP_COMPILER_CUDA_TOOLKIT_ROOT
    # - CMAKE_HIP_COMPILER_CUDA_LIBRARY_ROOT
    # We save them in CMakeHIPCompiler.cmake.
    # Match arguments with cmake_cuda_architectures_all call.
    include(Internal/CMakeCUDAFindToolkit)
    cmake_cuda_find_toolkit(HIP CMAKE_HIP_COMPILER_CUDA_)

    # If the user set CMAKE_HIP_ARCHITECTURES, validate its value.
    include(Internal/CMakeCUDAArchitecturesValidate)
    cmake_cuda_architectures_validate(HIP)

    if(NOT CMAKE_HIP_HOST_COMPILER AND NOT $ENV{HIPHOSTCXX} STREQUAL "")
      get_filename_component(CMAKE_HIP_HOST_COMPILER $ENV{HIPHOSTCXX} PROGRAM)
      if(NOT EXISTS "${CMAKE_HIP_HOST_COMPILER}")
        message(FATAL_ERROR "Could not find compiler set in environment variable HIPHOSTCXX:\n$ENV{HIPHOSTCXX}.\n${CMAKE_HIP_HOST_COMPILER}")
      endif()
    endif()
  endif()

  if(CMAKE_HIP_COMPILER_ID STREQUAL "Clang")
    list(APPEND CMAKE_HIP_COMPILER_ID_TEST_FLAGS_FIRST "-v")
  elseif(CMAKE_HIP_COMPILER_ID STREQUAL "NVIDIA")
    # Tell nvcc to treat .hip files as CUDA sources.
    list(APPEND CMAKE_HIP_COMPILER_ID_TEST_FLAGS_FIRST "-x cu -v")
    if(CMAKE_HIP_HOST_COMPILER)
      string(APPEND CMAKE_HIP_COMPILER_ID_TEST_FLAGS_FIRST " -ccbin=\"${CMAKE_HIP_HOST_COMPILER}\"")
    endif()
  endif()

  # We perform compiler identification for a second time to extract implicit linking info.
  # We need to unset the compiler ID otherwise CMAKE_DETERMINE_COMPILER_ID() doesn't work.
  set(CMAKE_HIP_COMPILER_ID)
  set(CMAKE_HIP_PLATFORM_ID)
  file(READ ${CMAKE_ROOT}/Modules/CMakePlatformId.h.in
    CMAKE_HIP_COMPILER_ID_PLATFORM_CONTENT)

  CMAKE_DETERMINE_COMPILER_ID(HIP HIPFLAGS CMakeHIPCompilerId.hip)

  if(CMAKE_HIP_COMPILER_ID STREQUAL "NVIDIA")
    include(Internal/CMakeCUDAArchitecturesAll)
    # From CMAKE_HIP_COMPILER_CUDA_TOOLKIT_VERSION and CMAKE_HIP_COMPILER_{ID,VERSION}, get:
    # - CMAKE_HIP_ARCHITECTURES_ALL
    # - CMAKE_HIP_ARCHITECTURES_ALL_MAJOR
    # Match arguments with cmake_cuda_find_toolkit call.
    cmake_cuda_architectures_all(HIP CMAKE_HIP_COMPILER_CUDA_)
  endif()

  _cmake_find_compiler_sysroot(HIP)
endif()

if(NOT CMAKE_HIP_COMPILER_ROCM_ROOT AND CMAKE_HIP_COMPILER_ID STREQUAL "Clang")
   execute_process(COMMAND "${CMAKE_HIP_COMPILER}" -v -print-targets
    OUTPUT_STRIP_TRAILING_WHITESPACE
    RESULT_VARIABLE _CMAKE_HIP_COMPILER_RESULT
    OUTPUT_VARIABLE _CMAKE_HIP_COMPILER_STDOUT
    ERROR_VARIABLE _CMAKE_HIP_COMPILER_STDERR
    )

  if(_CMAKE_HIP_COMPILER_RESULT EQUAL 0 AND _CMAKE_HIP_COMPILER_STDERR MATCHES "Found HIP installation: *([^,]*)[,\n]")
    set(CMAKE_HIP_COMPILER_ROCM_ROOT "${CMAKE_MATCH_1}")
    file(TO_CMAKE_PATH "${CMAKE_HIP_COMPILER_ROCM_ROOT}" CMAKE_HIP_COMPILER_ROCM_ROOT)
  endif()
endif()
if(NOT CMAKE_HIP_COMPILER_ROCM_ROOT)
  execute_process(
    COMMAND hipconfig --rocmpath
    OUTPUT_VARIABLE _CMAKE_HIPCONFIG_ROCMPATH
    RESULT_VARIABLE _CMAKE_HIPCONFIG_RESULT
    )
  if(_CMAKE_HIPCONFIG_RESULT EQUAL 0 AND EXISTS "${_CMAKE_HIPCONFIG_ROCMPATH}")
    set(CMAKE_HIP_COMPILER_ROCM_ROOT "${_CMAKE_HIPCONFIG_ROCMPATH}")
  endif()
endif()
if(NOT CMAKE_HIP_COMPILER_ROCM_ROOT)
  message(FATAL_ERROR "Failed to find ROCm root directory.")
endif()

if(CMAKE_HIP_PLATFORM STREQUAL "amd")
  # For this platform we need the hip-lang cmake package.

  # Normally implicit link information is not detected until ABI detection,
  # but we need to populate CMAKE_HIP_LIBRARY_ARCHITECTURE to find hip-lang.
  cmake_parse_implicit_link_info("${CMAKE_HIP_COMPILER_PRODUCED_OUTPUT}"
    _CMAKE_HIP_COMPILER_ID_IMPLICIT_LIBS
    _CMAKE_HIP_COMPILER_ID_IMPLICIT_DIRS
    _CMAKE_HIP_COMPILER_ID_IMPLICIT_FWKS
    _CMAKE_HIP_COMPILER_ID_IMPLICIT_LOG
    "" LANGUAGE HIP)
  message(CONFIGURE_LOG
    "Parsed HIP implicit link information from compiler id output:\n${_CMAKE_HIP_COMPILER_ID_IMPLICIT_LOG}\n\n")
  cmake_parse_library_architecture(HIP "${_CMAKE_HIP_COMPILER_ID_IMPLICIT_DIRS}" "" CMAKE_HIP_LIBRARY_ARCHITECTURE)
  if(CMAKE_HIP_LIBRARY_ARCHITECTURE)
    message(CONFIGURE_LOG
      "Parsed HIP library architecture from compiler id output: ${CMAKE_HIP_LIBRARY_ARCHITECTURE}\n")
  endif()
  unset(_CMAKE_HIP_COMPILER_ID_IMPLICIT_LIBS)
  unset(_CMAKE_HIP_COMPILER_ID_IMPLICIT_DIRS)
  unset(_CMAKE_HIP_COMPILER_ID_IMPLICIT_FWKS)
  unset(_CMAKE_HIP_COMPILER_ID_IMPLICIT_LOG)

  if(NOT CMAKE_HIP_COMPILER_ROCM_LIB)
    set(_CMAKE_HIP_COMPILER_ROCM_LIB_DIRS
      "${CMAKE_HIP_COMPILER_ROCM_ROOT}/lib"
      "${CMAKE_HIP_COMPILER_ROCM_ROOT}/lib64"
      )
    if(CMAKE_HIP_LIBRARY_ARCHITECTURE)
      list(APPEND _CMAKE_HIP_COMPILER_ROCM_LIB_DIRS "${CMAKE_HIP_COMPILER_ROCM_ROOT}/lib/${CMAKE_HIP_LIBRARY_ARCHITECTURE}")
    endif()
    foreach(dir IN LISTS _CMAKE_HIP_COMPILER_ROCM_LIB_DIRS)
      if(EXISTS "${dir}/cmake/hip-lang/hip-lang-config.cmake")
        set(CMAKE_HIP_COMPILER_ROCM_LIB "${dir}")
        break()
      endif()
    endforeach()
    if(NOT CMAKE_HIP_COMPILER_ROCM_LIB)
      list(TRANSFORM _CMAKE_HIP_COMPILER_ROCM_LIB_DIRS APPEND "/cmake/hip-lang/hip-lang-config.cmake")
      string(REPLACE ";" "\n " _CMAKE_HIP_COMPILER_ROCM_LIB_DIRS "${_CMAKE_HIP_COMPILER_ROCM_LIB_DIRS}")
      message(FATAL_ERROR
        "The ROCm root directory:\n"
        " ${CMAKE_HIP_COMPILER_ROCM_ROOT}\n"
        "does not contain the HIP runtime CMake package, expected at one of:\n"
        " ${_CMAKE_HIP_COMPILER_ROCM_LIB_DIRS}\n"
        )
    endif()
    unset(_CMAKE_HIP_COMPILER_ROCM_LIB_DIRS)
  endif()
  if(CMAKE_HIP_COMPILER_ROCM_LIB MATCHES "/lib64$" AND NOT DEFINED CMAKE_SIZEOF_VOID_P)
    # We have not yet determined the target ABI but we need 'find_package' to
    # search lib64 directories to find hip-lang CMake package dependencies.
    # This will be replaced by ABI detection later.
    set(CMAKE_HIP_SIZEOF_DATA_PTR 8)
  endif()
endif()

if (NOT _CMAKE_TOOLCHAIN_LOCATION)
  get_filename_component(_CMAKE_TOOLCHAIN_LOCATION "${CMAKE_HIP_COMPILER}" PATH)
endif ()

set(_CMAKE_PROCESSING_LANGUAGE "HIP")
include(CMakeFindBinUtils)
include(Compiler/${CMAKE_HIP_COMPILER_ID}-FindBinUtils OPTIONAL)
unset(_CMAKE_PROCESSING_LANGUAGE)

if(CMAKE_HIP_COMPILER_ID STREQUAL "Clang")
  set(CMAKE_HIP_RUNTIME_LIBRARY_DEFAULT "SHARED")
elseif(CMAKE_HIP_COMPILER_ID STREQUAL "NVIDIA")
  include(Internal/CMakeNVCCParseImplicitInfo)
  # Parse CMAKE_HIP_COMPILER_PRODUCED_OUTPUT to get:
  # - CMAKE_HIP_ARCHITECTURES_DEFAULT
  # - CMAKE_HIP_HOST_IMPLICIT_LINK_DIRECTORIES
  # - CMAKE_HIP_HOST_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES
  # - CMAKE_HIP_HOST_IMPLICIT_LINK_LIBRARIES
  # - CMAKE_HIP_HOST_LINK_LAUNCHER
  # - CMAKE_HIP_RUNTIME_LIBRARY_DEFAULT
  # - CMAKE_HIP_CUDA_TOOLKIT_INCLUDE_DIRECTORIES
  # Match arguments with cmake_nvcc_filter_implicit_info call in CMakeTestHIPCompiler.
  cmake_nvcc_parse_implicit_info(HIP CMAKE_HIP_CUDA_)

  include(Internal/CMakeCUDAFilterImplicitLibs)
  # Filter out implicit link libraries that should not be passed unconditionally.
  cmake_cuda_filter_implicit_libs(CMAKE_HIP_HOST_IMPLICIT_LINK_LIBRARIES)
endif()

if(CMAKE_HIP_COMPILER_SYSROOT)
  string(CONCAT _SET_CMAKE_HIP_COMPILER_SYSROOT
    "set(CMAKE_HIP_COMPILER_SYSROOT \"${CMAKE_HIP_COMPILER_SYSROOT}\")\n"
    "set(CMAKE_COMPILER_SYSROOT \"${CMAKE_HIP_COMPILER_SYSROOT}\")")
else()
  set(_SET_CMAKE_HIP_COMPILER_SYSROOT "")
endif()

if(CMAKE_HIP_COMPILER_ARCHITECTURE_ID)
  set(_SET_CMAKE_HIP_COMPILER_ARCHITECTURE_ID
    "set(CMAKE_HIP_COMPILER_ARCHITECTURE_ID ${CMAKE_HIP_COMPILER_ARCHITECTURE_ID})")
else()
  set(_SET_CMAKE_HIP_COMPILER_ARCHITECTURE_ID "")
endif()

if(MSVC_HIP_ARCHITECTURE_ID)
  set(SET_MSVC_HIP_ARCHITECTURE_ID
    "set(MSVC_HIP_ARCHITECTURE_ID ${MSVC_HIP_ARCHITECTURE_ID})")
endif()

if(CMAKE_HIP_COMPILER_ID STREQUAL "NVIDIA")
  if(NOT "$ENV{CUDAARCHS}" STREQUAL "")
    set(CMAKE_HIP_ARCHITECTURES "$ENV{CUDAARCHS}" CACHE STRING "CUDA architectures")
  endif()

  # If the user did not set CMAKE_HIP_ARCHITECTURES, use the compiler's default.
  if("${CMAKE_HIP_ARCHITECTURES}" STREQUAL "")
    set(CMAKE_HIP_ARCHITECTURES "${CMAKE_HIP_ARCHITECTURES_DEFAULT}" CACHE STRING "HIP architectures" FORCE)
    if(NOT CMAKE_HIP_ARCHITECTURES)
      message(FATAL_ERROR "Failed to detect a default HIP architecture.\n\nCompiler output:\n${CMAKE_HIP_COMPILER_PRODUCED_OUTPUT}")
    endif()
  endif()
  unset(CMAKE_HIP_ARCHITECTURES_DEFAULT)
elseif(NOT DEFINED CMAKE_HIP_ARCHITECTURES)
  # Use 'rocm_agent_enumerator' to get the current GPU architecture.
  set(_CMAKE_HIP_ARCHITECTURES)
  find_program(_CMAKE_HIP_ROCM_AGENT_ENUMERATOR
    NAMES rocm_agent_enumerator
    HINTS "${CMAKE_HIP_COMPILER_ROCM_ROOT}/bin"
    NO_CACHE)
  if(_CMAKE_HIP_ROCM_AGENT_ENUMERATOR)
    execute_process(COMMAND "${_CMAKE_HIP_ROCM_AGENT_ENUMERATOR}" -t GPU
      RESULT_VARIABLE _CMAKE_ROCM_AGENT_ENUMERATOR_RESULT
      OUTPUT_VARIABLE _CMAKE_ROCM_AGENT_ENUMERATOR_STDOUT
      ERROR_VARIABLE  _CMAKE_ROCM_AGENT_ENUMERATOR_STDERR
    )
    if(_CMAKE_ROCM_AGENT_ENUMERATOR_RESULT EQUAL 0)
      separate_arguments(_hip_archs NATIVE_COMMAND "${_CMAKE_ROCM_AGENT_ENUMERATOR_STDOUT}")
      foreach(_hip_arch ${_hip_archs})
        if(_hip_arch STREQUAL "gfx000")
          continue()
        endif()
        string(FIND ${_hip_arch} ":" pos)
        if(NOT pos STREQUAL "-1")
          string(SUBSTRING ${_hip_arch} 0 ${pos} _hip_arch)
        endif()
        list(APPEND _CMAKE_HIP_ARCHITECTURES "${_hip_arch}")
      endforeach()
    endif()
    unset(_CMAKE_ROCM_AGENT_ENUMERATOR_RESULT)
    unset(_CMAKE_ROCM_AGENT_ENUMERATOR_STDOUT)
    unset(_CMAKE_ROCM_AGENT_ENUMERATOR_STDERR)
  endif()
  unset(_CMAKE_HIP_ROCM_AGENT_ENUMERATOR)
  if(_CMAKE_HIP_ARCHITECTURES)
    set(CMAKE_HIP_ARCHITECTURES "${_CMAKE_HIP_ARCHITECTURES}" CACHE STRING "HIP architectures")
  elseif(CMAKE_HIP_COMPILER_PRODUCED_OUTPUT MATCHES " -target-cpu ([a-z0-9]+) ")
    set(CMAKE_HIP_ARCHITECTURES "${CMAKE_MATCH_1}" CACHE STRING "HIP architectures")
  else()
    message(FATAL_ERROR "Failed to find a default HIP architecture.")
  endif()
  unset(_CMAKE_HIP_ARCHITECTURES)
endif()

# configure variables set in this file for fast reload later on
configure_file(${CMAKE_ROOT}/Modules/CMakeHIPCompiler.cmake.in
  ${CMAKE_PLATFORM_INFO_DIR}/CMakeHIPCompiler.cmake
  @ONLY
  )
set(CMAKE_HIP_COMPILER_ENV_VAR "HIPCXX")