From 9f56bb608ecfbb8978c6cb72a04d9e8b23162d82 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 25 Aug 2024 21:40:13 +0200 Subject: [PATCH] GHA/configure-vs-cmake: check `libcurl.pc`/`curl-config`, fix issues Add CI checker to compare `libcurl.pc` and `curl-config` files generated by autotools and cmake builds. Fix differences and apply tiny cleanups: - curl-config: use single-quotes for literals. - curl-config: quote all variables. - curl-config: replace double with single quotes in a substituted value that's always literal (`@prefix@`). - libcurl.pc: spelling in `Description:`. - libcurl.pc: avoid substitution in a comment. - cmake: fill `libdir` with `${exec_prefix}` instead of a literal. To sync with './configure'. - configure: fix `CURL_CA_BUNDLE` value to not generate nested quotes in `curl-config`. - configure: add missing `LDFLAGS` to `Libs.private` in `libcurl.pc`. To sync with CMake. - cmake: skip adding `CMAKE_C_IMPLICIT_LINK_LIBRARIES` for MINGW and UNIX. They added these values as seen in CI: MINGW: `-lmingw32 -lgcc -lmoldname -lmingwex -ladvapi32 -lshell32 -luser32 -lkernel32 -lmingw32 -lgcc -lmoldname -lmingwex` Linux: `-lgcc -lgcc_s -lc -lgcc -lgcc_s` - cmake: delete FIXME about enabling libssh2 by default. `./configure` has special defaults for these packages (called: "off"): brotli, zstd, libpsl, libssh2, libssh, wolfssl, librtmp It looks for them, but only at system locations, which makes them never detected e.g. on macOS. CMake doesn't offer such default mode for now. - GHA/macos: drop now redundant `-DCURL_DISABLE_LDAPS=ON`. - cmake: use `CMAKE_INSTALL_INCLUDEDIR` and `CMAKE_INSTALL_LIBDIR` instead of hardcoded `include`/`lib` when generating `libcurl.pc`. Updates to the GHA workflow: - move autotools out-of-tree and rename cmake out-of-tree directory to `bld_cm` to tell it's cmake. - disable static libcurl for `./configure` to match cmake. - enable `pkg-config` debug output with `./configure`. - dump list of Homebrew packages on macOS. - dump `./configure` detailed logs. - disable zstd and brotli for Linux, to match cmake. There remain differences, mostly due to detection order and method. Also some values are inherently different when using CMake and autotools, such as `--cc`, `--configure`. autotools also generates duplicates for `-lssl` and `-lcrypto`. macOS LDAP wants to link `-lber` while autotools doesn't. Some build defaults are also different in autotools and cmake. These differences are smoothened out for now by the checker script, or via build options. Notice that lib order (a dupes) _can_ be significant in some cases. E.g. the binutils linker is infamous for that on Windows. Closes #14681 --- .github/scripts/cmp-pkg-config.sh | 49 +++++++++++++++++++ .github/workflows/configure-vs-cmake.yml | 61 ++++++++++++++++++++---- CMakeLists.txt | 30 +++++++++--- acinclude.m4 | 2 +- curl-config.in | 32 ++++++------- libcurl.pc.in | 4 +- 6 files changed, 144 insertions(+), 34 deletions(-) create mode 100755 .github/scripts/cmp-pkg-config.sh diff --git a/.github/scripts/cmp-pkg-config.sh b/.github/scripts/cmp-pkg-config.sh new file mode 100755 index 0000000000..37a316218c --- /dev/null +++ b/.github/scripts/cmp-pkg-config.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash +# Copyright (C) Viktor Szakats +# +# SPDX-License-Identifier: curl + +# Sort list of libs, libpaths, cflags found in libcurl.pc and curl-config files, +# then diff the autotools and cmake generated ones. + +sort_lists() { + prevline='' + section='' + while IFS= read -r l; do + if [[ "${prevline}" =~ (--cc|--configure) ]]; then # curl-config + echo "" + else + # libcurl.pc + if [[ "${l}" =~ ^(Requires|Libs|Cflags)(\.private)?:\ (.+)$ ]]; then + if [ "${BASH_REMATCH[1]}" = 'Requires' ]; then + # Spec does not allow duplicates here: + # https://manpages.debian.org/unstable/pkg-config/pkg-config.1.en.html#Requires: + # "You may only mention the same package one time on the Requires: line" + val="$(printf '%s' "${BASH_REMATCH[3]}" | tr ',' '\n' | sort | tr '\n' ' ')" + else + val="$(printf '%s' "${BASH_REMATCH[3]}" | tr ' ' '\n' | sort -u | tr '\n' ' ')" + fi + l="${BASH_REMATCH[1]}${BASH_REMATCH[2]}: ${val}" + # curl-config + elif [[ "${section}" =~ (--libs|--static-libs) && "${l}" =~ ^( *echo\ \")(.+)(\")$ ]]; then + val="$(printf '%s' "${BASH_REMATCH[2]}" | tr ' ' '\n' | sort -u | tr '\n' ' ')" + l="${BASH_REMATCH[1]}${val}${BASH_REMATCH[3]}" + section='' + fi + echo "${l}" + fi + # curl-config + prevline="${l}" + if [[ "${l}" =~ --[a-z-]+\) ]]; then + section="${BASH_REMATCH[0]}" + fi + done < "$1" +} + +am=$(mktemp -t autotools.XXX); sort_lists "$1" > "${am}" +cm=$(mktemp -t cmake.XXX) ; sort_lists "$2" > "${cm}" +diff -u "${am}" "${cm}" +res="$?" +rm -r -f "${am}" "${cm}" + +exit "${res}" diff --git a/.github/workflows/configure-vs-cmake.yml b/.github/workflows/configure-vs-cmake.yml index b7819f1075..b9960fd0bf 100644 --- a/.github/workflows/configure-vs-cmake.yml +++ b/.github/workflows/configure-vs-cmake.yml @@ -37,14 +37,27 @@ jobs: - name: run configure --with-openssl run: | autoreconf -fi - ./configure --with-openssl --without-libpsl + export PKG_CONFIG_DEBUG_SPEW=1 + mkdir bld-am && cd bld-am && ../configure --enable-static=no --with-openssl --without-libpsl --without-brotli --without-zstd - name: run cmake run: | - cmake -B build -DCURL_USE_LIBPSL=OFF + cmake -B bld-cm -DCURL_USE_LIBPSL=OFF + + - name: 'configure log' + run: cat bld-am/config.log 2>/dev/null || true + + - name: 'cmake log' + run: cat bld-cm/CMakeFiles/CMakeConfigureLog.yaml 2>/dev/null || true - name: compare generated curl_config.h files - run: ./.github/scripts/cmp-config.pl lib/curl_config.h build/lib/curl_config.h + run: ./.github/scripts/cmp-config.pl bld-am/lib/curl_config.h bld-cm/lib/curl_config.h + + - name: compare generated libcurl.pc files + run: ./.github/scripts/cmp-pkg-config.sh bld-am/libcurl.pc bld-cm/libcurl.pc + + - name: compare generated curl-config files + run: ./.github/scripts/cmp-pkg-config.sh bld-am/curl-config bld-cm/curl-config check-macos: runs-on: macos-latest @@ -53,21 +66,38 @@ jobs: run: | while [[ $? == 0 ]]; do for i in 1 2 3; do brew update && brew install libtool autoconf automake && break 2 || { echo Error: wait to try again; sleep 10; } done; false Too many retries; done + - name: 'toolchain versions' + run: | + echo '::group::brew packages installed'; ls -l "$(brew --prefix)/opt"; echo '::endgroup::' + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 - name: run configure --with-openssl run: | autoreconf -fi - ./configure --with-openssl --without-libpsl + export PKG_CONFIG_DEBUG_SPEW=1 + mkdir bld-am && cd bld-am && ../configure --enable-static=no --with-openssl --without-libpsl --disable-ldap - name: run cmake run: | - cmake -B build -DCURL_USE_LIBPSL=OFF \ + cmake -B bld-cm -DCURL_USE_LIBPSL=OFF -DCURL_DISABLE_LDAP=ON \ "-DCMAKE_C_COMPILER_TARGET=$(uname -m | sed 's/arm64/aarch64/')-apple-darwin$(uname -r)" \ -DCURL_USE_LIBSSH2=OFF + - name: 'configure log' + run: cat bld-am/config.log 2>/dev/null || true + + - name: 'cmake log' + run: cat bld-cm/CMakeFiles/CMakeConfigureLog.yaml 2>/dev/null || true + - name: compare generated curl_config.h files - run: ./.github/scripts/cmp-config.pl lib/curl_config.h build/lib/curl_config.h + run: ./.github/scripts/cmp-config.pl bld-am/lib/curl_config.h bld-cm/lib/curl_config.h + + - name: compare generated libcurl.pc files + run: ./.github/scripts/cmp-pkg-config.sh bld-am/libcurl.pc bld-cm/libcurl.pc + + - name: compare generated curl-config files + run: ./.github/scripts/cmp-pkg-config.sh bld-am/curl-config bld-cm/curl-config check-windows: runs-on: ubuntu-latest @@ -82,14 +112,27 @@ jobs: - name: run configure --with-schannel run: | autoreconf -fi - ./configure --with-schannel --without-libpsl --host=${TRIPLET} + export PKG_CONFIG_DEBUG_SPEW=1 + mkdir bld-am && cd bld-am && ../configure --enable-static=no --with-schannel --without-libpsl --host=${TRIPLET} - name: run cmake run: | - cmake -B build -DCURL_USE_SCHANNEL=ON -DCURL_USE_LIBPSL=OFF \ + cmake -B bld-cm -DCURL_USE_SCHANNEL=ON -DCURL_USE_LIBPSL=OFF \ -DCMAKE_SYSTEM_NAME=Windows \ -DCMAKE_C_COMPILER_TARGET=${TRIPLET} \ -DCMAKE_C_COMPILER=${TRIPLET}-gcc + - name: 'configure log' + run: cat bld-am/config.log 2>/dev/null || true + + - name: 'cmake log' + run: cat bld-cm/CMakeFiles/CMakeConfigureLog.yaml 2>/dev/null || true + - name: compare generated curl_config.h files - run: ./.github/scripts/cmp-config.pl lib/curl_config.h build/lib/curl_config.h + run: ./.github/scripts/cmp-config.pl bld-am/lib/curl_config.h bld-cm/lib/curl_config.h + + - name: compare generated libcurl.pc files + run: ./.github/scripts/cmp-pkg-config.sh bld-am/libcurl.pc bld-cm/libcurl.pc + + - name: compare generated curl-config files + run: ./.github/scripts/cmp-pkg-config.sh bld-am/curl-config bld-cm/curl-config diff --git a/CMakeLists.txt b/CMakeLists.txt index 498e6cdf18..dc49368148 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1077,7 +1077,7 @@ if(CURL_USE_LIBPSL) endif() # libssh2 -option(CURL_USE_LIBSSH2 "Use libssh2" ON) # FIXME: default is OFF in autotools +option(CURL_USE_LIBSSH2 "Use libssh2" ON) mark_as_advanced(CURL_USE_LIBSSH2) set(USE_LIBSSH2 OFF) @@ -1948,9 +1948,17 @@ if(NOT CURL_DISABLE_INSTALL) set(VERSIONNUM "${CURL_VERSION_NUM}") set(prefix "${CMAKE_INSTALL_PREFIX}") set(exec_prefix "\${prefix}") - set(includedir "\${prefix}/include") + if(IS_ABSOLUTE ${CMAKE_INSTALL_INCLUDEDIR}) + set(includedir "${CMAKE_INSTALL_INCLUDEDIR}") + else() + set(includedir "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}") + endif() + if(IS_ABSOLUTE ${CMAKE_INSTALL_LIBDIR}) + set(libdir "${CMAKE_INSTALL_LIBDIR}") + else() + set(libdir "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}") + endif() set(LDFLAGS "${CMAKE_SHARED_LINKER_FLAGS}") - set(libdir "${CMAKE_INSTALL_PREFIX}/lib") # "a" (Linux) or "lib" (Windows) string(REPLACE "." "" libext "${CMAKE_STATIC_LIBRARY_SUFFIX}") @@ -1983,7 +1991,12 @@ if(NOT CURL_DISABLE_INSTALL) endif() endforeach() - foreach(_lib IN LISTS CMAKE_C_IMPLICIT_LINK_LIBRARIES CURL_LIBS) + unset(_implicit_libs) + if(NOT MINGW AND NOT UNIX) + set(_implicit_libs ${CMAKE_C_IMPLICIT_LINK_LIBRARIES}) + endif() + + foreach(_lib IN LISTS _implicit_libs CURL_LIBS) if(TARGET "${_lib}") set(_libname "${_lib}") get_target_property(_imported "${_libname}" IMPORTED) @@ -2029,8 +2042,8 @@ if(NOT CURL_DISABLE_INSTALL) if(_ldflags) list(REMOVE_DUPLICATES _ldflags) string(REPLACE ";" " " _ldflags "${_ldflags}") - set(LIBCURL_PC_LIBS_PRIVATE "${_ldflags} ${LIBCURL_PC_LIBS_PRIVATE}") - string(STRIP "${LIBCURL_PC_LIBS_PRIVATE}" LIBCURL_PC_LIBS_PRIVATE) + set(LDFLAGS "${LDFLAGS} ${_ldflags}") + string(STRIP "${LDFLAGS}" LDFLAGS) endif() set(LIBCURL_PC_CFLAGS_PRIVATE "-DCURL_STATICLIB") @@ -2097,6 +2110,11 @@ if(NOT CURL_DISABLE_INSTALL) # prefix # SUPPORT_FEATURES # SUPPORT_PROTOCOLS + # Documentation: + # https://people.freedesktop.org/~dbn/pkg-config-guide.html + # https://manpages.debian.org/unstable/pkgconf/pkg-config.1.en.html + # https://manpages.debian.org/unstable/pkg-config/pkg-config.1.en.html + # https://www.msys2.org/docs/pkgconfig/ configure_file( "${CURL_SOURCE_DIR}/libcurl.pc.in" "${CURL_BINARY_DIR}/libcurl.pc" @ONLY) diff --git a/acinclude.m4 b/acinclude.m4 index 9f5e373d12..5476c9a8ee 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -1304,7 +1304,7 @@ AS_HELP_STRING([--without-ca-path], [Don't use a default CA path]), fi if test "x$ca" != "xno"; then - CURL_CA_BUNDLE='"'$ca'"' + CURL_CA_BUNDLE="$ca" AC_DEFINE_UNQUOTED(CURL_CA_BUNDLE, "$ca", [Location of default ca bundle]) AC_SUBST(CURL_CA_BUNDLE) AC_MSG_RESULT([$ca]) diff --git a/curl-config.in b/curl-config.in index 294e083ec7..2dc40edcdc 100644 --- a/curl-config.in +++ b/curl-config.in @@ -25,13 +25,13 @@ # shellcheck disable=SC2006 -prefix="@prefix@" -# Used in @libdir@ +prefix='@prefix@' +# Used in 'libdir' # shellcheck disable=SC2034 -exec_prefix=@exec_prefix@ +exec_prefix="@exec_prefix@" # shellcheck disable=SC2034 -includedir=@includedir@ -cppflag_curl_staticlib=@LIBCURL_PC_CFLAGS@ +includedir="@includedir@" +cppflag_curl_staticlib='@LIBCURL_PC_CFLAGS@' usage() { @@ -83,7 +83,7 @@ while test "$#" -gt 0; do ;; --feature|--features) - for feature in @SUPPORT_FEATURES@ ""; do + for feature in @SUPPORT_FEATURES@ ''; do test -n "$feature" && echo "$feature" done ;; @@ -101,7 +101,7 @@ while test "$#" -gt 0; do ;; --checkfor) - checkfor=$2 + checkfor="$2" cmajor=`echo "$checkfor" | cut -d. -f1` cminor=`echo "$checkfor" | cut -d. -f2` # when extracting the patch part we strip off everything after a @@ -142,12 +142,12 @@ while test "$#" -gt 0; do ;; --cflags) - if test "X$cppflag_curl_staticlib" = "X-DCURL_STATICLIB"; then - CPPFLAG_CURL_STATICLIB="-DCURL_STATICLIB " + if test "X$cppflag_curl_staticlib" = 'X-DCURL_STATICLIB'; then + CPPFLAG_CURL_STATICLIB='-DCURL_STATICLIB ' else - CPPFLAG_CURL_STATICLIB="" + CPPFLAG_CURL_STATICLIB='' fi - if test "X@includedir@" = "X/usr/include"; then + if test "X@includedir@" = 'X/usr/include'; then echo "${CPPFLAG_CURL_STATICLIB}" else echo "${CPPFLAG_CURL_STATICLIB}-I@includedir@" @@ -155,12 +155,12 @@ while test "$#" -gt 0; do ;; --libs) - if test "X@libdir@" != "X/usr/lib" -a "X@libdir@" != "X/usr/lib64"; then + if test "X@libdir@" != 'X/usr/lib' -a "X@libdir@" != 'X/usr/lib64'; then CURLLIBDIR="-L@libdir@ " else - CURLLIBDIR="" + CURLLIBDIR='' fi - if test "X@ENABLE_SHARED@" = "Xno"; then + if test 'X@ENABLE_SHARED@' = 'Xno'; then echo "${CURLLIBDIR}-lcurl @LIBCURL_PC_LIBS_PRIVATE@" else echo "${CURLLIBDIR}-lcurl" @@ -172,8 +172,8 @@ while test "$#" -gt 0; do ;; --static-libs) - if test "X@ENABLE_STATIC@" != "Xno" ; then - echo "@libdir@/libcurl.@libext@" @LDFLAGS@ @LIBCURL_PC_LIBS_PRIVATE@ + if test 'X@ENABLE_STATIC@' != 'Xno'; then + echo "@libdir@/libcurl.@libext@ @LDFLAGS@ @LIBCURL_PC_LIBS_PRIVATE@" else echo 'curl was built with static libraries disabled' >&2 exit 1 diff --git a/libcurl.pc.in b/libcurl.pc.in index 8f6f9b4f5a..4c60a7ec76 100644 --- a/libcurl.pc.in +++ b/libcurl.pc.in @@ -31,11 +31,11 @@ supported_features="@SUPPORT_FEATURES@" Name: libcurl URL: https://curl.se/ -Description: Library to transfer files with ftp, http, etc. +Description: Library to transfer files with HTTP, FTP, etc. Version: @CURLVERSION@ Requires: @LIBCURL_PC_REQUIRES@ Requires.private: @LIBCURL_PC_REQUIRES_PRIVATE@ Libs: -L${libdir} -lcurl @LIBCURL_PC_LIBS@ -Libs.private: @LIBCURL_PC_LIBS_PRIVATE@ +Libs.private: @LDFLAGS@ @LIBCURL_PC_LIBS_PRIVATE@ Cflags: -I${includedir} @LIBCURL_PC_CFLAGS@ Cflags.private: @LIBCURL_PC_CFLAGS_PRIVATE@ -- 2.47.3