]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
cmake: optimize building examples in CI
authorViktor Szakats <commit@vsz.me>
Wed, 6 Aug 2025 20:17:50 +0000 (22:17 +0200)
committerViktor Szakats <commit@vsz.me>
Sat, 9 Aug 2025 00:27:43 +0000 (02:27 +0200)
In CI we want to ensure that examples build cleanly, but we don't want
to actually run them there. Meaning it's enough to just compile, but not
link them in CI. Saving time up to 2-4x (MSVC), and disk space up
to 1.2GB (or 8-70x).

Add a new cmake target that compiles all examples without linking them
into runnable binaries. Keep a full build for a single example to test
if it links correctly.

Also:
- CI: switch over all `curl-examples` targets to `curl-examples-build`
- GHA/linux-old: build examples in one of the cmake builds.

Result highlights:

Job                 | Bef. |  Bef. | Aft. | Aft. |
:------------------ | ---: | ----: | ---: |----: |
cygwin              |  15s |   9MB |  10s |  1MB |
msys                |  13s |   8MB |   7s |  1MB |
dl-mingw 15         |  39s |  113M |  34s |  2MB |
dl-mingw 9.5.0      |  49s | 115MB |  42s |  2MB |
dl-mingw 7.3.0      |  19s | 113MB |  14s |  2MB |
dl-mingw 6.4.0      |   9s |  12MB |   7s |  4MB |
Linux cross         |  19s |  28MB |  19s |  2MB |
MSVC UWP            |  65s | 374MB |   9s | 17MB |
MSVC x64            |  22s | 846MB |   9s | 17MB |
VS2010              |  48s | 105MB |  15s |  9MB |
VS2022 clang-cl     | 195s | 1.2GB |  51s | 20MB |
iOS Xcode           |   8s |       |   5s |      |
macOS LibreSSL      |  16s |       |  11s |      |
Linux aws-lc        |   3s |       |   1s |      |

Follow-up to dda251ef1020da07dc4640a225e01051cb977535 #18232

Closes #18209

.github/workflows/http3-linux.yml
.github/workflows/linux-old.yml
.github/workflows/linux.yml
.github/workflows/macos.yml
.github/workflows/non-native.yml
.github/workflows/windows.yml
appveyor.sh
docs/examples/CMakeLists.txt

index 3dab2b56cfb0ed2aa69686ccf0cc0129670edafa..3fec315199f400aea7518aad2389c99926dacf5b 100644 (file)
@@ -546,7 +546,7 @@ jobs:
       - name: 'build examples'
         run: |
           if [ "${MATRIX_BUILD}" = 'cmake' ]; then
-            cmake --build bld --verbose --target curl-examples
+            cmake --build bld --verbose --target curl-examples-build
           else
             make -C bld V=1 examples
           fi
index 5b8f92f03b475ba3a562d9f10ef5d29cd374290c..736a3cc100707dd3166fe66aaa7e0a2f6ce9b4ad 100644 (file)
@@ -123,6 +123,9 @@ jobs:
       - name: 'cmake run tests'
         run: make -C bld-cares test-ci
 
+      - name: 'cmake build examples'
+        run: make -C bld-cares curl-examples-build
+
       - name: 'autoreconf'
         run: autoreconf -if
 
index b293a140f767964686e82b4c0aecca93537b665f..7c64a2355843cf8a3a051f9b4e9e942b0fbc3e90 100644 (file)
@@ -698,7 +698,7 @@ jobs:
         if: ${{ matrix.build.make-custom-target != 'tidy' }}
         run: |
           if [ "${MATRIX_BUILD}" = 'cmake' ]; then
-            ${MATRIX_MAKE_PREFIX} cmake --build bld --verbose --target curl-examples
+            ${MATRIX_MAKE_PREFIX} cmake --build bld --verbose --target curl-examples-build
           else
             ${MATRIX_MAKE_PREFIX} make -C bld V=1 examples
           fi
index 04c30a75c015da0dafbe61a72f4b1fc09b2409d5..90d04fab17f1187a54358b7f90379925fead3ec1 100644 (file)
@@ -199,7 +199,7 @@ jobs:
       - name: 'build examples'
         run: |
           if [ "${MATRIX_BUILD}" = 'cmake' ]; then
-            cmake --build bld ${MATRIX_OPTIONS} --parallel 4 --target curl-examples --verbose
+            cmake --build bld ${MATRIX_OPTIONS} --parallel 4 --target curl-examples-build --verbose
           else
             make -C bld examples V=1
           fi
@@ -520,7 +520,7 @@ jobs:
         if: ${{ contains(matrix.build.name, '+examples') }}
         run: |
           if [ "${MATRIX_BUILD}" = 'cmake' ]; then
-            cmake --build bld --verbose --target curl-examples
+            cmake --build bld --verbose --target curl-examples-build
           else
             make -C bld examples V=1
           fi
index 9a92804219a27380c8357351b3b1f98be84c33bb..e8a105e39cb8158fa6f1fa2b9c78024d21eefe70 100644 (file)
@@ -83,7 +83,7 @@ jobs:
               time cmake --build bld --target test-ci
             fi
             echo '::group::build examples'
-            time cmake --build bld --target curl-examples
+            time cmake --build bld --target curl-examples-build
             echo '::endgroup::'
 
   openbsd:
@@ -128,7 +128,7 @@ jobs:
               time cmake --build bld --target test-ci
             fi
             echo '::group::build examples'
-            time cmake --build bld --target curl-examples
+            time cmake --build bld --target curl-examples-build
             echo '::endgroup::'
 
   freebsd:
@@ -232,7 +232,7 @@ jobs:
             if [ "${MATRIX_DESC#*!examples*}" = "${MATRIX_DESC}" ]; then
               echo '::group::build examples'
               if [ "${MATRIX_BUILD}" = 'cmake' ]; then
-                time cmake --build bld --target curl-examples
+                time cmake --build bld --target curl-examples-build
               else
                 time make -C bld examples
               fi
@@ -361,7 +361,7 @@ jobs:
       - name: 'build examples'
         run: |
           if [ "${MATRIX_BUILD}" = 'cmake' ]; then
-            cmake --build bld --target curl-examples
+            cmake --build bld --target curl-examples-build
           else
             make -C bld examples
           fi
@@ -473,7 +473,7 @@ jobs:
         if: ${{ matrix.build == 'cmake' }}  # skip for autotools to save time
         run: |
           if [ "${MATRIX_BUILD}" = 'cmake' ]; then
-            cmake --build bld --target curl-examples
+            cmake --build bld --target curl-examples-build
           else
             make -C bld examples
           fi
index d0e1157f7bc32641698bbbc629d17a1dcb08833e..5d9aac713b94c0cb8ae13722cbe6005e30e806f9 100644 (file)
@@ -177,7 +177,7 @@ jobs:
         run: |
           PATH=/usr/bin
           if [ "${MATRIX_BUILD}" = 'cmake' ]; then
-            cmake --build bld --verbose --target curl-examples
+            cmake --build bld --verbose --target curl-examples-build
           else
             make -C bld V=1 examples
           fi
@@ -404,7 +404,7 @@ jobs:
         timeout-minutes: 5
         run: |
           if [ "${MATRIX_BUILD}" = 'cmake' ]; then
-            cmake --build bld --verbose --target curl-examples
+            cmake --build bld --verbose --target curl-examples-build
           else
             make -C bld V=1 examples
           fi
@@ -589,7 +589,7 @@ jobs:
         timeout-minutes: 5
         run: |
           PATH="/d/my-cache/${MATRIX_DIR}/bin:$PATH"
-          cmake --build bld --target curl-examples
+          cmake --build bld --target curl-examples-build
 
       - name: 'disk space used'
         run: du -sh .; echo; du -sh -t 250KB ./*; echo; du -h -t 250KB bld
@@ -687,7 +687,7 @@ jobs:
         if: ${{ matrix.compiler != 'clang-tidy' }}  # Save time by skipping this for clang-tidy
         run: |
           if [ "${MATRIX_BUILD}" = 'cmake' ]; then
-            cmake --build bld --target curl-examples
+            cmake --build bld --target curl-examples-build
           else
             make -C bld examples
           fi
@@ -935,7 +935,7 @@ jobs:
       - name: 'build examples'
         timeout-minutes: 5
         if: ${{ contains(matrix.name, '+examples') }}
-        run: cmake --build bld --config "${MATRIX_TYPE}" --parallel 5 --target curl-examples
+        run: cmake --build bld --config "${MATRIX_TYPE}" --parallel 5 --target curl-examples-build
 
       - name: 'disk space used'
         run: du -sh .; echo; du -sh -t 250KB ./*; echo; du -h -t 250KB bld
index 225d577f8c75a30369b1ab5cc2a3d8494ea01b69..e9871415e006d26db77dc808021db1acdbedbc1d 100644 (file)
@@ -163,7 +163,7 @@ fi
 
 if [ "${EXAMPLES}" = 'ON' ] && \
    [ "${BUILD_SYSTEM}" = 'CMake' ]; then
-  time cmake --build _bld --config "${PRJ_CFG}" --parallel 2 --target curl-examples
+  time cmake --build _bld --config "${PRJ_CFG}" --parallel 2 --target curl-examples-build
 fi
 
 # disk space used
index f69445fbfe70eb8c42e8af1f53a38228a3d91a07..cb1d983890c698de7ba75ed46d4c1fcf3387a88f 100644 (file)
@@ -28,10 +28,40 @@ add_custom_target(curl-examples)
 curl_transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
 include("${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
 
-foreach(_target IN LISTS check_PROGRAMS)
+set(_all_canary "")
+set(_all "all")
+foreach(_target IN LISTS check_PROGRAMS _all)  # keep '_all' last
   set(_target_name "curl-example-${_target}")
-  add_executable(${_target_name} EXCLUDE_FROM_ALL "${_target}.c")
-  add_dependencies(curl-examples ${_target_name})
+  if(_target STREQUAL "all")
+    if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12)
+      set(_examples_c "${check_PROGRAMS}")
+      list(TRANSFORM _examples_c APPEND ".c")
+      add_library(${_target_name} OBJECT EXCLUDE_FROM_ALL ${_examples_c})
+      if(MSVC AND NOT CMAKE_C_COMPILER_ID STREQUAL "Clang")
+        # CMake generates a static library for the OBJECT target. Silence these 'lib.exe' warnings:
+        # warning LNK4006: main already defined in ....obj; second definition ignored
+        # warning LNK4221: This object file does not define any previously undefined public symbols,
+        #                  so it will not be used by any link operation that consumes this library
+        if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.13)
+          set_target_properties(${_target_name} PROPERTIES STATIC_LIBRARY_OPTIONS "-ignore:4006;-ignore:4221")
+        else()
+          set_target_properties(${_target_name} PROPERTIES STATIC_LIBRARY_FLAGS "-ignore:4006 -ignore:4221")
+        endif()
+      endif()
+    else()
+      set(_examples_c "")
+      foreach(_src IN LISTS check_PROGRAMS)
+        list(APPEND _examples_c "${_src}.c")
+      endforeach()
+      add_library(${_target_name} STATIC EXCLUDE_FROM_ALL ${_examples_c})
+    endif()
+    add_custom_target(curl-examples-build)  # Special target to compile all tests quickly and build a single test to probe linkage
+    add_dependencies(curl-examples-build ${_target_name} ${_all_canary})  # Include a full build of a single test
+  else()
+    set(_all_canary ${_target_name})  # Save the last test for the curl-examples-build target
+    add_executable(${_target_name} EXCLUDE_FROM_ALL "${_target}.c")
+    add_dependencies(curl-examples ${_target_name})
+  endif()
   target_link_libraries(${_target_name} ${LIB_SELECTED} ${CURL_NETWORK_AND_TIME_LIBS})
   target_compile_definitions(${_target_name} PRIVATE "CURL_NO_OLDIES"
     "$<$<BOOL:${WIN32}>:WIN32_LEAN_AND_MEAN>" "$<$<BOOL:${MSVC}>:_CRT_SECURE_NO_DEPRECATE>")