Browse Source

cmake: add support for single libcurl compilation pass

Before this patch CMake builds used two separate compilation passes to
build the shared and static libcurl respectively. This patch allows to
reduce that to a single pass if the target platform and build settings
allow it.

This reduces CMake build times when building both static and shared
libcurl at the same time, making these dual builds an almost zero-cost
option.

Enable this feature for Windows builds, where the difference between the
two passes was the use of `__declspec(dllexport)` attribute for exported
API functions for the shared builds. This patch replaces this method
with the use of `libcurl.def` at DLL link time.

Also update `Makefile.mk` to use `libcurl.def` to export libcurl API
symbols on Windows. This simplifies (or fixes) this build method (e.g.
in curl-for-win, which generated a `libcurl.def` from `.h` files using
an elaborate set of transformations).

`libcurl.def` has the maintenance cost of keeping the list of public
libcurl API symbols up-to-date. This list seldom changes, so the cost
is low.

Closes #11546
Viktor Szakats 9 months ago
parent
commit
2ebc74c36a
5 changed files with 138 additions and 4 deletions
  1. 4 0
      .reuse/dep5
  2. 2 1
      Makefile.am
  3. 39 3
      lib/CMakeLists.txt
  4. 1 0
      lib/Makefile.mk
  5. 92 0
      libcurl.def

+ 4 - 0
.reuse/dep5

@@ -23,6 +23,10 @@ Files: projects/Windows/*
 Copyright: Daniel Stenberg, <daniel@haxx.se>, et al.
 License: curl
 
+Files: libcurl.def
+Copyright: Daniel Stenberg, <daniel@haxx.se>, et al.
+License: curl
+
 # Single files we do not want to edit directly
 Files: CHANGES
 Copyright: Daniel Stenberg, <daniel@haxx.se>, et al.

+ 2 - 1
Makefile.am

@@ -148,7 +148,8 @@ PLAN9_DIST = plan9/include/mkfile \
 
 EXTRA_DIST = CHANGES COPYING maketgz Makefile.dist curl-config.in            \
  RELEASE-NOTES buildconf libcurl.pc.in MacOSX-Framework $(CMAKE_DIST)        \
- $(VC_DIST) $(WINBUILD_DIST) $(PLAN9_DIST) lib/libcurl.vers.in buildconf.bat
+ $(VC_DIST) $(WINBUILD_DIST) $(PLAN9_DIST) lib/libcurl.vers.in buildconf.bat \
+ libcurl.def
 
 CLEANFILES = $(VC10_LIBVCXPROJ) $(VC10_SRCVCXPROJ) $(VC11_LIBVCXPROJ)        \
  $(VC11_SRCVCXPROJ) $(VC12_LIBVCXPROJ) $(VC12_SRCVCXPROJ) $(VC14_LIBVCXPROJ) \

+ 39 - 3
lib/CMakeLists.txt

@@ -108,10 +108,46 @@ if(WIN32 AND
   set(IMPORT_LIB_SUFFIX "_imp")
 endif()
 
+# On supported platforms, do a single compilation pass for libcurl sources
+# and reuse these objects to generate both static and shared target.
+# This is possible where PIC is the default for both shared and static and
+# there is a way to tell the linker which libcurl symbols it should export
+# (vs. marking these symbols exportable at compile-time).
+if(WIN32 AND NOT DEFINED SHARE_LIB_OBJECT)
+  set(SHARE_LIB_OBJECT ON)
+endif()
+
+if(SHARE_LIB_OBJECT)
+  set(LIB_OBJECT "libcurl_object")
+  add_library(${LIB_OBJECT} OBJECT ${HHEADERS} ${CSOURCES})
+  target_link_libraries(${LIB_OBJECT} PRIVATE ${CURL_LIBS})
+  set_target_properties(${LIB_OBJECT} PROPERTIES
+    COMPILE_DEFINITIONS "BUILDING_LIBCURL"
+    INTERFACE_COMPILE_DEFINITIONS "CURL_STATICLIB")
+  if(HIDES_CURL_PRIVATE_SYMBOLS)
+    set_target_properties(${LIB_OBJECT} PROPERTIES
+      COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS"
+      COMPILE_FLAGS "${CURL_CFLAG_SYMBOLS_HIDE}")
+  endif()
+  if(CURL_HAS_LTO)
+    set_target_properties(${LIB_OBJECT} PROPERTIES
+      INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE
+      INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE)
+  endif()
+
+  target_include_directories(${LIB_OBJECT} INTERFACE
+    $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
+    $<BUILD_INTERFACE:${CURL_SOURCE_DIR}/include>)
+
+  set(LIB_SOURCE $<TARGET_OBJECTS:${LIB_OBJECT}>)
+else()
+  set(LIB_SOURCE ${HHEADERS} ${CSOURCES})
+endif()
+
 # we want it to be called libcurl on all platforms
 if(BUILD_STATIC_LIBS)
   list(APPEND libcurl_export ${LIB_STATIC})
-  add_library(${LIB_STATIC} STATIC ${HHEADERS} ${CSOURCES})
+  add_library(${LIB_STATIC} STATIC ${LIB_SOURCE})
   add_library(${PROJECT_NAME}::${LIB_STATIC} ALIAS ${LIB_STATIC})
   target_link_libraries(${LIB_STATIC} PRIVATE ${CURL_LIBS})
   # Remove the "lib" prefix since the library is already named "libcurl".
@@ -142,10 +178,10 @@ endif()
 
 if(BUILD_SHARED_LIBS)
   list(APPEND libcurl_export ${LIB_SHARED})
-  add_library(${LIB_SHARED} SHARED ${HHEADERS} ${CSOURCES})
+  add_library(${LIB_SHARED} SHARED ${LIB_SOURCE})
   add_library(${PROJECT_NAME}::${LIB_SHARED} ALIAS ${LIB_SHARED})
   if(WIN32)
-    set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES libcurl.rc)
+    set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES libcurl.rc ${CURL_SOURCE_DIR}/libcurl.def)
   endif()
   target_link_libraries(${LIB_SHARED} PRIVATE ${CURL_LIBS})
   # Remove the "lib" prefix since the library is already named "libcurl".

+ 1 - 0
lib/Makefile.mk

@@ -388,6 +388,7 @@ ifdef WIN32
 CURL_DLL_SUFFIX ?=
 libcurl_dll_LIBRARY := libcurl$(CURL_DLL_SUFFIX).dll
 libcurl_dll_a_LIBRARY := libcurl.dll.a
+CURL_LDFLAGS_LIB += $(PROOT)/libcurl.def
 ifdef MAP
 libcurl_map_LIBRARY := libcurl$(CURL_DLL_SUFFIX).map
 CURL_LDFLAGS_LIB += -Wl,-Map,$(libcurl_map_LIBRARY)

+ 92 - 0
libcurl.def

@@ -0,0 +1,92 @@
+EXPORTS
+curl_easy_cleanup
+curl_easy_duphandle
+curl_easy_escape
+curl_easy_getinfo
+curl_easy_header
+curl_easy_init
+curl_easy_nextheader
+curl_easy_option_by_id
+curl_easy_option_by_name
+curl_easy_option_next
+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_multi_wakeup
+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_url_strerror
+curl_version
+curl_version_info
+curl_ws_meta
+curl_ws_recv
+curl_ws_send