CMake Tutorial to build better biicode projects

Biicode is a C and C++ dependency manager. And uses CMake to configure and build your projects. Hope there are no surprises here!

This post is a CMake Tutorial to understand the basics of generating biicode projects for your usual tools and some tips to make projects multi-os compatible via CMakeLists.txt.

Custom CMake toolchain is now a feature in biicode

Develop as usual

To start, let’s configure a biicode project to work with your usual editor, compiler and IDE.
Execute:

to show a list of CMake generators available in your system, these might be “Eclipse CDT4 - Ninja”, “Unix Makefiles”, “Visual Studio 10”, “Sublime Text 2” or others. Choose yours and tell bii to configure:

Is it an arduino project? Write bii arduino:configure -G “Eclipse CDT4 - Unix Makefiles”

Want to debug? $ bii cpp:configure -D CMAKE_BUILD_TYPE=DEBUG

Use them all together:

Note that bii cpp:configure admits any CMake directives

bii clean to restore default project settings, those are MinGW Makefiles (Windows) or UNIX Makefiles (MacOS and Linux) and no IDE.

Advanced CMake configuration through CMakeLists.txt

It’s usual to have a previous build config in which some parts are shared with biicode and others are specific for the old way out of dependency hell. We’ve developed a way to maintain both ways on your CMakeLists.txt:

And that’s it, as you can see in previous posts , this process is more or less straight forward depending on the library’s complexity: Json11 by Dropbox, Box2D by Erin Catto, Little CMS by Marti Maria or Oscpack by Ross Bencina.

INIT_BIICODE_BLOCK()

This function defines these variables:

  • ${BII_BLOCK_NAME} The name of the current block (e.g. “box2d”)
  • ${BII_BLOCK_USER} The user’s name (e.g. “phil”)
  • ${BII_BLOCK_PREFIX} The directory where the block is located (“blocks” or “deps”)

It also loads variables and  you can use or modify them. Check the default CMakeLists.txt comments to learn more.

ADD_BIICODE_TARGETS()

A CMake TARGET represents each one of the executables or libraries CMake compiles. This function defines these variables:

  • ${BII_BLOCK_TARGETS} List of targets defined in this block
  • ${BII_LIB_TARGET} This is the library biicode builds for each one of the blocks within your project. Just the target library name, usually in the form “user_block”
  •  You can also use directly the name of the executable target (e.g. user_block_main)

10 CMake Tips

#1 Variable declaration

STRING is a basic CMake variable. It can be used as part of any other identificator.
Like the preprocessor, if the var name is enclosed between {} and preceded by $, that expression is equal to the contents of the variable:

As CMake stores the sets as a string where elements are separated by “;”-> MYVAR2 contains the string “element1;element1_name;element3;hello”

#2 Logging to Screen

Fatal error messages interrupt the CMake execution:

#3 Relevant CMake vars

DIRECTORIES

  • CMAKE_CURRENT_SOURCE_DIR: source directory currently being processed
  • CMAKE_CURRENT_BINARY_DIR: binary directory currently being processed
  • CMAKE_RUNTIME_OUTPUT_DIRECTORY: directory being used as IDE run

SYSTEM DESCRIPTION

  • APPLE: True if running on Mac OS X
  • UNIX: True for UNIX and UNIX like operating systems (i.e.: APPLE and CYGWIN)
  • MSVC: True when using Microsoft Visual C
  • WIN32: True on windows systems, including win64
  • MINGW: True when generating MinGW Makefiles
  • CMAKE_SYSTEM_NAME: Name of system cmake is being run on

SDL CMakeLists.txt is a clarifying example of use, take a look at from line 193 and on to see CMake vars in use.

#4 Conditionals

CMake Control Statements have an opening and a closing keyword that must be placed in exclusive lines. Also, CMake commands always have to include “()”

Here’s some common if expressions:

  • if(MSVC)  True if the compiler is visual studio
  • if(NOT APPLE) True if Linux, Windows, …
  • if(WIN32 AND NOT MSVC) True  on MinGW compiler env
  • if(TARGET target-name) True if the given name is an existing target.
  • if(CMAKE_SYSTEM_NAME MATCHES “.*Linux”) true for linux systems
  • if(MINGW) useful for MinGW detection
  • if(UNIX AND NOT APPLE)
      set(UNIX_SYS ON)
    else()
      set(UNIX_SYS OFF)
    endif()   Simple way to differentiate between Apple and UNIX
  • if(MSVC_VERSION GREATER 1600) True for MSVC 12 and more recent versions

#5 Operations with lists

Removing elements from a “;” list:

Or (removing elements from a list)

Remove “UDPwin32.cpp” source file on compilation time:

This one is pretty useful when you don’t want to consider or not a file depending on the OS compiling.

Adding elements to a list

Check if a list contains a value

#6 Setting the directories used by the compiler

Adding an include path to the compiler for the current project.

This syntax is better for directories needed only in compilation phase, not to be reused.

View the directories that are set in the path

Per-target public include directories.

Include the PUBLIC keyword to transitively transmit the directories property to all the targets using the lib. Use it to transmit a public header path.

#7 Set the compile flags used by the compiler

Add a preprocessor definition for the current project

Per-target public/private definitions

On the 3rd point of tip #6, PUBLIC modifier is used to transmit a “include directory” to dependent targets. Here we use the PRIVATE modifier instead with target_compile_definitions so the DO_GNU_TESTS is only used for the specific target compilation, and it is not transmitted to its dependent targets .

Per-target public/private compile flags

Several flags are compiler specific, and are not preprocessor definitions. Use this command for non-standard flags:

#8 Set linker Flags

Setting Windows application linker option

Per-target public/private linker flags and libs

#9 Finding and using external libs

OpenGL example

Boost components example

#10 Copying files

Copying files of some type to the binary and runtime directories

Copying a directory to the binary dir

Hope you enjoy this CMake Tutorial and, as always, we look forward to hear what you think. Just click on the sidebar button to try biicode and check our docs, forum, Stackoverflow tag for questions and answers.


Related Posts