Search code examples
macoscmakehomebrewqwt

Use Qwt installed via brew in CMake


I Try to build an application using Qwt with CMake on a MacOS virtual machine.

I installed Qt5 and Qwt using brew:

brew install qt5 qwt

The result is a Qwt framework installation.

The header is there:

/usr/local/Cellar/qwt/6.1.4/lib/qwt.framework/Versions/6/Headers/qwt.h

and the library is here

file /usr/local/Cellar/qwt/6.1.4/lib/qwt.framework/qwt /usr/local/Cellar/qwt/6.1.4/lib/qwt.framework/qwt: Mach-O 64-bit dynamically linked shared library x86_64

It is easy to use it during buid with qmake

LIBS+= -F/usr/local/Cellar/qwt/6.1.4/lib LIBS += -framework qwt

but I'm stuck with CMake.I don't succeed to find how to do the same.

I have written my own FindQwt module based on find_library has indicated in CMake documentation. It works very well on Linux but I don't succeed to make it works on MacOS without the following hacks:

symbolic links to make appear qwt headers in an include directory and qwt as libqwt.dyn_lib:

ln -sf /usr/local/Cellar/qwt/6.1.4/lib/qwt.framework/Versions/6/Headers /usr/local/Cellar/qwt/6.1.4/include ln -sf /usr/local/Cellar/qwt/6.1.4/lib/qwt.framework/qwt /usr/local/Cellar/qwt/6.1.4/libqwt.dylib

I also have to remove /usr/local/lib/qwt.framework ( symbolic link on /usr/local/Cellar/qwt/6.1.4/lib/qwt.framework ) that was found by my FindQwt Cmake module after the 2 previous hack but I don't find any reason for that and was causing a link issue ( ld error 22 )

Here is the code of my Qwt cmake module

find_package(PkgConfig)
pkg_check_modules(PC_QWT QUIET libqwt)
if("${PC_QWT}" STREQUAL "")
    set(QWT_HINTS $ENV{QWT_INSTALL})

    set(QWT_PATHS
        /usr
        /usr/local/
        /usr/local/share/
        /usr/share/
       )
    if(NOT ${QWT_HINTS} STREQUAL "")
        set(QWT_PATHS ${QWT_HINTS})
    endif(NOT ${QWT_HINTS} STREQUAL "")

    find_path(Qwt_INCLUDE_DIR
              NAMES qwt.h
              PATHS ${QWT_PATHS}
              HINTS ${QWT_HINTS}
              PATH_SUFFIXES include qwt-qt4 qwt-qt5 qwt
              DOC "Variable storing the location of Qwt header"
             )

    set(ARCH_SUFFIX "lib")
    if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
      set(ARCH_SUFFIX "")
    endif("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")

    find_library(Qwt_LIBRARY
                 NAMES qwt qwt-qt4 qwt-qt5
                 PATHS ${QWT_PATHS}
                 HINTS ${QWT_HINTS}
                 PATH_SUFFIXES ${ARCH_SUFFIX}
                 DOC "Variable storing the location of Qwt library"
                 NO_DEFAULT_PATH
                 NO_CMAKE_PATH
                )

    set(Qwt_VERSION ${Qwt_FIND_VERSION})
    include(FindPackageHandleStandardArgs)
    find_package_handle_standard_args(Qwt
                                      FOUND_VAR Qwt_FOUND
                                      REQUIRED_VARS
                                      Qwt_LIBRARY
                                      Qwt_INCLUDE_DIR
                                      VERSION_VAR Qwt_VERSION
                                      )

    if(Qwt_FOUND)
        set(Qwt_LIBRARIES ${Qwt_LIBRARY})
        set(Qwt_INCLUDE_DIRS ${Qwt_INCLUDE_DIR})
        #set(Qwt_DEFINITIONS ${PC_Qwt_CFLAGS_OTHER})
    endif()
    if(Qwt_FOUND AND NOT TARGET Qwt::Qwt)
        add_library(Qwt::Qwt UNKNOWN IMPORTED)
        set_target_properties(Qwt::Qwt PROPERTIES
        IMPORTED_LOCATION "${Qwt_LIBRARY}"
        INTERFACE_COMPILE_OPTIONS ""
        INTERFACE_INCLUDE_DIRECTORIES "${Qwt_INCLUDE_DIR}")
    endif()
endif("${PC_QWT}" STREQUAL "")

If you have some ideas some ideas to avoid the hacks described above and hanle it in a more elegant way with CMake module they will be welcomed

Solution working without previously described hacks

  • Refer to usr/local/opt/qwt/lib that is Qwt version independant
  • Use the CMake module below modified thanks to Pedro's answer ( main modifications are related to target properties at the end and a light one to header search )

Here is the code

find_package(PkgConfig)
pkg_check_modules(PC_QWT QUIET libqwt)
if("${PC_QWT}" STREQUAL "")
    set(QWT_HINTS $ENV{QWT_INSTALL})

    set(QWT_PATHS
        /usr
        /usr/local/
        /usr/local/share/
        /usr/share/
       )
    if(NOT ${QWT_HINTS} STREQUAL "")
        set(QWT_PATHS ${QWT_HINTS})
    endif(NOT ${QWT_HINTS} STREQUAL "")

    find_path(Qwt_INCLUDE_DIR
              NAMES qwt.h
              PATHS ${QWT_PATHS}
              HINTS ${QWT_HINTS}
              PATH_SUFFIXES include qwt-qt4 qwt-qt5 qwt Headers
              DOC "Variable storing the location of Qwt header"
             )

    set(ARCH_SUFFIX "lib")
    if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
       set(ARCH_SUFFIX "")
    endif("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")

    find_library(Qwt_LIBRARY
                 NAMES qwt qwt-qt4 qwt-qt5
                 PATHS ${QWT_PATHS}
                 HINTS ${QWT_HINTS}
                 PATH_SUFFIXES ${ARCH_SUFFIX}
                 DOC "Variable storing the location of Qwt library"
                )

    set(Qwt_VERSION ${Qwt_FIND_VERSION})
    include(FindPackageHandleStandardArgs)
    find_package_handle_standard_args(Qwt
                                      FOUND_VAR Qwt_FOUND
                                      REQUIRED_VARS
                                      Qwt_LIBRARY
                                      Qwt_INCLUDE_DIR
                                      VERSION_VAR Qwt_VERSION
                                     )

    if(Qwt_FOUND)
        set(Qwt_LIBRARIES ${Qwt_LIBRARY})
        set(Qwt_INCLUDE_DIRS ${Qwt_INCLUDE_DIR})
    endif()
    if(Qwt_FOUND AND NOT TARGET Qwt::Qwt)
        if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
            get_filename_component(FRAMEWORK_LOC ${Qwt_LIBRARY} DIRECTORY)
            add_library(Qwt::Qwt INTERFACE IMPORTED)
            set_target_properties(Qwt::Qwt PROPERTIES
                                  INTERFACE_COMPILE_OPTIONS ""
                                  INTERFACE_INCLUDE_DIRECTORIES "${Qwt_INCLUDE_DIR}"
                                  )

            target_link_libraries(Qwt::Qwt INTERFACE "-F${FRAMEWORK_LOC} -framework qwt")
        else("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
            add_library(Qwt::Qwt UNKNOWN IMPORTED)
            set_target_properties(Qwt::Qwt PROPERTIES
                                  IMPORTED_LOCATION "${Qwt_LIBRARIES}"
                                  INTERFACE_COMPILE_OPTIONS ""
                                  INTERFACE_INCLUDE_DIRECTORIES "${Qwt_INCLUDE_DIR}"
                                  )
        endif("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
    endif()
endif("${PC_QWT}" STREQUAL "")

Solution

  • Assuming that you are already familiar with cmake/qt basics, this is my proposal:

    if(APPLE)
        set(CMAKE_FIND_FRAMEWORK ONLY)
        find_library(QWT
            NAMES qwt
            HINTS /usr/local/opt/qwt/lib/
            REQUIRED)
        if(QWT)
            include_directories(${QWT}/Headers)
            link_libraries(${QWT})
            message("QWT found: ${QWT}")
        endif()
    endif()
    

    The CMake variable CMAKE_FIND_FRAMEWORK affects how find_* commands choose between macOS Frameworks and unix-style dylibs. You may observe that executing cmake with the above snippet outputs:

    QWT found: /usr/local/Cellar/qwt/6.1.4/lib/qwt.framework
    

    This snippet adds the qwt framework to any target defined in your CMakeLists.txt, but you may prefer to apply the link part to only one target, like this:

    target_link_libraries(yourtarget ${QWT})
    

    Another caveat: you should link your program to the same Qt5 frameworks linked by Qwt, and also installed by brew: QTDIR=/usr/local/opt/qt5