Skip to content

ECMFindModuleHelpers.cmake: Use imported targets from PkgConfig

Hello. I was having trouble building Qt 6.4.1 for Linux and making it use a static version of XCB. One of the problems was that the xcb_syslibs test in src/gui/configure.cmake was failing because it was not passing all the required linker arguments when linking a small test program that uses XCB. Qt relies on this project to find XCB.

Parts of XCB rely on libXau, so any program using a static version of XCB must remember to link in libXau. The best way to do that is to run pkg-config and pay attention to all the flags it returns. For example, in my environment (which I'd be happy to share with you as a Nix expression and help you use it), if I run pkg-config-cross xcb --libs, the result is:

-L/nix/store/gnq8lg2z7267g5awk1kwhap1lybx09a3-libxcb-1.13.1-i686-linux-musleabi/lib -lxcb -L/nix/store/ayijz2v117hwpzjhdnz5p9h8vxc9gl5p-libxau-1.0.8-i686-linux-musleabi/lib -lXau

Unfortunately, it seems like ECMFindModuleHelpers.cmake ignores most of the info returned by its numerous invocations of pkg-config. It only uses those calls to get hints about things like where to find the include directory and the library file. So it was totally missing the requirement to link to libXau, and I got the following error message when compiling a simple test program:

[100%] Linking C executable test_find_xcb
/nix/store/xyys3fv9ysshd6cns0a4vwxm3j46zyph-libxall-i686-linux-musleabi/lib/libxcb.a(xcb_auth.o): In function `get_authptr':
/tmp/nix-build-libxcb-1.13.1-i686-linux-musleabi.drv-0/build/src/../../libxcb/src/xcb_auth.c:163: undefined reference to `XauGetBestAuthByAddr'
/nix/store/xyys3fv9ysshd6cns0a4vwxm3j46zyph-libxall-i686-linux-musleabi/lib/libxcb.a(xcb_auth.o): In function `_xcb_get_auth_info':
/tmp/nix-build-libxcb-1.13.1-i686-linux-musleabi.drv-0/build/src/../../libxcb/src/xcb_auth.c:377: undefined reference to `XauDisposeAuth'
/tmp/nix-build-libxcb-1.13.1-i686-linux-musleabi.drv-0/build/src/../../libxcb/src/xcb_auth.c:369: undefined reference to `XauDisposeAuth'
collect2: error: ld returned 1 exit status

My suggested solution is that ECMFindModuleHelpers.cmake should ask pkg_check_modules to make an imported target and then link to that target as a dependency. By the way, if we can use that imported target, most of the other work being done in ECMFindModuleHelpers.cmake is irrelevant. If this were my project, I'd be trying to remove most of that code and just replace it with simple calls to pkg_check_modules that create an imported target.

The imported target feature of PkgConfig is only available in CMake 3.6 and later, but I hope that isn't a problem. Qt itself requires CMake 3.16 or later.

With this change the xcb_syslibs test in Qt6 now passes (but I'm still working on other issues and haven't produced a successful build yet).

Simple test program

Here is the simple test program I used to verify that the problem was happening outside of Qt6, and verify that this merge request fixes the problem. It is based on Qt's xcb_syslibs test.

CMakeLists.txt:

cmake_minimum_required(VERSION 3.21.1)
project(helloworld)
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/extra-cmake-modules/find-modules")
find_package(XCB)
add_executable(test_find_xcb main.c)
target_link_libraries(test_find_xcb
  XCB::ICCCM XCB::IMAGE XCB::KEYSYMS  XCB::RANDR
  XCB::RENDER XCB::RENDERUTIL XCB::SHAPE XCB::SHM
  XCB::SYNC XCB::XFIXES XCB::XKB XCB::XCB)

main.c:

#include <xcb/xcb.h>
#include <xcb/xcb_image.h>
#include <xcb/xcb_keysyms.h>
#include <xcb/randr.h>
#include <xcb/render.h>
#include <xcb/shape.h>
#include <xcb/shm.h>
#include <xcb/sync.h>
#include <xcb/xfixes.h>
#include <xcb/xcb_icccm.h>
#include <xcb/xcb_renderutil.h>
#include <xcb/xkb.h>

int main(void)
{
  int primaryScreen = 0;
  xcb_connection_t * c = xcb_connect("", &primaryScreen);
  xcb_generic_error_t * error = NULL;
  xcb_render_query_pict_formats_cookie_t formatsCookie =
    xcb_render_query_pict_formats(c);
  xcb_render_query_pict_formats_reply_t * formatsReply =
    xcb_render_query_pict_formats_reply(c, formatsCookie, &error);
  xcb_render_util_find_standard_format(NULL, XCB_PICT_STANDARD_ARGB_32);
  xcb_xkb_get_kbd_by_name_replies_key_names_value_list_sizeof(
    NULL, 0, 0, 0, 0, 0, 0, 0, 0);
}
Edited by David Grayson

Merge request reports