How to include a certain Qt installation using CMa

2019-01-22 02:56发布

问题:

We have plenty Qt copies on every dev PC - each project has its own Qt copy in the thirdparties directory. That's done due to each project is developed and tested with its own Qt; an often case is that we need a custom build of Qt for some project. So due to mentioned above we have a separate SVN repo for holding various Qt builds and an external in each Qt project, which refers to one among those builds.

The problem is, when using CMake we can only select a version of Qt and the Qt4 finder decides what Qt to use by itself. And that's not the correct one. We need to redirect the finder to configure all stuff for a particular Qt copy in project's third parties directory.

I've tried to specify the PATHS option for FIND_PACKAGE like that: FIND_PACKAGE( Qt4 REQUIRED PATHS "thirdparty/Qt" ) but that didn't help. I have tried to set the QT_QMAKE_EXECUTABLE variable, but that didn't work. I've tried to add the required QMake's path (it's used by the FindQt4.cmake to determine all directories) to the PATH variable before the installed one, but that didn't help too.

Is there a way to use all the stuff which the FIND_PACKAGE provides but for a certain Qt copy? I really don't want to implement all Qt wrappers, set all definitions, includes, dirs, etc manually.

Here is my CMake project. Maybe that will help:

CMAKE_MINIMUM_REQUIRED( VERSION 2.8 )

#############################################################################

MACRO( ADD_FILES_TO_FILTER rootFilterName rootFilterPath files )
    FOREACH( curFile ${files} )
        FILE( RELATIVE_PATH curFilter "${CMAKE_CURRENT_SOURCE_DIR}/${rootFilterPath}" "${CMAKE_CURRENT_SOURCE_DIR}/${curFile}" )
        FILE( RELATIVE_PATH test "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/${curFile}" )
        GET_FILENAME_COMPONENT( curFilter ${curFilter} PATH )
        SET( curFilter "${rootFilterName}/${curFilter}" )
        STRING( REPLACE "/" "\\\\" curFilter ${curFilter} )
        SOURCE_GROUP( ${curFilter} FILES ${curFile} )
    ENDFOREACH( curFile )
ENDMACRO( ADD_FILES_TO_FILTER rootFilterName rootFilterPath files )

MACRO( TO_RELATIVE_PATHS filePaths )
    SET( resPaths "" )
    FOREACH( curPath ${${filePaths}} )
        FILE( RELATIVE_PATH relPath ${CMAKE_CURRENT_SOURCE_DIR} ${curPath} )
        SET( resPaths ${resPaths} ${relPath} )
    ENDFOREACH( curPath )
    SET( ${filePaths} ${resPaths} )
ENDMACRO( TO_RELATIVE_PATHS filePaths )

######################################################################

# Define project settings
PROJECT( RealTimeCapture )
FIND_PACKAGE( Qt4 REQUIRED PATHS "thirdparty/Qt" )
SET( BOOST_ROOT "thirdparty/boost" )
FIND_PACKAGE( Boost REQUIRED )

# Collect all required files for build
FILE( GLOB_RECURSE headers RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/RTCF/include/*.h" )
FILE( GLOB_RECURSE sources RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/RTCF/src/*.cpp" )
FILE( GLOB_RECURSE resources RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.qrc" )
FILE( GLOB_RECURSE forms RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.ui" )

# Preprocess all Qt files
QT4_WRAP_CPP( header_mocs ${headers} )
QT4_WRAP_UI( form_headers ${forms} )
QT4_ADD_RESOURCES( resources_rcc ${resources} )

# Convert all generated files paths to relative ones
TO_RELATIVE_PATHS( header_mocs )
TO_RELATIVE_PATHS( form_headers )
TO_RELATIVE_PATHS( resources_rcc )

# Create executable
ADD_EXECUTABLE( RealTimeCapture ${headers} ${sources} ${header_mocs} ${form_headers} ${resources_rcc} )
SET_TARGET_PROPERTIES( RealTimeCapture PROPERTIES COMPILE_FLAGS "/Zc:wchar_t-" )

# Set filters for project according to its namespaces
FILE( RELATIVE_PATH buildDir ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} )
ADD_FILES_TO_FILTER( "Headers" "src/RTCF/include" "${headers}" )
ADD_FILES_TO_FILTER( "Sources" "src/RTCF/src" "${sources}" )
ADD_FILES_TO_FILTER( "Generated" "${buildDir}/src/RTCF/include" "${header_mocs}" )
ADD_FILES_TO_FILTER( "Forms" "${buildDir}/src/RTCF/include" "${form_headers}" )
ADD_FILES_TO_FILTER( "Resources" "${buildDir}" "${resources_rcc}" )

# Set additional include directories
INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_BINARY_DIR} )
INCLUDE_DIRECTORIES( "src" )
INCLUDE_DIRECTORIES( "src/RTCF/include" )
INCLUDE_DIRECTORIES( "thirdparty" )

# Configure Qt
SET( QT_USE_QTNETWORK TRUE )
SET( QT_USE_QTSQL TRUE )
SET( QT_USE_QTSCRIPT TRUE )
SET( QT_USE_QTXML TRUE )
SET( QT_USE_QTWEBKIT TRUE )
INCLUDE( ${QT_USE_FILE} )
ADD_DEFINITIONS( ${QT_DEFINITIONS} )
TARGET_LINK_LIBRARIES( RealTimeCapture ${QT_LIBRARIES} )

# Add boost support
INCLUDE_DIRECTORIES( ${Boost_INCLUDE_DIR} )
TARGET_LINK_LIBRARIES( RealTimeCapture ${Boost_LIBRARIES} )

# Add other libs include dirs
INCLUDE_DIRECTORIES( "thirdparty/SimpleCrypt" )
INCLUDE_DIRECTORIES( "thirdparty/id3lib/include" )
INCLUDE_DIRECTORIES( "thirdparty/libtwitcurl" )
INCLUDE_DIRECTORIES( "thirdparty/curl-7.24.0/curl/include" )
INCLUDE_DIRECTORIES( "thirdparty/log4qt/include" )
INCLUDE_DIRECTORIES( "thirdparty/fervor-auto" )

# Add defines
ADD_DEFINITIONS( RealTimeCapture -DQUAZIP_STATIC )
ADD_DEFINITIONS( RealTimeCapture -DBUILDING_LIBCURL )
ADD_DEFINITIONS( RealTimeCapture -DID3LIB_LINKOPTION=1 )
ADD_DEFINITIONS( -DUNICODE -D_UNICODE ) #enable unicode support

UPDATE

As it's mentioned in the comments to the accepted answer, I've managed to set a custom qmake.exe (different from the one added to the OS PATH variable) by setting the QT_QMAKE_EXECUTABLE CMake variable. But the problem was, the qmake executable has hardcoded paths to all Qt's modules. So I have solved it by providing a custom qt.conf file (as it's mentioned in the answer). I haven't found any examples of it in the internet, so here it is, maybe it will help someone:

[Paths]
Prefix=..
Documentation=doc
Headers=include
Libraries=lib
Binaries=bin
Plugins=plugins
Imports=imports
Data=
Translations=
Settings=
Examples=
Demos=

I used exactly this. You can consider specifying an absolute path to the Qt install in the prefix though. I just didn't want to use an absolute path in a repo, which can be cloned in an arbitrary location. See this link about details on using qt.conf.

回答1:

You're on the right track with QT_QMAKE_EXECUTABLE. That variable is a cache variable, so simply setting it won't work... the cached value will stick around unless you change it via the GUI, or before running cmake the first time, or in CMakeCache.txt, or with the CACHE and FORCE options to SET.

Here's the idiom I use, since I have fixed logic to choose my QT directory based on variables known at configure time. Here, I set the variable before ever running FIND_PACKAGE, so no cache issues.

IF(WIN32 AND ${CMAKE_SIZEOF_VOID_P} MATCHES 8)
  # Hardcode a location for a QT toolkit compiled for Win64.  By overriding QT_QMAKE, all the rest is found
  # Choose any version of QT found in the 64-bit tools area
  FILE(GLOB QTROOTS c:/Tools_x64/Qt/*/bin)     # */
  FIND_PROGRAM(QT_QMAKE_EXECUTABLE NAMES qmake qmake4 qmake-qt4 qmake-mac PATHS ${QTROOTS})
ENDIF()

Put this before FIND_PACKAGE( Qt4 )

EDITING based on new information in comments:

Oh, I'm with you now. You have what amount to broken Qt installations. The FindQt module will always use the qmake executable to discover the settings for the Qt tree. Qmake stores this information in a set of "persistent properties", which can be queried with qmake -query, and set with qmake -set. So you can "fix" a Qt installation by running it's qmake and setting the QT_INSTALL_PREFIX property, as documented here: http://doc.qt.digia.com/4.7-snapshot/qmake-environment-reference.html

qmake -set "QT_INSTALL_PREFIX" /path/to/qt/

Or, in an old SO question qmake and QT_INSTALL_PREFIX. How can I select a new location for Qt library?, a non-accepted answer uses qt.conf to override the QT prefix.

Both of these solutions involve modifying the Qt installation. I'm not sure there's any way around this, but how this fits into your repository and build system is out of scope here.



回答2:

If I may, I'd like to complete / confirm some information said here and give a complete example.

Like Occulta, I have a custom-built Qt environment which I must use for my project. These are the step I reproduced to make the project compiles :

  1. The CMakeLists.txt of my project, already possessing all CMake stuff, just include a 'qt.cmake' file

    include(qt)
    
  2. The qt.cmake file contains Peter's solution, decorated with additionnal stuff. With this configuration, I can use moc, uic and rcc to manage UI files, resources files, etc. Here's my file with some comments. Don't hesitate to fix them if they are not strictly correct (the way CMake works is still cloudy for me):

    # The path where Qt is.
    SET(QT_ROOT_DIR "path/to/qt")
    
    set(QT_QMAKE_EXECUTABLE ${QT_ROOT_DIR}/osx/bin/qmake)
    
    # Loads CMake macros bound to Qt.
    find_package(Qt4 REQUIRED)
    # Includes used Qt headers.
    include(${QT_USE_FILE})
    
  3. I also added the qt.conf file of Occulta at the same level as the qmake executable.

Everything went fine once these three steps were done. Hope this full example will help someone.

Thank you guys, you clearly helped me out here!



回答3:

I'm using the cmake config flag-DQt5_DIR=/usr/lib/x86_64-linux-gnu/cmake/Qt5 and it seems to work fine.

Edit: This method works file with an empty build dir. However, if a previous CMakeCache.txt exists, the per-component variables (i.e. Qt5Core_DIR) are not updated by setting a new Qt5_DIR. The easiest way to fix that is to delete the CMakeCache.txt and configure again.



回答4:

This is what worked for me :

set( QT_ROOT /opt/myqt/ )
set( ENV(CMAKE_PREFIX_PATH) ${QT_ROOT} )
FIND_PACKAGE( Qt4 COMPONENTS QtCore QtGui QtDBUS REQUIRED )

This is going to change the PATH environment variable, but I haven't found another way. Other answers didn't work for me.



标签: qt cmake