summaryrefslogtreecommitdiffstats
path: root/Modules/CMakeFindBinUtils.cmake
blob: 5e85440b70020e210ae4e9e7d672366a16fadab1 (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
# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.


# search for additional tools required for C/C++ (and other languages ?)
#
# If the internal cmake variable _CMAKE_TOOLCHAIN_PREFIX is set, this is used
# as prefix for the tools (e.g. arm-elf-gcc etc.)
# If the cmake variable _CMAKE_TOOLCHAIN_LOCATION is set, the compiler is
# searched only there. The other tools are at first searched there, then
# also in the default locations.
#
# Sets the following variables:
#   CMAKE_AR
#   CMAKE_RANLIB
#   CMAKE_LINKER
#   CMAKE_MT
#   CMAKE_STRIP
#   CMAKE_INSTALL_NAME_TOOL

# on UNIX, cygwin and mingw

cmake_policy(PUSH)
cmake_policy(SET CMP0057 NEW) # if IN_LIST

# Resolve full path of CMAKE_TOOL from user-defined name and SEARCH_PATH.
function(__resolve_tool_path CMAKE_TOOL SEARCH_PATH DOCSTRING)

  if(${CMAKE_TOOL})
    # We only get here if CMAKE_TOOL was
    # specified using -D or a pre-made CMakeCache.txt (e.g. via ctest)
    # or set in CMAKE_TOOLCHAIN_FILE.

    get_filename_component(_CMAKE_USER_TOOL_PATH "${${CMAKE_TOOL}}" DIRECTORY)
    # Is CMAKE_TOOL a user-defined name instead of a full path?
    if(NOT _CMAKE_USER_TOOL_PATH)

      # Find CMAKE_TOOL in the SEARCH_PATH directory by user-defined name.
      find_program(_CMAKE_TOOL_WITH_PATH NAMES ${${CMAKE_TOOL}} HINTS ${SEARCH_PATH} NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH)
      if(_CMAKE_TOOL_WITH_PATH)

        # Overwrite CMAKE_TOOL with full path found in SEARCH_PATH.
        set(${CMAKE_TOOL} ${_CMAKE_TOOL_WITH_PATH} PARENT_SCOPE)

        get_property(_CMAKE_TOOL_CACHED CACHE ${CMAKE_TOOL} PROPERTY TYPE)
        # If CMAKE_TOOL is present in the CMake Cache, then overwrit it as well.
        if(_CMAKE_TOOL_CACHED)
          set(${CMAKE_TOOL} "${_CMAKE_TOOL_WITH_PATH}" CACHE STRING ${DOCSTRING} FORCE)
        endif()

      endif()
      unset(_CMAKE_TOOL_WITH_PATH CACHE)

    endif()

  endif()

endfunction()

__resolve_tool_path(CMAKE_LINKER "${_CMAKE_TOOLCHAIN_LOCATION}" "Default Linker")
__resolve_tool_path(CMAKE_MT     "${_CMAKE_TOOLCHAIN_LOCATION}" "Default Manifest Tool")

macro(__resolve_linker_path __linker_type __name __search_path __doc)
  if(NOT CMAKE_LINKER_${__linker_type})
    set( CMAKE_LINKER_${__linker_type} "${__name}")
  endif()
  __resolve_tool_path(CMAKE_LINKER_${__linker_type} "${__search_path}" "${__doc}")
endmacro()

set(_CMAKE_TOOL_VARS "")

# if it's the MS C/CXX compiler, search for link
if(("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_SIMULATE_ID}" STREQUAL "xMSVC" AND
   ("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC"
    OR NOT "x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL "xClang"))
   OR "x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL "xMSVC"
   OR (CMAKE_HOST_WIN32 AND "x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL "xPGI")
   OR (CMAKE_HOST_WIN32 AND "x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL "xNVIDIA")
   OR (CMAKE_HOST_WIN32 AND "x${_CMAKE_PROCESSING_LANGUAGE}" STREQUAL "xISPC")
   OR (CMAKE_GENERATOR MATCHES "Visual Studio"
       AND NOT CMAKE_VS_PLATFORM_NAME STREQUAL "Tegra-Android"))

  # Start with the canonical names.
  set(_CMAKE_LINKER_NAMES "link")
  set(_CMAKE_AR_NAMES "lib")
  set(_CMAKE_MT_NAMES "mt")

  # Prepend toolchain-specific names.
  if("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" MATCHES "^x(Clang|LLVMFlang)$")
    set(_CMAKE_NM_NAMES "llvm-nm" "nm")
    list(PREPEND _CMAKE_AR_NAMES "llvm-lib")
    # llvm-mt is not ready to be used as a replacement for mt.exe
    # list(PREPEND _CMAKE_MT_NAMES "llvm-mt")
    list(PREPEND _CMAKE_LINKER_NAMES "lld-link")
    list(APPEND _CMAKE_TOOL_VARS NM)
  elseif("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL "xIntel")
    list(PREPEND _CMAKE_AR_NAMES "xilib")
    list(PREPEND _CMAKE_LINKER_NAMES "xilink")
  endif()

  list(APPEND _CMAKE_TOOL_VARS LINKER MT AR)

  # look-up for possible usable linker
  __resolve_linker_path(LINK "link" "${_CMAKE_TOOLCHAIN_LOCATION}" "link Linker")
  __resolve_linker_path(LLD "lld-link" "${_CMAKE_TOOLCHAIN_LOCATION}" "lld-link Linker")

elseif("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" MATCHES "^x(Open)?Watcom$")
  set(_CMAKE_LINKER_NAMES "wlink")
  set(_CMAKE_AR_NAMES "wlib")
  list(APPEND _CMAKE_TOOL_VARS LINKER AR)

elseif("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" MATCHES "^xIAR$")
  # Small helper declaring an IAR tool (e.g. linker) to avoid repeating the same idiom every time
  macro(__append_IAR_tool TOOL_VAR NAME)
    set(_CMAKE_${TOOL_VAR}_NAMES "${NAME}" "${NAME}.exe")
    list(APPEND _CMAKE_TOOL_VARS ${TOOL_VAR})
  endmacro()

  # Resolve hint path from an IAR compiler
  function(__resolve_IAR_hints COMPILER RESULT)
    get_filename_component(_CMAKE_IAR_HINT "${COMPILER}" REALPATH)
    get_filename_component(_CMAKE_IAR_HINT "${_CMAKE_IAR_HINT}" DIRECTORY)
    list(APPEND _IAR_HINTS "${_CMAKE_IAR_HINT}")

    get_filename_component(_CMAKE_IAR_HINT "${COMPILER}" DIRECTORY)
    list(APPEND _IAR_HINTS "${_CMAKE_IAR_HINT}")

    set(${RESULT} "${_IAR_HINTS}" PARENT_SCOPE)
  endfunction()

  __resolve_IAR_hints("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER}" _CMAKE_TOOLCHAIN_LOCATION)
  set(_CMAKE_IAR_ITOOLS "ARM" "RX" "RH850" "RL78" "RISCV" "RISC-V" "STM8")
  set(_CMAKE_IAR_XTOOLS "AVR" "MSP430" "V850" "8051")

  string(TOLOWER "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" _CMAKE_IAR_LOWER_ARCHITECTURE_ID)

  if("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" IN_LIST _CMAKE_IAR_ITOOLS)
    __append_IAR_tool(AR "iarchive")
    __append_IAR_tool(LINKER "ilink${_CMAKE_IAR_LOWER_ARCHITECTURE_ID}")

    __append_IAR_tool(IAR_ELFDUMP "ielfdump${_CMAKE_IAR_LOWER_ARCHITECTURE_ID}")
    __append_IAR_tool(IAR_ELFTOOL "ielftool")
    __append_IAR_tool(IAR_OBJMANIP "iobjmanip")
    __append_IAR_tool(IAR_SYMEXPORT "isymexport")

  elseif("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" IN_LIST _CMAKE_IAR_XTOOLS)
    __append_IAR_tool(AR "xar")
    if("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" STREQUAL "AVR" AND
      (CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_VERSION VERSION_GREATER_EQUAL 8))
      # IAR UBROF Linker V8.10+ for Microchip AVR is `xlinkavr`
      __append_IAR_tool(LINKER "xlink${_CMAKE_IAR_LOWER_ARCHITECTURE_ID}")
    else()
      __append_IAR_tool(LINKER "xlink")
    endif()

  else()
    message(FATAL_ERROR "Failed to find linker and librarian for ${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID} on ${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}.")
  endif()

  unset(_CMAKE_IAR_LOWER_ARCHITECTURE_ID)
  unset(_CMAKE_IAR_ITOOLS)
  unset(_CMAKE_IAR_XTOOLS)

# in all other cases search for ar, ranlib, etc.
else()
  if(CMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN)
    set(_CMAKE_TOOLCHAIN_LOCATION ${_CMAKE_TOOLCHAIN_LOCATION} ${CMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN}/bin)
  endif()
  if(CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN)
    set(_CMAKE_TOOLCHAIN_LOCATION ${_CMAKE_TOOLCHAIN_LOCATION} ${CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN}/bin)
  endif()

  # Start with the canonical names.
  set(_CMAKE_AR_NAMES "ar")
  set(_CMAKE_RANLIB_NAMES "ranlib")
  set(_CMAKE_STRIP_NAMES "strip")
  set(_CMAKE_LINKER_NAMES "ld")
  set(_CMAKE_NM_NAMES "nm")
  set(_CMAKE_OBJDUMP_NAMES "objdump")
  set(_CMAKE_OBJCOPY_NAMES "objcopy")
  set(_CMAKE_READELF_NAMES "readelf")
  set(_CMAKE_DLLTOOL_NAMES "dlltool")
  set(_CMAKE_ADDR2LINE_NAMES "addr2line")
  set(_CMAKE_TAPI_NAMES "tapi")

  # Prepend toolchain-specific names.
  if("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL Clang)
    if("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_SIMULATE_ID}" STREQUAL "xMSVC")
      list(PREPEND _CMAKE_LINKER_NAMES "lld-link")
    elseif(NOT APPLE)
      list(PREPEND _CMAKE_LINKER_NAMES "ld.lld")
    endif()
    # llvm-ar does not generate a symbol table that the Apple ld64 linker accepts.
    if(NOT APPLE)
      list(PREPEND _CMAKE_AR_NAMES "llvm-ar")
    endif()
    list(PREPEND _CMAKE_RANLIB_NAMES "llvm-ranlib")
    # llvm-strip versions prior to 11 require additional flags we do not yet add.
    if("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_VERSION}" VERSION_GREATER_EQUAL 11)
      # llvm-strip does not seem to support chained fixup format on macOS correctly.
      if(NOT APPLE)
        list(PREPEND _CMAKE_STRIP_NAMES "llvm-strip")
      endif()
    endif()
    list(PREPEND _CMAKE_NM_NAMES "llvm-nm")
    if("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_VERSION}" VERSION_GREATER_EQUAL 9)
      # llvm-objcopy and llvm-objdump on versions prior to 9 did not support everything we need.
      list(PREPEND _CMAKE_OBJCOPY_NAMES "llvm-objcopy")
      list(PREPEND _CMAKE_OBJDUMP_NAMES "llvm-objdump")
    endif()
    list(PREPEND _CMAKE_READELF_NAMES "llvm-readelf")
    list(PREPEND _CMAKE_DLLTOOL_NAMES "llvm-dlltool")
    list(PREPEND _CMAKE_ADDR2LINE_NAMES "llvm-addr2line")
  elseif("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL ARMClang)
    list(PREPEND _CMAKE_AR_NAMES "armar")
    list(PREPEND _CMAKE_LINKER_NAMES "armlink")
  endif()

  list(APPEND _CMAKE_TOOL_VARS AR RANLIB STRIP LINKER NM OBJDUMP OBJCOPY READELF DLLTOOL ADDR2LINE TAPI)
endif()

foreach(_CMAKE_TOOL IN LISTS _CMAKE_TOOL_VARS)
  # Build the final list of prefixed/suffixed names.
  set(_CMAKE_${_CMAKE_TOOL}_FIND_NAMES "")
  foreach(_CMAKE_TOOL_NAME IN LISTS _CMAKE_${_CMAKE_TOOL}_NAMES)
    list(APPEND _CMAKE_${_CMAKE_TOOL}_FIND_NAMES
      ${_CMAKE_TOOLCHAIN_PREFIX}${_CMAKE_TOOL_NAME}${_CMAKE_TOOLCHAIN_SUFFIX}
      ${_CMAKE_TOOLCHAIN_PREFIX}${_CMAKE_TOOL_NAME}
      ${_CMAKE_TOOL_NAME}${_CMAKE_TOOLCHAIN_SUFFIX}
      ${_CMAKE_TOOL_NAME}
      )
  endforeach()
  list(REMOVE_DUPLICATES _CMAKE_${_CMAKE_TOOL}_FIND_NAMES)

  find_program(CMAKE_${_CMAKE_TOOL} NAMES ${_CMAKE_${_CMAKE_TOOL}_FIND_NAMES} HINTS ${_CMAKE_TOOLCHAIN_LOCATION} NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH)
  unset(_CMAKE_${_CMAKE_TOOL}_FIND_NAMES)
endforeach()

if(NOT CMAKE_RANLIB)
    set(CMAKE_RANLIB : CACHE INTERNAL "noop for ranlib")
endif()

if(APPLE AND "TAPI" IN_LIST _CMAKE_TOOL_VARS AND NOT CMAKE_TAPI)
  # try to pick-up from Apple toolchain
  execute_process(COMMAND xcrun --find tapi
    OUTPUT_VARIABLE _xcrun_out
    OUTPUT_STRIP_TRAILING_WHITESPACE
    ERROR_QUIET
    RESULT_VARIABLE _xcrun_failed)
  if(NOT _xcrun_failed AND EXISTS "${_xcrun_out}")
    set_property(CACHE CMAKE_TAPI PROPERTY VALUE "${_xcrun_out}")
  endif()
  unset(_xcrun_out)
  unset(_xcrun_failed)
endif()


if(CMAKE_PLATFORM_HAS_INSTALLNAME)
  find_program(CMAKE_INSTALL_NAME_TOOL NAMES ${_CMAKE_TOOLCHAIN_PREFIX}install_name_tool HINTS ${_CMAKE_TOOLCHAIN_LOCATION} NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH)

  if(NOT CMAKE_INSTALL_NAME_TOOL)
    message(FATAL_ERROR "Could not find install_name_tool, please check your installation.")
  endif()

  list(APPEND _CMAKE_TOOL_VARS INSTALL_NAME_TOOL)
endif()

# Mark any tool cache entries as advanced.
foreach(_CMAKE_TOOL IN LISTS _CMAKE_TOOL_VARS)
  get_property(_CMAKE_TOOL_CACHED CACHE CMAKE_${_CMAKE_TOOL} PROPERTY TYPE)
  if(_CMAKE_TOOL_CACHED)
    mark_as_advanced(CMAKE_${_CMAKE_TOOL})
  endif()
  unset(_CMAKE_${_CMAKE_TOOL}_NAMES)
endforeach()
unset(_CMAKE_TOOL_VARS)
unset(_CMAKE_TOOL_CACHED)
unset(_CMAKE_TOOL_NAME)
unset(_CMAKE_TOOL)

if("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" MATCHES "^xIAR$")
  # Set for backwards compatibility
  set(CMAKE_IAR_ARCHIVE "${CMAKE_AR}" CACHE FILEPATH "The IAR archiver")
  set(CMAKE_IAR_LINKER "${CMAKE_LINKER}" CACHE FILEPATH "The IAR ILINK linker")
  mark_as_advanced(CMAKE_IAR_LINKER CMAKE_IAR_AR)
endif()

cmake_policy(POP)