# Porting a CMake project to qiBuild ¶

## Requirements ¶

This tutorial assumes that you already have a CMake-based project.

We will see how qiBuild can help you writing less code, while staying close to the “official” CMake recommendations when dealing with the  Find<>.cmake  or  <>-config.cmake  files.

In this tutorial, we will use a simple project called  foobar  .

It is pure CMake code, there is a  foo  library, and a  bar  executable linking with the  foo  library.

The sources of the pure CMake  foobar  project can be found here:  foobar_pure_cmake.zip 

Extract the archive in you qiBuild worktree, you should end up with something like:



.qi
|__ qibuild.xml
|__ foobar
|__ CMakeLists.txt
|__ libbar
|__ CMakeLists.txt
|__ bar
|__ bar.h
|__ bar.cpp
|__ foo
|__ CMakeLists.txt
|__ main.cpp



## A standard CMake project ¶

The standard  CMakeLists.txt  files for such a project look like this:

CMakeLists.txt



cmake_minimum_required(VERSION 2.8)
project(foobar)



libbar/CMakeLists.txt



include_directories(".")

bar/bar.hpp
bar/bar.cpp)

install(TARGETS bar
RUNTIME DESTINATION "lib"
ARCHIVE DESTINATION "lib"
LIBRARY DESTINATION "lib")

install(FILES bar/bar.h
DESTINATION "include/bar")



foo/CMakeLists.txt



include_directories("${CMAKE_SOURCE_DIR}/libbar") add_executable(foo main.cpp) target_link_libraries(foo bar) install(TARGETS foo DESTINATION "bin")  ## A few CMake limitations ¶ • You have to specify install rules for every target • If you move the  bar  library to an other directory, you will have to fix  foo/CMakeLists.txt  • You cannot use  foobar  as a subdirectory of a new project (because of the use of  CMAKE_SOURCE_DIR  • You have a standard layout when you install your targets:  <prefix> |__ lib |__ libbar.a |__ bin |__ foo |__ include |__ bar |__ bar.hpp  But it has nothing to do with where targets are in your build directory. (  foo  is somewhere in  build/foo/  and  libbar.a  in  build/bar  ). • If you want to give a  foobar  SDK for someone working with Visual Studio, you will have to make sure  libbar  and  foo  contain a  _d  when there are build on debug (unless you are very careful, you cannot mix debug and release libraries on Visual Studio, so the  _d  is the safest way to do it) • If you want other people to use the  bar  library from an other project, you will have to configure a  bar-config.cmake  looking like:  find_path(BAR_INCLUDE_DIR bar/bar.hpp) find_library(BAR_LIBRARY bar) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(bar DEFAULT_MSG BAR_INCLUDE_DIR BAR_LIBRARY) mark_as_advanced(${BAR_INCLUDE_DIR} ${BAR_LIBRARY})  (and of course create the install rule for the  bar-config.cmake)  • Then, someone willing to use the  bar  library from an other project can do:  find_package(bar) include_directories(${BAR_INCLUDE_DIRS})
target_link_libraries(myexe ${BAR_LIBRARIES})  This assumes that the person has installed the  bar  packaged somewhere CMake can find it. (For instance in  /usr/local/share/cmake/bar-config.cmake  ), or that he sets  -DBAR_DIR  . It the person also happens to have the  foboar  sources built somewhere, it cannot use them... Neither  libbar  or  bar.hpp  can be found by CMake:  bar.hpp  is hidden somewhere in the sources of  foobar,  and  libbar.a  somewhere in the build directory of  foobar,  so it is impossible to use the carefully home-made  bar-config.cmake  , unless you install  libbar  to  /usr/local/lib/libbar.a  for instance. ## qiBuild to the rescue! ¶ The motivation for qiBuild is to help solve this CMake limitations with a clean, easy way, while staying the more compatible possible with other CMake projects. ### Preparation ¶ Add a call to  find_package(qibuild)  file at the root of the project and have it included right after the  project()  line.  cmake_minimum_required(VERSION 2.8) project(foobar) find_package(qibuild)  Note that you somehow have to find the  qibuild-config.cmake  find from you qibuild sources, if  qibuild  is not installed on your system. You can do that by: • Using  cmake -Dqibuild_DIR=/path/to/qibuild/cmake/qibuild  , or: • Create the  qiproject.xml  and use  qibuild configure  which will set the  qibuild_DIR  CMake variable for you. ### Install rules ¶ Replace the  add_library  by  qi_create_lib  , and remove the install rules to use  qi_install_header  instead:  include_directories(".") qi_create_lib(bar bar/bar.hpp bar/bar.cpp) qi_stage_lib(bar) qi_install_header(bar/bar.hpp SUBFOLDER bar)  • The install rules will been properly generated for the library • For the headers, you must choose a subfolder in which to put your headers. (otherwise, it is too easy to have conflicts, especially when you are generating a big SDK.) Unless you have a very good reason not to, please choose the same folder name to put you headers inside your source tree, and once your header is installed. (here, the  bar  argument of  qi_install_header  matches the location of  bar.hpp  :  bar/bar.hpp  ). • A  sdk  directory will be created, with  libbar  in  skd/lib  See also ### Using the bar library ¶ Add the following line in  libbar/CMakeLists.txt  :  qi_stage_lib(bar)  And replace code in  foo/CMakeLists.txt  to have  qi_use_lib(foo bar)  (no need to call  include_directories  or  target_link_libraries  anymore) You should end up with  qi_create_bin(foo main.cpp) qi_use_lib(foo bar)  So what happened? Two versions of the  foo-config.cmake  file have been generated: • The first one is in  build/cmake/sdk/bar-config.cmake  : this one is supposed to be installed. You can see it is only using relative paths to find the library. • The second one is in  build/sdk/cmake/bar-config.cmake  : this one is supposed to be used inside your project: it contains absolute paths only. So, since the layout in  build/sdk  is the same as the layout when the library is installed, and since the  foo-config  file has been automatically generated (along with the install rules), it makes no difference whether you want to find the  bar  library you have just built in the  foobar  project, using the  bar  library you have just built in a other project, or using the installed  bar  library. Finding the  bar-config.cmake  in  foobar/build/skd  from an other project is as easy as:  list(APPEND CMAKE_FIND_ROOT_PATH "/path/to/foobar/build/sdk")  Finding the  bar-config.cmake  once bar has been installed in as easy as:  # No qiBuild required: the installed bar-config.cmake contains # no qibuild-specific code: find_package(bar) include_directories(${BAR_INCLUDE_DIRS})

# Or, still using qibuild:
qi_use_lib(... bar)



Note

We always generate variables in the form <PREFIX>_INCLUDE_DIRS and <PREFIX>_LIBRARIES (all upper case, no version number, plural form)

## Conclusion ¶

This is what the final code looks like when you are done:

CMakeLists.txt



cmake_minimum_required(VERSION 2.8)
project(foobar)
find_package(qibuild)



libbar/CMakeLists.txt



include_directories(".")

qi_create_lib(bar
bar/bar.hpp
bar/bar.cpp)

qi_stage_lib(bar)

SUBFOLDER bar)



foo/CMakeLists.txt



qi_create_bin(foo main.cpp)
qi_use_lib(foo bar)



Less code, so many features !

• You have a nice layout in  build/sdk 
• You can use the newly compiled bar library inside the  foobar  project, outside the  foobar  project, or using an installed  foobar  package with always the same line:


qi_use_lib(foo bar)


• You did not have to write any install rule.
• You did not have to write any  bar-config.cmake. 
• You can build SDK packages for other people to use, even on Visual Studio, without handling all the annoying cross-platform stuff (for instance, on windows, the .dll must be generated next to the .exe otherwise the use has to set %PATH%, and so on...)
• It is still pure, standard CMake code: you did not have to use the qibuild script.
• Absolutely nothing has been generated in the source directory,  build/sdk  only contains the useful, re-distributable binaries (no .o here)

The final project can be found here:  foobar_qibuild.zip