As mentioned in the previous entry, my good buddy Jayson is going to contribute additional programming/technical/geeky articles on the blog. Below is his first such article. Enjoy!
Today’s article is going to be about CMake. I started using this at work recently. It took a bit of time for me to get it working with my setup at work; figuring out how it operates. So I’m here to provide hints so that maybe if you’re starting out using CMake, you can have a better clue as to how to use it.
This guide is going to be generic and assume a gcc development environment; be that MinGW inside Windows or gcc inside Linux.
First and foremost, as their documentation states, you need a CMakeLists.txt file in each directory you’re going to do some compiling in.
For just a simple basic single file application, you would have this as your directory and file structure:
CMakeLists.txt main.c
Now, the CMakeLists.txt file is pretty simple for this:
cmake_minimum_required(VERSION 2.6)
project(mini)
add_executable(mini main.c)
And our main.c file is rather drafty as well:
Now, on a Linux system, this is what I typed at the command line to generate Unix Make files: cmake –G “Unix Makefiles”
The above command will then parse through the CMakeLists.txt file and generate everything needed to build the project. After it completes, all that is needed is to type make at the command line. Actually, from here on out, if you were to add other source files to the project, all you’d need to do is type make. The only time you ever need to run the cmake command directly is the first time you run it. Every other time, you can simply type make.
Now, the above small little project isn’t exactly using anything useful. Most of the time, if you’re doing a project, you’re using other libraries. CMake includes search functions for a lot of libraries. The syntax for searching for each library is fairly similar, so I’m only going to give some examples for a couple[1].
First, we’ll highlight using the wxWidgets library. We’ll start with the structure in the CMakeLists.txt file as to how to search for wx.
cmake_minimum_required(VERSION 2.6)
project(first_wx)
find_package(wxWidgets COMPONENTS base core aui REQUIRED)
include(${wxWidgets_USE_FILE})
set(FIRST_WX_SRC app.cpp)
add_executable(first_wx ${FIRST_WX_SRC})
target_link_libraries(first_wx ${wxWidgets_LIBRARIES})
Now, this is still pretty simple, but I’ve added a few things that I’d like to elaborate upon. First, find_package(). Shipped with CMake are, as mentioned above, some functions to search for popular libraries. To use these, just call find_package() with the library name, some COMPONENTS you’d like to use from the library, and whether those components are REQUIRED. What this does is searches the system for the package, and the sub-components. If it finds them, the components listed are automatically added to the link stage. However, as the code states below the find_package() call, you still need to explicity add the include and link directories. Each library may have different syntax for these variables, so don’t blindly assume they are all the same.[1][2]
Next I add a variable to store the source files in. I just use this as a convenience, so that just in case I use it in multiple places, I only have to type the variable.
Our directory structure is flat, for now:
CMakeLists.txt app.cpp app.h
Our app.h and app.cpp files are simple:
#define __app_file_h_included__
#include “wx/app.h“
class app : public wxApp
{
public:
bool OnInit();
int OnExit();
};
#endif
#include <wx/frame.h>
#include <wx/intl.h>
IMPLEMENT_APP(app)
bool app::OnInit()
{
wxFrame* frame = new wxFrame (0L, wxID_ANY, _(“Hello, World!”));
if (!frame) {
return (false);
}
frame->Show ();
return (true);
}
int app::OnExit()
{
return (0);
}
Now that we have that working, we’ll move on to add boost to our program. We’ll still not have it be very elaborate. We’ll take one of the asio demo’s, so that we can use actual libraries; in addition to some header only stuff.[3]
The layout stays the same, but here’s the modified CMakeLists.txt file:
cmake_minimum_required(VERSION 2.6)
project(wx_boost)
find_package(wxWidgets COMPONENTS base core aui REQUIRED)
include(${wxWidgets_USE_FILE})
set(Boost_USE_MULTITHREADED ON)
find_package(Boost 1.39.0 COMPONENTS date_time thread system)
include(${Boost_INCLUDE_DIRS})
set(FIRST_WX_SRC app.cpp)
add_executable(wx_boost ${FIRST_WX_SRC})
target_link_libraries(wx_boost ${wxWidgets_LIBRARIES} ${Boost_LIBRARIES})
The app.h file was not modified, but here’s the changed app.cpp:
#include <wx/frame.h>
#include <wx/intl.h>
#include <wx/msgdlg.h>
#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
IMPLEMENT_APP(app)
static wxFrame* frame = 0;
void popup(const boost::system::error_cc lang=“c”& /*e*/)
{
wxMessageBox (_(“Pop up!”), _(“Box”), wxOK, frame);
}
bool app::OnInit()
{
frame = new wxFrame (0L, wxID_ANY, _(“Hello, World!”));
if (!frame) {
return (false);
}
boost::asio::io_service io;
frame->Show ();
boost::asio::deadline_timer t (io, boost::posix_time::seconds(5));
t.async_wait (popup);
io.run ();
return (true);
}
int app::OnExit()
{
return (0);
}
So, now that we’ve seen how to implement a couple libraries into an executable, I’ll go through a handy setting for the install() function.
install() is as it states[2], it will install things to the designated locations. When using cmake to build libraries, I found the following to be very handy:
FILES MATCHING PATTERN “*.h“
PATTERN “.svn” EXCLUDE
)
Now, the above will copy all the header files in the directory listing, excluding the .svn directory. Without the exclude, the .svn directory would get copied to the installation path. That will handle include pathing for your own custom library, but the installation of the library itsel would go like this:
install(TARGETS ARCHIVE DESTINATION lib)
This would create a static library [.a|.lib] for your project and then copy it to the lib directory on the DESTINATION path. This path can be set up by setting the following:
[1] The wiki page for Finding Libraries on your system
[2] The official document page for CMake detailing _every_ available call