How to add icon to a Qt application on Windows using a .rc file on a CMake project?
Asked Answered
B

6

9

I'm trying to add an application icon to an application I'm writing, following what is described in https://doc.qt.io/qt-5/appicon.html

I'm using Qt Desktop 5.15.2 (64) and 6.1.2 (64) for both MinGW and MSVC, on Windows 10 64 bits. They all compile without error or warnings, but the icon doesn't show up.

My CMakeFile.txt:

cmake_minimum_required(VERSION 3.14)

project(MyApp VERSION 0.1 LANGUAGES CXX)

set(CMAKE_INCLUDE_CURRENT_DIR ON)

set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# QtCreator supports the following variables for Android, which are identical to qmake Android variables.
# Check https://doc.qt.io/qt/deployment-android.html for more information.
# They need to be set before the find_package(...) calls below.

if(ANDROID)
    set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")
#    if (ANDROID_ABI STREQUAL "armeabi-v7a")
#        set(ANDROID_EXTRA_LIBS
#            ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libcrypto.so
#            ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libssl.so)
#    endif()
endif()

find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Quick LinguistTools REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Quick LinguistTools REQUIRED)

set(TS_FILES _pt_BR.ts)

set(PROJECT_SOURCES
        main.cpp
        qml.qrc
        ${TS_FILES}
)

if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
    set(APP_ICON_RESOURCE_WINDOWS "${CMAKE_CURRENT_SOURCE_DIR}/MyApp.rc")
    qt_add_executable(MyApp
        MANUAL_FINALIZATION
        ${PROJECT_SOURCES}
        ${APP_ICON_RESOURCE_WINDOWS}
    )

    qt_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES})
else()
    if(ANDROID)
        add_library(MyApp SHARED
            ${PROJECT_SOURCES}
        )
    elseif(WIN32)
        set(APP_ICON_RESOURCE_WINDOWS "${CMAKE_CURRENT_SOURCE_DIR}/windows/MyApp.rc")
        add_executable(MyApp
            ${PROJECT_SOURCES}
            ${APP_ICON_RESOURCE_WINDOWS}
        )

    else()
        add_executable(MyApp
          ${PROJECT_SOURCES}
        )
    endif()

    qt5_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES})
endif()

target_compile_definitions(MyApp
  PRIVATE $<$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>:QT_QML_DEBUG>)
target_link_libraries(MyApp
  PRIVATE Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Quick)

set_target_properties(MyApp PROPERTIES
    MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com
    MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
    MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
)

if(QT_VERSION_MAJOR EQUAL 6)
    qt_import_qml_plugins(MyApp)
    qt_finalize_executable(MyApp)
endif()

MyApp.rc:

MyAppIcon ICON "MyApp.ico"

The .ico contains a single 256x256 32-bit RGBA image.

For what matters, after so many failures I tried creating a test project using qmake, and added the icon using RC_ICONS = QtTest.ico the .pro file, which worked (got the correct icon). When I tried using the RC_FILE = QtTest.rc instead it used the default icon, but without any warnings or errors.

Just in case I generated the .res file using windres, but to no avail. Changed QtTestIco ICON "QtTest.ico" and regenerated the .res, the same result.

Substituting the CMakeList.txt for a .pro file and using the RC_ICONS is not an option, sadly.

Somebody could help me, please?

Thanks in advance.

Bespoke answered 25/7, 2021 at 10:10 Comment(3)
i'm having same issue, the Qt documentation doesn't seem to point out how to specify the icon specifically, just point to RC file. Is QRC same as RC??Cornetcy
No, the .rc file in Windows is another one that describes some specifics of the generated Windows binary. What bothers me is that the Qmake template allows us to easily add an icon, but the Cmake way is mich more convoluted.Bespoke
Idk much about cmake but if your rc file's encoding doesnt match #pragma code_page(#codepage#) definition, strings could be misinterpreted.Eyeglass
U
6

In order to add a Microsoft resources (RC) file, you need to tell CMake to support the "RC" language by enabling Microsoft's RC language. This will kick in the resource compiler when it detects a file with the *.rc extension in your project.

Here is a sample code snippet:

if (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
    enable_language("RC")
    set (WIN32_RESOURCES ${CMAKE_CURRENT_SOURCE_DIR}/windows/MyApp.rc)
endif()

add_executable(MyApp WIN32
    ${PROJECT_SOURCES}
    ${WIN32_RESOURCES}
)

Build your project and Microsoft Explorer will then see your icon.

Unprejudiced answered 11/1, 2022 at 18:54 Comment(1)
Simply adding the .rc to the add_executable call was needed for me.Statute
C
3

Here's what worked for me using Qt 6 and CMake.

First of all, an .rc file is different than .qrc. This isn't explained at all in the Qt documentation for setting up an application icon (link), they just assume everyone knows that. Both formats are text files, they don't contain any pixel data. They're just text files with a different extension.

I'm assuming you already have an .ico file. This post isn't about creating one. Ideally, it should have multiple versions embedded inside of it at different resolutions: 64x64, 48x48, 40x40, 32x32, 24x24, 20x20, 16x16.

In my project folder I have it as "./res/img/favicon.ico" but the name of the .ico file doesn't matter, you can name it "appicon.ico" if you want, or whatever.

And a text file renamed as favicon.rc next to it, with the following contents:

IDI_ICON1 ICON "favicon.ico"

And as a side note, Visual Studio generated an .rc file (in another project) with the following comment above it:

// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_ICON1               ICON                    "LearnOpenGL.ico"

So the "IDI_ICON1" name seems to serve an actual purpose.

You could, technically, rename that label anything you wanted, like "MyAppIcon" instead of "IDI_ICON1". Just like the OP did in the question at the very top.

However, then only the .exe icon will be set, not the window icon as well. Which I suppose can be set separately, using Qt Designer (or editing the .ui in Qt Creator) for the top-most widget "QMainWindow", since there's a "windowIcon" field there. Or programmatically with .setWindowIcon(). But that's besides the point. It doesn't make sense (to me) to have separate icons for the .exe and for the window. As long as it's set in CMake correctly, it will apply to both the .exe and the window.

Moving on.

In the CMakeLists.txt file, create an app_icon_resource_windows variable (with set) before adding it to qt_add_executable(...):

if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
    set(app_icon_resource_windows "${CMAKE_CURRENT_SOURCE_DIR}/res/img/favicon.rc")
    qt_add_executable(YourCoolProjectNameHere
        MANUAL_FINALIZATION
        ${PROJECT_SOURCES}
        ${app_icon_resource_windows}
    )

AND THAT'S IT!

Rebuild your project (or Clean + Build, same thing) and enjoy!

PS: The app_icon_resource_windows CMake variable is in lowercase in my example (same as in the Qt documentation), while the OP had it in uppercase. It doesn't matter, as long as it's consistent in both places. Otherwise it compiles fine but with no icon and without even a WARNING!

PS #2: If you don't want the .rc file next to your .ico files or images or whatever, you can place it 2 folders above it, but then the contents of the file should point to it correctly:

IDI_ICON1 ICON "res/img/favicon.ico"

And then obviously update "CMakeLists.txt" to stop looking for the .rc file in "/res/img/":

set(app_icon_resource_windows "${CMAKE_CURRENT_SOURCE_DIR}/favicon.rc")

The idea is to have CMake point at a .res file, which itself points at an .ico file. As long as you set the paths correctly, it will work out just fine.

Costumier answered 31/3 at 21:36 Comment(0)
D
1

Suppose you have (core and myapp just as an example):

core/
   CMakeLists.txt
   myapp.ico
   myapp.rc
   ...other dirs with your sources...

Your myapp.rc contains:

IDI_ICON1               ICON    DISCARDABLE     "myapp.ico"

Suppose you have MS VC Build Tools installed and you have x64 Native Tools Command Prompt open. And you build your project using cmake, etc. It means that there you also have rc cmd program there. So in your prompt do:

C:\Users\MyName\myapprepo\core>    rc  myapp.rc

Then you get a binary file myapp.res:

core/
   CMakeLists.txt
   myapp.ico
   myapp.rc
   myapp.res

So now, you need to link this binary file to our lib/app. In my case it was a lib I called core and I would link it to my executable myapp. It does not matter. The point is that you should link the file:

# core/CMakeLists.txt

target_link_libraries(${CORE_LIBRARY_NAME} 
                      ${CMAKE_CURRENT_SOURCE_DIR}/myapp.res 
                      Qt5::Widgets)

The MS VC compiler knows what to do when linking the res file to your lib/exe. So don't worry about the strange entity. In general, the whole procedure is exactly as it is described in the docs https://doc.qt.io/archives/qt-4.8/appicon.html:

If you do not use qmake, the necessary steps are: first, run the rc program on the .rc file, then link your application with the resulting .res file.

If any question, ask in comments. Good luck!

Dredger answered 23/6, 2022 at 9:34 Comment(0)
P
0
  1. Create a rc file and add icon resource. (resources.rc)

IDI_ICON1 ICON "main.ico"

The main.ico should be located in same location with rc file

  1. Add resource compile script on the cmakefile.

`add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/resources.res COMMAND rc.exe ARGS /fo ${CMAKE_CURRENT_BINARY_DIR}/resources.res ${CMAKE_CURRENT_SOURCE_DIR}/resources.rc DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/resources.rc WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} )

  1. add resource file on the add_executable and target_link_libraries

    ...

add_executable(<your_appname> ${PROJECT_SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/resources.res)

...

target_link_libraries(<your_appname> PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/resources.res)

...

it worked for me.

Porphyrin answered 27/9, 2023 at 17:54 Comment(0)
C
0

I've seen a lot of posts basically giving the same instructions, which didn't work for me... at least not in Qt5. What does seem to work universally is converting the icon.rc file into an icon.o object file using the windres utility, and then adding the icon.o file to the build using the add_executable() in CMake.

Here's a step by step:

  1. Create an icon.rc file that has the following line:

    IDI_ICON1 ICON DISCARDABLE "icon.ico"

  2. In the command line run the following command:

    $ windres icon.rc -o icon.o

  3. Add the source object to your CMake as follows:

    add_executable(MyApp
        main.cpp
        icon.o
    )
    
Chalcidice answered 10/1 at 21:26 Comment(0)
B
0

I had the same issue and this is how I resolved for it to work:

1.You need to create a resource file (.rc) file which is different from .qrc that is mentioned in the https://doc.qt.io/qt-6/appicon.html official documentation with the contents in this format **IDI_ICON1 ICON "assets/myAppIcon.ico" **. I created this .rc file in VsCode then copied it into my project directory. I then imported it into my project in QtCreator if you're here I assume you know how to import files in QtCreator.

2.In your CMakeList.txt add this code to tell CMake to support the "RC" language by enabling Microsoft's RC language. This will kick in the resource compiler when it detects a file with the *.rc extension in your project as mentioned by another answer above.

Here is the code:

    if (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
    enable_language("RC")
    set (WIN32_RESOURCES ${CMAKE_CURRENT_SOURCE_DIR}/windows/MyApp.rc)
endif()

3.Modify the CMakeList.txt again to set the icon like in this code:

    if(WIN32)
    set(APP_ICON_RESOURCE_WINDOWS "${CMAKE_CURRENT_SOURCE_DIR}/appIcon.rc")
    set_target_properties(MyApp PROPERTIES
        WIN32_EXECUTABLE TRUE
        RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}"
    )
    add_custom_command(TARGET appQuick POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy "${APP_ICON_RESOURCE_WINDOWS}" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/MyApp.ico"
    )
endif()
  1. In the main.cpp file you can modify like this:

    #include QGuiApplication #include QQmlApplicationEngine #include QIcon //remember to add the tag signs

    int main(int argc, char *argv[]) { QGuiApplication app(argc, argv);

     app.setWindowIcon(QIcon(":/assets/myAppIcon.ico"));
    
  2. Build and run to see changes.

Basso answered 5/8 at 18:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.