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:
5FindIconv
6---------
7
8.. versionadded:: 3.11
9
10This module finds the ``iconv()`` POSIX.1 functions on the system.
11These functions might be provided in the regular C library or externally
12in the form of an additional library.
13
14The following variables are provided to indicate iconv support:
15
16.. variable:: Iconv_FOUND
17
18  Variable indicating if the iconv support was found.
19
20.. variable:: Iconv_INCLUDE_DIRS
21
22  The directories containing the iconv headers.
23
24.. variable:: Iconv_LIBRARIES
25
26  The iconv libraries to be linked.
27
28.. variable:: Iconv_VERSION
29
30  .. versionadded:: 3.21
31
32  The version of iconv found (x.y)
33
34.. variable:: Iconv_VERSION_MAJOR
35
36  .. versionadded:: 3.21
37
38  The major version of iconv
39
40.. variable:: Iconv_VERSION_MINOR
41
42  .. versionadded:: 3.21
43
44  The minor version of iconv
45
46.. variable:: Iconv_IS_BUILT_IN
47
48  A variable indicating whether iconv support is stemming from the
49  C library or not. Even if the C library provides `iconv()`, the presence of
50  an external `libiconv` implementation might lead to this being false.
51
52Additionally, the following :prop_tgt:`IMPORTED` target is being provided:
53
54.. variable:: Iconv::Iconv
55
56  Imported target for using iconv.
57
58The following cache variables may also be set:
59
60.. variable:: Iconv_INCLUDE_DIR
61
62  The directory containing the iconv headers.
63
64.. variable:: Iconv_LIBRARY
65
66  The iconv library (if not implicitly given in the C library).
67
68.. note::
69  On POSIX platforms, iconv might be part of the C library and the cache
70  variables ``Iconv_INCLUDE_DIR`` and ``Iconv_LIBRARY`` might be empty.
71
72.. note::
73  Some libiconv implementations don't embed the version number in their header files.
74  In this case the variables ``Iconv_VERSION*`` will be empty.
75
76#]=======================================================================]
77
78include(${CMAKE_CURRENT_LIST_DIR}/CMakePushCheckState.cmake)
79if(CMAKE_C_COMPILER_LOADED)
80  include(${CMAKE_CURRENT_LIST_DIR}/CheckCSourceCompiles.cmake)
81elseif(CMAKE_CXX_COMPILER_LOADED)
82  include(${CMAKE_CURRENT_LIST_DIR}/CheckCXXSourceCompiles.cmake)
83else()
84  # If neither C nor CXX are loaded, implicit iconv makes no sense.
85  set(Iconv_IS_BUILT_IN FALSE)
86endif()
87
88# iconv can only be provided in libc on a POSIX system.
89# If any cache variable is already set, we'll skip this test.
90if(NOT DEFINED Iconv_IS_BUILT_IN)
91  if(UNIX AND NOT DEFINED Iconv_INCLUDE_DIR AND NOT DEFINED Iconv_LIBRARY)
92    cmake_push_check_state(RESET)
93    # We always suppress the message here: Otherwise on supported systems
94    # not having iconv in their C library (e.g. those using libiconv)
95    # would always display a confusing "Looking for iconv - not found" message
96    set(CMAKE_FIND_QUIETLY TRUE)
97    # The following code will not work, but it's sufficient to see if it compiles.
98    # Note: libiconv will define the iconv functions as macros, so CheckSymbolExists
99    # will not yield correct results.
100    set(Iconv_IMPLICIT_TEST_CODE
101      "
102      #include <stddef.h>
103      #include <iconv.h>
104      int main() {
105        char *a, *b;
106        size_t i, j;
107        iconv_t ic;
108        ic = iconv_open(\"to\", \"from\");
109        iconv(ic, &a, &i, &b, &j);
110        iconv_close(ic);
111      }
112      "
113    )
114    if(CMAKE_C_COMPILER_LOADED)
115      check_c_source_compiles("${Iconv_IMPLICIT_TEST_CODE}" Iconv_IS_BUILT_IN)
116    else()
117      check_cxx_source_compiles("${Iconv_IMPLICIT_TEST_CODE}" Iconv_IS_BUILT_IN)
118    endif()
119    cmake_pop_check_state()
120  else()
121    set(Iconv_IS_BUILT_IN FALSE)
122  endif()
123endif()
124
125set(_Iconv_REQUIRED_VARS)
126if(Iconv_IS_BUILT_IN)
127  set(_Iconv_REQUIRED_VARS _Iconv_IS_BUILT_IN_MSG)
128  set(_Iconv_IS_BUILT_IN_MSG "built in to C library")
129else()
130  set(_Iconv_REQUIRED_VARS Iconv_LIBRARY Iconv_INCLUDE_DIR)
131
132  find_path(Iconv_INCLUDE_DIR
133    NAMES "iconv.h"
134    DOC "iconv include directory")
135  set(Iconv_LIBRARY_NAMES "iconv" "libiconv")
136  mark_as_advanced(Iconv_INCLUDE_DIR)
137
138  find_library(Iconv_LIBRARY
139    NAMES iconv libiconv
140    NAMES_PER_DIR
141    DOC "iconv library (if not in the C library)")
142  mark_as_advanced(Iconv_LIBRARY)
143endif()
144
145# NOTE: glibc's iconv.h does not define _LIBICONV_VERSION
146if(Iconv_INCLUDE_DIR AND EXISTS "${Iconv_INCLUDE_DIR}/iconv.h")
147  file(STRINGS ${Iconv_INCLUDE_DIR}/iconv.h Iconv_VERSION_DEFINE REGEX "_LIBICONV_VERSION (.*)")
148
149  if(Iconv_VERSION_DEFINE MATCHES "(0x[A-Fa-f0-9]+)")
150    set(Iconv_VERSION_NUMBER "${CMAKE_MATCH_1}")
151    # encoding -> version number: (major<<8) + minor
152    math(EXPR Iconv_VERSION_MAJOR "${Iconv_VERSION_NUMBER} >> 8" OUTPUT_FORMAT HEXADECIMAL)
153    math(EXPR Iconv_VERSION_MINOR "${Iconv_VERSION_NUMBER} - (${Iconv_VERSION_MAJOR} << 8)" OUTPUT_FORMAT HEXADECIMAL)
154
155    math(EXPR Iconv_VERSION_MAJOR "${Iconv_VERSION_MAJOR}" OUTPUT_FORMAT DECIMAL)
156    math(EXPR Iconv_VERSION_MINOR "${Iconv_VERSION_MINOR}" OUTPUT_FORMAT DECIMAL)
157    set(Iconv_VERSION "${Iconv_VERSION_MAJOR}.${Iconv_VERSION_MINOR}")
158  endif()
159
160  unset(Iconv_VERSION_DEFINE)
161  unset(Iconv_VERSION_NUMBER)
162endif()
163
164include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
165find_package_handle_standard_args(Iconv
166                                  REQUIRED_VARS ${_Iconv_REQUIRED_VARS}
167                                  VERSION_VAR Iconv_VERSION)
168
169if(Iconv_FOUND)
170  if(Iconv_IS_BUILT_IN)
171    set(Iconv_INCLUDE_DIRS "")
172    set(Iconv_LIBRARIES "")
173  else()
174    set(Iconv_INCLUDE_DIRS "${Iconv_INCLUDE_DIR}")
175    set(Iconv_LIBRARIES "${Iconv_LIBRARY}")
176  endif()
177  if(NOT TARGET Iconv::Iconv)
178    add_library(Iconv::Iconv INTERFACE IMPORTED)
179    set_property(TARGET Iconv::Iconv PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${Iconv_INCLUDE_DIRS}")
180    set_property(TARGET Iconv::Iconv PROPERTY INTERFACE_LINK_LIBRARIES "${Iconv_LIBRARIES}")
181  endif()
182endif()
183