Russian Qt Forum

Qt => Общие вопросы => Тема начата: kuzulis от Февраль 18, 2010, 14:56



Название: pimpl + CMake + qmake + #include "moc_...." . Кто решил проблему?
Отправлено: kuzulis от Февраль 18, 2010, 14:56
Доброго времени!

Бьюсь над переводом своего проекта с qmake на CMAke

Но возникает проблема с тем, что в реализации моего проекта при использовании pimpl приходится для qmake в некоторых *.cpp файлах проекта в самом их конце инклюдить moc_*.cpp файлы.

Так вот: если использовать для сборки qmake - то все собирается прекрасно, НО как только использую CMake - так оно ругается на отсутствие этих самых файлов moc_*.cpp   (точнее одного единственного).

Я на этом форуме наткнулся на: http://www.prog.org.ru/index.php?topic=9165.msg65906
где была аналогичгая проблема. Там советовали убрать вообще инклюд  #include "moc_*.cpp"  из файла   *.cpp проекта - тогда CMake будет собирать, но qmake - нет!
-----------

Вопрос: как решить эту проблему, чтобы и qmake и CMake могли собрать проект?

и в догонку: как реализовать в CMake аналогию этого:
Код:
...
CONFIG          -= debug_and_release debug
...
...
OBJECTS_DIR     = build/obj
MOC_DIR         = build/moc
...

win32 {
    SOURCES     += xyz.cpp
}

unix {
    SOURCES     += zyx.cpp
}
??


Название: Re: pimpl + CMake + qmake + #include "moc_...." . Кто решил проблему?
Отправлено: kuzulis от Февраль 19, 2010, 10:05
Еще в догонку:

если собирать статик библиотеку используя CMake - то она собирается, никаких ворнингов и ошибок при сборке нет. НО если её потом подключить к проекту и попытаться собрать при помощи qmake - то при компиляции вылезают ошибки типа:
Цитировать
...
...... undefined reference to `vtable for ...
....

уже не знаю и как быть...

На всякий случай привожу CMakeLists.txt библиотечки:
Код:
project( SerialDeviceWatcher )
cmake_minimum_required( VERSION 2.6.0 )

set(TARGET "qserialdevicewatcher"   CACHE string "Name of the library")

set( OPTIMIZATION_FLAGS "-O2" )

set( SERIALDEVICEWATCHER_SRCS
    serialdevicewatcher.cpp
    serialdevicewatcher_p_win.cpp
)

set( SERIALDEVICEWATCHER_MOC_HDRS
    serialdevicewatcher.h
    serialdevicewatcher_p.h    
)

find_package( Qt4 REQUIRED )
include( ${QT_USE_FILE} )

set( QT_DONT_USE_QTGUI )

#qt4_wrap_cpp( SERIALDEVICEWATCHER_MOC_SOURCES ${SERIALDEVICEWATCHER_SRCS} )
qt4_automoc ( ${SERIALDEVICEWATCHER_SRCS} ${SERIALDEVICEWATCHER_MOC_HDRS} )  

add_definitions(
    -Wall
    -DQT_NO_DEBUG
    ${OPTIMIZATION_FLAGS}
    ${QT_DEFINITIONS}
)

#include_directories(
#    ${QT_INCLUDES}
#    ${QT_INCLUDE_DIR}
#    ${CMAKE_BINARY_DIR}
#    .
#)

add_library(
    ${TARGET}
    STATIC
    ${SERIALDEVICEWATCHER_SRCS}
)

TARGET_LINK_LIBRARIES(
    ${TARGET}
    ${QT_LIBRARIES}
)


Название: Re: pimpl + CMake + qmake + #include "moc_...." . Кто решил проблему?
Отправлено: BRE от Февраль 19, 2010, 10:16
Попробуй так:

Код:
project( SerialDeviceWatcher )
cmake_minimum_required( VERSION 2.6.0 )

set(TARGET "qserialdevicewatcher"   CACHE string "Name of the library")

set( OPTIMIZATION_FLAGS "-O2" )

set( SERIALDEVICEWATCHER_SRCS
    serialdevicewatcher.cpp
    serialdevicewatcher_p_win.cpp
)

set( SERIALDEVICEWATCHER_MOC_HDRS
    serialdevicewatcher.h
    serialdevicewatcher_p.h   
)

find_package( Qt4 REQUIRED )
include( ${QT_USE_FILE} )

set( QT_DONT_USE_QTGUI )

qt4_wrap_cpp( SERIALDEVICEWATCHER_MOC_SOURCES ${SERIALDEVICEWATCHER_MOC_HDRS} ) # <<<<<<
#qt4_automoc ( ${SERIALDEVICEWATCHER_SRCS} ${SERIALDEVICEWATCHER_MOC_HDRS} )   

add_definitions(
    -Wall
    -DQT_NO_DEBUG
    ${OPTIMIZATION_FLAGS}
    ${QT_DEFINITIONS}
)

#include_directories(
#    ${QT_INCLUDES}
#    ${QT_INCLUDE_DIR}
#    ${CMAKE_BINARY_DIR}
#    .
#)

add_library(
    ${TARGET}
    STATIC
    ${SERIALDEVICEWATCHER_SRCS}
    ${SERIALDEVICEWATCHER_MOC_SOURCES} # <<<<<<<<<<
)

TARGET_LINK_LIBRARIES(
    ${TARGET}
    ${QT_LIBRARIES}
)


Название: Re: pimpl + CMake + qmake + #include "moc_...." . Кто решил проблему?
Отправлено: kuzulis от Февраль 19, 2010, 10:41
А при таком раскладе:
Код:
#


project( SerialDeviceWatcher )
cmake_minimum_required( VERSION 2.6.0 )

set(TARGET "qserialdevicewatcher" CACHE string "Name of the library")

set( OPTIMIZATION_FLAGS "-O2" )

set( SERIALDEVICEWATCHER_SRCS
    serialdevicewatcher.cpp
    serialdevicewatcher_p_win.cpp
)

set( SERIALDEVICEWATCHER_HDRS
    serialdevicewatcher.h
    serialdevicewatcher_p.h
)

find_package( Qt4 REQUIRED )
include( ${QT_USE_FILE} )

set( QT_DONT_USE_QTGUI )

qt4_wrap_cpp( SERIALDEVICEWATCHER_MOC_SOURCES ${SERIALDEVICEWATCHER_HDRS})
#qt4_automoc( ${SERIALDEVICEWATCHER_SRCS} ${SERIALDEVICEWATCHER_MOC_SOURCES} )   

add_definitions(
    -Wall
    -DQT_NO_DEBUG
    ${OPTIMIZATION_FLAGS}
    ${QT_DEFINITIONS}
)

#include_directories(
#    .
#)

add_library(
    ${TARGET}
    STATIC
    ${SERIALDEVICEWATCHER_SRCS}
    ${SERIALDEVICEWATCHER_MOC_SOURCES}
)

TARGET_LINK_LIBRARIES(
    ${TARGET}
    ${QT_LIBRARIES}
)

Пишет:
Цитировать
D:\SVN\qserialdevice-scm-2010-02-17\qserialdevicewatcher-build>make
[ 16%] Generating moc_serialdevicewatcher_p.cxx
D:/SVN/qserialdevice-scm-2010-02-17/qserialdevicewatcher/serialdevicewatcher_p.h:0: Warning: No relevant classes found. No output generated.
[ 33%] Generating moc_serialdevicewatcher.cxx
Scanning dependencies of target qserialdevicewatcher
[ 50%] Building CXX object CMakeFiles/qserialdevicewatcher.dir/serialdevicewatcher.cpp.obj
[ 66%] Building CXX object CMakeFiles/qserialdevicewatcher.dir/serialdevicewatcher_p_win.cpp.obj
[ 83%] Building CXX object CMakeFiles/qserialdevicewatcher.dir/moc_serialdevicewatcher.cxx.obj
D:\SVN\qserialdevice-scm-2010-02-17\qserialdevicewatcher-build\moc_serialdevicewatcher.cxx: In member function `virtual int SerialDeviceWatcher::qt_me
tacall(QMetaObject::Call, int, void**)':
D:\SVN\qserialdevice-scm-2010-02-17\qserialdevicewatcher-build\moc_serialdevicewatcher.cxx:72: error: invalid use of undefined type `struct SerialDevi
ceWatcherPrivate'
D:\SVN\qserialdevice-scm-2010-02-17\qserialdevicewatcher-build\../qserialdevicewatcher/serialdevicewatcher.h:31: error: forward declaration of `struct
 SerialDeviceWatcherPrivate'
mingw32-make[2]: *** [CMakeFiles/qserialdevicewatcher.dir/moc_serialdevicewatcher.cxx.obj] Error 1
mingw32-make[1]: *** [CMakeFiles/qserialdevicewatcher.dir/all] Error 2
mingw32-make: *** [all] Error 2

D:\SVN\qserialdevice-scm-2010-02-17\qserialdevicewatcher-build>


Название: Re: pimpl + CMake + qmake + #include "moc_...." . Кто решил проблему?
Отправлено: BRE от Февраль 19, 2010, 11:32
kuzulis, прикрепи архив с проектом, что бы его не искать.


Название: Re: pimpl + CMake + qmake + #include "moc_...." . Кто решил проблему?
Отправлено: kuzulis от Февраль 19, 2010, 12:28
Ссылка тут: http://fireforge.net/scm/?group_id=199

В аттаче - архив со ВСЕМ проектом + CMakeLists.txt с которым я в данный момент ковыряюсь.
Мне необходимо пока что портировать /qserialdevicewatcher на CMake.


 


Название: Re: pimpl + CMake + qmake + #include "moc_...." . Кто решил проблему?
Отправлено: kuzulis от Февраль 19, 2010, 12:51
Так, нашел в чем была проблема при сборке CMake:
- в файле serialdevicewatcher_p_win.cpp в самом его конце нужно написать:
Код:
#include "serialdevicewatcher.moc"

т.е. чтобы собрать с CMake нужно:
Код:
 //#include "moc_serialdevicewatcher.cpp"
#include "serialdevicewatcher.moc"

т.е. чтобы собрать с qmake нужно:
Код:
#include "moc_serialdevicewatcher.cpp"
//#include "serialdevicewatcher.moc"

Вот CMakeLists.txt:
Код:
#


project( SerialDeviceWatcher )
cmake_minimum_required( VERSION 2.6.0 )

set(TARGET "qserialdevicewatcher" CACHE string "Name of the library")

set( OPTIMIZATION_FLAGS "-O2" )

set( SERIALDEVICEWATCHER_SRCS
    serialdevicewatcher.cpp
    serialdevicewatcher_p_win.cpp
)

set( SERIALDEVICEWATCHER_HDRS
    serialdevicewatcher.h
    serialdevicewatcher_p.h
)

find_package( Qt4 REQUIRED )
include( ${QT_USE_FILE} )

set( QT_DONT_USE_QTGUI )

qt4_automoc( ${SERIALDEVICEWATCHER_SRCS} )  

add_definitions(
    -Wall
    -DQT_NO_DEBUG
    ${OPTIMIZATION_FLAGS}
    ${QT_DEFINITIONS}
)

include_directories(
    ${CMAKE_CURRENT_BINARY_DIR}
    ${QT_INCLUDES}
    .
)

add_library(
    ${TARGET}
    STATIC
    ${SERIALDEVICEWATCHER_SRCS}
)

TARGET_LINK_LIBRARIES(
    ${TARGET}
    ${QT_LIBRARIES}
)

Вот такая штука получается :(  . т.е. как сделать не меняя(правя) исходники , можно было бы собирать проекты в CMake и qmake я не знаю :(

-------------
------
и я тут посмотрел, что файлы "moc_serialdevicewatcher.cpp" и  "serialdevicewatcher.moc" - имеют одинаковое содержимое.
У меня возникла мысль сделать так, чтобы CMake генерил вместо файла "serialdevicewatcher.moc" -> "moc_serialdevicewatcher.cpp" - и тогда не пришлось бы править исходники!!! Но что-то пока не удается заставить CMake генерить файл с именем отличным от *.moc :(


Название: Re: pimpl + CMake + qmake + #include "moc_...." . Кто решил проблему?
Отправлено: kuzulis от Февраль 19, 2010, 13:56
Нашел интересную закономерность, которая заключается в том, что даже если и удается заставить генерировать CMake *.moc файл с нужным именем, и, если это имя заканчивается на *.cpp - то проект не собирается!!!

Пример:
в файле "serialdevicewatcher_p_win.cpp" в самом конце пишу : #include "moc_serialdevicewatcher.cpp1"

Далее создаю CMakeLists.txt c таким содержанием:
Код:
#


project( SerialDeviceWatcher )
cmake_minimum_required( VERSION 2.6.0 )

set(TARGET "qserialdevicewatcher" CACHE string "Name of the library")

set( OPTIMIZATION_FLAGS "-O2" )

set( SERIALDEVICEWATCHER_SRCS
    serialdevicewatcher.cpp
    serialdevicewatcher_p_win.cpp
)

set( SERIALDEVICEWATCHER_HDRS
    serialdevicewatcher.h
    serialdevicewatcher_p.h
)

find_package( Qt4 REQUIRED )
include( ${QT_USE_FILE} )

set( QT_DONT_USE_QTGUI )

qt4_generate_moc(serialdevicewatcher.h ${CMAKE_CURRENT_BINARY_DIR}/moc_serialdevicewatcher.cpp1) 

add_definitions(
    -Wall
    -DQT_NO_DEBUG
    ${OPTIMIZATION_FLAGS}
    ${QT_DEFINITIONS}
)

include_directories(
    ${CMAKE_CURRENT_BINARY_DIR}
    ${QT_INCLUDES}
    .
)

add_library(
    ${TARGET}
    STATIC
    ${SERIALDEVICEWATCHER_SRCS}
    ${CMAKE_CURRENT_BINARY_DIR}/moc_serialdevicewatcher.cpp1
)

TARGET_LINK_LIBRARIES(
    ${TARGET}
    ${QT_LIBRARIES}
)


и собираю проект - то собирается нормально и все работает!

НО - стоит лишь изменить везде moc_*.cpp1 (или любое другое имя файла)  на moc_*.cpp и попробовать заново собрать - то сборка вылетает с ошибками!

ЗЫ: я это затеял с тем, чтобы сделать возможной сборку проекта как CMake, так и qmake не меняя ничего в исходниках!

И вся "фишка" в том, что qmake -то создает файл moc_*.cpp и все работает (собирается). Но стоит лишь только сделать чтобы CMake генерил такое же имя - то начинаются проблемы :(


Название: Re: pimpl + CMake + qmake + #include "moc_...." . Кто решил проблему?
Отправлено: Пантер от Февраль 25, 2010, 07:22
Инклюды можно вот так сделать:
Код
C++ (Qt)
#ifdef -=CMAKE=-
#include "file.moc"
#else
#include "moc_file.cpp"
#endif
 
Не проверял. Дефайн -=CMAKE=- объявить в CMakeLists, если нет стандартного.


Название: Re: pimpl + CMake + qmake + #include "moc_...." . Кто решил проблему?
Отправлено: kuzulis от Февраль 25, 2010, 11:29
2 Пантер ,

спасибо, наверное так и придется сделать.

---

Но у меня есть еще один вопрос (в тему) : почему при сборке своего проекта с помощью CMake - результирующий размер бинарика получается больше , чем при сборке c помощью qmake (у меня по крайней мере) ?
Цитировать
qmake   -> 190270 Байт
CMake   -> 230502 Байт

Какие нужно опции дописать в CMake , чтобы отключить ненужные сущности и чтобы в результате размеры скомпилированных бинариков примерно совпали?

Сейчас у меня только это есть:
Код:
...
set( OPTIMIZATION_FLAGS "-O2" )
set( QT_DONT_USE_QTGUI )

add_definitions( -Wall -DQT_NO_DEBUG )
...


Название: Re: pimpl + CMake + qmake + #include "moc_...." . Кто решил проблему?
Отправлено: BRE от Февраль 25, 2010, 12:34
Скорее всего в случае с CMake файл создается с отладочной информацией.
Попробуй при генерации добавить в опции cmake:
-DCMAKE_BUILD_TYPE=Release
а для сборки в режиме debug соответственно:
-DCMAKE_BUILD_TYPE=Debug


Название: Re: pimpl + CMake + qmake + #include "moc_...." . Кто решил проблему?
Отправлено: Rcus от Февраль 25, 2010, 12:38
А сравнить Makefile от qmake и CMakeFiles/<target>.dir/flags.make? Может CMake добавляет -rdynamic или еще чего.


Название: Re: pimpl + CMake + qmake + #include "moc_...." . Кто решил проблему?
Отправлено: kuzulis от Февраль 25, 2010, 13:03
Итак, сделал другим путем:
посмотрел Makefile который генерит qmake и написал в CMakeLists.txt так: (под виндовс)
Цитировать
set( QT_DEFINITIONS
    -DUNICODE
    -DQT_NO_DEBUG
    -DQT_CORE_LIB
    -DQT_THREAD_SUPPORT
)

set( QT_DONT_USE_QTGUI )

add_definitions( -Wall
    ${OPTIMIZATION_FLAGS}
    ${QT_DEFINITIONS}
)

и размер бинарика собранного CMake уменьшился до: 191372 Байт :)


Название: Re: pimpl + CMake + qmake + #include "moc_...." . Кто решил проблему?
Отправлено: kuzulis от Февраль 25, 2010, 13:14
Цитировать
А сравнить Makefile от qmake и CMakeFiles/<target>.dir/flags.make? Может CMake добавляет -rdynamic или еще чего.
Сравнил после того как добился уменьшения размера:

Makefile от qmake:
Цитировать
...
CC            = gcc
CXX           = g++
DEFINES       = -DUNICODE -DQT_LARGEFILE_SUPPORT -DQT_NO_DEBUG -DQT_CORE_LIB -DQT_THREAD_SUPPORT
CFLAGS        = -O2 -Wall $(DEFINES)
CXXFLAGS      = -O2 -frtti -fexceptions -mthreads -Wall $(DEFINES)
INCPATH       = -I"..\..\..\..\Qt\2009.04\qt\include\QtCore" -I"..\..\..\..\Qt\2009.04\qt\include" -I"..\..\..\..\Qt\2009.04\qt\include\ActiveQt" -I"build\moc" -I"..\..\..\..\Qt\2009.04\qt\mkspecs\win32-g++"
...

flags.make от CMake:
Цитировать
...
CXX_FLAGS = -ID:\Qt\2009.04\qt\include -ID:\Qt\2009.04\qt\include\QtGui -ID:\Qt\2009.04\qt\include\QtCore   -Wall -O2

CXX_DEFINES = -DQT_DLL -DQT_GUI_LIB -DQT_CORE_LIB -DUNICODE -DQT_NO_DEBUG -DQT_CORE_LIB -DQT_THREAD_SUPPORT
...

как видно, в flags.make есть лишнее: -DQT_DLL -DQT_GUI_LIB !!! Почему? Ведь я явно указал НЕ использовать GUI в CMakeLists.txt:
Цитировать
...
set( QT_DONT_USE_QTGUI )
...

и не указывал нигде -DQT_DLL!!


Название: Re: pimpl + CMake + qmake + #include "moc_...." . Кто решил проблему?
Отправлено: Rcus от Февраль 25, 2010, 13:45
А find_package с аргументом COMPONENTS использовали? Я попробовал на Arch'е с пакетами из репов - все нормально работает.
C QT_DLL непонятно почему вас это беспокоит.
Цитировать
  # build using shared Qt needs -DQT_DLL
  IF(NOT QT_CONFIG MATCHES "static")
    # warning currently only qconfig.pri on Windows potentially contains "static"
    # so QT_DLL might not get defined properly on other platforms.
    SET(QT_DEFINITIONS ${QT_DEFINITIONS} -DQT_DLL)
  ENDIF(NOT QT_CONFIG MATCHES "static")
See? No magic


Название: Re: pimpl + CMake + qmake + #include "moc_...." . Кто решил проблему?
Отправлено: kuzulis от Февраль 25, 2010, 14:42
2 Rcus

Цитировать
А find_package с аргументом COMPONENTS использовали?
Спасибо, помогло! (не знал и не думал, что это будет влиять на зависимости в итоге)

Цитировать
C QT_DLL непонятно почему вас это беспокоит.
Больше не беспокоит :) Спс

2 Пантер

пробовал объявлять дефайн, сделал так в конце *.cpp файла:
Код:
#ifndef (BUILD_IS_CMAKE)
#include "moc_myfile.cpp" //for qmake only
#else
#include "myfile.moc"     //for CMake only
#endif

, где BUILD_IS_CMAKE - это придуманный мною дефайн

НО почему-то при использовании qmake не хочет собираться проект, говорит что не может найти "myfile.moc" o_O.
Только если заккоментировать лишнее и оставить только #include "moc_myfile.cpp" - то собирается

PS: пробовал и #ifndef и #ifdef - результат один :(