From 16a636f29b98a986da902cbf81b8ca9cf3fa1214 Mon Sep 17 00:00:00 2001 From: Konstantin Belyavskiy <k.belyavskiy@tarantool.org> Date: Wed, 21 Feb 2018 17:03:38 +0300 Subject: [PATCH] Fix linking with iconv under FreeBSD On FreeBSD we have either system iconv (part of libc) or the one in /usr/local. The first one is not fully compatible with Linux/ OSX iconv and both adds specific prefixes to function names. So to use them via Lua FFI mechanism, specific names are required. Proposal fix: Under FreeBSD link with /usr/local/lib/libiconv.so and add prefix. Closes gh-3073. --- src/CMakeLists.txt | 6 ++++++ src/lua/iconv.lua | 33 ++++++++++++++++++++++++++++----- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 01f73a0aae..8ab09e968b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -234,6 +234,12 @@ if (TARGET_OS_FREEBSD AND NOT TARGET_OS_DEBIAN_FREEBSD) else() set (common_libraries ${common_libraries} ${INTL}) endif() + find_library (ICONV iconv) + if (NOT ICONV) + message(FATAL_ERROR "iconv library not found") + else() + set (common_libraries ${common_libraries} ${ICONV}) + endif() endif() set (common_libraries ${common_libraries} ${LIBUUID_LIBRARIES}) diff --git a/src/lua/iconv.lua b/src/lua/iconv.lua index 304768d8fa..6a6bfeb761 100644 --- a/src/lua/iconv.lua +++ b/src/lua/iconv.lua @@ -8,6 +8,13 @@ iconv_t iconv_open(const char *tocode, const char *fromcode); void iconv_close(iconv_t cd); size_t iconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft); +/* + * add prefix 'lib' under FreeBSD + */ +iconv_t libiconv_open(const char *tocode, const char *fromcode); +void libiconv_close(iconv_t cd); +size_t libiconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, + char **outbuf, size_t *outbytesleft); ]] local iconv_t = ffi.typeof('struct iconv') @@ -16,6 +23,22 @@ local cchar_ptr_arr_t = ffi.typeof('const char *[1]') local cchar_ptr_t = ffi.typeof('const char *') local size_t_arr_t = ffi.typeof('size_t [1]') +local _iconv_open +local _iconv_close +local _iconv + +-- To fix #3073, BSD iconv implementation is not fully +-- compatible with iconv, so use external iconv.so lib +if jit.os == 'BSD' then + _iconv_open = ffi.C.libiconv_open + _iconv_close = ffi.C.libiconv_close + _iconv = ffi.C.libiconv +else + _iconv_open = ffi.C.iconv_open + _iconv_close = ffi.C.iconv_close + _iconv = ffi.C.iconv +end + local E2BIG = errno['E2BIG'] local EINVAL = errno['EINVAL'] local EILSEQ = errno['EILSEQ'] @@ -41,10 +64,10 @@ local function iconv_convert(iconv, data) while data_left[0] > 0 do buf_ptr[0] = buf:reserve(output_len) buf_left[0] = buf:unused() - local res = ffi.C.iconv(iconv, data_ptr, data_left, + local res = _iconv(iconv, data_ptr, data_left, buf_ptr, buf_left) if res == ffi.cast('size_t', -1) and errno() ~= E2BIG then - ffi.C.iconv(iconv, nil, nil, nil, nil) + _iconv(iconv, nil, nil, nil, nil) if errno() == EINVAL then error('Invalid multibyte sequence') end @@ -57,7 +80,7 @@ local function iconv_convert(iconv, data) end -- iconv function sets cd's conversion state to the initial state - ffi.C.iconv(iconv, nil, nil, nil, nil) + _iconv(iconv, nil, nil, nil, nil) local result = ffi.string(buf.rpos, buf:size()) buf:reset() return result @@ -65,7 +88,7 @@ end local iconv_mt = { __call = iconv_convert, - __gc = ffi.C.iconv_close, + __gc = _iconv_close, __tostring = function(iconv) return string.format("iconv: %p", iconv) end } @@ -75,7 +98,7 @@ local function iconv_new(to, from) if type(to) ~= 'string' or type(from) ~= 'string' then error('Usage: iconv.new("CP1251", "KOI8-R")') end - local iconv = ffi.C.iconv_open(to, from) + local iconv = _iconv_open(to, from) if iconv == conv_rv_error then error('iconv: '..errno.strerror()) end -- GitLab