当使用QT5_ADD_RESOURCES和多线程编译与CMake时损坏的资源.cpp文件 [英] Corrupted resource .cpp file when using QT5_ADD_RESOURCES and multithread compiling with CMake

查看:2171
本文介绍了当使用QT5_ADD_RESOURCES和多线程编译与CMake时损坏的资源.cpp文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Qt的5.0版本带来了一系列更简单的命令来使用CMake来构建Qt项目。
请参见 http://qt-project.org/doc/ qt-5 / cmake-manual.html



如果我的资源文件命名为Icon32.qrc,则 QT5_ADD_RESOURCES > QT5_ADD_RESOURCES(RESOURCES Icon32.qrc)命令会自动将其转换为 qrc_Icon32.cpp 文件,并定义一个 $ {RESOURCES} 变量



这样做效果非常好,除了我在CDash中得到一个编译错误,大约每20个构建一次。错误通常是以下形式:

  /.../ CMake / build / qrc_Icon32.cpp:272380:1:错误:未知类型名称'qCleanupResources_Icon32'

发生的是,最后一行的可变部分



记录什么是正常的文件结束时, qrc_Icon32.cpp 文件会重复。 CMake确实看起来,似乎 QT5_ADD_RESOURCES 的行为如下:每当它到达需要资源的项目时,它会执行一个特定于 depend 的文件但仍然会在构建目录的根目录中写入 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)

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

设置(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 zm 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的文件夹,并添加一个您选择的名称为YourImage.png的png图像。 p>

最后,创建一个构建目录,输入并运行:

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

输出应该是

 扫描目标的依赖关系FirstTarget_automoc 
扫描依赖关系目标SecondTarget_automoc
[10%] [20%] Automoc目标FirstTarget
Automoc目标SecondTarget
[20%] [20%]内置目标FirstTarget_automoc
内置目标SecondTarget_automoc
[30%] [40%]生成qrc_Icon32.cpp
生成qrc_Icon32.cpp
扫描目标SecondTarget的依赖关系
扫描目标FirstTarget的依赖关系
[50%] [60 %]构建CXX对象CMakeFiles / SecondTarget.dir / Main2.cpp.o
构建CXX对象CMakeFiles / FirstTarget.dir / Main1.cpp.o
[70%] [80%]构建CXX对象CMakeFiles /SecondTarget.dir/qrc_Icon32.cpp.o
构建CXX对象CMakeFiles / FirstTarget.dir / qrc_Icon32.cpp.o
[90%] [100%]构建CXX对象CMakeFiles / SecondTarget.dir / SecondTarget_automoc .cpp.o
构建CXX对象CMakeFiles / FirstTarget.dir / FirstTarget_automoc.cpp.o
链接CXX可执行文件SecondTarget
链接CXX可执行文件FirstTarget

您可以看到,qrc_Icon32.cpp大约同时创建两次,位于build目录的根目录。 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功能:



a href =http://www.cmake.org/cmake/help/v3.0/manual/cmake-qt.7.html#autorcc =nofollow> 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


The 5.0 release of Qt has brought a set of easier commands to build Qt projects using CMake. See http://qt-project.org/doc/qt-5/cmake-manual.html. Resources for a project need to be included using the command QT5_ADD_RESOURCES.

If my resource file is named for instance Icon32.qrc, the QT5_ADD_RESOURCES(RESOURCES Icon32.qrc) command will automatically convert it into a qrc_Icon32.cpp file and define a ${RESOURCES} variable that I will then be able to include into the proper targets.

Doing this works perfectly, except that I get a compilation error in CDash roughly once every 20 builds. The error is typically of the following form:

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

What is happening is that a variable portion of the last line of the qrc_Icon32.cpp file is repeated after what should normally the end of file, thus creating one last nonsensical line for the compiler.

Logging what CMake does, it seems that the behavior of QT5_ADD_RESOURCES is the following: whenever it reaches a project that requires the resources in question, it executes a depend make file that is specific to the compilation target but that still would write the qrc_Icon32.cpp at the root of the build directory, and this for all targets. So if two targets are being compiled in parallel, two invocations of rcc could be writing into the same file at the same time, hence the corruption.

I have not found any report/discussion of this issue/feature on the web so I am wondering if I might have missed something:

Is there a way to tell CMake to save the generated qrc_Icon32.cpp in a different location for each target? Better yet, is it possible to tell CMake to call rcc only once from its main make file so that qrc_Icon32.cpp is later available for all targets?

I guess a workaround would be to create a static library that would be the only one using ${RESOURCES} and then to link that library into all targets. But still, I think CMake ought to be able to manage its dependencies properly when compiling with the multithreading -j flag.


To reproduce the issue, in an empty folder, create a CMakeList.txt containing the following

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})

Then Main1.cpp and Main2.cpp are created using

#include <iostream>

using namespace std;

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

The qrc file is

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

Then create a folder named Icon32 and add a png image of your choice name YourImage.png.

Finally, create a build directory, enter it and run:

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

The output should be something like

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

You can see that qrc_Icon32.cpp is created twice at about the same time, at the root of the build directory. The qrc_Icon32.cpp.o files though are properly created in the FirstTarget.dir and SecondTarget.dir so there are no conflicts.

My point is that either: 1) qrc_Icon32.cpp should be created in FirstTarget.dir and SecondTarget.dir as well or 2) it should be created at the root of the build directory, but only once for all targets.

解决方案

qt5_add_resources writes the file to CMAKE_CURRENT_BINARY_DIR, not CMAKE_BINARY_DIR

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

Ditto Qt 4:

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

Update:

With the source code you provided in your update, it is possible to see the issue.

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

The workaround is to add a custom target and add explicit depends on that.

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 has an AUTORCC feature:

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

It also puts the generated qrc_ file in the current build dir. CMake 3.1 will put it in a target-specific directory, making this problem go away:

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

这篇关于当使用QT5_ADD_RESOURCES和多线程编译与CMake时损坏的资源.cpp文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆