CMake's equivalent to Visual Studio's Property Sheets (.vsprops)

1.9k Views Asked by At

I'm trying to migrate from Visual Studio towards Jetbrains' (awesome) CLion IDE which uses CMake to organize the projects.

Until now, the transition has been smooth: creating CMake projects and importing them into CLion is easy, and I can begin coding on one plateform then continue on another one without problems.

However, one aspect of Visual Studio that I couldn't find an equivalent to in CMake is property sheets: I use them mainly for holding the include directories' paths and the linking libs for libraries (i.e. one .vsprops file for each library, e.g. OpenCV.vsprops, Boost.vsprops, etc.).

This way, in VS, I could share a library's .vsprops file between different projects without having to configure the paths/libs each time.

Does CMake have a similar mechanism to Visual Studio's property sheets ? How is it possible to store a library's includes/libs in a CMake-parsable file then "import" it in CMakeLists.txt in order to link against the library ?

Basically, what I want to do is:

  1. Create a "cmake property sheet" (for lack of a better name) for a given library.
  2. Then, in CMakeLists.txt, write something like link_target_to_libs(myTarget "path/to/propertySheet1" "path/to/propertySheet2" ...) .
3

There are 3 best solutions below

3
On BEST ANSWER

Since I really want to make the libraries' inclusion/linking into a one-line command, and as far as my (basic) knowledge of CMake goes, I think that some compromise should be made -- mainly sharing the target name's variable between CMakeLists.txt and the "property sheets". So this is my solution... until someone proposes a simpler/cleaner one:

  1. A CMake property sheet is a .cmake text file,
  2. A well-known variable name --TARGET-- designates the target (i.e. the first argument of add_executable()),
  3. Aside from library-specific commands, a .cmake file contains a call to target_include_directories(${TARGET} PRIVATE ${PATH_TO_INCLUDE_DIR}) and target_link_libraries(${TARGET} ${LIST_OF_LIBS}),
  4. In order to use/link against a library, call include("path/to/.cmake") in CMakeLists.txt.

I have successfully built and executed a simple program that uses X11 and OpenCV with the following files:

x11.cmake

target_include_directories(${TARGET} PRIVATE "/usr/include/X11")
target_link_libraries(${TARGET} "/usr/lib/x86_64-linux-gnu/libX11.so")

opencv.cmake

# OpenCV-specific stuff
set(OpenCV_DIR "/PATH/TO/OPENCV/INSTALL/DIR/share/OpenCV") # path to OpenCVConfig.cmake
find_package(OpenCV REQUIRED)
# include path
target_include_directories(${TARGET} PRIVATE ${OpenCV_INCLUDE_DIRS})
# linking libs
target_link_libraries(${TARGET} opencv_world opencv_ts)

CMakeLists.txt

cmake_minimum_required(VERSION 2.8.4)
project(hello_clion)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")

## hello-clion ##############################
# make a new target name
set(TARGET hello-clion)

# find sources
file(GLOB_RECURSE SOURCE_FILES "src/*.cpp" "src/*.hpp")

# declare a target
add_executable(${TARGET} ${SOURCE_FILES})

# link the libraries (to the last-declared ${TARGET}, which should be the last-added executable)
include("x11.cmake")
include("opencv.cmake")
#############################################

main.cpp

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <thread>

#include <opencv2/opencv.hpp>

#include <Xlib.h>

int main_x11()
{
    // adapted from: http://rosettacode.org/wiki/Window_creation/X11#Xlib
}

int main_ocv()
{
    // adapted from: http://docs.opencv.org/doc/tutorials/introduction/display_image/display_image.html#source-code
}

int main()
{
    using namespace std;

    thread tocv(main_ocv);
    thread tx11(main_x11);

    tocv.join();
    tx11.join();

    return 0;
}

Now, each time I want to use OpenCV in a project/program, I just have to put include("opencv.cmake") in the corresponding CMakeLists.txt.

0
On

In CMake, libraries can export a package with IMPORTED targets which other buildsystems import using find_package:

http://www.cmake.org/cmake/help/v3.1/manual/cmake-packages.7.html

http://www.cmake.org/cmake/help/v3.0/manual/cmake-buildsystem.7.html

http://www.cmake.org/cmake/help/v3.0/manual/cmake-buildsystem.7.html#imported-targets

Instead of 'linking to property sheets', you link to the IMPORTED targets.

target_link_libraries(myTarget Dep1::Dep1 Dep2::Dep2)

Not all libraries create IMPORTED targets, and not all provide cmake config-file packages. In those cases (including OpenCV and Boost), CMake provides find modules:

http://www.cmake.org/cmake/help/v3.0/manual/cmake-developer.7.html#find-modules

which you use with find_package and link to the contents of variables.

3
On

This seems to work great, but there could certainly be problems I haven't discovered. (I was worried multiple macros adding the same target_link_libraries would cause "already defined" linking errors , but at least g++ 5.1.0 handles being given the same library name multiple times without error.)

In root CMakeLists.txt, BEFORE add_subdirectory() calls or globs, include:

macro(USES_WX)
    include_directories(SYSTEM /usr/local/include/wx-3.0)
    include_directories(SYSTEM /usr/local/lib/wx/include/gtk3-unicode-3.0)
    link_directories(/usr/local/lib)
    add_definitions(-D_FILE_OFFSET_BITS=64 -DWXUSINGDLL -D__WXGTK__ -pthread)
    target_link_libraries(${TARGET} pthread wx_gtk3u_xrc-3.0 wx_gtk3u_html-3.0 wx_gtk3u_qa-3.0 wx_gtk3u_adv-3.0 wx_gtk3u_core-3.0 wx_baseu_xml-3.0 wx_baseu_net-3.0 wx_baseu-3.0)
endmacro()

(You can make the macro more fancy, like checking for if CMAKE_BUILD_TYPE is "Debug" or "Release" to link to the appropriate libraries, vary preprocessor definitions, etc. See http://www.cmake.org/cmake/help/v3.0/command/if.html)

And have your project's CMakeLists.txt be like this:

set(TARGET myProgramName)
add_executable(${TARGET} myProgramName.cpp)
USES_WX()

^^ The macro call MUST be after add_executable()


And, if you want multiple target support, modify the line in the root CMakeLists.txt section shown above to:

    ...
    target_link_libraries(${ARGV0} pthread wx_gtk3u_xrc-3.0 ...)
    ...

And have your project's CMakeLists.txt be like this (less lines, but more chance for error):

add_executable(myProgramName myProgramName.cpp)
USES_WX(myProgramName)