Qt + CMake: Modern Approach to Managing icons.qrc




The icons.qrc Nightmare: Every Qt Developer’s Pain

If you’ve been designing Qt applications for a while, you’ve probably faced the same icons.qrc nightmare I have. You know the drill: your designer hands you a beautiful set of icons — 30, 50, maybe 100 different assets for your application. Each one needs to be properly integrated into your Qt project through that seemingly innocent XML file.

But here’s where the trouble begins. Every time you add a new icon, you find yourself opening that icons.qrc file, manually typing (or copy-pasting) yet another line:


     prefix="/icons">
        splashscreen.png
        flags/usa.svg
        info/default.svg
        info/hover.svg
        info/pressed.svg
        
    

Enter fullscreen mode

Exit fullscreen mode

At first, it doesn’t seem so bad. A few icons here and there — what’s the big deal? But as your project grows, so does the pain:

  • The “oops I forgot” moment: You add new icons to the icons/ folder but forget to update icons.qrc.
  • The typo disaster: One misplaced character in the XML, and your entire resource system breaks.
  • The merge conflict horror: When working in a team, multiple developers editing the same icons.qrc file inevitably leads to Git merge conflicts.
  • The maintenance burden: Removing old icons? Better remember to delete them from both the folder AND the .qrc file.

I’ve lost count of how many hours I’ve wasted on what should be the simplest part of application development — managing static resources. It feels horrible to manually maintain what should be an automatically generated file by default.

But what if I told you there’s a better way? A method that eliminates this manual process entirely, automatically includes every icon in your directory, and turns this maintenance nightmare into a set-it-and-forget-it solution?

In this article, I’ll show you how to combine Qt with CMake’s powerful file operations to automate icons.qrc management once and for all. No more manual edits, no more forgotten icons, no more merge conflicts. Let’s fix this problem properly.



The Traditional Approach: Manual icons.qrc Management

Before we dive into the modern solution, let’s take a closer look at the conventional way of handling icons in Qt projects. If you’ve worked with Qt for any length of time, this workflow will look painfully familiar.



The Standard icons.qrc Structure

Typically, your project structure looks something like this:

project/
├── CMakeLists.txt
├── src/
|   ├── MainWindow.ui
|   ├── MainWindow.h
|   ├── MainWindow.cpp
|   └── main.cpp
└── icons/
    ├── add.png
    ├── delete.png
    ├── edit.png
    ├── settings.png
    └── icons.qrc  
Enter fullscreen mode

Exit fullscreen mode

And your icons.qrc file contains all the manual entries:


     prefix="/icons">
        add.png
        delete.png
        edit.png
        settings.png
    

Enter fullscreen mode

Exit fullscreen mode



The CMake Integration

In your CMakeLists.txt, you’d typically include it like this:

project(MyApp LANGUAGES CXX)

file(GLOB_RECURSE PROJECT_SOURCES src/*.cpp)
qt_add_resources(PROJECT_SOURCES icons/icons.qrc)

add_executable(${PROJECT_NAME}
    ${PROJECT_SOURCES}
)
Enter fullscreen mode

Exit fullscreen mode

Or maybe even in a simpler way:

project(MyApp LANGUAGES CXX)

add_executable(${PROJECT_NAME}
    ...
    icons/icons.qrc
)
Enter fullscreen mode

Exit fullscreen mode



Where It All Falls Apart

When you have a lot of icons in multiple themes, the problems become impossible to ignore:

  1. The Adding New Icons Dance:
    • Copy new icon file to icons/ folder
    • Open icons.qrc in editor
    • Scroll to bottom of the file
    • Add new new_icon.png
    • Save and rebuild
  2. The Removal Nightmare:
    • Remove icon file from icons/ folder
    • Open icons.qrc
    • Search for the corresponding entry
    • Delete the line
    • Save and rebuild
  3. Team Collaboration Headaches:
Auto-merging icons/icons.qrc
CONFLICT (content): Merge conflict in icons/icons.qrc
Enter fullscreen mode

Exit fullscreen mode

You’d end up with merge conflicts that look like this:

<<<<<<< HEAD
        new_feature_icon.png
=======
        another_feature_icon.png
>>>>>>> feature-branch
Enter fullscreen mode

Exit fullscreen mode

In the next section, I’ll show you how to eliminate this manual process completely using CMake’s powerful file operations. No more editing XML, no more merge conflicts, no more forgotten icons.



The Modern Solution: Automated icons.qrc Generation with CMake

Now for the part you’ve been waiting for — how to eliminate the manual work completely. The solution lies in using CMake’s file operations to automatically generate our icons.qrc file during the build process.
Start by creating a cmake_utils/find_assets.cmake file in your project

# Copyright (c) 2025 Oleksandr Movchan
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# =======================================================================
# FUNCTION: generate_icons_qrc
#
# Automatically generates a Qt Resource File (.qrc) for icon assets.
# Specifically designed for managing icons with fixed prefix and supported formats.
#
# USAGE:
#   generate_icons_qrc(
#       ${CMAKE_CURRENT_SOURCE_DIR}/icons
#       ${CMAKE_CURRENT_BINARY_DIR}/icons.qrc
#   )
#
# PARAMETERS:
#   icons_directory - Input directory containing icon files
#   output_file     - Path where the generated .qrc file will be written
# =======================================================================

function(generate_icons_qrc icons_directory output_file)

    if(IS_ABSOLUTE ${output_file})
        set(absolute_output_file ${output_file})
    else()
        get_filename_component(absolute_output_file ${output_file} ABSOLUTE BASE_DIR ${CMAKE_CURRENT_BINARY_DIR})
    endif()

    if(IS_ABSOLUTE ${icons_directory})
        set(absolute_icons_directory ${icons_directory})
    else()
        get_filename_component(absolute_icons_directory ${icons_directory} ABSOLUTE BASE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
    endif()

    # Validate that the icons directory exists
    if(NOT EXISTS ${absolute_icons_directory})
        message(WARNING "Icons directory not found: ${absolute_icons_directory}")
        # Create an empty .qrc file to prevent build errors
        file(WRITE ${absolute_output_file}
            "\n    \"/icons\">\n    \n")
        return()
    endif()

    # Recursively find all supported icon files
    # Fixed formats: SVG, PNG, ICO (most common icon formats, might be extended if needed)
    file(GLOB_RECURSE icon_files
        ${absolute_icons_directory}/*.svg
        ${absolute_icons_directory}/*.png
        ${absolute_icons_directory}/*.ico
    )

    # Provide feedback about the number of icons found
    list(LENGTH icon_files icon_count)
    message(STATUS "Generated ${output_file}: ${icon_count} icons")

    # Get output directory path
    get_filename_component(output_dir ${absolute_output_file} DIRECTORY)

    # Create output dir if not exists
    if(NOT EXISTS ${output_dir})
        file(MAKE_DIRECTORY ${output_dir})
    endif()

    # Start building the QRC file content with fixed prefix "/icons"
    set(QRC_CONTENT "\"1.0\" encoding=\"UTF-8\"?>\n")
    set(QRC_CONTENT "${QRC_CONTENT}\n    \"/icons\">\n")

    # Process each icon file and add it to the QRC content
    foreach(icon_file ${icon_files})
        # Get relative path to output directory
        file(RELATIVE_PATH relative_path ${output_dir} ${icon_file})
        file(RELATIVE_PATH alias_name ${absolute_icons_directory} ${icon_file})

        # Normalize path separators to forward slashes for cross-platform compatibility
        string(REPLACE "\\" "https://dev.to/" relative_path "${relative_path}")
        # Using alias for saving virtual structure of folders in Qt resource file
        string(REPLACE "\\" "https://dev.to/" alias_name "${alias_name}")

        # Add the icon entry to the QRC content
        set(QRC_CONTENT "${QRC_CONTENT}        \"${alias_name}\">${relative_path}\n")
    endforeach()

    # Close the QRC XML structure
    set(QRC_CONTENT "${QRC_CONTENT}    \n")

    # Write the complete QRC content to the output file
    file(WRITE ${absolute_output_file} "${QRC_CONTENT}")
endfunction()

# =======================================================================
# EXAMPLE USAGE:
#
# Generate icons.qrc for your project:
# generate_icons_qrc(
#     ${CMAKE_CURRENT_SOURCE_DIR}/icons
#     ${CMAKE_CURRENT_BINARY_DIR}/icons.qrc
# )
#
# Then include it in your Qt project:
# qt_add_resources(PROJECT_SOURCES
#     ${CMAKE_CURRENT_BINARY_DIR}/icons.qrc
# )
#
# =======================================================================
Enter fullscreen mode

Exit fullscreen mode

I would definitely recommend putting this function in a separate file, like find_assets.cmake and then using it for each project with icons:

project(MyApp LANGUAGES CXX)

include(cmake_utils/find_assets.cmake)
generate_icons_qrc(icons ${CMAKE_CURRENT_BINARY_DIR}/icons.qrc)

qt_add_resources(PROJECT_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/icons.qrc)
Enter fullscreen mode

Exit fullscreen mode



Advanced: Relative Paths Supported

The generated file will automatically handle nested directory structures:



     prefix="/icons">
         alias="search.svg">../../icons/search.svg
         alias="theme/dark/info/default.svg">../../icons/theme/dark/info/default.svg
         alias="theme/dark/info/disabled.svg">../../icons/theme/dark/info/disabled.svg
         alias="theme/dark/info/hover.svg">../../icons/theme/dark/info/hover.svg
         alias="theme/dark/info/pressed.svg">../../icons/theme/dark/info/pressed.svg
         alias="theme/dark/remove/default.svg">../../icons/theme/dark/remove/default.svg
        
         alias="theme/light/info/default.svg">../../icons/theme/light/info/default.svg
         alias="theme/light/info/disabled.svg">../../icons/theme/light/info/disabled.svg
         alias="theme/light/info/hover.svg">../../icons/theme/light/info/hover.svg
         alias="theme/light/info/pressed.svg">../../icons/theme/light/info/pressed.svg
         alias="theme/light/remove/default.svg">../../icons/theme/light/remove/default.svg
        
    

Enter fullscreen mode

Exit fullscreen mode



Usage in Your Code

The best part? Your C++ code doesn’t change at all:

// Use icons exactly as before - no code changes needed!
QIcon lightInfoIconDefault(":/icons/theme/light/info/default.svg");
QIcon darkInfoIconDefault(":/icons/theme/dark/info/default.svg");
Enter fullscreen mode

Exit fullscreen mode



Conclusion: Why This Approach Wins

After implementing this solution across multiple projects, the benefits are undeniable:

  • ✅ Zero Maintenance: Add icons to the folder — they’re automatically included
  • ✅ No More Merge Conflicts: Generated file, no team coordination needed
  • ✅ Error-Free: No typos in XML paths
  • ✅ Scalable: Works with any count of icons
  • ✅ Fast: Regenerates only when icons change
  • ✅ Flexible: Easy to extend

The manual icons.qrc approach is a relic from a time when we didn’t have better build system tools. With modern CMake, we can automate this tedious process and focus on what really matters — building great applications.



Next Steps:

Try implementing this in your current Qt project. Once you experience the freedom of automatic icon management, you’ll never go back to manual editing. And don’t forget to remove your old icons.qrc.

If you prefer to keep the file in the same location, simply add it to .gitignore.

# Auto-generated Qt resource files
icons.qrc
generated_*.qrc

# Build directories
build/
*-build/
Enter fullscreen mode

Exit fullscreen mode

Have questions or improvements? Share your thoughts in the comments below!



Source link

Leave a Reply

Your email address will not be published. Required fields are marked *