Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I'm trying to write a portable CMake script for a simple Qt application. The target platforms are Win and Mac OSX. But as you can see, it's quite a monster already.

Are there any CMake profs? Can you see any essentially wrong approaches used in this script? I bet there are a few.

CMAKE_MINIMUM_REQUIRED( VERSION 2.8.6 )

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

MACRO( CHOOSE_QT path )
    FILE( GLOB QTROOTS "${path}/bin" )
    FIND_PROGRAM( QT_QMAKE_EXECUTABLE NAMES qmake qmake4 qmake-qt4 qmake-mac PATHS ${QTROOTS} )
ENDMACRO( CHOOSE_QT path )

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 )

MACRO( COPY_TO_BUNDLE resourcePath bundlePath )
    LIST( APPEND BUNDLE_COPY_RESOURCES ${resourcePath} )
    SET_SOURCE_FILES_PROPERTIES( ${resourcePath} PROPERTIES MACOSX_PACKAGE_LOCATION ${bundlePath} )
ENDMACRO( COPY_TO_BUNDLE )

MACRO( ADD_FRAMEWORK fwname fwpath appname )
    TARGET_LINK_LIBRARIES( ${appname} ${fwpath}/${fwname} )
    MESSAGE( STATUS "Framework ${fwname} found at ${fwpath}" )
ENDMACRO()

MACRO( ADD_SYSTEM_FRAMEWORK fwname appname )
    FIND_LIBRARY( FRAMEWORK_${fwname} NAMES ${fwname} PATHS ${CMAKE_OSX_SYSROOT}/System/Library PATH_SUFFIXES Frameworks NO_DEFAULT_PATH )
    if( ${FRAMEWORK_${fwname}} STREQUAL FRAMEWORK_${fwname}-NOTFOUND )
        MESSAGE( ERROR ": Framework ${fwname} not found" )
    else()
        ADD_FRAMEWORK( ${fwname} ${FRAMEWORK_${fwname}} ${appname} )
    endif()
ENDMACRO( ADD_SYSTEM_FRAMEWORK )

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

# Define project settings
PROJECT( TrackerSoftware )
SET( APP_NAME "TRACKer" )

# Find Qt library
if( WIN32 )
    CHOOSE_QT( "${CMAKE_CURRENT_SOURCE_DIR}/cxx/thirdparty/Qt" )
endif( WIN32 )
SET( CMAKE_AUTOMOC TRUE )
FIND_PACKAGE( Qt4 REQUIRED )

# Find Boost library
if( WIN32 )
    SET( BOOST_ROOT "cxx/thirdparty/boost" )
elseif( APPLE )
    SET( BOOST_ROOT "osx/FRP/vendors/libraries/include/boost" )
endif( WIN32 )
FIND_PACKAGE( Boost REQUIRED )

# Collect all required files for build
FILE( GLOB_RECURSE headers RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "cxx/src/RTCS/include/*.h" )
FILE( GLOB_RECURSE sources RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "cxx/src/RTCS/src/*.cpp" )
FILE( GLOB_RECURSE resources RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "cxx/src/*.qrc" )
FILE( GLOB_RECURSE win_resources RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "cxx/src/*.rc" )
FILE( GLOB_RECURSE forms RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "cxx/src/*.ui" )
SET( thirdparty_sources "cxx/thirdparty/SimpleCrypt/simplecrypt.cpp" )
if( APPLE )
    FILE( GLOB_RECURSE mac_sources RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "cxx/src/RTCS/src/*.m" )
    LIST( APPEND sources ${mac_sources} )
endif( APPLE )

# Preprocess forms
FILE( RELATIVE_PATH buildDir ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} )
QT4_WRAP_UI( form_headers ${forms} )
TO_RELATIVE_PATHS( form_headers )
ADD_FILES_TO_FILTER( "Forms" "${buildDir}/src/RTCS/include" "${form_headers}" )

# Preprocess resources
QT4_ADD_RESOURCES( resources_rcc ${resources} )
TO_RELATIVE_PATHS( resources_rcc )
ADD_FILES_TO_FILTER( "Resources" "${buildDir}" "${resources_rcc}" )

# Mark all sources as ObjectiveC++
if( APPLE )
    foreach( curSource ${sources} )
        SET_SOURCE_FILES_PROPERTIES( ${curSource} PROPERTIES COMPILE_FLAGS "-x objective-c++" )
    endforeach( curSource )
endif( APPLE )

# Set all link libraries directories - it should be specified Before any targets creation
if( WIN32 )
    LINK_DIRECTORIES( "${CMAKE_CURRENT_SOURCE_DIR}/cxx/thirdparty/boost/lib" )
    LINK_DIRECTORIES( "${CMAKE_CURRENT_SOURCE_DIR}/cxx/thirdparty/libtwitcurl/lib/x86" )
    LINK_DIRECTORIES( "${CMAKE_CURRENT_SOURCE_DIR}/cxx/thirdparty/id3lib/lib/x86" )
    LINK_DIRECTORIES( "${CMAKE_CURRENT_SOURCE_DIR}/cxx/thirdparty/curl/curl/lib/lib/x86" )
    LINK_DIRECTORIES( "${CMAKE_CURRENT_SOURCE_DIR}/cxx/thirdparty/log4qt/lib/x86" )
    LINK_DIRECTORIES( "${CMAKE_CURRENT_SOURCE_DIR}/cxx/thirdparty/WinSparkle/lib/x86/$(ConfigurationName)" )
    LINK_DIRECTORIES( "${CMAKE_CURRENT_SOURCE_DIR}/cxx/thirdparty/fervor-auto/lib/$(Configuration)" )
    LINK_DIRECTORIES( "${CMAKE_CURRENT_SOURCE_DIR}/cxx/thirdparty/quazip/lib/$(Configuration)" )
elseif( APPLE )
    LINK_DIRECTORIES( "${CMAKE_CURRENT_SOURCE_DIR}/osx/FRP/vendors/libraries/lib" )
endif( WIN32 )

# Set up Bundle settings for the Mac OSX
if( APPLE )
    SET( MACOSX_BUNDLE true )
    SET( MACOSX_BUNDLE_SHORT_VERSION_STRING 0.7-beta2 )
    SET( MACOSX_BUNDLE_VERSION 0.7-beta2 )
    SET( MACOSX_BUNDLE_LONG_VERSION_STRING Version 0.7-beta2 )
    #SET( CMAKE_OSX_ARCHITECTURES ppc;i386 ) #Comment out if not universal binary

    # Add a bundle icon
    SET( MACOSX_BUNDLE_ICON_FILE multimonIcon.icns )
    COPY_TO_BUNDLE( "osx/FRP/${MACOSX_BUNDLE_ICON_FILE}" Resources )

    # Copy all private frameworks into the bundle
    #COPY_TO_BUNDLE( "osx/FRP/vendors/libraries/lib/Sparkle.framework" Frameworks )
    #foreach( curFramework ${QT_LIBRARIES} )
        #COPY_TO_BUNDLE( "${curFramework}" Frameworks )
    #endforeach( curFramework )

    # Fixup bundle, copy dynamic libraries into app bundle
    SET( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/out )
    MESSAGE( STATUS "!!! BUNDLE PATH: ${EXECUTABLE_OUTPUT_PATH}/${APP_NAME}.app" )
    SET( APPS "\${CMAKE_INSTALL_PREFIX}/${APP_NAME}.app" ) # paths to executables
    SET( DIRS "${CMAKE_SOURCE_DIR}/osx/FRP/vendors/libraries/lib" ) # directories to search for prerequisites
    INSTALL( CODE "
        include(BundleUtilities)
        fixup_bundle(\"${APPS}\" \"\" \"${DIRS}\")
    ")
endif( APPLE )

# Create executable
if( WIN32 )
    ADD_EXECUTABLE( Tracker WIN32 ${headers} ${sources} ${form_headers} ${resources_rcc} ${thirdparty_sources} ${win_resources} )
    SET_TARGET_PROPERTIES( Tracker PROPERTIES OUTPUT_NAME "tracker" )
    SET_TARGET_PROPERTIES( Tracker PROPERTIES COMPILE_FLAGS "/Zc:wchar_t-" )
elseif( APPLE )
    ADD_EXECUTABLE( Tracker MACOSX_BUNDLE ${headers} ${sources} ${form_headers} ${resources_rcc} ${thirdparty_sources} ${BUNDLE_COPY_RESOURCES} )
    SET_TARGET_PROPERTIES( Tracker PROPERTIES OUTPUT_NAME ${APP_NAME} )
    SET( CMAKE_XCODE_ATTRIBUTE_GCC_VERSION "com.apple.compilers.llvm.clang.1_0" )
endif( WIN32 )

# Set filters for project according to its namespaces
ADD_FILES_TO_FILTER( "Headers" "cxx/src/RTCS/include" "${headers}" )
ADD_FILES_TO_FILTER( "Sources" "cxx/src/RTCS/src" "${sources}" )
ADD_FILES_TO_FILTER( "Resources" "cxx/src/RTCS/rc" "${win_resources}" )
ADD_FILES_TO_FILTER( "Thirdparty" "cxx/thirdparty" "${thirdparty_sources}" )

# Set additional include directories
INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_BINARY_DIR} )
INCLUDE_DIRECTORIES( "cxx/src" )
INCLUDE_DIRECTORIES( "cxx/src/RTCS/include" )
INCLUDE_DIRECTORIES( "cxx/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( Tracker ${QT_LIBRARIES} )
TARGET_LINK_LIBRARIES( Tracker ${QT_QTMAIN_LIBRARY} )

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

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

# Add other libs to link
if( WIN32 )
    TARGET_LINK_LIBRARIES( Tracker debug "twitcurlD.lib" )
    TARGET_LINK_LIBRARIES( Tracker debug "id3libD.lib" )
    TARGET_LINK_LIBRARIES( Tracker debug "libcurlD.lib" )
    TARGET_LINK_LIBRARIES( Tracker debug "log4qtD.lib" )

    TARGET_LINK_LIBRARIES( Tracker optimized "twitcurl.lib" )
    TARGET_LINK_LIBRARIES( Tracker optimized "id3lib.lib" )
    TARGET_LINK_LIBRARIES( Tracker optimized "libcurl.lib" )
    TARGET_LINK_LIBRARIES( Tracker optimized "log4qt.lib" )

    TARGET_LINK_LIBRARIES( Tracker "fervor.lib" )
    TARGET_LINK_LIBRARIES( Tracker "quazip.lib" )

    TARGET_LINK_LIBRARIES( Tracker "Wininet.lib" )
    TARGET_LINK_LIBRARIES( Tracker "ws2_32.lib" )
    TARGET_LINK_LIBRARIES( Tracker "winmm.lib" )
    TARGET_LINK_LIBRARIES( Tracker "wldap32.lib" )
    TARGET_LINK_LIBRARIES( Tracker "Shell32.lib" )
    TARGET_LINK_LIBRARIES( Tracker "Version.lib" )
elseif( APPLE )
    TARGET_LINK_LIBRARIES( Tracker "libiconv.a" )
    TARGET_LINK_LIBRARIES( Tracker "libid3.a" )
    TARGET_LINK_LIBRARIES( Tracker "liblibtwitcurl.a" )
    TARGET_LINK_LIBRARIES( Tracker "libLog4Qt.a" )
    TARGET_LINK_LIBRARIES( Tracker "libz.a" )
    TARGET_LINK_LIBRARIES( Tracker "libboost_date_time.a" )
    TARGET_LINK_LIBRARIES( Tracker "libboost_iostreams.a" )
    TARGET_LINK_LIBRARIES( Tracker "libboost_serialization.a" )
    TARGET_LINK_LIBRARIES( Tracker "libboost_thread-mt.a" )
    TARGET_LINK_LIBRARIES( Tracker "curl" )

    # Add frameworks
    ADD_FRAMEWORK( "Sparkle.framework" "${CMAKE_CURRENT_SOURCE_DIR}/osx/FRP/vendors/libraries/lib" Tracker )

    # Add system frameworks
    ADD_SYSTEM_FRAMEWORK( Foundation Tracker )
    ADD_SYSTEM_FRAMEWORK( CoreFoundation Tracker )
    ADD_SYSTEM_FRAMEWORK( AppKit Tracker )
endif( WIN32 )

# Add defines
ADD_DEFINITIONS( -DQUAZIP_STATIC )
ADD_DEFINITIONS( -DBUILDING_LIBCURL )
ADD_DEFINITIONS( -DID3LIB_LINKOPTION=1 )
ADD_DEFINITIONS( -DUNICODE -D_UNICODE ) #enable unicode support
share|improve this question
    
Would [Win x64] fall under the Win32 branch? –  Mat's Mug Nov 19 '13 at 1:24
    
@retailcoder as i remember, yes, it would and it does. those are selectors among platforms like windows, linux and mac. –  Occulta Nov 19 '13 at 9:54
    
Isn't there a tool called qmake that people normally use? –  ChrisW Mar 18 at 15:06
    
I've worked with a CMake file that invoked FIND_PACKAGE (Qt4 4.8.0 COMPONENTS QtCore QtNetwork REQUIRED) and INCLUDE(${QT_USE_FILE}) early in the script, invoked QT4_WRAP_CPP once, and included ${QT_LIBRARIES} as one of the input arguments of TARGET_LINK_LIBRARIES. Other than that, it seems not to need to mention Qt, in particular there is nothing like CHOOSE_QT( "${CMAKE_CURRENT_SOURCE_DIR}/cxx/thirdparty/Qt" ). But perhaps this depends on how you install Qt. –  David K May 19 at 17:46
    
@DavidK we don't install Qt, we keep several repos of different Qt builds and use them as subrepos or just clone somewhere and set env variables for paths. So, all scripts were made to support that scheme. We do it because we have various projects that use different Qts and we don't wanna port some old projects to a new Qt, because it occasionally introduces bugs. You can read about all that mess in my question about selecting a Qt instance on stackoverflow right here stackoverflow.com/questions/12511370/… –  Occulta May 20 at 8:38
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.