5

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" ...) .
maddouri
  • 3,737
  • 5
  • 29
  • 51
  • ***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 Feb 02 '15 at 18:08
  • ***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 Feb 02 '15 at 18:13
  • 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 Feb 02 '15 at 18:20

3 Answers3

1

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.

steveire
  • 10,694
  • 1
  • 37
  • 48
1

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.

maddouri
  • 3,737
  • 5
  • 29
  • 51
  • That won't be a good solution when you define multiple targets in one directory. I suggest you look at the docs links I provided. – steveire Feb 07 '15 at 14:55
  • Can you elaborate on why this solution might be problematic, please ? I can see that the *include* path might be *polluted* (i.e. contain unnecessary directories) but that, I think, isn't an issue... is it ? – maddouri Feb 07 '15 at 18:04
  • I've edited my solution to use `target_include_directories()` in order to have per-target include directories. – maddouri Feb 22 '15 at 20:58
1

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)
user1902689
  • 1,655
  • 2
  • 22
  • 33
  • Thank you for answering. I should say that I have improved my solution by "encapsulating" the contents of the `.cmake` property sheets inside functions that take for input the name of the target (I don't have to rely on a global `TARGET` variable anymore). Also, I have made a `add_executable()`-like function that takes care of managing the property sheets' inclusion etc. It has actually some similarities with what you've suggested :) – maddouri May 04 '15 at 18:59
  • If I have time, I'll put my final solution in my public repo or somewhere.. might prove useful for people who, like me, have a local repo of libs and need a quick, 1-line-mechanism for using them in their cmake-based projects... – maddouri May 04 '15 at 19:01
  • That would be great if you could put it up somewhere. I'd be happy to see a better / different solution. – user1902689 May 04 '15 at 19:19