mirror of
https://github.com/Kitware/CMake.git
synced 2025-10-14 02:08:27 +08:00
FindIconv: Add the FindIconv module.
This module provides abstraction over the various ways POSIX platforms handle the iconv calls defined in POSIX.1-2001 and later versions.
This commit is contained in:

committed by
Christian Pfeiffer

parent
9c4a74559d
commit
95646591d6
@@ -130,6 +130,7 @@ All Modules
|
||||
/module/FindIcotool
|
||||
/module/FindICU
|
||||
/module/FindImageMagick
|
||||
/module/FindIconv
|
||||
/module/FindIntl
|
||||
/module/FindITK
|
||||
/module/FindJasper
|
||||
|
1
Help/module/FindIconv.rst
Normal file
1
Help/module/FindIconv.rst
Normal file
@@ -0,0 +1 @@
|
||||
.. cmake-module:: ../../Modules/FindIconv.cmake
|
4
Help/release/dev/FindIconv.rst
Normal file
4
Help/release/dev/FindIconv.rst
Normal file
@@ -0,0 +1,4 @@
|
||||
FindIconv
|
||||
---------
|
||||
|
||||
* A :module:`FindIconv` module was added to locate iconv support.
|
133
Modules/FindIconv.cmake
Normal file
133
Modules/FindIconv.cmake
Normal file
@@ -0,0 +1,133 @@
|
||||
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||
|
||||
#[=======================================================================[.rst:
|
||||
FindIconv
|
||||
---------
|
||||
|
||||
This module finds the ``iconv()`` POSIX.1 functions on the system.
|
||||
These functions might be provided in the regular C library or externally
|
||||
in the form of an additional library.
|
||||
|
||||
The following variables are provided to indicate iconv support:
|
||||
|
||||
.. variable:: Iconv_FOUND
|
||||
|
||||
Variable indicating if the iconv support was found.
|
||||
|
||||
.. variable:: Iconv_INCLUDE_DIRS
|
||||
|
||||
The directories containing the iconv headers.
|
||||
|
||||
.. variable:: Iconv_LIBRARIES
|
||||
|
||||
The iconv libraries to be linked.
|
||||
|
||||
.. variable:: Iconv_IS_BUILT_IN
|
||||
|
||||
A variable indicating whether iconv support is stemming from the
|
||||
C library or not. Even if the C library provides `iconv()`, the presence of
|
||||
an external `libiconv` implementation might lead to this being false.
|
||||
|
||||
Additionally, the following :prop_tgt:`IMPORTED` target is being provided:
|
||||
|
||||
.. variable:: Iconv::Iconv
|
||||
|
||||
Imported target for using iconv.
|
||||
|
||||
The following cache variables may also be set:
|
||||
|
||||
.. variable:: Iconv_INCLUDE_DIR
|
||||
|
||||
The directory containing the iconv headers.
|
||||
|
||||
.. variable:: Iconv_LIBRARY
|
||||
|
||||
The iconv library (if not implicitly given in the C library).
|
||||
|
||||
.. note::
|
||||
On POSIX platforms, iconv might be part of the C library and the cache
|
||||
variables ``Iconv_INCLUDE_DIR`` and ``Iconv_LIBRARY`` might be empty.
|
||||
|
||||
#]=======================================================================]
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/CMakePushCheckState.cmake)
|
||||
if(CMAKE_C_COMPILER_LOADED)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/CheckCSourceCompiles.cmake)
|
||||
elseif(CMAKE_CXX_COMPILER_LOADED)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/CheckCXXSourceCompiles.cmake)
|
||||
else()
|
||||
# If neither C nor CXX are loaded, implicit iconv makes no sense.
|
||||
set(Iconv_IS_BUILT_IN FALSE)
|
||||
endif()
|
||||
|
||||
# iconv can only be provided in libc on a POSIX system.
|
||||
# If any cache variable is already set, we'll skip this test.
|
||||
if(NOT DEFINED Iconv_IS_BUILT_IN)
|
||||
if(UNIX AND NOT DEFINED Iconv_INCLUDE_DIR AND NOT DEFINED Iconv_LIBRARY)
|
||||
cmake_push_check_state(RESET)
|
||||
# We always suppress the message here: Otherwise on supported systems
|
||||
# not having iconv in their C library (e.g. those using libiconv)
|
||||
# would always display a confusing "Looking for iconv - not found" message
|
||||
set(CMAKE_FIND_QUIETLY TRUE)
|
||||
# The following code will not work, but it's sufficient to see if it compiles.
|
||||
# Note: libiconv will define the iconv functions as macros, so CheckSymbolExists
|
||||
# will not yield correct results.
|
||||
set(Iconv_IMPLICIT_TEST_CODE
|
||||
"
|
||||
#include <stddef.h>
|
||||
#include <iconv.h>
|
||||
int main() {
|
||||
char *a, *b;
|
||||
size_t i, j;
|
||||
iconv_t ic;
|
||||
ic = iconv_open(\"to\", \"from\");
|
||||
iconv(ic, &a, &i, &b, &j);
|
||||
iconv_close(ic);
|
||||
}
|
||||
"
|
||||
)
|
||||
if(CMAKE_C_COMPILER_LOADED)
|
||||
check_c_source_compiles("${Iconv_IMPLICIT_TEST_CODE}" Iconv_IS_BUILT_IN)
|
||||
else()
|
||||
check_cxx_source_compiles("${Iconv_IMPLICIT_TEST_CODE}" Iconv_IS_BUILT_IN)
|
||||
endif()
|
||||
cmake_pop_check_state()
|
||||
else()
|
||||
set(Iconv_IS_BUILT_IN FALSE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT Iconv_IS_BUILT_IN)
|
||||
find_path(Iconv_INCLUDE_DIR
|
||||
NAMES "iconv.h"
|
||||
DOC "iconv include directory")
|
||||
set(Iconv_LIBRARY_NAMES "iconv" "libiconv")
|
||||
else()
|
||||
set(Iconv_INCLUDE_DIR "" CACHE FILEPATH "iconv include directory")
|
||||
set(Iconv_LIBRARY_NAMES "c")
|
||||
endif()
|
||||
|
||||
find_library(Iconv_LIBRARY
|
||||
NAMES ${Iconv_LIBRARY_NAMES}
|
||||
DOC "iconv library (potentially the C library)")
|
||||
|
||||
mark_as_advanced(Iconv_INCLUDE_DIR)
|
||||
mark_as_advanced(Iconv_LIBRARY)
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
|
||||
if(NOT Iconv_IS_BUILT_IN)
|
||||
find_package_handle_standard_args(Iconv REQUIRED_VARS Iconv_LIBRARY Iconv_INCLUDE_DIR)
|
||||
else()
|
||||
find_package_handle_standard_args(Iconv REQUIRED_VARS Iconv_LIBRARY)
|
||||
endif()
|
||||
|
||||
if(Iconv_FOUND)
|
||||
set(Iconv_INCLUDE_DIRS "${Iconv_INCLUDE_DIR}")
|
||||
set(Iconv_LIBRARIES "${Iconv_LIBRARY}")
|
||||
if(NOT TARGET Iconv::Iconv)
|
||||
add_library(Iconv::Iconv INTERFACE IMPORTED)
|
||||
endif()
|
||||
set_property(TARGET Iconv::Iconv PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${Iconv_INCLUDE_DIRS}")
|
||||
set_property(TARGET Iconv::Iconv PROPERTY INTERFACE_LINK_LIBRARIES "${Iconv_LIBRARIES}")
|
||||
endif()
|
@@ -1433,6 +1433,10 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
|
||||
add_subdirectory(GoogleTest)
|
||||
endif()
|
||||
|
||||
if(CMake_TEST_FindIconv)
|
||||
add_subdirectory(FindIconv)
|
||||
endif()
|
||||
|
||||
if(CMake_TEST_FindICU)
|
||||
add_subdirectory(FindICU)
|
||||
endif()
|
||||
|
10
Tests/FindIconv/CMakeLists.txt
Normal file
10
Tests/FindIconv/CMakeLists.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
add_test(NAME FindIconv.Test COMMAND
|
||||
${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
|
||||
--build-and-test
|
||||
"${CMake_SOURCE_DIR}/Tests/FindIconv/Test"
|
||||
"${CMake_BINARY_DIR}/Tests/FindIconv/Test"
|
||||
${build_generator_args}
|
||||
--build-project TestFindIconv
|
||||
--build-options ${build_options}
|
||||
--test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
|
||||
)
|
14
Tests/FindIconv/Test/CMakeLists.txt
Normal file
14
Tests/FindIconv/Test/CMakeLists.txt
Normal file
@@ -0,0 +1,14 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
project(TestFindIconv CXX)
|
||||
include(CTest)
|
||||
|
||||
find_package(Iconv REQUIRED)
|
||||
|
||||
add_executable(test_iconv_tgt main.cxx)
|
||||
target_link_libraries(test_iconv_tgt Iconv::Iconv)
|
||||
add_test(NAME test_iconv_tgt COMMAND test_iconv_tgt)
|
||||
|
||||
add_executable(test_iconv_var main.cxx)
|
||||
target_include_directories(test_iconv_var PRIVATE ${Iconv_INCLUDE_DIRS})
|
||||
target_link_libraries(test_iconv_var PRIVATE ${Iconv_LIBRARIES})
|
||||
add_test(NAME test_iconv_var COMMAND test_iconv_var)
|
52
Tests/FindIconv/Test/main.cxx
Normal file
52
Tests/FindIconv/Test/main.cxx
Normal file
@@ -0,0 +1,52 @@
|
||||
extern "C" {
|
||||
#include <iconv.h>
|
||||
}
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
|
||||
class iconv_desc
|
||||
{
|
||||
private:
|
||||
iconv_t iconvd_;
|
||||
|
||||
public:
|
||||
iconv_desc(const std::string& tocode, const std::string& fromcode)
|
||||
{
|
||||
iconvd_ = iconv_open(tocode.c_str(), fromcode.c_str());
|
||||
if (iconvd_ == reinterpret_cast<iconv_t>(-1))
|
||||
throw std::system_error(errno, std::system_category());
|
||||
}
|
||||
|
||||
~iconv_desc() { iconv_close(iconvd_); }
|
||||
|
||||
operator iconv_t() { return this->iconvd_; }
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
try {
|
||||
auto conv_d = iconv_desc{ "ISO-8859-1", "UTF-8" };
|
||||
auto from_str = std::array<char, 10>{ u8"a\xC3\xA4o\xC3\xB6u\xC3\xBC" };
|
||||
auto to_str = std::array<char, 7>{};
|
||||
|
||||
auto from_str_ptr = from_str.data();
|
||||
auto from_len = from_str.size();
|
||||
auto to_str_ptr = to_str.data();
|
||||
auto to_len = to_str.size();
|
||||
const auto iconv_ret =
|
||||
iconv(conv_d, &from_str_ptr, &from_len, &to_str_ptr, &to_len);
|
||||
if (iconv_ret == static_cast<std::size_t>(-1))
|
||||
throw std::system_error(errno, std::system_category());
|
||||
std::cout << '\'' << from_str.data() << "\' converted to \'"
|
||||
<< to_str.data() << '\'' << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
} catch (const std::system_error& ex) {
|
||||
std::cerr << "ERROR: " << ex.code() << '\n'
|
||||
<< ex.code().message() << std::endl;
|
||||
}
|
||||
return EXIT_FAILURE;
|
||||
}
|
Reference in New Issue
Block a user