c++ - 使用 QT5_ADD_RESOURCES 和使用 CMake 进行多线程编译时损坏的资源 .cpp 文件

标签 c++ multithreading qt cmake qt5

Qt 5.0 版本带来了一组更简单的命令来使用 CMake 构建 Qt 项目。 参见 http://qt-project.org/doc/qt-5/cmake-manual.html .需要使用命令 QT5_ADD_RESOURCES 包含项目的资源。

如果我的资源文件名为 Icon32.qrc,QT5_ADD_RESOURCES(RESOURCES Icon32.qrc) 命令会自动将其转换为 qrc_Icon32.cpp 文件并定义一个 ${RESOURCES} 变量,然后我可以将其包含到适当的目标中。

这样做很完美,除了我在 CDash 中大约每 20 个构建出现一次编译错误。错误通常采用以下形式:

/.../CMake/build/qrc_Icon32.cpp:272380:1: error: unknown type name 'qCleanupResources_Icon32'

发生的事情是 qrc_Icon32.cpp 文件最后一行的可变部分在通常应该是文件末尾的位置之后重复,从而为编译器创建了最后一行无意义的行。

记录 CMake 所做的事情,似乎 QT5_ADD_RESOURCES 的行为如下:每当它到达需要相关资源的项目时,它就会执行 depend make特定于编译目标的文件,但仍会在 构建目录的根目录 中写入 qrc_Icon32.cpp,这适用于所有目标。因此,如果并行编译两个目标,则 rcc 的两次调用可能会同时写入同一个文件,从而导致损坏。

我没有在网上找到任何关于这个问题/特性的报告/讨论,所以我想知道我是否遗漏了什么:

有没有办法告诉 CMake 将生成的 qrc_Icon32.cpp 保存在每个目标的不同位置?更好的是,是否可以告诉 CMake 从其主 make 文件中仅调用一次 rcc,以便以后所有目标都可以使用 qrc_Icon32.cpp

我想一个解决方法是创建一个静态库,该库将是唯一使用 ${RESOURCES} 的静态库,然后将该库链接到所有目标。但是,我仍然认为 CMake 在使用多线程 -j 标志进行编译时应该能够正确管理其依赖项。


要重现该问题,请在空文件夹中创建包含以下内容的 CMakeList.txt

CMAKE_MINIMUM_REQUIRED(VERSION 2.8.11)
PROJECT(SSCCE CXX)

set(CMAKE_PREFIX_PATH /usr/local/Qt-5.3.0 ${CMAKE_PREFIX_PATH})

set(CMAKE_AUTOMOC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)

INCLUDE_DIRECTORIES(SYSTEM "/usr/local/Qt-5.3.0/include/QtCore")
find_package(Qt5Core REQUIRED)
QT5_ADD_RESOURCES(RESOURCES Icon32.qrc)

SET(LIBLIST gobject-2.0 X11-xcb Xi xcb-render-util SM ICE xcb-glx xcb-render xcb-atom xcb-property xcb-event dbus-1 xcb xcb-image xcb-icccm xcb-sync xcb-xfixes xcb-shm xcb-randr xcb-shape xcb-keysyms fontconfig freetype Xrender Xext X11 jpeg png Qt5::Core z m dl gthread-2.0 rt glib-2.0 GL pthread)

ADD_EXECUTABLE(FirstTarget Main1.cpp ${RESOURCES})
TARGET_LINK_LIBRARIES(FirstTarget ${LIBLIST})
ADD_EXECUTABLE(SecondTarget Main2.cpp ${RESOURCES})
TARGET_LINK_LIBRARIES(SecondTarget ${LIBLIST})

然后 Main1.cpp 和 Main2.cpp 是使用创建的

#include <iostream>

using namespace std;

int main(int argc, char** argv) {
        std::cout<<"Hello World 1"<<std::endl;
        return 0;
}

qrc文件是

<RCC>
    <qresource prefix="/">
        <file>Icon32/YourImage.png</file>
    </qresource>
</RCC>

然后创建一个名为 Icon32 的文件夹并添加一个您选择的 png 图像名称 YourImage.png。

最后创建build目录,进入并运行:

cmake -DCMAKE_CXX_COMPILER=g++-4.8 -DCMAKE_CXX_FLAGS='-std=c++11 -fPIE' ..
make -j2

输出应该是这样的

Scanning dependencies of target FirstTarget_automoc
Scanning dependencies of target SecondTarget_automoc
[ 10%] [ 20%] Automoc for target FirstTarget
Automoc for target SecondTarget
[ 20%] [ 20%] Built target FirstTarget_automoc
Built target SecondTarget_automoc
[ 30%] [ 40%] Generating qrc_Icon32.cpp
Generating qrc_Icon32.cpp
Scanning dependencies of target SecondTarget
Scanning dependencies of target FirstTarget
[ 50%] [ 60%] Building CXX object CMakeFiles/SecondTarget.dir/Main2.cpp.o
Building CXX object CMakeFiles/FirstTarget.dir/Main1.cpp.o
[ 70%] [ 80%] Building CXX object CMakeFiles/SecondTarget.dir/qrc_Icon32.cpp.o
Building CXX object CMakeFiles/FirstTarget.dir/qrc_Icon32.cpp.o
[ 90%] [100%] Building CXX object CMakeFiles/SecondTarget.dir /SecondTarget_automoc.cpp.o
Building CXX object CMakeFiles/FirstTarget.dir/FirstTarget_automoc.cpp.o
Linking CXX executable SecondTarget
Linking CXX executable FirstTarget

可以看到qrc_Icon32.cpp大约同时被创建了两次,都在构建目录的根目录下。尽管 qrc_Icon32.cpp.o 文件已在 FirstTarget.dir 和 SecondTarget.dir 中正确创建,因此没有冲突。

我的观点是: 1) qrc_Icon32.cpp 也应该在 FirstTarget.dir 和 SecondTarget.dir 中创建,或者 2) 它应该在构建目录的根目录下创建,但对所有目标只创建一次。

最佳答案

qt5_add_resources 将文件写入CMAKE_CURRENT_BINARY_DIR,而不是CMAKE_BINARY_DIR

https://qt.gitorious.org/qt/qtbase/source/d953d9a4c3bdc5ed3b8d380c4b893b51b523bc50:src/corelib/Qt5CoreMacros.cmake#L205

同上 Qt 4:

http://cmake.org/gitweb?p=cmake.git;a=blob;f=Modules/Qt4Macros.cmake;h=b1b12d68b07aac076719c681fb844f4f98ba8151;hb=HEAD#l212

更新:

使用您在更新中提供的源代码,可以看到问题。

http://www.cmake.org/pipermail/cmake/2008-October/024492.html

http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=0ece8f79

http://public.kitware.com/Bug/view.php?id=12311

解决方法是添加自定义目标并添加显式依赖。

cmake_minimum_required(VERSION 2.8.11)

project(MyTest)

find_package(Qt5Core)

qt5_add_resources(RSCS somefile.qrc)
add_custom_target(gen_qrc DEPENDS ${RSCS})

add_executable(foo foo.cpp ${RSCS})
add_dependencies(foo gen_qrc)
add_executable(bar bar.cpp ${RSCS})
add_dependencies(bar gen_qrc)

CMake 3.0 具有 AUTORCC 功能:

http://www.cmake.org/cmake/help/v3.0/manual/cmake-qt.7.html#autorcc

它还将生成的 qrc_ 文件放在当前构建目录中。 CMake 3.1 会将其放在特定于目标的目录中,从而解决此问题:

http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=33774ca2

关于c++ - 使用 QT5_ADD_RESOURCES 和使用 CMake 进行多线程编译时损坏的资源 .cpp 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23041356/

相关文章:

qt - 如何检测 Qt 中工具提示内的鼠标单击?

c++ - 在 WIFI_AP_STA 中设置 AP 和 STA 之间的路由

c++ - 未解析的外部符号 "unsigned long gVar"

c# - 我必须向我的 Web API REST 方法添加显式线程吗?

c - 缩减变量在外部上下文中是私有(private)的

java - 单个java信号量上的死锁?

c++ - SDL_Surface 分割错误

c++ - 如何让 CPU 在 1 毫秒内精确忙碌?

QT5 标题栏遮盖了 Windows 10 上的顶行按钮

c++ - 显示 QMessageBox 时如何防止双槽调用?