C++

How to Use CMake pkg_search_module() When Compiling Under Window

How to Use CMake pkg_search_module() When Compiling Under Window

I’ve been building a game with SDL2 and CMake lately. On Linux, my setup was simple and life was good. All I had to do was drop this into my CMakeLists.txt:

include(FindPkgConfig)
pkg_search_module(SDL2 REQUIRED sdl2)
target_link_libraries(MYLIB SDL2)

everything compiled perfectly on Fedora.

Could NOT find PkgConfig (missing:  PKG_CONFIG_EXECUTABLE) 
checking for one of the modules 'sdl2'
CMake Error at C:/Program Files (x86)/CMake/share/cmake-3.0/Modules/FindPkgConfig.cmake:425 (message):
None of the required 'sdl2' found

Understanding the Error

What’s going on here is simple but sneaky. The pkg_search_module() function depends on pkg config (a standalone tool) and .pc files (metadata about libraries).

On Linux, pkg-config is already there, and .pc files for SDL2 are in standard system directories. On a fresh Windows install.

  • No pkg-config.
  • No .pc files in known locations.

So CMake tries to run pkg-config and fails before it even looks for SDL2.

The code itself isn’t wrong it’s just assuming a Linux style environment.

Two Ways I Fix This

Option A – Keep using pkg_search_module on Windows

If I want to stick with pkg config, I just install it (and SDL2) using MSYS2:

pacman -S mingw-w64-x86_64-pkg-config mingw-w64-x86_64-SDL2

Then in CMake:

set(PKG_CONFIG_EXECUTABLE "C:/msys64/mingw64/bin/pkg-config.exe")
set(ENV{PKG_CONFIG_PATH} "C:/msys64/mingw64/lib/pkgconfig")

include(FindPkgConfig)
pkg_search_module(SDL2 REQUIRED sdl2)

add_library(MYLIB ...)
target_include_directories(MYLIB PRIVATE ${SDL2_INCLUDE_DIRS})
target_link_libraries(MYLIB ${SDL2_LIBRARIES})

Pros: minimal changes to my Linux setup.
Cons: drags MSYS2 into my Windows workflow, not super “native” for Visual Studio.

Option B – Switch to SDL2 CMake package

Modern SDL2 ships with its own SDL2Config.cmake, so I can skip pkg-config entirely:

find_package(SDL2 CONFIG REQUIRED)
target_link_libraries(MYLIB PRIVATE SDL2::SDL2 SDL2::SDL2main)

On Windows, I can grab SDL2’s CMake package via:

  • vcpkg:
vcpkg install sdl2
cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake
  • Official SDL2 dev zip:
    Download from libsdl.org, unzip, and set:
-DSDL2_DIR="C:/path/to/SDL2/cmake"

Pros: works cleanly with Visual Studio, no extra tools.
Cons: needs a proper SDL2 build with the CMake package.

My hybrid CMakeLists.txt

Here’s the cross-platform CMakeLists.txt I ended up with. It tries the CMake package first (best on Windows) and falls back to pkg-config if that fails:

cmake_minimum_required(VERSION 3.20)
project(ExampleSDL2 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_library(MYLIB STATIC src/mylib.cpp include/mylib.hpp)
target_include_directories(MYLIB PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)

set(SDL2_FOUND_BY_CONFIG OFF)
find_package(SDL2 CONFIG QUIET)

if(SDL2_FOUND)
set(SDL2_FOUND_BY_CONFIG ON)
target_link_libraries(MYLIB PRIVATE SDL2::SDL2 SDL2::SDL2main)
else()
include(FindPkgConfig)
pkg_search_module(SDL2 REQUIRED sdl2)
target_include_directories(MYLIB PRIVATE ${SDL2_INCLUDE_DIRS})
target_link_libraries(MYLIB PRIVATE ${SDL2_LIBRARIES})
endif()

add_executable(ExampleApp src/main.cpp)
target_link_libraries(ExampleApp PRIVATE MYLIB)

if(WIN32 AND SDL2_FOUND_BY_CONFIG)
add_custom_command(TARGET ExampleApp POST_BUILD
COMMAND ${CMAKE_COMMAND} -E cmake_copy_if_different
$<TARGET_FILE:SDL2::SDL2> $<TARGET_FILE_DIR:ExampleApp>)
endif()

Test Main.cpp

#include <SDL.h>
#include <cstdio>

int main(int, char**) {
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
std::printf("SDL_Init failed: %s\n", SDL_GetError());
return 1;
}
SDL_Window* win = SDL_CreateWindow("Hello SDL2",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
640, 480, SDL_WINDOW_SHOWN);
if (!win) {
std::printf("SDL_CreateWindow failed: %s\n", SDL_GetError());
SDL_Quit();
return 1;
}
SDL_Delay(500);
SDL_DestroyWindow(win);
SDL_Quit();
return 0;
}

Final thought

I learned the hard way that pkg_search_module() is fantastic if pkg-config is there. On Linux, it’s a no-brainer. On Windows, it’s hit-or-miss unless I set up MSYS2. For maximum portability, I now use SDL2’s CMake package when I can, and only fall back to pkg config when I must. That way, my Linux builds keep working, and my Windows builds stay smooth in Visual Studio.

John Melek

About John Melek

Senior Software Engineer with over 10 years of experience in designing and developing cutting-edge embedded automotive products. Proficient in C and C++, with a strong passion for delivering innovative solutions that drive business growth.

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments