[Tarantool-patches] [PATCH 1/3] build: export libCURL symbols

Roman Khabibov roman.habibov at tarantool.org
Fri Apr 9 22:54:44 MSK 2021



> On Apr 1, 2021, at 02:56, Alexander Turenko <alexander.turenko at tarantool.org> wrote:
> 
> On Fri, Mar 19, 2021 at 05:13:06PM +0300, Roman Khabibov wrote:
>> Export the symbols to tarantool executable in the case of libCURL
>> included as bundled library.
>> 
>> This patch is just 1.10 adaptation of the original commit 9fc57c4
>> performed by Yaroslav Dynnikov <yaroslav.dynnikov at gmail.com>.
> 
> The commit hash you reference is not reachable from the master branch.
Fixed.

> Aside of this, some logic arrives from
> 47c19eeb4f67cb7257ce32542443c09410b6e752 ('build: don't re-export
> libcurl.so/dylib symbols').
> 
>> diff --git a/extra/curl_symbols b/extra/curl_symbols
>> new file mode 100755
>> index 000000000..89e247a00
>> --- /dev/null
>> +++ b/extra/curl_symbols
>> @@ -0,0 +1,81 @@
>> +curl_easy_cleanup
>> +curl_easy_duphandle
>> +curl_easy_escape
> 
> It is the part of extra/exports, so I would name it
> extra/exports_libcurl.
> 
> I would also keep Yaroslav's comment at the start:
> 
> | # The following list was obtained by parsing libcurl.a static library:
> | # nm libcurl.a | grep -oP 'T \K(curl_.+)$' | sort
> |
> | curl_easy_cleanup
> | curl_easy_duphandle
> | <...>
diff --git a/extra/exports_libcurl b/extra/exports_libcurl
new file mode 100755
index 000000000..d9f420d03
--- /dev/null
+++ b/extra/exports_libcurl
@@ -0,0 +1,84 @@
+# The following list was obtained by parsing libcurl.a static
+# library: nm libcurl.a | grep -oP 'T \K(curl_.+)$' | sort
+

>> diff --git a/extra/mkexports b/extra/mkexports
>> index 145e5b8ce..c10f20ae4 100755
>> --- a/extra/mkexports
>> +++ b/extra/mkexports
>> @@ -2,22 +2,30 @@
>> # $1 - in  file
>> # $2 - out file
>> # $3 - os
>> -# $4 - export templates
>> +# $4 - is bundled curl on/off flag
>> +# $5 - curl symbols
>> +# $6 - export templates
> 
> I would just pass one or two files (extra/exports,
> extra/exports_libcurl) in $1: it'll be easier to read.
> 
> My diff (from 1.10):
> 
> | diff --git a/extra/mkexports b/extra/mkexports
> | index 145e5b8ce..95c3f8eed 100755
> | --- a/extra/mkexports
> | +++ b/extra/mkexports
> | @@ -1,5 +1,5 @@
> |  #! /bin/sh
> | -# $1 - in  file
> | +# $1 - in file(s)
> |  # $2 - out file
> |  # $3 - os
> |  # $4 - export templates
> | diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
> | index 1e840aab9..db771cce9 100644
> | --- a/src/CMakeLists.txt
> | +++ b/src/CMakeLists.txt
> | @@ -301,6 +301,13 @@ if(BUILD_STATIC)
> |      endif()
> |  endif()
> |  
> | +set(exports_file_sources ${CMAKE_SOURCE_DIR}/extra/exports)
> | +if (EXPORT_LIBCURL_SYMBOLS)
> | +    set(exports_file_sources ${exports_file_sources}
> | +        ${CMAKE_SOURCE_DIR}/extra/exports_libcurl)
> | +endif()
> | +string(REPLACE ";" " " exports_file_sources "${exports_file_sources}")
> | +
> |  # Exports syntax is toolchain-dependent, preprocessing is necessary
> |  set(exports_file ${CMAKE_BINARY_DIR}/extra/exports.${CMAKE_SYSTEM_NAME})
> |  add_custom_target(preprocess_exports
> | @@ -309,7 +316,7 @@ add_custom_command(
> |      OUTPUT  ${exports_file}
> |      DEPENDS ${CMAKE_SOURCE_DIR}/extra/exports
> |      COMMAND ${CMAKE_SOURCE_DIR}/extra/mkexports
> | -            ${CMAKE_SOURCE_DIR}/extra/exports
> | +            ${exports_file_sources}
> |              ${exports_file} ${CMAKE_SYSTEM_NAME}
> |              ${EXPORT_LIST}
> |  )
I choose it.

> ----
> 
> Just for the record: I also tried another implementation variant:
> 
> | diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
> | index 1e840aab9..6804ba301 100644
> | --- a/src/CMakeLists.txt
> | +++ b/src/CMakeLists.txt
> | @@ -284,8 +284,9 @@ if(BUILD_STATIC)
> |              list(APPEND EXPORT_LIST ${SYMBOLS_LIB})
> |              # set variable to allow rescan (CMake depended)
> |              set(SYMBOLS_LIB "SYMBOLS_LIB-NOTFOUND")
> | -        elseif (${libstatic} STREQUAL bundled-libcurl OR
> | -                ${libstatic} STREQUAL bundled-ares)
> | +        elseif (${libstatic} STREQUAL bundled-libcurl)
> | +            # Handled below.
> | +        elseif (${libstatic} STREQUAL bundled-ares)
> |              message("We don't need to export symbols from statically linked ${libstatic}, skipped")
> |          else()
> |              message(WARNING "${libstatic} should be a static")
> | @@ -301,10 +302,24 @@ if(BUILD_STATIC)
> |      endif()
> |  endif()
> |  
> | +# Expose libcurl symbols.
> | +if(ENABLE_BUNDLED_LIBCURL OR BUILD_STATIC)
> | +    set(reexport_libraries ${reexport_libraries} ${CURL_LIBRARIES})
> | +
> | +    if (ENABLE_BUNDLED_LIBCURL)
> | +        get_target_property(libstatic bundled-libcurl IMPORTED_LOCATION)
> | +        string(REGEX REPLACE "libcurl.a" "libcurl.so" libdynamic ${libstatic})
> | +    else()
> | +        find_library(libdynamic NAMES curl)
> | +    endif()
> | +
> | +    set(EXPORT_LIST ${EXPORT_LIST} ${libdynamic})
> | +endif()
> | +
> |  # Exports syntax is toolchain-dependent, preprocessing is necessary
> |  set(exports_file ${CMAKE_BINARY_DIR}/extra/exports.${CMAKE_SYSTEM_NAME})
> |  add_custom_target(preprocess_exports
> | -                  DEPENDS ${exports_file})
> | +                  DEPENDS ${exports_file} build_bundled_libs)
> |  add_custom_command(
> |      OUTPUT  ${exports_file}
> |      DEPENDS ${CMAKE_SOURCE_DIR}/extra/exports
> 
> (At least it works for libcurl bundling, but I didn't verified it with static
> build.)
> 
> However explicit listing of public libcurl symbols looks easier to understand
> and in tune with master.

commit aee16d72d6740f2b5b18c034ab0ec0f0379745f3
Author: Roman Khabibov <roman.habibov at tarantool.org>
Date:   Fri Jan 15 01:07:55 2021 +0300

    build: export libcurl symbols
    
    Export the symbols to tarantool executable in the case of libcurl
    included as bundled library.
    
    This patch is just 1.10 adaptation of the original commit 29ec628
    performed by Yaroslav Dynnikov <yaroslav.dynnikov at gmail.com>.

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 84e019eb0..7e2ddb503 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -347,6 +347,16 @@ else()
     find_package(CURL)
 endif()
 
+#
+# Export libcurl symbols if the library is bundled.
+#
+if (ENABLE_BUNDLED_LIBCURL)
+    set(EXPORT_LIBCURL_SYMBOLS ON)
+else()
+    set(EXPORT_LIBCURL_SYMBOLS OFF)
+endif()
+message(STATUS "EXPORT_LIBCURL_SYMBOLS: ${EXPORT_LIBCURL_SYMBOLS}")
+
 #
 # ReadLine
 #
diff --git a/extra/exports_libcurl b/extra/exports_libcurl
new file mode 100755
index 000000000..d9f420d03
--- /dev/null
+++ b/extra/exports_libcurl
@@ -0,0 +1,84 @@
+# The following list was obtained by parsing libcurl.a static
+# library: nm libcurl.a | grep -oP 'T \K(curl_.+)$' | sort
+
+curl_easy_cleanup
+curl_easy_duphandle
+curl_easy_escape
+curl_easy_getinfo
+curl_easy_init
+curl_easy_pause
+curl_easy_perform
+curl_easy_recv
+curl_easy_reset
+curl_easy_send
+curl_easy_setopt
+curl_easy_strerror
+curl_easy_unescape
+curl_easy_upkeep
+curl_escape
+curl_formadd
+curl_formfree
+curl_formget
+curl_free
+curl_getdate
+curl_getenv
+curl_global_cleanup
+curl_global_init
+curl_global_init_mem
+curl_global_sslset
+curl_maprintf
+curl_mfprintf
+curl_mime_addpart
+curl_mime_data
+curl_mime_data_cb
+curl_mime_encoder
+curl_mime_filedata
+curl_mime_filename
+curl_mime_free
+curl_mime_headers
+curl_mime_init
+curl_mime_name
+curl_mime_subparts
+curl_mime_type
+curl_mprintf
+curl_msnprintf
+curl_msprintf
+curl_multi_add_handle
+curl_multi_assign
+curl_multi_cleanup
+curl_multi_fdset
+curl_multi_info_read
+curl_multi_init
+curl_multi_perform
+curl_multi_poll
+curl_multi_remove_handle
+curl_multi_setopt
+curl_multi_socket
+curl_multi_socket_action
+curl_multi_socket_all
+curl_multi_strerror
+curl_multi_timeout
+curl_multi_wait
+curl_mvaprintf
+curl_mvfprintf
+curl_mvprintf
+curl_mvsnprintf
+curl_mvsprintf
+curl_pushheader_byname
+curl_pushheader_bynum
+curl_share_cleanup
+curl_share_init
+curl_share_setopt
+curl_share_strerror
+curl_slist_append
+curl_slist_free_all
+curl_strequal
+curl_strnequal
+curl_unescape
+curl_url
+curl_url_cleanup
+curl_url_dup
+curl_url_get
+curl_url_set
+curl_version
+curl_version_info
diff --git a/extra/mkexports b/extra/mkexports
index 145e5b8ce..15bd8e727 100755
--- a/extra/mkexports
+++ b/extra/mkexports
@@ -1,6 +1,6 @@
 #! /bin/sh
 # $1 - in  file
-# $2 - out file
+# $2 - out file(s)
 # $3 - os
 # $4 - export templates
 if [ "x$3x" = xDarwinx ]; then
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 04289af3d..c2d3e7fcd 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -231,13 +231,12 @@ target_link_libraries(server core bit uri uuid ${ICU_LIBRARIES})
 # Rule of thumb: if exporting a symbol from a static library, list the
 # library here.
 set (reexport_libraries server core misc bitset csv
-     ${LUAJIT_LIBRARIES} ${MSGPUCK_LIBRARIES} ${ICU_LIBRARIES})
+     ${LUAJIT_LIBRARIES} ${MSGPUCK_LIBRARIES} ${ICU_LIBRARIES} ${CURL_LIBRARIES})
 
 set (common_libraries
     ${reexport_libraries}
     ${LIBYAML_LIBRARIES}
     ${READLINE_LIBRARIES}
-    ${CURL_LIBRARIES}
     ${ICONV_LIBRARIES}
     ${OPENSSL_LIBRARIES}
 )
@@ -300,6 +299,13 @@ if(BUILD_STATIC)
     endif()
 endif()
 
+set(exports_file_sources ${CMAKE_SOURCE_DIR}/extra/exports)
+if (EXPORT_LIBCURL_SYMBOLS)
+    set(exports_file_sources ${exports_file_sources}
+        ${CMAKE_SOURCE_DIR}/extra/exports_libcurl)
+endif()
+string(REPLACE ";" " " exports_file_sources "${exports_file_sources}")
+
 # Exports syntax is toolchain-dependent, preprocessing is necessary
 set(exports_file ${CMAKE_BINARY_DIR}/extra/exports.${CMAKE_SYSTEM_NAME})
 add_custom_target(preprocess_exports
@@ -308,7 +314,7 @@ add_custom_command(
     OUTPUT  ${exports_file}
     DEPENDS ${CMAKE_SOURCE_DIR}/extra/exports
     COMMAND ${CMAKE_SOURCE_DIR}/extra/mkexports
-            ${CMAKE_SOURCE_DIR}/extra/exports
+            ${exports_file_sources}
             ${exports_file} ${CMAKE_SYSTEM_NAME}
             ${EXPORT_LIST}
 )
diff --git a/test/box-tap/curl-build.test.lua b/test/box-tap/curl-build.test.lua
new file mode 100755
index 000000000..300d60b07
--- /dev/null
+++ b/test/box-tap/curl-build.test.lua
@@ -0,0 +1,177 @@
+#!/usr/bin/env tarantool
+
+local tap = require('tap')
+local ffi = require('ffi')
+ffi.cdef([[
+    void *dlsym(void *handle, const char *symbol);
+    struct curl_version_info_data {
+        int age;                  /* see description below */
+        const char *version;      /* human readable string */
+        unsigned int version_num; /* numeric representation */
+        const char *host;         /* human readable string */
+        int features;             /* bitmask, see below */
+        char *ssl_version;        /* human readable string */
+        long ssl_version_num;     /* not used, always zero */
+        const char *libz_version; /* human readable string */
+        const char * const *protocols; /* protocols */
+
+        /* when 'age' is CURLVERSION_SECOND or higher, the members below exist */
+        const char *ares;         /* human readable string */
+        int ares_num;             /* number */
+
+        /* when 'age' is CURLVERSION_THIRD or higher, the members below exist */
+        const char *libidn;       /* human readable string */
+
+        /* when 'age' is CURLVERSION_FOURTH or higher (>= 7.16.1), the members
+           below exist */
+        int iconv_ver_num;       /* '_libiconv_version' if iconv support enabled */
+
+        const char *libssh_version; /* human readable string */
+
+        /* when 'age' is CURLVERSION_FIFTH or higher (>= 7.57.0), the members
+           below exist */
+        unsigned int brotli_ver_num; /* Numeric Brotli version
+                                        (MAJOR << 24) | (MINOR << 12) | PATCH */
+        const char *brotli_version; /* human readable string. */
+
+        /* when 'age' is CURLVERSION_SIXTH or higher (>= 7.66.0), the members
+           below exist */
+        unsigned int nghttp2_ver_num; /* Numeric nghttp2 version
+                                         (MAJOR << 16) | (MINOR << 8) | PATCH */
+        const char *nghttp2_version; /* human readable string. */
+
+        const char *quic_version;    /* human readable quic (+ HTTP/3) library +
+                                        version or NULL */
+
+        /* when 'age' is CURLVERSION_SEVENTH or higher (>= 7.70.0), the members
+           below exist */
+        const char *cainfo;          /* the built-in default CURLOPT_CAINFO, might
+                                        be NULL */
+        const char *capath;          /* the built-in default CURLOPT_CAPATH, might
+                                        be NULL */
+    };
+
+    struct curl_version_info_data *curl_version_info(int age);
+]])
+
+local info = ffi.C.curl_version_info(7)
+local test = tap.test('curl-features')
+test:plan(3)
+
+if test:ok(info.ssl_version ~= nil, 'Curl built with SSL support') then
+    test:diag('ssl_version: ' .. ffi.string(info.ssl_version))
+end
+if test:ok(info.libz_version ~= nil, 'Curl built with LIBZ') then
+    test:diag('libz_version: ' .. ffi.string(info.libz_version))
+end
+
+local RTLD_DEFAULT
+-- See `man 3 dlsym`:
+-- RTLD_DEFAULT
+--   Find  the  first occurrence of the desired symbol using the default
+--   shared object search order.  The search will include global symbols
+--   in the executable and its dependencies, as well as symbols in shared
+--   objects that were dynamically loaded with the RTLD_GLOBAL flag.
+if jit.os == "OSX" then
+    RTLD_DEFAULT = ffi.cast("void *", -2LL)
+else
+    RTLD_DEFAULT = ffi.cast("void *", 0LL)
+end
+
+-- The following list was obtained by parsing libcurl.a static library:
+-- nm libcurl.a | grep -oP 'T \K(curl_.+)$' | sort
+local curl_symbols = {
+    'curl_easy_cleanup',
+    'curl_easy_duphandle',
+    'curl_easy_escape',
+    'curl_easy_getinfo',
+    'curl_easy_init',
+    'curl_easy_pause',
+    'curl_easy_perform',
+    'curl_easy_recv',
+    'curl_easy_reset',
+    'curl_easy_send',
+    'curl_easy_setopt',
+    'curl_easy_strerror',
+    'curl_easy_unescape',
+    'curl_easy_upkeep',
+    'curl_escape',
+    'curl_formadd',
+    'curl_formfree',
+    'curl_formget',
+    'curl_free',
+    'curl_getdate',
+    'curl_getenv',
+    'curl_global_cleanup',
+    'curl_global_init',
+    'curl_global_init_mem',
+    'curl_global_sslset',
+    'curl_maprintf',
+    'curl_mfprintf',
+    'curl_mime_addpart',
+    'curl_mime_data',
+    'curl_mime_data_cb',
+    'curl_mime_encoder',
+    'curl_mime_filedata',
+    'curl_mime_filename',
+    'curl_mime_free',
+    'curl_mime_headers',
+    'curl_mime_init',
+    'curl_mime_name',
+    'curl_mime_subparts',
+    'curl_mime_type',
+    'curl_mprintf',
+    'curl_msnprintf',
+    'curl_msprintf',
+    'curl_multi_add_handle',
+    'curl_multi_assign',
+    'curl_multi_cleanup',
+    'curl_multi_fdset',
+    'curl_multi_info_read',
+    'curl_multi_init',
+    'curl_multi_perform',
+    'curl_multi_poll',
+    'curl_multi_remove_handle',
+    'curl_multi_setopt',
+    'curl_multi_socket',
+    'curl_multi_socket_action',
+    'curl_multi_socket_all',
+    'curl_multi_strerror',
+    'curl_multi_timeout',
+    'curl_multi_wait',
+    'curl_mvaprintf',
+    'curl_mvfprintf',
+    'curl_mvprintf',
+    'curl_mvsnprintf',
+    'curl_mvsprintf',
+    'curl_pushheader_byname',
+    'curl_pushheader_bynum',
+    'curl_share_cleanup',
+    'curl_share_init',
+    'curl_share_setopt',
+    'curl_share_strerror',
+    'curl_slist_append',
+    'curl_slist_free_all',
+    'curl_strequal',
+    'curl_strnequal',
+    'curl_unescape',
+    'curl_url',
+    'curl_url_cleanup',
+    'curl_url_dup',
+    'curl_url_get',
+    'curl_url_set',
+    'curl_version',
+    'curl_version_info',
+}
+
+test:test('curl_symbols', function(t)
+    t:plan(#curl_symbols)
+    for _, sym in ipairs(curl_symbols) do
+        t:ok(
+            ffi.C.dlsym(RTLD_DEFAULT, sym) ~= nil,
+            ('Symbol %q found'):format(sym)
+        )
+    end
+end)
+
+os.exit(test:check() and 0 or 1)



More information about the Tarantool-patches mailing list