Поврежденный файл ресурса .cpp при использовании QT5_ADD_RESOURCES и многопоточной компиляции с помощью CMake.

StackOverflow https://stackoverflow.com//questions/23041356

Вопрос

В выпуске Qt 5.0 появился набор более простых команд для создания проектов Qt с использованием CMake.Видеть http://qt-project.org/doc/qt-5/cmake-manual.html.Ресурсы для проекта необходимо подключить с помощью команды QT5_ADD_RESOURCES.

Если мой файл ресурсов называется, например, Icon32.qrc, QT5_ADD_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 file повторяется после того, что обычно должно быть в конце файла, таким образом создавая последнюю бессмысленную строку для компилятора.

Регистрируя действия CMake, кажется, что поведение QT5_ADD_RESOURCES следующее:всякий раз, когда он достигает проекта, требующего рассматриваемых ресурсов, он выполняет зависеть make файл, специфичный для цели компиляции, но все равно записывающий qrc_Icon32.cpp в корне каталога сборки, и это для всех целей.Таким образом, если две цели компилируются параллельно, два вызова РСС может одновременно записываться в один и тот же файл, отсюда и повреждение.

Я не нашел в Интернете ни одного отчета/обсуждения этой проблемы/функции, поэтому мне интересно, возможно, я что-то пропустил:

Есть ли способ сказать CMake сохранить сгенерированный qrc_Icon32.cpp в разных местах для каждой цели?А еще лучше, можно ли сказать CMake, чтобы он позвонил РСС только один раз из основного файла make, чтобы 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.

Наконец, создайте каталог сборки, войдите в него и запустите:

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

Другие советы

Указанное поведение связано с тем фактом, что QT5_ADD_РЕСУРСЫ вызывается на ранней стадии процесса, во время настройки и перед фактическим запуском компиляции.В этот момент переменная ${CMAKE_CURRENT_BINARY_DIR} указанное стивайром определяется как корневая папка сборки.(Это можно легко проверить, добавив СООБЩЕНИЕ( вывод в Qt5CoreMacros.cmake.

Результат выполнения функции QT5_ADD_РЕСУРСЫ заключается в создании пользовательских команд, которые будут вызываться в процессе компиляции:https://qt.gitorious.org/qt/qtbase/source/d953d9a4c3bdc5ed3b8d380c4b893b51b523bc50%3asrc/corelib/Qt5CoreMacros.cmake#L231

Если определено несколько целевых объектов, то эти пользовательские команды позже могут вызываться параллельно в одно и то же время.В этот момент ${выходной файл} не будет переопределен с использованием текущего значения ${CMAKE_CURRENT_BINARY_DIR} и, таким образом, параллельные процессы будут записывать данные в один и тот же файл в корневом каталоге сборки.

Просматривая код для QT5_ADD_РЕСУРСЫ по-видимому, нет механизма / опции для исправления такого поведения в случае многопоточной компиляции, однако, как указал steveire, обходной путь для базовой пользовательской командной функции также может быть успешно применен.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top