]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
cmake: support building static and shared libcurl in one go
authorViktor Szakats <commit@vsz.me>
Thu, 22 Jun 2023 09:24:37 +0000 (09:24 +0000)
committerViktor Szakats <commit@vsz.me>
Sat, 29 Jul 2023 00:40:01 +0000 (00:40 +0000)
This patch adds the ability to build a static and shared libcurl library
in a single build session. It also adds an option to select which one to
use when building the curl executable.

New build options:
- `BUILD_STATIC_LIBS`. Default: `OFF`.
  Enabled automatically if `BUILD_SHARED_LIBS` is `OFF`.
- `BUILD_STATIC_CURL`. Default: `OFF`.
  Requires `BUILD_STATIC_LIBS` enabled.
  Enabled automatically if building static libcurl only.
- `STATIC_LIB_SUFFIX`. Default: empty.
- `IMPORT_LIB_SUFFIX`. Default: `_imp` if implib filename would collide
  with static lib name (typically with MSVC) in Windows builds.
  Otherwise empty.

Also:

- Stop setting the `CURL_STATICLIB` macro via `curl_config.h`, and pass
  it directly to the compiler. This also allows to delete a condition
  from `tests/server/CMakeLists.txt`.

- Complete a TODO by following the logic used in autotools (also for
  `LIBCURL_NO_SHARED`), and set `-DCURL_STATICLIB` in `Cflags:` of
  `libcurl.pc` for _static-only_ curl builds.

- Convert an existing CI test to build both shared and static libcurl.

Closes #11505

.github/workflows/macos.yml
CMake/curl-config.cmake.in
CMakeLists.txt
lib/CMakeLists.txt
lib/curl_config.h.cmake
src/CMakeLists.txt
tests/libtest/CMakeLists.txt
tests/server/CMakeLists.txt

index 2b382dd95025b35e3255b32020b3d885489dd7d3..b7138cb911b50718e971ca41a1777c774dc891d9 100644 (file)
@@ -180,7 +180,7 @@ jobs:
           generate: -DOPENSSL_ROOT_DIR=/usr/local/opt/libressl -DCURL_DISABLE_LDAP=ON -DCURL_DISABLE_LDAPS=ON -DCMAKE_UNITY_BUILD=ON
         - name: libssh2
           install: nghttp2 openssl libssh2
-          generate: -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl -DCURL_USE_LIBSSH2=ON
+          generate: -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl -DCURL_USE_LIBSSH2=ON -DBUILD_SHARED_LIBS=ON -DBUILD_STATIC_LIBS=ON
     steps:
     - run: echo libtool autoconf automake pkg-config ${{ matrix.build.install }} | xargs -Ix -n1 echo brew '"x"' > /tmp/Brewfile
       name: 'brew bundle'
index dbe4ed21025760b621edd0ada0b640dfecbd9fe7..e76d0d64fc3851142add7a0236b64ca3f30d1019 100644 (file)
@@ -33,3 +33,6 @@ endif()
 
 include("${CMAKE_CURRENT_LIST_DIR}/@TARGETS_EXPORT_NAME@.cmake")
 check_required_components("@PROJECT_NAME@")
+
+# Alias for either shared or static library
+add_library(curl::libcurl ALIAS curl::@LIB_SELECTED@)
index 7a4c36fac9d27ab69ef099dc83fea2b5bb01e09c..a755377cec32c240f1e188d0b09466c5e7d8a89e 100644 (file)
@@ -103,6 +103,8 @@ option(CURL_WERROR "Turn compiler warnings into errors" OFF)
 option(PICKY_COMPILER "Enable picky compiler options" ON)
 option(BUILD_CURL_EXE "Set to ON to build curl executable." ON)
 option(BUILD_SHARED_LIBS "Build shared libraries" ON)
+option(BUILD_STATIC_LIBS "Build shared libraries" OFF)
+option(BUILD_STATIC_CURL "Build curl executable with static libcurl" OFF)
 option(ENABLE_ARES "Set to ON to enable c-ares support" OFF)
 if(WIN32)
   option(CURL_STATIC_CRT "Set to ON to build libcurl with static CRT on Windows (/MT)." OFF)
@@ -146,6 +148,32 @@ if(NOT DEFINED CMAKE_DEBUG_POSTFIX)
   set(CMAKE_DEBUG_POSTFIX "-d")
 endif()
 
+set(LIB_STATIC "libcurl_static")
+set(LIB_SHARED "libcurl_shared")
+
+if(NOT BUILD_SHARED_LIBS AND NOT BUILD_STATIC_LIBS)
+  set(BUILD_STATIC_LIBS ON)
+endif()
+if(NOT BUILD_STATIC_CURL AND NOT BUILD_SHARED_LIBS)
+  set(BUILD_STATIC_CURL ON)
+elseif(BUILD_STATIC_CURL AND NOT BUILD_STATIC_LIBS)
+  set(BUILD_STATIC_CURL OFF)
+endif()
+
+# lib flavour selected for curl tool
+if(BUILD_STATIC_CURL)
+  set(LIB_SELECTED_FOR_EXE ${LIB_STATIC})
+else()
+  set(LIB_SELECTED_FOR_EXE ${LIB_SHARED})
+endif()
+
+# lib flavour selected for example and test programs.
+if(BUILD_SHARED_LIBS)
+  set(LIB_SELECTED ${LIB_SHARED})
+else()
+  set(LIB_SELECTED ${LIB_STATIC})
+endif()
+
 # initialize CURL_LIBS
 set(CURL_LIBS "")
 
@@ -1539,8 +1567,6 @@ message(STATUS "Enabled SSL backends: ${SSL_BACKENDS}")
 set(CC                      "${CMAKE_C_COMPILER}")
 # TODO probably put a -D... options here?
 set(CONFIGURE_OPTIONS       "")
-# TODO when to set "-DCURL_STATICLIB" for CPPFLAG_CURL_STATICLIB?
-set(CPPFLAG_CURL_STATICLIB  "")
 set(CURLVERSION             "${CURL_VERSION}")
 set(exec_prefix             "\${prefix}")
 set(includedir              "\${prefix}/include")
@@ -1570,12 +1596,17 @@ foreach(_lib ${CMAKE_C_IMPLICIT_LINK_LIBRARIES} ${CURL_LIBS})
 endforeach()
 if(BUILD_SHARED_LIBS)
   set(ENABLE_SHARED         "yes")
-  set(ENABLE_STATIC         "no")
   set(LIBCURL_NO_SHARED     "")
+  set(CPPFLAG_CURL_STATICLIB "")
 else()
   set(ENABLE_SHARED         "no")
-  set(ENABLE_STATIC         "yes")
   set(LIBCURL_NO_SHARED     "${LIBCURL_LIBS}")
+  set(CPPFLAG_CURL_STATICLIB "-DCURL_STATICLIB")
+endif()
+if(BUILD_STATIC_LIBS)
+  set(ENABLE_STATIC         "yes")
+else()
+  set(ENABLE_STATIC         "no")
 endif()
 # "a" (Linux) or "lib" (Windows)
 string(REPLACE "." "" libext "${CMAKE_STATIC_LIBRARY_SUFFIX}")
index 712d7c7ab6d7330cdbb30048575fc587aac1544c..0239f805be728f10334897c7fb0927accba64170 100644 (file)
@@ -25,14 +25,6 @@ set(LIB_NAME libcurl)
 set(LIBCURL_OUTPUT_NAME libcurl CACHE STRING "Basename of the curl library")
 add_definitions(-DBUILDING_LIBCURL)
 
-if(BUILD_SHARED_LIBS)
-  set(CURL_STATICLIB NO)
-else()
-  set(CURL_STATICLIB YES)
-endif()
-
-# Use:
-# * CURL_STATICLIB
 configure_file(curl_config.h.cmake
   ${CMAKE_CURRENT_BINARY_DIR}/curl_config.h)
 
@@ -43,10 +35,6 @@ list(APPEND HHEADERS
   ${CMAKE_CURRENT_BINARY_DIR}/curl_config.h
   )
 
-if(WIN32 AND NOT CURL_STATICLIB)
-  list(APPEND CSOURCES libcurl.rc)
-endif()
-
 # The rest of the build
 
 include_directories(${CMAKE_CURRENT_BINARY_DIR}/../include)
@@ -59,11 +47,6 @@ if(USE_ARES)
   include_directories(${CARES_INCLUDE_DIR})
 endif()
 
-add_library(
-  ${LIB_NAME}
-  ${HHEADERS} ${CSOURCES}
-  )
-
 add_library(
   curlu # special libcurlu library just for unittests
   STATIC
@@ -72,32 +55,16 @@ add_library(
 )
 target_compile_definitions(curlu PUBLIC UNITTESTS CURL_STATICLIB)
 
-add_library(
-  ${PROJECT_NAME}::${LIB_NAME}
-  ALIAS ${LIB_NAME}
-  )
-
 if(ENABLE_CURLDEBUG)
   # We must compile memdebug.c separately to avoid memdebug.h redefinitions
   # being applied to memdebug.c itself.
   set_source_files_properties(memdebug.c PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
 endif()
-
-if(NOT BUILD_SHARED_LIBS)
-    set_target_properties(${LIB_NAME} PROPERTIES INTERFACE_COMPILE_DEFINITIONS CURL_STATICLIB)
-endif()
-
-target_link_libraries(${LIB_NAME} PRIVATE ${CURL_LIBS})
 target_link_libraries(curlu PRIVATE ${CURL_LIBS})
 
 transform_makefile_inc("Makefile.soname" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.soname.cmake")
 include(${CMAKE_CURRENT_BINARY_DIR}/Makefile.soname.cmake)
 
-set_target_properties(${LIB_NAME} PROPERTIES
-  COMPILE_DEFINITIONS BUILDING_LIBCURL
-  OUTPUT_NAME ${LIBCURL_OUTPUT_NAME}
-  )
-
 if(CMAKE_SYSTEM_NAME STREQUAL "AIX" OR
   CMAKE_SYSTEM_NAME STREQUAL "Linux" OR
   CMAKE_SYSTEM_NAME STREQUAL "Darwin" OR
@@ -114,39 +81,11 @@ if(CMAKE_SYSTEM_NAME STREQUAL "AIX" OR
 
   math(EXPR CMAKESONAME "${VERSIONCHANGE} - ${VERSIONDEL}")
   set(CMAKEVERSION "${CMAKESONAME}.${VERSIONDEL}.${VERSIONADD}")
-
-  set_target_properties(${LIB_NAME} PROPERTIES
-    VERSION ${CMAKEVERSION}
-    SOVERSION ${CMAKESONAME}
-  )
-
-endif()
-
-
-if(HIDES_CURL_PRIVATE_SYMBOLS)
-  set_property(TARGET ${LIB_NAME} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS")
-  set_property(TARGET ${LIB_NAME} APPEND PROPERTY COMPILE_FLAGS ${CURL_CFLAG_SYMBOLS_HIDE})
-endif()
-
-# Remove the "lib" prefix since the library is already named "libcurl".
-set_target_properties(${LIB_NAME} PROPERTIES PREFIX "")
-set_target_properties(${LIB_NAME} PROPERTIES IMPORT_PREFIX "")
-
-if(CURL_HAS_LTO)
-  set_target_properties(${LIB_NAME} PROPERTIES
-    INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE
-    INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE)
+else()
+  unset(CMAKESONAME)
 endif()
 
-if(WIN32)
-  if(BUILD_SHARED_LIBS)
-    if(MSVC)
-      # Add "_imp" as a suffix before the extension to avoid conflicting with
-      # the statically linked "libcurl.lib"
-      set_target_properties(${LIB_NAME} PROPERTIES IMPORT_SUFFIX "_imp.lib")
-    endif()
-  endif()
-elseif(NOT CMAKE_CROSSCOMPILING)
+if(NOT WIN32 AND NOT CMAKE_CROSSCOMPILING)
   # on not-Windows and not-crosscompiling, check for writable argv[]
     include(CheckCSourceRuns)
     check_c_source_runs("
@@ -159,19 +98,104 @@ int main(int argc, char **argv)
       HAVE_WRITABLE_ARGV)
 endif()
 
-target_include_directories(${LIB_NAME} INTERFACE
-  $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
-  $<BUILD_INTERFACE:${CURL_SOURCE_DIR}/include>)
+## Library definition
+
+# Add "_imp" as a suffix before the extension to avoid conflicting with
+# the statically linked "libcurl.lib" (typically with MSVC)
+if(WIN32 AND
+   NOT IMPORT_LIB_SUFFIX AND
+   CMAKE_STATIC_LIBRARY_SUFFIX STREQUAL CMAKE_IMPORT_LIBRARY_SUFFIX)
+  set(IMPORT_LIB_SUFFIX "_imp")
+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(${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".
+  set_target_properties(${LIB_STATIC} PROPERTIES
+    PREFIX "" OUTPUT_NAME "${LIBCURL_OUTPUT_NAME}"
+    SUFFIX "${STATIC_LIB_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX}"
+    COMPILE_DEFINITIONS "BUILDING_LIBCURL"
+    INTERFACE_COMPILE_DEFINITIONS "CURL_STATICLIB")
+  if(HIDES_CURL_PRIVATE_SYMBOLS)
+    set_target_properties(${LIB_STATIC} PROPERTIES
+      COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS"
+      COMPILE_FLAGS "${CURL_CFLAG_SYMBOLS_HIDE}")
+  endif()
+  if(CURL_HAS_LTO)
+    set_target_properties(${LIB_STATIC} PROPERTIES
+      INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE
+      INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE)
+  endif()
+  if(CMAKEVERSION AND CMAKESONAME)
+    set_target_properties(${LIB_STATIC} PROPERTIES
+      VERSION ${CMAKEVERSION} SOVERSION ${CMAKESONAME})
+  endif()
+
+  target_include_directories(${LIB_STATIC} INTERFACE
+    $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
+    $<BUILD_INTERFACE:${CURL_SOURCE_DIR}/include>)
+endif()
+
+if(BUILD_SHARED_LIBS)
+  list(APPEND libcurl_export ${LIB_SHARED})
+  add_library(${LIB_SHARED} SHARED ${HHEADERS} ${CSOURCES})
+  add_library(${PROJECT_NAME}::${LIB_SHARED} ALIAS ${LIB_SHARED})
+  if(WIN32)
+    set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES libcurl.rc)
+  endif()
+  target_link_libraries(${LIB_SHARED} PRIVATE ${CURL_LIBS})
+  # Remove the "lib" prefix since the library is already named "libcurl".
+  set_target_properties(${LIB_SHARED} PROPERTIES
+    PREFIX "" OUTPUT_NAME "${LIBCURL_OUTPUT_NAME}"
+    IMPORT_PREFIX "" IMPORT_SUFFIX "${IMPORT_LIB_SUFFIX}${CMAKE_IMPORT_LIBRARY_SUFFIX}"
+    COMPILE_DEFINITIONS "BUILDING_LIBCURL"
+    POSITION_INDEPENDENT_CODE ON)
+  if(HIDES_CURL_PRIVATE_SYMBOLS)
+    set_target_properties(${LIB_SHARED} PROPERTIES
+      COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS"
+      COMPILE_FLAGS "${CURL_CFLAG_SYMBOLS_HIDE}")
+  endif()
+  if(CURL_HAS_LTO)
+    set_target_properties(${LIB_SHARED} PROPERTIES
+      INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE
+      INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE)
+  endif()
+  if(CMAKEVERSION AND CMAKESONAME)
+    set_target_properties(${LIB_SHARED} PROPERTIES
+      VERSION ${CMAKEVERSION} SOVERSION ${CMAKESONAME})
+  endif()
+
+  target_include_directories(${LIB_SHARED} INTERFACE
+    $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
+    $<BUILD_INTERFACE:${CURL_SOURCE_DIR}/include>)
+endif()
+
+add_library(${LIB_NAME} ALIAS ${LIB_SELECTED})
+add_library(${PROJECT_NAME}::${LIB_NAME} ALIAS ${LIB_SELECTED})
 
 if(CURL_ENABLE_EXPORT_TARGET)
-  install(TARGETS ${LIB_NAME}
-    EXPORT ${TARGETS_EXPORT_NAME}
-    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
-    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
-    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
-  )
+  if(BUILD_STATIC_LIBS)
+    install(TARGETS ${LIB_STATIC}
+      EXPORT ${TARGETS_EXPORT_NAME}
+      ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+      LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+      RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    )
+  endif()
+  if(BUILD_SHARED_LIBS)
+    install(TARGETS ${LIB_SHARED}
+      EXPORT ${TARGETS_EXPORT_NAME}
+      ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+      LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+      RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    )
+  endif()
 
-  export(TARGETS ${LIB_NAME}
+  export(TARGETS ${libcurl_export}
          FILE ${PROJECT_BINARY_DIR}/libcurl-target.cmake
          NAMESPACE ${PROJECT_NAME}::
   )
index 20587123dc43a0c271ab5b4628bc28ddb077c021..7867e83474f05e1c392553aa7d2a8ed9e83c640c 100644 (file)
 /* Use Windows LDAP implementation */
 #cmakedefine USE_WIN32_LDAP 1
 
-/* when not building a shared library */
-#cmakedefine CURL_STATICLIB 1
-
 /* your Entropy Gathering Daemon socket pathname */
 #cmakedefine EGD_SOCKET ${EGD_SOCKET}
 
index bbe79be94611898cc2e64cee5f47649a01b4e685..38abf3575c1fc3a015c860bb933cff2a54d3784c 100644 (file)
@@ -62,7 +62,7 @@ if(WIN32)
 endif()
 
 # CURL_CFILES, CURLX_CFILES, CURL_HFILES come from Makefile.inc
-if(NOT BUILD_SHARED_LIBS)
+if(BUILD_STATIC_CURL)
   set(CURLX_CFILES ../lib/dynbuf.c)
 endif()
 
@@ -107,7 +107,7 @@ include_directories(
   )
 
 #Build curl executable
-target_link_libraries(${EXE_NAME} libcurl ${CURL_LIBS})
+target_link_libraries(${EXE_NAME} ${LIB_SELECTED_FOR_EXE} ${CURL_LIBS})
 
 ################################################################################
 
index 2579cef29ff8bdd21c62b517a4b587ce1b85db8b..98f5b9c67ec5203e518b94622ebc539da9859fab 100644 (file)
@@ -25,7 +25,7 @@ set(TARGET_LABEL_PREFIX "Test ")
 
 function(setup_test TEST_NAME)          # ARGN are the files in the test
 
-  if(NOT BUILD_SHARED_LIBS)
+  if(LIB_SELECTED STREQUAL LIB_STATIC)
     # These are part of the libcurl static lib. Do not compile/link them again.
     list(REMOVE_ITEM ARGN ${WARNLESS} ${MULTIBYTE} ${TIMEDIFF})
   endif()
@@ -44,7 +44,7 @@ function(setup_test TEST_NAME)          # ARGN are the files in the test
     include_directories(${CARES_INCLUDE_DIR})
   endif()
 
-  target_link_libraries(${TEST_NAME} libcurl ${CURL_LIBS})
+  target_link_libraries(${TEST_NAME} ${LIB_SELECTED} ${CURL_LIBS})
 
   set_target_properties(${TEST_NAME}
     PROPERTIES COMPILE_DEFINITIONS ${UPPER_TEST_NAME})
index d92f60fee34bdcc76223c53a8731fb08ece44fc4..46c943a8be72af4f53fc78c52b177acd2d215325 100644 (file)
@@ -50,10 +50,8 @@ function(SETUP_EXECUTABLE TEST_NAME)    # ARGN are the files in the test
   # to build the servers.  In order to achieve proper linkage of these
   # files on Win32 targets it is necessary to build the test servers
   # with CURL_STATICLIB defined, independently of how libcurl is built.
-  if(BUILD_SHARED_LIBS)
-    set_target_properties(${TEST_NAME} PROPERTIES
-      COMPILE_DEFINITIONS CURL_STATICLIB)       # ${UPPER_TEST_NAME}
-  endif()
+  set_target_properties(${TEST_NAME} PROPERTIES
+    COMPILE_DEFINITIONS CURL_STATICLIB)       # ${UPPER_TEST_NAME}
   set_target_properties(${TEST_NAME} PROPERTIES
     PROJECT_LABEL "${TARGET_LABEL_PREFIX}${TEST_NAME}")
 endfunction()