1# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2# file Copyright.txt or https://cmake.org/licensing for details.
3
4
5# search for additional tools required for C/C++ (and other languages ?)
6#
7# If the internal cmake variable _CMAKE_TOOLCHAIN_PREFIX is set, this is used
8# as prefix for the tools (e.g. arm-elf-gcc etc.)
9# If the cmake variable _CMAKE_TOOLCHAIN_LOCATION is set, the compiler is
10# searched only there. The other tools are at first searched there, then
11# also in the default locations.
12#
13# Sets the following variables:
14#   CMAKE_AR
15#   CMAKE_RANLIB
16#   CMAKE_LINKER
17#   CMAKE_MT
18#   CMAKE_STRIP
19#   CMAKE_INSTALL_NAME_TOOL
20
21# on UNIX, cygwin and mingw
22
23cmake_policy(PUSH)
24cmake_policy(SET CMP0057 NEW) # if IN_LIST
25
26# Resolve full path of CMAKE_TOOL from user-defined name and SEARCH_PATH.
27function(__resolve_tool_path CMAKE_TOOL SEARCH_PATH DOCSTRING)
28
29  if(${CMAKE_TOOL})
30    # We only get here if CMAKE_TOOL was
31    # specified using -D or a pre-made CMakeCache.txt (e.g. via ctest)
32    # or set in CMAKE_TOOLCHAIN_FILE.
33
34    get_filename_component(_CMAKE_USER_TOOL_PATH "${${CMAKE_TOOL}}" DIRECTORY)
35    # Is CMAKE_TOOL a user-defined name instead of a full path?
36    if(NOT _CMAKE_USER_TOOL_PATH)
37
38      # Find CMAKE_TOOL in the SEARCH_PATH directory by user-defined name.
39      find_program(_CMAKE_TOOL_WITH_PATH NAMES ${${CMAKE_TOOL}} HINTS ${SEARCH_PATH} NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH)
40      if(_CMAKE_TOOL_WITH_PATH)
41
42        # Overwrite CMAKE_TOOL with full path found in SEARCH_PATH.
43        set(${CMAKE_TOOL} ${_CMAKE_TOOL_WITH_PATH} PARENT_SCOPE)
44
45        get_property(_CMAKE_TOOL_CACHED CACHE ${CMAKE_TOOL} PROPERTY TYPE)
46        # If CMAKE_TOOL is present in the CMake Cache, then overwrit it as well.
47        if(_CMAKE_TOOL_CACHED)
48          set(${CMAKE_TOOL} "${_CMAKE_TOOL_WITH_PATH}" CACHE STRING ${DOCSTRING} FORCE)
49        endif()
50
51      endif()
52      unset(_CMAKE_TOOL_WITH_PATH CACHE)
53
54    endif()
55
56  endif()
57
58endfunction()
59
60__resolve_tool_path(CMAKE_LINKER "${_CMAKE_TOOLCHAIN_LOCATION}" "Default Linker")
61__resolve_tool_path(CMAKE_MT     "${_CMAKE_TOOLCHAIN_LOCATION}" "Default Manifest Tool")
62
63set(_CMAKE_TOOL_VARS "")
64
65# if it's the MS C/CXX compiler, search for link
66if(("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_SIMULATE_ID}" STREQUAL "xMSVC" AND
67   ("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC"
68    OR NOT "x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL "xClang"))
69   OR "x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL "xMSVC"
70   OR (CMAKE_HOST_WIN32 AND "x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL "xPGI")
71   OR (CMAKE_HOST_WIN32 AND "x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL "xNVIDIA")
72   OR (CMAKE_HOST_WIN32 AND "x${_CMAKE_PROCESSING_LANGUAGE}" STREQUAL "xISPC")
73   OR (CMAKE_GENERATOR MATCHES "Visual Studio"
74       AND NOT CMAKE_VS_PLATFORM_NAME STREQUAL "Tegra-Android"))
75
76  # Start with the canonical names.
77  set(_CMAKE_LINKER_NAMES "link")
78  set(_CMAKE_AR_NAMES "lib")
79  set(_CMAKE_MT_NAMES "mt")
80
81  # Prepend toolchain-specific names.
82  if("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL "xClang")
83    set(_CMAKE_NM_NAMES "llvm-nm" "nm")
84    list(PREPEND _CMAKE_AR_NAMES "llvm-lib")
85    list(PREPEND _CMAKE_MT_NAMES "llvm-mt")
86    list(PREPEND _CMAKE_LINKER_NAMES "lld-link")
87    list(APPEND _CMAKE_TOOL_VARS NM)
88  elseif("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL "xIntel")
89    list(PREPEND _CMAKE_AR_NAMES "xilib")
90    list(PREPEND _CMAKE_LINKER_NAMES "xilink")
91  endif()
92
93  list(APPEND _CMAKE_TOOL_VARS LINKER MT AR)
94
95elseif("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" MATCHES "^x(Open)?Watcom$")
96  set(_CMAKE_LINKER_NAMES "wlink")
97  set(_CMAKE_AR_NAMES "wlib")
98  list(APPEND _CMAKE_TOOL_VARS LINKER AR)
99
100elseif("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" MATCHES "^xIAR$")
101  # Small helper declaring an IAR tool (e.g. linker) to avoid repeating the same idiom every time
102  macro(__append_IAR_tool TOOL_VAR NAME)
103    set(_CMAKE_${TOOL_VAR}_NAMES "${NAME}" "${NAME}.exe")
104    list(APPEND _CMAKE_TOOL_VARS ${TOOL_VAR})
105  endmacro()
106
107  # Resolve hint path from an IAR compiler
108  function(__resolve_IAR_hints COMPILER RESULT)
109    get_filename_component(_CMAKE_IAR_HINT "${COMPILER}" REALPATH)
110    get_filename_component(_CMAKE_IAR_HINT "${_CMAKE_IAR_HINT}" DIRECTORY)
111    list(APPEND _IAR_HINTS "${_CMAKE_IAR_HINT}")
112
113    get_filename_component(_CMAKE_IAR_HINT "${COMPILER}" DIRECTORY)
114    list(APPEND _IAR_HINTS "${_CMAKE_IAR_HINT}")
115
116    set(${RESULT} "${_IAR_HINTS}" PARENT_SCOPE)
117  endfunction()
118
119  __resolve_IAR_hints("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER}" _CMAKE_TOOLCHAIN_LOCATION)
120  set(_CMAKE_IAR_ITOOLS "ARM" "RX" "RH850" "RL78" "RISCV" "RISC-V" "STM8")
121  set(_CMAKE_IAR_XTOOLS "AVR" "MSP430" "V850" "8051")
122
123  if("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" IN_LIST _CMAKE_IAR_ITOOLS)
124    string(TOLOWER "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" _CMAKE_IAR_LOWER_ARCHITECTURE_ID)
125
126    __append_IAR_tool(AR "iarchive")
127    __append_IAR_tool(LINKER "ilink${_CMAKE_IAR_LOWER_ARCHITECTURE_ID}")
128
129    __append_IAR_tool(IAR_ELFDUMP "ielfdump${_CMAKE_IAR_LOWER_ARCHITECTURE_ID}")
130    __append_IAR_tool(IAR_ELFTOOL "ielftool")
131    __append_IAR_tool(IAR_OBJMANIP "iobjmanip")
132    __append_IAR_tool(IAR_SYMEXPORT "isymexport")
133
134    unset(_CMAKE_IAR_LOWER_ARCHITECTURE_ID)
135
136  elseif("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" IN_LIST _CMAKE_IAR_XTOOLS)
137    __append_IAR_tool(AR "xar")
138    __append_IAR_tool(LINKER "xlink")
139
140  else()
141    message(FATAL_ERROR "Failed to find linker and librarian for ${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID} on ${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}.")
142  endif()
143
144  unset(_CMAKE_IAR_ITOOLS)
145  unset(_CMAKE_IAR_XTOOLS)
146
147# in all other cases search for ar, ranlib, etc.
148else()
149  if(CMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN)
150    set(_CMAKE_TOOLCHAIN_LOCATION ${_CMAKE_TOOLCHAIN_LOCATION} ${CMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN}/bin)
151  endif()
152  if(CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN)
153    set(_CMAKE_TOOLCHAIN_LOCATION ${_CMAKE_TOOLCHAIN_LOCATION} ${CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN}/bin)
154  endif()
155
156  # Start with the canonical names.
157  set(_CMAKE_AR_NAMES "ar")
158  set(_CMAKE_RANLIB_NAMES "ranlib")
159  set(_CMAKE_STRIP_NAMES "strip")
160  set(_CMAKE_LINKER_NAMES "ld")
161  set(_CMAKE_NM_NAMES "nm")
162  set(_CMAKE_OBJDUMP_NAMES "objdump")
163  set(_CMAKE_OBJCOPY_NAMES "objcopy")
164  set(_CMAKE_READELF_NAMES "readelf")
165  set(_CMAKE_DLLTOOL_NAMES "dlltool")
166  set(_CMAKE_ADDR2LINE_NAMES "addr2line")
167
168  # Prepend toolchain-specific names.
169  if("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL Clang)
170    if("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_SIMULATE_ID}" STREQUAL "xMSVC")
171      list(PREPEND _CMAKE_LINKER_NAMES "lld-link")
172    else()
173      list(PREPEND _CMAKE_LINKER_NAMES "ld.lld")
174    endif()
175    list(PREPEND _CMAKE_AR_NAMES "llvm-ar")
176    list(PREPEND _CMAKE_RANLIB_NAMES "llvm-ranlib")
177    if("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_VERSION}" VERSION_GREATER_EQUAL 11)
178      # llvm-strip versions prior to 11 require additional flags we do not yet add.
179      list(PREPEND _CMAKE_STRIP_NAMES "llvm-strip")
180    endif()
181    list(PREPEND _CMAKE_NM_NAMES "llvm-nm")
182    if("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_VERSION}" VERSION_GREATER_EQUAL 9)
183      # llvm-objdump versions prior to 9 did not support everything we need.
184      list(PREPEND _CMAKE_OBJDUMP_NAMES "llvm-objdump")
185    endif()
186    list(PREPEND _CMAKE_OBJCOPY_NAMES "llvm-objcopy")
187    list(PREPEND _CMAKE_READELF_NAMES "llvm-readelf")
188    list(PREPEND _CMAKE_DLLTOOL_NAMES "llvm-dlltool")
189    list(PREPEND _CMAKE_ADDR2LINE_NAMES "llvm-addr2line")
190  elseif("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL ARMClang)
191    list(PREPEND _CMAKE_AR_NAMES "armar")
192    list(PREPEND _CMAKE_LINKER_NAMES "armlink")
193  endif()
194
195  list(APPEND _CMAKE_TOOL_VARS AR RANLIB STRIP LINKER NM OBJDUMP OBJCOPY READELF DLLTOOL ADDR2LINE)
196endif()
197
198foreach(_CMAKE_TOOL IN LISTS _CMAKE_TOOL_VARS)
199  # Build the final list of prefixed/suffixed names.
200  set(_CMAKE_${_CMAKE_TOOL}_FIND_NAMES "")
201  foreach(_CMAKE_TOOL_NAME IN LISTS _CMAKE_${_CMAKE_TOOL}_NAMES)
202    list(APPEND _CMAKE_${_CMAKE_TOOL}_FIND_NAMES
203      ${_CMAKE_TOOLCHAIN_PREFIX}${_CMAKE_TOOL_NAME}${_CMAKE_TOOLCHAIN_SUFFIX}
204      ${_CMAKE_TOOLCHAIN_PREFIX}${_CMAKE_TOOL_NAME}
205      ${_CMAKE_TOOL_NAME}${_CMAKE_TOOLCHAIN_SUFFIX}
206      ${_CMAKE_TOOL_NAME}
207      )
208  endforeach()
209  list(REMOVE_DUPLICATES _CMAKE_${_CMAKE_TOOL}_FIND_NAMES)
210
211  find_program(CMAKE_${_CMAKE_TOOL} NAMES ${_CMAKE_${_CMAKE_TOOL}_FIND_NAMES} HINTS ${_CMAKE_TOOLCHAIN_LOCATION} NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH)
212  unset(_CMAKE_${_CMAKE_TOOL}_FIND_NAMES)
213endforeach()
214
215if(NOT CMAKE_RANLIB)
216    set(CMAKE_RANLIB : CACHE INTERNAL "noop for ranlib")
217endif()
218
219
220if(CMAKE_PLATFORM_HAS_INSTALLNAME)
221  find_program(CMAKE_INSTALL_NAME_TOOL NAMES ${_CMAKE_TOOLCHAIN_PREFIX}install_name_tool HINTS ${_CMAKE_TOOLCHAIN_LOCATION} NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH)
222
223  if(NOT CMAKE_INSTALL_NAME_TOOL)
224    message(FATAL_ERROR "Could not find install_name_tool, please check your installation.")
225  endif()
226
227  list(APPEND _CMAKE_TOOL_VARS INSTALL_NAME_TOOL)
228endif()
229
230# Mark any tool cache entries as advanced.
231foreach(_CMAKE_TOOL IN LISTS _CMAKE_TOOL_VARS)
232  get_property(_CMAKE_TOOL_CACHED CACHE CMAKE_${_CMAKE_TOOL} PROPERTY TYPE)
233  if(_CMAKE_TOOL_CACHED)
234    mark_as_advanced(CMAKE_${_CMAKE_TOOL})
235  endif()
236  unset(_CMAKE_${_CMAKE_TOOL}_NAMES)
237endforeach()
238unset(_CMAKE_TOOL_VARS)
239unset(_CMAKE_TOOL_CACHED)
240unset(_CMAKE_TOOL_NAME)
241unset(_CMAKE_TOOL)
242
243if("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" MATCHES "^xIAR$")
244  # Set for backwards compatibility
245  set(CMAKE_IAR_ARCHIVE "${CMAKE_AR}" CACHE FILEPATH "The IAR archiver")
246  set(CMAKE_IAR_LINKER "${CMAKE_LINKER}" CACHE FILEPATH "The IAR ILINK linker")
247  mark_as_advanced(CMAKE_IAR_LINKER CMAKE_IAR_AR)
248endif()
249
250cmake_policy(POP)
251