5
votes

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
How can I emulate Visual Studio's property sheets (for libraries) in CMake ? You have to generate these yourself using cmake commands to create files.drescherjm
I use them mainly for holding the include directories' paths and the linking libs for libraries I would just use CMake's handling if libraries and include files. Or are you meaning to not create your Visual Studio projects with CMake.drescherjm
I've edited the last part of my post in order to clarify my intentions :) And you are right, I don't want to use VS anymore. I just want to have CMake projects which source code I'm going to edit using CLion.maddouri

3 Answers

1
votes

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.

1
votes

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.

1
votes

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)