Skip to content

Commit 67db401

Browse files
committed
CMake: Fix iconv detection
The current implementations check for iconv.h and set HAVE_ICONV_H but don't set HAVE_ICONV, which is the macro we actually depend on. In the autotools build system, HAVE_ICONV is set by the `AM_ICONV` macro, if you have gettext-devel installed (note, this will cause an autoreconf warning if you don't have gettext-devel installed). Anyways... to fix this in CMake, I've added FindICONV.cmake module which is a slightly modified variant of the official CMake iconv detection module. This one has some additional features including setting the ICONV_CONST macro as needed. This commit fixes the cabextract "encoding" test, which was the final outstanding issue with CMake support, excluding the fact that there are no cabextract feature tests for Windows. I think this is acceptable for now, since it's not like there were any before switching to CMake.
1 parent 6572fa7 commit 67db401

File tree

7 files changed

+192
-9
lines changed

7 files changed

+192
-9
lines changed

cabextract/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
/build
2+
13
# CabExtract specific
24
COPYING
35
INSTALL

cabextract/CMakeLists.txt

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ check_include_file(dirent.h HAVE_DIRENT_H)
5353
check_include_file(sys/types.h HAVE_SYS_TYPES_H)
5454
check_include_file(sys/stat.h HAVE_SYS_STAT_H)
5555
check_include_file(fnmatch.h HAVE_FNMATCH_H)
56-
check_include_file(iconv.h HAVE_ICONV_H)
5756
check_include_file(locale.h HAVE_LOCALE_H)
5857
check_include_file(stdarg.h HAVE_STDARG_H)
5958
check_include_file(stdlib.h HAVE_STDLIB_H)
@@ -191,6 +190,16 @@ set(libdir ${CMAKE_INSTALL_FULL_LIBDIR})
191190
set(includedir ${CMAKE_INSTALL_FULL_INCLUDEDIR})
192191
set(VERSION ${PROJECT_VERSION})
193192

193+
#
194+
# External library dependencies
195+
#
196+
if(NOT WIN32)
197+
find_package(ICONV)
198+
if(ICONV_FOUND)
199+
set(HAVE_ICONV 1)
200+
endif()
201+
endif()
202+
194203
# Generate config.h
195204
add_definitions(-DHAVE_CONFIG_H)
196205
configure_file(config.h.in.cmake config.h)
@@ -219,6 +228,9 @@ else()
219228
target_include_directories(cabextract PRIVATE ${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/win32)
220229
target_sources(cabextract PRIVATE win32/dirent.h)
221230
target_link_libraries(cabextract Shlwapi.lib)
231+
if(HAVE_ICONV)
232+
target_link_libraries( cabextract PRIVATE ICONV::Iconv )
233+
endif()
222234
endif()
223235
target_include_directories(cabextract PRIVATE ${PROJECT_SOURCE_DIR})
224236
target_link_libraries(cabextract MSPack::mspack)
@@ -252,4 +264,7 @@ message(STATUS "Summary of build options:
252264
WARNCFLAGS: ${WARNCFLAGS}
253265
Features:
254266
External mspack: ${ENABLE_EXTERNAL_MSPACK}
267+
Text conversion:
268+
iconv ${ICONV_INCLUDE_DIRS}
269+
${ICONV_LIBRARIES}
255270
")

cabextract/cmake/FindICONV.cmake

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
# From https://github.com/Kitware/CMake/blob/master/Modules/FindIconv.cmake
2+
#
3+
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
4+
# file Copyright.txt or https://cmake.org/licensing for details.
5+
6+
# Mods by Micah Snyder to support systems with both libc's iconv + libconv
7+
8+
#[=======================================================================[.rst:
9+
FindICONV
10+
---------
11+
12+
.. versionadded:: 3.11
13+
14+
This module finds the ``iconv()`` POSIX.1 functions on the system.
15+
These functions might be provided in the regular C library or externally
16+
in the form of an additional library.
17+
18+
The following variables are provided to indicate iconv support:
19+
20+
.. variable:: ICONV_FOUND
21+
22+
Variable indicating if the iconv support was found.
23+
24+
.. variable:: ICONV_CONST
25+
26+
Variable to use when declaring "in" char* variable for the iconv() function
27+
so that it is const if the iconv implementation expects it to be const.
28+
29+
.. variable:: ICONV_INCLUDE_DIRS
30+
31+
The directories containing the iconv headers.
32+
33+
.. variable:: ICONV_LIBRARIES
34+
35+
The iconv libraries to be linked.
36+
37+
.. variable:: ICONV_IS_BUILT_IN
38+
39+
A variable indicating whether iconv support is stemming from the
40+
C library or not. Even if the C library provides `iconv()`, the presence of
41+
an external `libiconv` implementation might lead to this being false.
42+
43+
Additionally, the following :prop_tgt:`IMPORTED` target is being provided:
44+
45+
.. variable:: ICONV::Iconv
46+
47+
Imported target for using iconv.
48+
49+
The following cache variables may also be set:
50+
51+
.. variable:: ICONV_INCLUDE_DIR
52+
53+
The directory containing the iconv headers.
54+
55+
.. variable:: ICONV_LIBRARY
56+
57+
The iconv library (if not implicitly given in the C library).
58+
59+
.. note::
60+
On POSIX platforms, iconv might be part of the C library and the cache
61+
variables ``ICONV_INCLUDE_DIR`` and ``ICONV_LIBRARY`` might be empty.
62+
63+
#]=======================================================================]
64+
65+
include(CMakePushCheckState)
66+
include(CheckCSourceCompiles)
67+
include(CheckCXXSourceCompiles)
68+
69+
# iconv can only be provided in libc on a POSIX system.
70+
# If any cache variable is already set, we'll skip this test.
71+
if(NOT DEFINED ICONV_IS_BUILT_IN)
72+
# Check for iconv.h first.
73+
# If it's not the built-in one, then ICONV_INCLUDE_DIR will
74+
find_path(ICONV_INCLUDE_DIR
75+
NAMES "iconv.h"
76+
DOC "iconv include directory")
77+
set(ICONV_LIBRARY_NAMES "iconv" "libiconv")
78+
79+
if(UNIX AND ICONV_INCLUDE_DIR AND NOT DEFINED ICONV_LIBRARY)
80+
cmake_push_check_state(RESET)
81+
# We always suppress the message here: Otherwise on supported systems
82+
# not having iconv in their C library (e.g. those using libiconv)
83+
# would always display a confusing "Looking for iconv - not found" message
84+
set(CMAKE_FIND_QUIETLY TRUE)
85+
# The following code will not work, but it's sufficient to see if it compiles.
86+
# Note: libiconv will define the iconv functions as macros, so CheckSymbolExists
87+
# will not yield correct results.
88+
set(ICONV_IMPLICIT_TEST_CODE
89+
"
90+
#include <stddef.h>
91+
#include <iconv.h>
92+
int main() {
93+
char *a, *b;
94+
size_t i, j;
95+
iconv_t ic;
96+
ic = iconv_open(\"to\", \"from\");
97+
iconv(ic, &a, &i, &b, &j);
98+
iconv_close(ic);
99+
}
100+
"
101+
)
102+
103+
# Make sure we're using the iconv.h we found above. This way we don't
104+
# accidentally compile against libiconv's header later but link with only
105+
# libc on systems that have both (eg FreeBSD with libiconv pkg installed).
106+
set(CMAKE_REQUIRED_INCLUDES ${ICONV_INCLUDE_DIR})
107+
108+
if(CMAKE_C_COMPILER_LOADED)
109+
check_c_source_compiles("${ICONV_IMPLICIT_TEST_CODE}" ICONV_IS_BUILT_IN)
110+
else()
111+
check_cxx_source_compiles("${ICONV_IMPLICIT_TEST_CODE}" ICONV_IS_BUILT_IN)
112+
endif()
113+
cmake_pop_check_state()
114+
else()
115+
set(ICONV_IS_BUILT_IN FALSE)
116+
endif()
117+
endif()
118+
119+
if(ICONV_IS_BUILT_IN)
120+
set(ICONV_INCLUDE_DIR "" CACHE FILEPATH "iconv include directory")
121+
set(ICONV_LIBRARY_NAMES "c")
122+
endif()
123+
124+
find_library(ICONV_LIBRARY
125+
NAMES ${ICONV_LIBRARY_NAMES}
126+
NAMES_PER_DIR
127+
DOC "iconv library (potentially the C library)")
128+
129+
mark_as_advanced(ICONV_INCLUDE_DIR)
130+
mark_as_advanced(ICONV_LIBRARY)
131+
132+
include(FindPackageHandleStandardArgs)
133+
if(NOT ICONV_IS_BUILT_IN)
134+
find_package_handle_standard_args(ICONV REQUIRED_VARS ICONV_LIBRARY ICONV_INCLUDE_DIR)
135+
else()
136+
find_package_handle_standard_args(ICONV REQUIRED_VARS ICONV_LIBRARY)
137+
endif()
138+
139+
if(ICONV_FOUND)
140+
# Check if the second argument for iconv() needs to be const
141+
set(OLD_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}")
142+
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -Werror")
143+
check_c_source_compiles("
144+
#include <iconv.h>
145+
int main() {
146+
iconv_t conv = 0;
147+
const char* in = 0;
148+
size_t ilen = 0;
149+
char* out = 0;
150+
size_t olen = 0;
151+
iconv(conv, &in, &ilen, &out, &olen);
152+
return 0;
153+
}
154+
" ICONV_SECOND_ARGUMENT_IS_CONST )
155+
set(CMAKE_REQUIRED_FLAGS "${OLD_CMAKE_REQUIRED_FLAGS}")
156+
157+
if(ICONV_SECOND_ARGUMENT_IS_CONST)
158+
set(ICONV_CONST "const")
159+
endif(ICONV_SECOND_ARGUMENT_IS_CONST)
160+
161+
set(ICONV_INCLUDE_DIRS "${ICONV_INCLUDE_DIR}")
162+
set(ICONV_LIBRARIES "${ICONV_LIBRARY}")
163+
if(NOT TARGET ICONV::Iconv)
164+
add_library(ICONV::Iconv INTERFACE IMPORTED)
165+
endif()
166+
set_property(TARGET ICONV::Iconv PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${ICONV_INCLUDE_DIRS}")
167+
set_property(TARGET ICONV::Iconv PROPERTY INTERFACE_LINK_LIBRARIES "${ICONV_LIBRARIES}")
168+
endif()

cabextract/config.h.in.cmake

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,6 @@
3535
/* Define to 1 if you have the <fnmatch.h> header file. */
3636
#cmakedefine HAVE_FNMATCH_H 1
3737

38-
/* Define to 1 if you have the <iconv.h> header file. */
39-
#cmakedefine HAVE_ICONV_H 1
40-
4138
/* Define to 1 if you have the <locale.h> header file. */
4239
#cmakedefine HAVE_LOCALE_H 1
4340

@@ -79,7 +76,10 @@
7976

8077

8178
/* Define to empty if `const' does not conform to ANSI C. */
82-
#cmakedefine ICONV_CONST "@ICONV_CONST@"
79+
#define ICONV_CONST @ICONV_CONST@
80+
81+
/* Define to 1 if you have the iconv library. */
82+
#cmakedefine HAVE_ICONV 1
8383

8484

8585
/* The size of `off_t', as computed by sizeof. */

libmspack/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
/build
2+
13
# Logs
24
*.log
35

libmspack/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@ check_include_file(dirent.h HAVE_DIRENT_H)
8080
check_include_file(sys/types.h HAVE_SYS_TYPES_H)
8181
check_include_file(sys/stat.h HAVE_SYS_STAT_H)
8282
check_include_file(fnmatch.h HAVE_FNMATCH_H)
83-
check_include_file(iconv.h HAVE_ICONV_H)
8483
check_include_file(locale.h HAVE_LOCALE_H)
8584
check_include_file(stdarg.h HAVE_STDARG_H)
8685
check_include_file(stdlib.h HAVE_STDLIB_H)

libmspack/config.h.in.cmake

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,6 @@
3535
/* Define to 1 if you have the <fnmatch.h> header file. */
3636
#cmakedefine HAVE_FNMATCH_H 1
3737

38-
/* Define to 1 if you have the <iconv.h> header file. */
39-
#cmakedefine HAVE_ICONV_H 1
40-
4138
/* Define to 1 if you have the <locale.h> header file. */
4239
#cmakedefine HAVE_LOCALE_H 1
4340

0 commit comments

Comments
 (0)