From: Viktor Szakats Date: Thu, 22 Jun 2023 09:24:37 +0000 (+0000) Subject: cmake: support building static and shared libcurl in one go X-Git-Tag: curl-8_3_0~283 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1199308dbc902c52be67fc805c72dd2582520d30;p=thirdparty%2Fcurl.git cmake: support building static and shared libcurl in one go 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 --- diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 2b382dd950..b7138cb911 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -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' diff --git a/CMake/curl-config.cmake.in b/CMake/curl-config.cmake.in index dbe4ed2102..e76d0d64fc 100644 --- a/CMake/curl-config.cmake.in +++ b/CMake/curl-config.cmake.in @@ -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@) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a4c36fac9..a755377cec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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}") diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 712d7c7ab6..0239f805be 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -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 - $ - $) +## 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 + $ + $) +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 + $ + $) +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}:: ) diff --git a/lib/curl_config.h.cmake b/lib/curl_config.h.cmake index 20587123dc..7867e83474 100644 --- a/lib/curl_config.h.cmake +++ b/lib/curl_config.h.cmake @@ -132,9 +132,6 @@ /* 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} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bbe79be946..38abf3575c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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}) ################################################################################ diff --git a/tests/libtest/CMakeLists.txt b/tests/libtest/CMakeLists.txt index 2579cef29f..98f5b9c67e 100644 --- a/tests/libtest/CMakeLists.txt +++ b/tests/libtest/CMakeLists.txt @@ -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}) diff --git a/tests/server/CMakeLists.txt b/tests/server/CMakeLists.txt index d92f60fee3..46c943a8be 100644 --- a/tests/server/CMakeLists.txt +++ b/tests/server/CMakeLists.txt @@ -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()