Skip to content

Commit 66ad54e

Browse files
committed
cmake: add CURL_DROP_UNUSED option to reduce binary sizes
To enable known linker options dropping unused, dead, code and data from the executables built. Useful to reduce binary sizes for curl, libcurl shared lib and apps linking static libcurl. It's effective on both "unity" and non-unity builds. Aligning "unity" build sizes with default, non-unity ones. Supported platforms: Apple, MSVC, llvm/clang and GCC on all tested platforms: Linux, BSDs, Windows, MSYS2/Cygwin, Android, MS-DOS. Notes: - Static libraries grow 20-30% with non-Apple toolchains. This effect is controlled by separate, optional compiler flags on non-Apple. This patch enables them automatically for public binaries (libcurl and curl tool), and leaves them off for internal/test ones. - MSVC enables this option by default for 'Release' configurations. The curl build option has no effect on it. - Observed effect on VS2010 is negligible. VS2012+ is recommended. - Works with LTO, Fil-C. - No observed/conclusive effect on build speed. - On Windows with clang/gcc (mingw-w64/MSYS2/Cygwin) it also enables `-fno-asynchronous-unwind-tables` as a workaround to make the toolchain options actually work. Ref: https://sourceware.org/bugzilla/show_bug.cgi?id=11539 Thanks-to: Andarwinux Also: - GHA: enable in Linux and MinGW jobs to test it. Size changes: - linux aws-lc H3: curl: 2000000 -> 1937152, libcurl.a: 2065724 -> 2716532 bytes - macos clang HTTP-only: curl: 1364376 -> 128799 bytes, libcurl.a: unchanged - macos llvm MultiSSL: curl: 410056 -> 405720, libcurl.dylib: 1350336 -> 1348480 bytes - mingw schannel c-ares U: curl: 1588736 -> 1507328, libcurl-d.a: 3322040 -> 3884746 bytes bld: 34 -> 35MB - GHA: enable in MSVC and Apple jobs to reduce disk footprint, with no obvious downside. Size changes: - AppVeyor CI VS2019: curl: 2339840 -> 1295872, libcurl-d.dll: 3155968 -> 1900544 bytes bld: 161 -> 97MB - AppVeyor CI VS2022 clang-cl: curl: 2933248 -> 2332160, libcurl-d.lib: 4762688 -> 5511330 bytes bld: 133 -> 121MB - AppVeyor CI VS2022 HTTP-only: curl: 3514368 -> 2177024, libcurl-d.lib: 2538420 -> 3151740 bytes bld: 137 -> 83MB - GHA intel: curl: 2629120 -> 2023424, libcurl-d.lib: 4366652 -> 5350670 bytes bld: 86 -> 69MB - GHA arm64: curl: 2832896 -> 2063872, libcurl-d.lib: 4690616 -> 5597250 bytes bld: 82 -> 66MB Refs: https://maskray.me/blog/2021-02-28-linker-garbage-collection https://web.archive.org/web/20110811230637/msdn.microsoft.com/en-us/library/bxwfs976.aspx (VS2010) https://learn.microsoft.com/cpp/build/reference/opt-optimizations https://learn.microsoft.com/cpp/build/reference/gy-enable-function-level-linking Closes #20357
1 parent aacbe4d commit 66ad54e

File tree

9 files changed

+50
-8
lines changed

9 files changed

+50
-8
lines changed

.github/workflows/http3-linux.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ jobs:
389389
tflags: '--min=1790'
390390
generate: >-
391391
-DOPENSSL_ROOT_DIR=/home/runner/awslc/build -DUSE_NGTCP2=ON -DBUILD_SHARED_LIBS=OFF
392-
-DCMAKE_UNITY_BUILD=ON
392+
-DCMAKE_UNITY_BUILD=ON -DCURL_DROP_UNUSED=ON
393393
394394
- name: 'boringssl'
395395
install_steps: skipall

.github/workflows/linux.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ jobs:
121121
tflags: '--min=830 1 to 950'
122122
LDFLAGS: -Wl,-rpath,/home/runner/mbedtls/lib
123123
PKG_CONFIG_PATH: /home/runner/mbedtls/lib/pkgconfig
124-
generate: -DCURL_USE_MBEDTLS=ON -DENABLE_DEBUG=ON -DCURL_USE_GSSAPI=ON
124+
generate: -DCURL_USE_MBEDTLS=ON -DENABLE_DEBUG=ON -DCURL_USE_GSSAPI=ON -DCURL_DROP_UNUSED=ON
125125

126126
- name: 'mbedtls gss valgrind 2'
127127
install_packages: libnghttp2-dev libidn2-dev libldap-dev libgss-dev valgrind
@@ -163,7 +163,7 @@ jobs:
163163
- name: 'awslc'
164164
install_packages: libidn2-dev
165165
install_steps: awslc
166-
generate: -DOPENSSL_ROOT_DIR=/home/runner/awslc -DUSE_ECH=ON -DCMAKE_UNITY_BUILD=OFF
166+
generate: -DOPENSSL_ROOT_DIR=/home/runner/awslc -DUSE_ECH=ON -DCMAKE_UNITY_BUILD=OFF -DCURL_DROP_UNUSED=ON
167167

168168
- name: 'boringssl'
169169
install_steps: boringssl pytest

.github/workflows/macos.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ jobs:
151151
# https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-ios-tvos-visionos-or-watchos
152152
[ -n "${MATRIX_GENERATOR}" ] && options="-G ${MATRIX_GENERATOR}"
153153
cmake -B bld -G Ninja -D_CURL_PREFILL=ON \
154-
-DCMAKE_UNITY_BUILD=ON -DCURL_WERROR=ON \
154+
-DCMAKE_UNITY_BUILD=ON -DCURL_DROP_UNUSED=ON -DCURL_WERROR=ON \
155155
-DCMAKE_SYSTEM_NAME=iOS \
156156
-DUSE_APPLE_IDN=ON \
157157
${MATRIX_GENERATE} ${options}
@@ -417,7 +417,7 @@ jobs:
417417
[ "${_chkprefill}" = '_chkprefill' ] && options+=' -D_CURL_PREFILL=OFF'
418418
cmake -B "bld${_chkprefill}" -G Ninja -D_CURL_PREFILL=ON \
419419
-DCMAKE_INSTALL_PREFIX="$HOME"/curl-install \
420-
-DCMAKE_UNITY_BUILD=ON -DCURL_WERROR=ON \
420+
-DCMAKE_UNITY_BUILD=ON -DCURL_DROP_UNUSED=ON -DCURL_WERROR=ON \
421421
-DCMAKE_OSX_SYSROOT="${sysroot}" \
422422
-DCMAKE_C_COMPILER_TARGET="$(uname -m | sed 's/arm64/aarch64e/')-apple-darwin$(uname -r)" \
423423
${MATRIX_GENERATE} ${options}
@@ -652,7 +652,7 @@ jobs:
652652
[ -n "${MATRIX_MACOS_VERSION_MIN}" ] && options+=" -DCMAKE_OSX_DEPLOYMENT_TARGET=${MATRIX_MACOS_VERSION_MIN}"
653653
# would pick up nghttp2, libidn2, and libssh2
654654
cmake -B bld -G Ninja -D_CURL_PREFILL=ON \
655-
-DCMAKE_UNITY_BUILD=ON -DCURL_WERROR=ON \
655+
-DCMAKE_UNITY_BUILD=ON -DCURL_DROP_UNUSED=ON -DCURL_WERROR=ON \
656656
-DCMAKE_OSX_SYSROOT="${sysroot}" \
657657
-DCMAKE_C_COMPILER_TARGET="$(uname -m | sed 's/arm64/aarch64e/')-apple-darwin$(uname -r)" \
658658
-DCMAKE_IGNORE_PREFIX_PATH=/opt/homebrew \

.github/workflows/windows.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ jobs:
204204
# MinGW
205205
- { build: 'autotools', sys: 'mingw64' , env: 'x86_64' , tflags: 'skiprun' , config: '--enable-debug --with-openssl --disable-threaded-resolver --enable-static --without-zlib', install: 'mingw-w64-x86_64-openssl mingw-w64-x86_64-libssh2', name: 'default' }
206206
- { build: 'autotools', sys: 'mingw64' , env: 'x86_64' , tflags: '' , config: '--enable-debug --with-openssl --enable-windows-unicode --enable-ares --enable-static --disable-shared --enable-ca-native', install: 'mingw-w64-x86_64-c-ares mingw-w64-x86_64-openssl mingw-w64-x86_64-nghttp3 mingw-w64-x86_64-libssh2', name: 'c-ares U' }
207-
- { build: 'cmake' , sys: 'mingw64' , env: 'x86_64' , tflags: '--min=1650', config: '-DENABLE_DEBUG=ON -DBUILD_SHARED_LIBS=OFF -DCURL_USE_SCHANNEL=ON -DENABLE_UNICODE=ON -DENABLE_ARES=ON', install: 'mingw-w64-x86_64-c-ares mingw-w64-x86_64-libssh2', type: 'Debug', name: 'schannel c-ares U' }
207+
- { build: 'cmake' , sys: 'mingw64' , env: 'x86_64' , tflags: '--min=1650', config: '-DENABLE_DEBUG=ON -DBUILD_SHARED_LIBS=OFF -DCURL_USE_SCHANNEL=ON -DENABLE_UNICODE=ON -DENABLE_ARES=ON -DCURL_DROP_UNUSED=ON', install: 'mingw-w64-x86_64-c-ares mingw-w64-x86_64-libssh2', type: 'Debug', name: 'schannel c-ares U' }
208208
# MinGW torture
209209
- { build: 'cmake' , sys: 'mingw64' , env: 'x86_64' , tflags: '-t --shallow=13 --min=700 1 to 950' , config: '-DENABLE_DEBUG=ON -DBUILD_SHARED_LIBS=OFF -DCURL_USE_SCHANNEL=ON -DENABLE_UNICODE=ON -DENABLE_ARES=ON', install: 'mingw-w64-x86_64-c-ares mingw-w64-x86_64-libssh2', type: 'Debug', name: 'schannel U torture 1' }
210210
- { build: 'cmake' , sys: 'mingw64' , env: 'x86_64' , tflags: '-t --shallow=13 --min=700 951 to 9999', config: '-DENABLE_DEBUG=ON -DBUILD_SHARED_LIBS=OFF -DCURL_USE_SCHANNEL=ON -DENABLE_UNICODE=ON -DENABLE_ARES=ON', install: 'mingw-w64-x86_64-c-ares mingw-w64-x86_64-libssh2', type: 'Debug', name: 'schannel U torture 2' }
@@ -213,7 +213,7 @@ jobs:
213213
# Windows. Do not use this component till there is a fix for these.
214214
# https://github.com/curl/curl-for-win/blob/3951808deb04df9489ee17430f236ed54436f81a/libssh.sh#L6-L8
215215
- { build: 'cmake' , sys: 'clang64' , env: 'clang-x86_64' , tflags: '' , config: '-DENABLE_DEBUG=ON -DBUILD_SHARED_LIBS=OFF -DCURL_USE_GNUTLS=ON -DENABLE_UNICODE=OFF -DUSE_NGTCP2=ON -DCURL_USE_LIBSSH2=OFF -DCURL_USE_LIBSSH=ON', install: 'mingw-w64-clang-x86_64-gnutls mingw-w64-clang-x86_64-nghttp3 mingw-w64-clang-x86_64-ngtcp2 mingw-w64-clang-x86_64-libssh', type: 'Debug', name: 'gnutls libssh' }
216-
- { build: 'cmake' , sys: 'clangarm64', env: 'clang-aarch64', tflags: 'skiprun' , config: '-DENABLE_DEBUG=OFF -DBUILD_SHARED_LIBS=ON -DCURL_USE_SCHANNEL=ON -DENABLE_UNICODE=ON', install: 'mingw-w64-clang-aarch64-libssh2', type: 'Release', name: 'schannel R', image: 'windows-11-arm' }
216+
- { build: 'cmake' , sys: 'clangarm64', env: 'clang-aarch64', tflags: 'skiprun' , config: '-DENABLE_DEBUG=OFF -DBUILD_SHARED_LIBS=ON -DCURL_USE_SCHANNEL=ON -DENABLE_UNICODE=ON -DCURL_DROP_UNUSED=ON', install: 'mingw-w64-clang-aarch64-libssh2', type: 'Release', name: 'schannel R', image: 'windows-11-arm' }
217217
- { build: 'cmake' , sys: 'clang64' , env: 'clang-x86_64' , tflags: 'skiprun' , config: '-DENABLE_DEBUG=ON -DBUILD_SHARED_LIBS=OFF -DCURL_USE_OPENSSL=ON -DENABLE_UNICODE=OFF -DUSE_NGTCP2=ON', install: 'mingw-w64-clang-x86_64-openssl mingw-w64-clang-x86_64-nghttp3 mingw-w64-clang-x86_64-ngtcp2 mingw-w64-clang-x86_64-libssh2', type: 'Release', name: 'openssl', chkprefill: '_chkprefill' }
218218
- { build: 'cmake' , sys: 'ucrt64' , env: 'ucrt-x86_64' , tflags: 'skiprun' , config: '-DENABLE_DEBUG=OFF -DBUILD_SHARED_LIBS=ON -DCURL_USE_OPENSSL=ON', install: 'mingw-w64-ucrt-x86_64-openssl mingw-w64-ucrt-x86_64-libssh2', type: 'Release', test: 'uwp', name: 'schannel' }
219219
# { build: 'autotools', sys: 'ucrt64' , env: 'ucrt-x86_64' , tflags: 'skiprun' , config: '--without-debug --with-schannel --disable-static', install: 'mingw-w64-ucrt-x86_64-libssh2', type: 'Release', test: 'uwp', name: 'schannel' }
@@ -528,6 +528,7 @@ jobs:
528528
-DCMAKE_C_COMPILER=gcc \
529529
-DCMAKE_BUILD_TYPE="${MATRIX_TYPE}" \
530530
-DCMAKE_UNITY_BUILD=ON -DCMAKE_UNITY_BUILD_BATCH_SIZE=30 \
531+
-DCURL_DROP_UNUSED=ON \
531532
-DCURL_WERROR=ON \
532533
-DUSE_LIBIDN2=OFF \
533534
${MATRIX_CONFIG}
@@ -891,6 +892,7 @@ jobs:
891892
-DCMAKE_EXE_LINKER_FLAGS="-INCREMENTAL:NO ${ldflags}" \
892893
-DCMAKE_SHARED_LINKER_FLAGS="-INCREMENTAL:NO ${ldflags}" \
893894
-DCMAKE_UNITY_BUILD=ON \
895+
-DCURL_DROP_UNUSED=ON \
894896
-DCURL_WERROR=ON \
895897
-DLIBPSL_INCLUDE_DIR="${MINGW_PREFIX}/include" \
896898
-DLIBPSL_LIBRARY="${MINGW_PREFIX}/lib/libpsl.dll.a" \

CMakeLists.txt

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,40 @@ if(CURL_CODE_COVERAGE)
300300
endif()
301301
endif()
302302

303+
set(CURL_CFLAGS "") # C flags set for libcurl and curl tool (aka public binaries) only
304+
305+
option(CURL_DROP_UNUSED "Drop unused code and data from built binaries" OFF)
306+
if(CURL_DROP_UNUSED OR TRUE)
307+
if(APPLE)
308+
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.13)
309+
set_property(DIRECTORY APPEND PROPERTY LINK_OPTIONS "-Wl,-dead_strip")
310+
else()
311+
set_property(DIRECTORY APPEND PROPERTY LINK_FLAGS "-Wl,-dead_strip")
312+
endif()
313+
elseif(MSVC) # Options below are toolchain defaults in Release configurations.
314+
# This option does not seem to have an effect with VS2010:
315+
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.13)
316+
set_property(DIRECTORY APPEND PROPERTY LINK_OPTIONS "-OPT:REF")
317+
else()
318+
set_property(DIRECTORY APPEND PROPERTY LINK_FLAGS "-OPT:REF")
319+
endif()
320+
# Optional, but reduces binary size further, with the cost of larger objects/static libraries:
321+
list(APPEND CURL_CFLAGS "-Gy")
322+
elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang")
323+
if(WIN32)
324+
# To make -Wl,--gc-sections work on Windows: https://sourceware.org/bugzilla/show_bug.cgi?id=11539
325+
set_property(DIRECTORY APPEND PROPERTY COMPILE_OPTIONS "-fno-asynchronous-unwind-tables")
326+
endif()
327+
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.13)
328+
set_property(DIRECTORY APPEND PROPERTY LINK_OPTIONS "-Wl,--gc-sections")
329+
else()
330+
set_property(DIRECTORY APPEND PROPERTY LINK_FLAGS "-Wl,--gc-sections")
331+
endif()
332+
# Optional, but reduces binary size further, with the cost of larger objects/static libraries:
333+
list(APPEND CURL_CFLAGS "-ffunction-sections" "-fdata-sections")
334+
endif()
335+
endif()
336+
303337
# For debug libs and exes, add "-d" postfix
304338
if(NOT DEFINED CMAKE_DEBUG_POSTFIX)
305339
set(CMAKE_DEBUG_POSTFIX "-d")

appveyor.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ if [ -n "${CMAKE_GENERATOR:-}" ]; then
8787
time cmake -G "${CMAKE_GENERATOR}" \
8888
-DENABLE_DEBUG=ON -DCURL_WERROR=ON \
8989
-DCURL_STATIC_CRT=ON \
90+
-DCURL_DROP_UNUSED=ON \
9091
-DCURL_USE_SCHANNEL=ON -DCURL_USE_LIBPSL=OFF \
9192
${CMAKE_GENERATE:-} \
9293
${options} \

docs/INSTALL-CMAKE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ target_link_libraries(my_target PRIVATE CURL::libcurl)
243243
- `CURL_LIBCURL_VERSIONED_SYMBOLS_PREFIX`: Override default versioned symbol prefix. Default: `<TLS-BACKEND>_` or `MULTISSL_`
244244
- `CURL_LINT`: Run lint checks while building. Default: `OFF`
245245
- `CURL_LTO`: Enable compiler Link Time Optimizations. Default: `OFF`
246+
- `CURL_DROP_UNUSED`: Drop unused code and data from built binaries. Default: `OFF`
246247
- `CURL_STATIC_CRT`: Build libcurl with static CRT with MSVC (`/MT`) (requires UCRT, static libcurl or no curl executable). Default: `OFF`
247248
- `CURL_TARGET_WINDOWS_VERSION`: Minimum target Windows version as hex string.
248249
- `CURL_WERROR`: Turn compiler warnings into errors. Default: `OFF`

lib/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ if(SHARE_LIB_OBJECT AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.12)
111111
target_link_libraries(${LIB_OBJECT} PRIVATE ${CURL_LIBS})
112112
set_target_properties(${LIB_OBJECT} PROPERTIES
113113
POSITION_INDEPENDENT_CODE ON)
114+
set_property(TARGET ${LIB_OBJECT} APPEND PROPERTY COMPILE_OPTIONS "${CURL_CFLAGS}")
114115
if(CURL_HIDES_PRIVATE_SYMBOLS)
115116
set_property(TARGET ${LIB_OBJECT} APPEND PROPERTY COMPILE_OPTIONS "${CURL_CFLAG_SYMBOLS_HIDE}")
116117
set_property(TARGET ${LIB_OBJECT} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS")
@@ -152,6 +153,7 @@ if(BUILD_STATIC_LIBS)
152153
PREFIX "" OUTPUT_NAME "${LIBCURL_OUTPUT_NAME}"
153154
SUFFIX "${STATIC_LIB_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX}"
154155
INTERFACE_COMPILE_DEFINITIONS "CURL_STATICLIB")
156+
set_property(TARGET ${LIB_STATIC} APPEND PROPERTY COMPILE_OPTIONS "${CURL_CFLAGS}")
155157
if(CURL_HIDES_PRIVATE_SYMBOLS)
156158
set_property(TARGET ${LIB_STATIC} APPEND PROPERTY COMPILE_OPTIONS "${CURL_CFLAG_SYMBOLS_HIDE}")
157159
set_property(TARGET ${LIB_STATIC} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS")
@@ -213,6 +215,7 @@ if(BUILD_SHARED_LIBS)
213215
PREFIX "" OUTPUT_NAME "${LIBCURL_OUTPUT_NAME}"
214216
IMPORT_PREFIX "" IMPORT_SUFFIX "${IMPORT_LIB_SUFFIX}${CMAKE_IMPORT_LIBRARY_SUFFIX}"
215217
POSITION_INDEPENDENT_CODE ON)
218+
set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_OPTIONS "${CURL_CFLAGS}")
216219
if(CURL_HIDES_PRIVATE_SYMBOLS)
217220
set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_OPTIONS "${CURL_CFLAG_SYMBOLS_HIDE}")
218221
set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS")

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ set_property(DIRECTORY APPEND PROPERTY INCLUDE_DIRECTORIES
105105
add_executable(${EXE_NAME} ${CURL_CFILES} ${CURL_HFILES} ${_curl_cfiles_gen} ${_curl_hfiles_gen} ${CURLX_CFILES} ${CURLX_HFILES})
106106
target_compile_definitions(${EXE_NAME} PRIVATE ${_curl_definitions})
107107
target_link_libraries(${EXE_NAME} ${LIB_SELECTED_FOR_EXE} ${CURL_LIBS})
108+
set_property(TARGET ${EXE_NAME} APPEND PROPERTY COMPILE_OPTIONS "${CURL_CFLAGS}")
108109

109110
add_executable(${PROJECT_NAME}::${EXE_NAME} ALIAS ${EXE_NAME})
110111

0 commit comments

Comments
 (0)