A simple CMake project

I’ve try to build a small Visual Studio project with CMake, before i will explain the basic principles of CMake itself.

Below you can see one of the simplest cmake files you can write.

cmake command required description
cmake_minimum_required yes This command define the minimum version of CMake which you want to use. If've recommend CMake 3.x
 project no this is (in visual studio context) the name of the solution
 add_library no This command create a target call HelloWorldLibrary, which is a static lib/dll project with the same name in our solution
 add_executable no This command create a target called HelloWorldApp which is a exe project in our solution (you get it, with the same name 🙂
 target_link_libraries no Here we link our HelloWorldApp with our HelloWorldLibrary, because we want to use some function from the library in our exe

So you can use this snippet, copy it and paste it into a file which you should name CMakeLists.txt.

  1. Create a directory
  2. Create a file named CMakeLists.txt
  3. Copy/Paste the code from above
  4. Add the missing code files (main.cpp, etc), all in the same directory
  5. Now you have 2 options to create your visual studio project in Windows (i prefer the console approach)
    1. Use the CMake Gui application
      Open the app, choose the source-directory and binary directory. Click on generate an choose the compiler (Visual Studio) version which is installed on your system. Be aware that that you have to choose between win64 and win32. In my example i choose the so call generator Visual Studio 10 2010 Win64. Now you will see an console output in the bottom section of the window. If something went wrong, please read the error messages in the console output section. If everything is fine, you can navigate (f.e. with the Windows explorer) to your binary directory and open your new Solution file, named after your project name, in my example MySolutionName.sln. Then you can compile it normally with Visual Studio
    2. Use the command prompt/console
      Here we need the same paramters as in the Gui approach, but in a console fashion.
      You should cd into your source directory and use the following command line parameters
      cmake -B<path to binary directory> -G “Visual Studio 10 2010 Win64”
      If you dont want to cd into your source-directory you could also use the paramter: -H<path to your source directory>
paramter description
Source directory the directory where your CMakeLists.txt lives
Binary directory the directory where your binaries, visual studio project files and some additional files will go.These files are temporary and should not be checked in to your repository! 

What is a target?

If you are starting with CMake you relatively often use a target, but what the heck is a target?

If you are coming from Visual Studio, a target is a Visual Studio project (*.vcxproject), so if your target is named MyAwesomeApp, your Visual Studio project will also be named MyAwesomeApp. The target concept is based on the principle of makefile targets (as many other things in CMake). A target is generally an entry point, something like a void main() function for your application, but you can have as many as you want.

The target is also the only type in cmake which not act like a string, but i will explain the in a later post.

Things I want to know before I started with CMake

In this blog series i will show some tipps and tricks about cmake, which i want to know before i started with CMake.

My CMake experience

I’ve start using CMake approximately 2 years ago. I’m only developing software for Microsoft Windows with Visual Studio (most of the time VS 2010 x64) and using the build-in project management from Visual Studio. But with the growing size of my project Visual Studio’s mouse-click/declarative approach was very painful and inflexible (supporting multiple Visual Studio/VC++ version at the same time is nearly impossible or rather unmaintainable and that’s only one big point), and so i decide to checkout some build-systems. I quickly realized that the most used one is CMake. But at that time i did not really understand why most C and C++ developer are using it and if it is a good decision for a Windows only project to switch to CMake.
Long story short, switch to CMake, it doesn’t matter how big or small your project is or if it is a Windows-only project (or another single-OS project).
Don’t understand me wrong, CMake is not perfect, it has it’s cons, but the benefits are to huge to ignore.

What is CMake?

CMake is a buildsystem/script language which helps you to build your project. CMake is mainly used for C an C++ project at any size and is the de facto standard build system (starting with 3.8 it will also support C#). It is a platform independent language an run on many OS’s like Windows, MacOS, Linux, …

So what can i do with CMake?

Lots of stuff. You can use it for building your project, but you can also use it for packaging your app too (CPack) which support a wide range of package formats from zip to WiX toolset. CMake can generate makefiles, Visual Studio files, XCode, …., so your code is mainly independent of your used platform (OS specific build system) and you can switch between different compiler versions easily. You can download file, clone git repos etc..

What could you expect from the blog series?

I will start with an overview and will port a Visual Studio project to cmake. The following articles will more focus on tipps, tricks and hints and some coding examples.

If you have any wishes or suggestions, please contact me.

Why every C++ developer should know about the pimpl idiom pattern

If you build a library in C++ and make it available for other people you should know about pimpl idiom. This pattern make it possible to encapsulate your real implementation from your API (and won’t break binary compatibility ABI).

So what is the problem about the “normal” C++ code?

If you build an API class (which can be used by the consumer of the library) you should first think about binary compatibility. Every binary-break is hard and frustrating for the consumer because he/she has to recompile the hole source code because you have break the compatibility. Adding new functions to an “normal” C++ code could be a hard job if you want (and you should) to keep binary compatibility. Most developer does not know that adding or delete private member can also break ABI as changing public functions/members. If you are new in creating C++ API you should read some books/blogs about creating good API (i prefer this book) – but if you don’t want to read a hole book, you could read this blog-post 😉

So the question is:
How can i design a class which is binary compatible as much as possible?

One (and most used) technique in C++ is Pimpl idiom (“pointer to the implementation”). It is simple but extrem effective. It is based on two facts:

  • a pointer to an object has always the same size (on the same compiler-version and platform)
  • class-forwarding make it possible that you don’t have to include the header-file for the forwarded class

So a API class has two parts

  • The API-methods (in your class)
  • The Pimpl idiom class (a private  pointer to the instance) which holds the real implementation

class MyClass
{
public:
MyClass();
˜MyClass();
void MyPublicFunction(int num);
private:
class Impl;
Impl* _Impl;
};

 

// first class is our pimpl idiom class
class MyClass::Impl //the pimpl class is a nested class because we don't want that the user can reuse this class
{
public:
void MyImplFunction(int num)
{
Num = num;
}
int Num;
}

// the API class
MyClass::MyClass():
_Impl(new Impl())
{}
MyClass::˜MyClass()
{
if(_Impl)
{
delete _Impl; // don't forget to delete the pimpl-object
}
}
void MyClass::MyPublicFunction(int num)
{
_Impl-&gt;MyImplFunction(num);
}

Now it is possible to add/change methods and members to the Impl-class without being afraid breaking binary-code of the API-class because the Impl is always a pointer (same size). You can also switch the complete backend-code (f.e. use another class as pimpl class)!

If you have an C++ 11 compiler (or use boost or Qt) you can use a unique/shared pointer around you pimpl idiom class => so you don’t need to delete your object yourself which makes that code much cleaner and safer.


#include &lt;memory&gt; // required for std::unique_ptr
class MyClass
{
public:
MyClass();
˜MyClass(); // if you use a uniqued_ptr you have declare an Destructor
void MyPublicFunction(int num);
private:
class Impl;
std::unique_ptr&lt;Impl&gt; _Impl;
};

When you use Pimpl idiom you have to think about one thing => the copy constructor. If you don’t override the copy-constructor, C++ will only make a copy of the pointer-address and not a clone of the hole object behind this pointer. This can lead into a big problem. You can have multiple object which refers to the same object. If you delete all your object it will crash because the first delete is ok, but a second delete will not work because the object is already deleted!
So you have two options:

  • You can implement a copy-constructor to make a good copy
  • You can disable the copy-constructor (make a little google search if you need that) so nobody can make a copy

In C++ 11 there is a little benefit about disabling the copy-constructor. The unique_prt will throw an compile-error if you try to copy it => so the copy-constructor is disabled by default if you use unique_prt.

If you use a naked pointer or the shared_prt-template you have to implement the copy-constructor yourself to avoid problems!

One little note about using std::unique_prt as a member: You need to define the destructor yourself. The deconstructor could be empty!

Pros:

  • Hide the private part of the class
  • The binary compatibility ABI isn’t broken if you change something in the pimpl idiom class
  • Lesser header dependencies => because most header now only needs to be in the *.cpp
  • Faster compilation times

Cons:

  • The pimpl idiom could slow down your code (because there is always a pointer access) but there are some technique to speed up a pimpl idiom
  • Extra heap-allocation
Posted in C++