91dcba5a8fbd7d03c79d90f3c11bbbfbfbea9aaf
[platform/upstream/cmake.git] / Modules / FindICU.cmake
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 #[=======================================================================[.rst:
5 FindICU
6 -------
7
8 .. versionadded:: 3.7
9
10 Find the International Components for Unicode (ICU) libraries and
11 programs.
12
13 This module supports multiple components.
14 Components can include any of: ``data``, ``i18n``, ``io``, ``le``,
15 ``lx``, ``test``, ``tu`` and ``uc``.
16
17 Note that on Windows ``data`` is named ``dt`` and ``i18n`` is named
18 ``in``; any of the names may be used, and the appropriate
19 platform-specific library name will be automatically selected.
20
21 .. versionadded:: 3.11
22   Added support for static libraries on Windows.
23
24 This module reports information about the ICU installation in
25 several variables.  General variables::
26
27   ICU_VERSION - ICU release version
28   ICU_FOUND - true if the main programs and libraries were found
29   ICU_LIBRARIES - component libraries to be linked
30   ICU_INCLUDE_DIRS - the directories containing the ICU headers
31
32 Imported targets::
33
34   ICU::<C>
35
36 Where ``<C>`` is the name of an ICU component, for example
37 ``ICU::i18n``; ``<C>`` is lower-case.
38
39 ICU programs are reported in::
40
41   ICU_GENCNVAL_EXECUTABLE - path to gencnval executable
42   ICU_ICUINFO_EXECUTABLE - path to icuinfo executable
43   ICU_GENBRK_EXECUTABLE - path to genbrk executable
44   ICU_ICU-CONFIG_EXECUTABLE - path to icu-config executable
45   ICU_GENRB_EXECUTABLE - path to genrb executable
46   ICU_GENDICT_EXECUTABLE - path to gendict executable
47   ICU_DERB_EXECUTABLE - path to derb executable
48   ICU_PKGDATA_EXECUTABLE - path to pkgdata executable
49   ICU_UCONV_EXECUTABLE - path to uconv executable
50   ICU_GENCFU_EXECUTABLE - path to gencfu executable
51   ICU_MAKECONV_EXECUTABLE - path to makeconv executable
52   ICU_GENNORM2_EXECUTABLE - path to gennorm2 executable
53   ICU_GENCCODE_EXECUTABLE - path to genccode executable
54   ICU_GENSPREP_EXECUTABLE - path to gensprep executable
55   ICU_ICUPKG_EXECUTABLE - path to icupkg executable
56   ICU_GENCMN_EXECUTABLE - path to gencmn executable
57
58 ICU component libraries are reported in::
59
60   ICU_<C>_FOUND - ON if component was found; ``<C>`` is upper-case.
61   ICU_<C>_LIBRARIES - libraries for component; ``<C>`` is upper-case.
62
63 ICU datafiles are reported in::
64
65   ICU_MAKEFILE_INC - Makefile.inc
66   ICU_PKGDATA_INC - pkgdata.inc
67
68 This module reads hints about search results from::
69
70   ICU_ROOT - the root of the ICU installation
71
72 The environment variable ``ICU_ROOT`` may also be used; the
73 ICU_ROOT variable takes precedence.
74
75 The following cache variables may also be set::
76
77   ICU_<P>_EXECUTABLE - the path to executable <P>; ``<P>`` is upper-case.
78   ICU_INCLUDE_DIR - the directory containing the ICU headers
79   ICU_<C>_LIBRARY - the library for component <C>; ``<C>`` is upper-case.
80
81 .. note::
82
83   In most cases none of the above variables will require setting,
84   unless multiple ICU versions are available and a specific version
85   is required.
86
87 Other variables one may set to control this module are::
88
89   ICU_DEBUG - Set to ON to enable debug output from FindICU.
90 #]=======================================================================]
91
92 # Written by Roger Leigh <rleigh@codelibre.net>
93
94 set(icu_programs
95   gencnval
96   icuinfo
97   genbrk
98   icu-config
99   genrb
100   gendict
101   derb
102   pkgdata
103   uconv
104   gencfu
105   makeconv
106   gennorm2
107   genccode
108   gensprep
109   icupkg
110   gencmn)
111
112 set(icu_data
113   Makefile.inc
114   pkgdata.inc)
115
116 # The ICU checks are contained in a function due to the large number
117 # of temporary variables needed.
118 function(_ICU_FIND)
119   # Set up search paths, taking compiler into account.  Search ICU_ROOT,
120   # with ICU_ROOT in the environment as a fallback if unset.
121   if(ICU_ROOT)
122     list(APPEND icu_roots "${ICU_ROOT}")
123   else()
124     if(NOT "$ENV{ICU_ROOT}" STREQUAL "")
125       file(TO_CMAKE_PATH "$ENV{ICU_ROOT}" NATIVE_PATH)
126       list(APPEND icu_roots "${NATIVE_PATH}")
127       set(ICU_ROOT "${NATIVE_PATH}"
128           CACHE PATH "Location of the ICU installation" FORCE)
129     endif()
130   endif()
131
132   # Find include directory
133   list(APPEND icu_include_suffixes "include")
134   find_path(ICU_INCLUDE_DIR
135             NAMES "unicode/utypes.h"
136             HINTS ${icu_roots}
137             PATH_SUFFIXES ${icu_include_suffixes}
138             DOC "ICU include directory")
139   set(ICU_INCLUDE_DIR "${ICU_INCLUDE_DIR}" PARENT_SCOPE)
140
141   # Get version
142   if(ICU_INCLUDE_DIR AND EXISTS "${ICU_INCLUDE_DIR}/unicode/uvernum.h")
143     file(STRINGS "${ICU_INCLUDE_DIR}/unicode/uvernum.h" icu_header_str
144       REGEX "^#define[\t ]+U_ICU_VERSION[\t ]+\".*\".*")
145
146     string(REGEX REPLACE "^#define[\t ]+U_ICU_VERSION[\t ]+\"([^ \\n]*)\".*"
147       "\\1" icu_version_string "${icu_header_str}")
148     set(ICU_VERSION "${icu_version_string}")
149     set(ICU_VERSION "${icu_version_string}" PARENT_SCOPE)
150     unset(icu_header_str)
151     unset(icu_version_string)
152   endif()
153
154   if(CMAKE_SIZEOF_VOID_P EQUAL 8)
155     # 64-bit binary directory
156     set(_bin64 "bin64")
157     # 64-bit library directory
158     set(_lib64 "lib64")
159   endif()
160
161
162   # Find all ICU programs
163   list(APPEND icu_binary_suffixes "${_bin64}" "bin" "sbin")
164   foreach(program ${icu_programs})
165     string(TOUPPER "${program}" program_upcase)
166     set(cache_var "ICU_${program_upcase}_EXECUTABLE")
167     set(program_var "ICU_${program_upcase}_EXECUTABLE")
168     find_program("${cache_var}"
169       NAMES "${program}"
170       HINTS ${icu_roots}
171       PATH_SUFFIXES ${icu_binary_suffixes}
172       DOC "ICU ${program} executable"
173       NO_PACKAGE_ROOT_PATH
174       )
175     mark_as_advanced("${cache_var}")
176     set("${program_var}" "${${cache_var}}" PARENT_SCOPE)
177   endforeach()
178
179   # Find all ICU libraries
180   list(APPEND icu_library_suffixes "${_lib64}" "lib")
181   set(ICU_REQUIRED_LIBS_FOUND ON)
182   set(static_prefix )
183   # static icu libraries compiled with MSVC have the prefix 's'
184   if(MSVC)
185     set(static_prefix "s")
186   endif()
187   foreach(component ${ICU_FIND_COMPONENTS})
188     string(TOUPPER "${component}" component_upcase)
189     set(component_cache "ICU_${component_upcase}_LIBRARY")
190     set(component_cache_release "${component_cache}_RELEASE")
191     set(component_cache_debug "${component_cache}_DEBUG")
192     set(component_found "ICU_${component_upcase}_FOUND")
193     set(component_found_compat "${component_upcase}_FOUND")
194     set(component_libnames "icu${component}")
195     set(component_debug_libnames "icu${component}d")
196
197     # Special case deliberate library naming mismatches between Unix
198     # and Windows builds
199     unset(component_libnames)
200     unset(component_debug_libnames)
201     list(APPEND component_libnames "icu${component}")
202     list(APPEND component_debug_libnames "icu${component}d")
203     if(component STREQUAL "data")
204       list(APPEND component_libnames "icudt")
205       # Note there is no debug variant at present
206       list(APPEND component_debug_libnames "icudtd")
207     endif()
208     if(component STREQUAL "dt")
209       list(APPEND component_libnames "icudata")
210       # Note there is no debug variant at present
211       list(APPEND component_debug_libnames "icudatad")
212     endif()
213     if(component STREQUAL "i18n")
214       list(APPEND component_libnames "icuin")
215       list(APPEND component_debug_libnames "icuind")
216     endif()
217     if(component STREQUAL "in")
218       list(APPEND component_libnames "icui18n")
219       list(APPEND component_debug_libnames "icui18nd")
220     endif()
221
222     if(static_prefix)
223       unset(static_component_libnames)
224       unset(static_component_debug_libnames)
225       foreach(component_libname ${component_libnames})
226         list(APPEND static_component_libnames
227           ${static_prefix}${component_libname})
228       endforeach()
229       foreach(component_libname ${component_debug_libnames})
230         list(APPEND static_component_debug_libnames
231           ${static_prefix}${component_libname})
232       endforeach()
233       list(APPEND component_libnames ${static_component_libnames})
234       list(APPEND component_debug_libnames ${static_component_debug_libnames})
235     endif()
236     find_library("${component_cache_release}"
237       NAMES ${component_libnames}
238       HINTS ${icu_roots}
239       PATH_SUFFIXES ${icu_library_suffixes}
240       DOC "ICU ${component} library (release)"
241       NO_PACKAGE_ROOT_PATH
242       )
243     find_library("${component_cache_debug}"
244       NAMES ${component_debug_libnames}
245       HINTS ${icu_roots}
246       PATH_SUFFIXES ${icu_library_suffixes}
247       DOC "ICU ${component} library (debug)"
248       NO_PACKAGE_ROOT_PATH
249       )
250     include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
251     select_library_configurations(ICU_${component_upcase})
252     mark_as_advanced("${component_cache_release}" "${component_cache_debug}")
253     if(${component_cache})
254       set("${component_found}" ON)
255       set("${component_found_compat}" ON)
256       list(APPEND ICU_LIBRARY "${${component_cache}}")
257     endif()
258     mark_as_advanced("${component_found}")
259     mark_as_advanced("${component_found_compat}")
260     set("${component_cache}" "${${component_cache}}" PARENT_SCOPE)
261     set("${component_found}" "${${component_found}}" PARENT_SCOPE)
262     set("${component_found_compat}" "${${component_found_compat}}" PARENT_SCOPE)
263     if(component_found OR component_found_compat)
264       if (ICU_FIND_REQUIRED_${component})
265         list(APPEND ICU_LIBS_FOUND "${component} (required): ${${component_cache}}")
266       else()
267         list(APPEND ICU_LIBS_FOUND "${component} (optional): ${${component_cache}}")
268       endif()
269     else()
270       if (ICU_FIND_REQUIRED_${component})
271         set(ICU_REQUIRED_LIBS_FOUND OFF)
272         list(APPEND ICU_LIBS_NOTFOUND "${component} (required)")
273       else()
274         list(APPEND ICU_LIBS_NOTFOUND "${component} (optional)")
275       endif()
276     endif()
277   endforeach()
278   set(_ICU_REQUIRED_LIBS_FOUND "${ICU_REQUIRED_LIBS_FOUND}" PARENT_SCOPE)
279   set(ICU_LIBRARY "${ICU_LIBRARY}" PARENT_SCOPE)
280
281   # Find all ICU data files
282   if(CMAKE_LIBRARY_ARCHITECTURE)
283     list(APPEND icu_data_suffixes
284       "${_lib64}/${CMAKE_LIBRARY_ARCHITECTURE}/icu/${ICU_VERSION}"
285       "lib/${CMAKE_LIBRARY_ARCHITECTURE}/icu/${ICU_VERSION}"
286       "${_lib64}/${CMAKE_LIBRARY_ARCHITECTURE}/icu"
287       "lib/${CMAKE_LIBRARY_ARCHITECTURE}/icu")
288   endif()
289   list(APPEND icu_data_suffixes
290     "${_lib64}/icu/${ICU_VERSION}"
291     "lib/icu/${ICU_VERSION}"
292     "${_lib64}/icu"
293     "lib/icu")
294   foreach(data ${icu_data})
295     string(TOUPPER "${data}" data_upcase)
296     string(REPLACE "." "_" data_upcase "${data_upcase}")
297     set(cache_var "ICU_${data_upcase}")
298     set(data_var "ICU_${data_upcase}")
299     find_file("${cache_var}"
300       NAMES "${data}"
301       HINTS ${icu_roots}
302       PATH_SUFFIXES ${icu_data_suffixes}
303       DOC "ICU ${data} data file")
304     mark_as_advanced("${cache_var}")
305     set("${data_var}" "${${cache_var}}" PARENT_SCOPE)
306   endforeach()
307
308   if(NOT ICU_FIND_QUIETLY)
309     if(ICU_LIBS_FOUND)
310       message(STATUS "Found the following ICU libraries:")
311       foreach(found ${ICU_LIBS_FOUND})
312         message(STATUS "  ${found}")
313       endforeach()
314     endif()
315     if(ICU_LIBS_NOTFOUND)
316       message(STATUS "The following ICU libraries were not found:")
317       foreach(notfound ${ICU_LIBS_NOTFOUND})
318         message(STATUS "  ${notfound}")
319       endforeach()
320     endif()
321   endif()
322
323   if(ICU_DEBUG)
324     message(STATUS "--------FindICU.cmake search debug--------")
325     message(STATUS "ICU binary path search order: ${icu_roots}")
326     message(STATUS "ICU include path search order: ${icu_roots}")
327     message(STATUS "ICU library path search order: ${icu_roots}")
328     message(STATUS "----------------")
329   endif()
330 endfunction()
331
332 _ICU_FIND()
333
334 include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
335 FIND_PACKAGE_HANDLE_STANDARD_ARGS(ICU
336                                   FOUND_VAR ICU_FOUND
337                                   REQUIRED_VARS ICU_INCLUDE_DIR
338                                                 ICU_LIBRARY
339                                                 _ICU_REQUIRED_LIBS_FOUND
340                                   VERSION_VAR ICU_VERSION
341                                   FAIL_MESSAGE "Failed to find all ICU components")
342
343 unset(_ICU_REQUIRED_LIBS_FOUND)
344
345 if(ICU_FOUND)
346   set(ICU_INCLUDE_DIRS "${ICU_INCLUDE_DIR}")
347   set(ICU_LIBRARIES "${ICU_LIBRARY}")
348   foreach(_ICU_component ${ICU_FIND_COMPONENTS})
349     string(TOUPPER "${_ICU_component}" _ICU_component_upcase)
350     set(_ICU_component_cache "ICU_${_ICU_component_upcase}_LIBRARY")
351     set(_ICU_component_cache_release "ICU_${_ICU_component_upcase}_LIBRARY_RELEASE")
352     set(_ICU_component_cache_debug "ICU_${_ICU_component_upcase}_LIBRARY_DEBUG")
353     set(_ICU_component_lib "ICU_${_ICU_component_upcase}_LIBRARIES")
354     set(_ICU_component_found "ICU_${_ICU_component_upcase}_FOUND")
355     set(_ICU_imported_target "ICU::${_ICU_component}")
356     if(${_ICU_component_found})
357       set("${_ICU_component_lib}" "${${_ICU_component_cache}}")
358       if(NOT TARGET ${_ICU_imported_target})
359         add_library(${_ICU_imported_target} UNKNOWN IMPORTED)
360         if(ICU_INCLUDE_DIR)
361           set_target_properties(${_ICU_imported_target} PROPERTIES
362             INTERFACE_INCLUDE_DIRECTORIES "${ICU_INCLUDE_DIR}")
363         endif()
364         if(EXISTS "${${_ICU_component_cache}}")
365           set_target_properties(${_ICU_imported_target} PROPERTIES
366             IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
367             IMPORTED_LOCATION "${${_ICU_component_cache}}")
368         endif()
369         if(EXISTS "${${_ICU_component_cache_release}}")
370           set_property(TARGET ${_ICU_imported_target} APPEND PROPERTY
371             IMPORTED_CONFIGURATIONS RELEASE)
372           set_target_properties(${_ICU_imported_target} PROPERTIES
373             IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX"
374             IMPORTED_LOCATION_RELEASE "${${_ICU_component_cache_release}}")
375         endif()
376         if(EXISTS "${${_ICU_component_cache_debug}}")
377           set_property(TARGET ${_ICU_imported_target} APPEND PROPERTY
378             IMPORTED_CONFIGURATIONS DEBUG)
379           set_target_properties(${_ICU_imported_target} PROPERTIES
380             IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX"
381             IMPORTED_LOCATION_DEBUG "${${_ICU_component_cache_debug}}")
382         endif()
383         if(CMAKE_DL_LIBS AND _ICU_component STREQUAL "uc")
384           set_target_properties(${_ICU_imported_target} PROPERTIES
385             INTERFACE_LINK_LIBRARIES "${CMAKE_DL_LIBS}")
386         endif()
387       endif()
388     endif()
389     unset(_ICU_component_upcase)
390     unset(_ICU_component_cache)
391     unset(_ICU_component_lib)
392     unset(_ICU_component_found)
393     unset(_ICU_imported_target)
394   endforeach()
395 endif()
396
397 if(ICU_DEBUG)
398   message(STATUS "--------FindICU.cmake results debug--------")
399   message(STATUS "ICU found: ${ICU_FOUND}")
400   message(STATUS "ICU_VERSION number: ${ICU_VERSION}")
401   message(STATUS "ICU_ROOT directory: ${ICU_ROOT}")
402   message(STATUS "ICU_INCLUDE_DIR directory: ${ICU_INCLUDE_DIR}")
403   message(STATUS "ICU_LIBRARIES: ${ICU_LIBRARIES}")
404
405   foreach(program IN LISTS icu_programs)
406     string(TOUPPER "${program}" program_upcase)
407     set(program_lib "ICU_${program_upcase}_EXECUTABLE")
408     message(STATUS "${program} program: ${program_lib}=${${program_lib}}")
409     unset(program_upcase)
410     unset(program_lib)
411   endforeach()
412
413   foreach(data IN LISTS icu_data)
414     string(TOUPPER "${data}" data_upcase)
415     string(REPLACE "." "_" data_upcase "${data_upcase}")
416     set(data_lib "ICU_${data_upcase}")
417     message(STATUS "${data} data: ${data_lib}=${${data_lib}}")
418     unset(data_upcase)
419     unset(data_lib)
420   endforeach()
421
422   foreach(component IN LISTS ICU_FIND_COMPONENTS)
423     string(TOUPPER "${component}" component_upcase)
424     set(component_lib "ICU_${component_upcase}_LIBRARIES")
425     set(component_found "ICU_${component_upcase}_FOUND")
426     set(component_found_compat "${component_upcase}_FOUND")
427     message(STATUS "${component} library found: ${component_found}=${${component_found}}")
428     message(STATUS "${component} library found (compat name): ${component_found_compat}=${${component_found_compat}}")
429     message(STATUS "${component} library: ${component_lib}=${${component_lib}}")
430     unset(component_upcase)
431     unset(component_lib)
432     unset(component_found)
433     unset(component_found_compat)
434   endforeach()
435   message(STATUS "----------------")
436 endif()
437
438 unset(icu_programs)