How can I use CMake to build wxwidgets on demand and link to it

I have the following situation:

  • I am working on an application that depends on a number of third party libraries, among them wxwidgets
  • I am building an application for multiple target configurations (x86, arm, Linux, Windows) using Linux as my build host system.
  • Due to the aforementioned multiple target configurations, I decided to build these 3rd party libraries from source using CMake's ExternalProject_Add function.
  • Third party libraries are built "on demand" in a location other than my CMAKE_BINARY_DIR application so that I can erase the build tree for my application without rebuilding the third party libraries (takes a while).
  • The location of the third party libraries differs depending on what target configuration I am creating them for (obviously).

I am very new to CMake and the problem I am currently facing is this: The source files in my application cannot find the wx include files, and I need to set the correct linker flags to be able to link my application to wxwidgets.

This appears to be handled by the wx-config utility, which provides exactly this information as output when run with the -cppflags or -libs flag. I cannot, however, figure out how to catch this output and add it to the include dirs and associated libraries that I install from my CMakeLists.txt files.

So basically I want.

  • Create wxwidgets (if it doesn't exist) for the current target config
  • Run wx-config -cppflags and -libs to find out the correct dirs and linker flags for the current target configuration.
  • Use the information from step 2 when creating goals that are my own application.

So far I have tried something like this:

# Set a target-configuration-specific location 
set(wxwidgetsTop ${MYPROJECT_EXTERNAL_DIR}/wxwidgets/wxwidgets_${MYPROJECT_CURRENT_TARGET_CFG})

# Build the project
ExternalProject_Add( wxWidgetsExternal
  PREFIX ${wxwidgetsTop}
  URL ${MYPROJECT_EXTERNAL_DIR}/tarballs/wxWidgets-3.0.2.tar.bz2
  SOURCE_DIR ${wxwidgetsTop}/src/wxwidgets
  CONFIGURE_COMMAND ${configure_cmdline}
  BUILD_COMMAND make -j${MYPROJECT_NCPU}
  INSTALL_COMMAND make install
  )

# Create a wxwidgets target to be used as a dependency from other code
add_library(wxWidgets IMPORTED STATIC GLOBAL)
add_dependencies(wxWidgets wxWidgetsExternal)

# (non-working) attempt to get the correct include dirs and linker
# flags for wxwidgets 
add_custom_command(TARGET wxWidgetsExternal
  POST_BUILD
  COMMAND ${INSTALL_DIR}/bin/wx-config ARGS --cppflags
  COMMENT "Running wx-config"
)

      

but the above does not provide a way to actually use the output from a custom command to add cppflags and linker options when creating the targets that make up my application.

What is a good way to achieve what I want?

+3


source to share


2 answers


I see three different ways to do this:

Method 1: use find_package

Use wxWidgets as a separate requirement for your project and expect the developers to install it before building your project. In your CMakeLists.txt you will need to call find_package(wxWidgets)

, for example:

    find_package(wxWidgets COMPONENTS net gl core base)
    if(wxWidgets_FOUND)
        include(${wxWidgets_USE_FILE})
        # and for each of your dependent executable/library targets:
        target_link_libraries(<YourTarget> ${wxWidgets_LIBRARIES})
    endif()

      

This has the advantage of not rebuilding the lib if you rebuild your project, however, it needs some work for its user (they need to handle wxWidgets manually) and for you (you need to set up include paths / compile definitions / ... manually).

Method 2. Embedding wxWidgets

The second option is to link wxWidgets in your repo (svn external or a git submodule) and usually (re) write the CMakeLists.txt of that library for target orientation. Then, in your topmost CMakeLists.txt, you can do the following:

    # for example, if you just need core and net:
    target_link_librairies(my_app PUBLIC wxWidgetsCore wxWidgetsNet)
    # No need to manually setup include dirs, etc...

      

To target CMakeLists.txt, you define include directories and other compilation properties for the target, not the directory. Example:



    # When defining wxWidgetsCore, for example
    add_library(wxWidgetsCore ...)
    target_include_directories(wxWidgetsCore PUBLIC someDir)
    target_compile_definitions(wxWidgetsCore PUBLIC -pedantic)
    target_link_libraries(wxWidgetsCore PUBLIC someLib)

      

The downside to this approach is that restoring your project will restore wxWidgets. It is possible, however, to trick this by not using "rebuild" but "only clean my application and then build". Here's some information on how to achieve this .

Method 3: some kind of hybrid

The big flaw in Method 2 leads to a third approach: don't put wxWidgets in your project, but create a CMakeLists.txt that will "import" the lib. Idea: you ask your user for the directory where wxWidgets is installed, then this script will configure everything for your project. First put CMakeLists.txt here:

    /your-project-root
        /thirdparty
            /wxWidgets
                CMakeLists.txt
    /dir-where-wxwidgets-is-installed
        ...

      

Now you define the imported target:

    # When defining wxWidgetsCore, for example
    set(WX_INCLUDE_DIR ${USER_SPECIFIED_WX_ROOT}/include)
    add_library(wxWidgetsCore IMPORTED GLOBAL)
    set_property(TARGET wxWidgetsCore APPEND PROPERTY
        INTERFACE_INCLUDE_DIRECTORIES ${WX_INCLUDE_DIR})

      

See INTERFACE_INCLUDE_DIRECTORIES and INTERFACE_LINK_LIBRARIES . You need your user to build wxWidgets somewhere on his system, but from your point of view, you just do target_link_libraries(your_app PUBLIC wxWidgets...)

like in method 2. The advantage is that this approach is transparent and interchangeable with method 2, and you don't put the whole dependency in your project.

+2


source


Setting the cppflags and linker flags should be done during CMake, but you try to run wx-config at build time and you still don't collect your output, so yours add_custom_command()

doesn't do anything useful other than printing things on the output of the build tool.

Ideally, you would use a module FindwxWidgets

that CMake already provides. This requires wxWidgets to be built already (but see below). Look CMake documentation for it and see, at least, it seems that you are trying to reach by hand, using wx-config. If you can get FindwxWidgets

to do the job for you, this would be a much cleaner approach.

Getting something to build during customization so that you can use it later in the CMakeLists.txt file is a little trickier. ExternalProject_Add()

loads and builds things at build time, but you need wxWidgets to be created earlier during setup. I recently wrote an article on how to do at least some of the load during setup, and you should be able to adapt it to run the entire build during setup. The article uses Google Test as an example and can be found here:



https://crascit.com/2015/07/25/cmake-gtest/

It would be trivial to get it to create wxWidgets everywhere, anywhere, not just in the scope CMAKE_BINARY_DIR

. This will allow you to create different wxWidgets builds for each build configuration and be able to destroy the application build tree independently of the wxWidgets build.

Hope you point in the right direction.

+1


source







All Articles