Category: tutorial


Hello everyone,
My previous post explained how CMake could manage a simple project (containing only one definition and implementation file).  Now we can have a look at a complex project, containing a common shared library, examples and unit tests. In this case, instead of a dumb HelloWorld project, I’ve chosen the Itemviews-NG project, which is an experimental project hosted by the Qt Labs and currently uses qmake as build system. The project itself consists of the following:

  • A common shared library containing the base classes;
  • A collection of examples for each class from the library;
  • A collection of unit tests for each class from the library;

NOTE: Documentation won’t be created for now – Itemview-NG uses qdoc to generate documentation, which AFAIK isn’t well integrated with CMake yet. There will be another post about using doxygen with CMake, together with lcov coverage and gcov HTML output integrated.

As a starting point, the project itself contains various files which needs to be processed by the MOC. To simplify this process, CMake can use the automoc tool which automagically finds the required files to be preprocessed and includes them at the target build. Qt libraries and includes are also provided by the Qt4 cmake package (built-in). To use Qt4 plus automoc cmake packages, you can include the following code on the CMakeFiles.txt located at the project’s root directory:

# Qt4 package is mandatory
find_package(Qt4 REQUIRED)
include(${QT_USE_FILE})
 
# Automoc4 is also mandatory
find_package(Automoc4 REQUIRED)

Now let’s see how the CMakeFiles.txt from the src/ directory changes:

set(CMAKE_INCLUDE_CURRENT_DIR ON)
 
# Create a variable containing a list of all implementation files
file(GLOB itemviews-ng_SOURCES *.cpp)
 
# The same applies for headers which generates MOC files (excluding private implementation ones)
file(GLOB itemviews-ng HEADERS *[^_p].h)
 
# Now the magic happens: The function below is responsible for generating the MOC files)
automoc4_moc_headers(itemviews-ng ${itemviews-ng_HEADERS})
 
# Creates a target itemviews-ng which creates a shard library with the given sources
automoc4_add_library(itemviews-ng SHARED ${itemviews-ng_SOURCES})
 
# Tells the shared library to be linked against Qt ones
target_link_libraries(itemviews-ng ${QT_LIBRARIES})
 
# Installs the header files into the {build_dir}/include/itemviews-ng directory
install(FILES ${itemviews-ng_HEADERS} DESTINATION include/itemviews-ng)
 
# Installs the target file (libitemviews-ng.so) into the {build_dir}/lib directory
install(TARGETS itemviews-ng LIBRARY DESTINATION lib)

Now every example or test from the project which uses that library could use the target itemviews-ng as a link dependency. As each examples and tests are compiled in a similar way, we can use functions which eases the compilation process. Below is an example of those functions:

function(example example_NAME example_SOURCES example_HEADERS)
automoc4_moc_headers(${example_NAME}_example ${examples_HEADERS})
# The third argument (resource files) is optional:
set(example_RESOURCES ${ARGV3})
if(example_RESOURCES)
    automoc4_add_executable(${example_NAME}_example
        ${example_SOURCES} {example_RESOURCES})
else(example_RESOURCES)
    automoc4_add_executable(${example_NAME}_example
        ${example_SOURCES})    endif(example_RESOURCES)
    target_link_libraries(${example_NAME}_example itemviews-ng
       {QT_LIBRARIES})
endfunction(example)
 
function(test test_NAME test_SOURCES)
set(test_RESOURCES ${ARGV2})
if(test_RESOURCES)
    automoc4_add_executable(${test_NAME}_test
        {test_SOURCES} ${test_RESOURCES})
else(test_RESOURCES)
    automoc4_add_executable(${test_NAME}_test
        ${test_SOURCES})    endif(test_RESOURCES)
    target_link_libraries(${test_NAME}_test itemviews-ng
        ${QT_LIBRARIES})
include_directories(${itemviews-ng_BINARY_DIR}/tests/${test_NAME})
add_test(${test_NAME} ${test_NAME}_test)
add_dependencies(check ${test_NAME}_test)
endfunction(test)

The functions above can be inserted into a .cmake file (eg: InternalMacros.cmake) that goes into cmake/modules directory. To load it, put the following line inside CMakeLists.txt from the root directory:

include(InternalMacros)

Now you can create a CMakeLists.txt for each example like this:

set(mycustomexample_SOURCES mycustomexample.cpp main.cpp )
set(mycustomexample_HEADERS mycustomexample.h )
 
example(mycustomexample "${mycustomexample_SOURCES}" "${mycustomexample_HEADERS}")

The same applies for tests:

test(mycustomtest "${mycustomtest_SOURCES}")

I’ve made a branch cmake at my personal gitorious itemviews-ng clone. You can have a look at it to see how does the code explained above behaves.

Hi!
After a long period of abstinence from blogging (mainly because I was freaking my head out with internal work), I’m going to share my achievements on learning how to use CMake. I must confess as a previous autotools (aka. auto-hell) and qmake user I got a little bit biased about CMake, but after looking at a few examples and reading some documentations I’ve found that it is way easier to learn and use than the previous build systems I’ve used. Basically, CMake uses a series of macros and functions which finds the required components for you, in a simple and precise way – this means no unnecessary dependencies!
As an example, I’ve found a very useful macro called MacroOutOfSourceBuild, which requires the user to build the source code outside the source code directory (build directory != source directory). This ensures the user uses a shadow build directory, which is a very good practice, by the way. Enough of talking, let’s have a look at some code examples. Suppose you have a small project “Hello World” (download source code here) which has its source files arranged like the diagram below:

helloworld/
  \_ CMakeLists.txt
  \_ cmake/
    \_ modules/
      \_ MacroOutOfSourceBuild.cmake
  \_ src/
    \_ CMakeLists.txt
    \_ main.cpp
    \_ helloworld.cpp
    \_ helloworld.h

In the case above, the files helloworld.cpp, main.cpp and hello.h are located inside the src/ directory, which is itself located on the project’s root directory. CMake states that each project directory (including recursive sub-directories) which contains source code should have a fille called CMakeLists.txt, which contains the build instructions for each directory. As the “Hello World” project does have two directories (root directory plus src/ directory), then two CMakeLists.txt files are created (shown below):

  • CMakeLists.txt – root directory:
# Project name is not mandatory, but you should use it
project(helloworld)
 
# States that CMake required version must be >= 2.6
cmake_minimum_required(VERSION 2.6)
 
# Appends the cmake/modules path inside the MAKE_MODULE_PATH variable which stores the
# directories of additional CMake modules (eg MacroOutOfSourceBuild.cmake):
set(CMAKE_MODULE_PATH ${helloworld_SOURCE_DIR}/cmake/modules ${CMAKE_MODULE_PATH})
 
# The macro below forces the build directory to be different from source directory:
include(MacroOutOfSourceBuild)
 
macro_ensure_out_of_source_build("${PROJECT_NAME} requires an out of source build.")
 
add_subdirectory(src)
  • CMakeLists.txt – src/ directory:
# Include the directory itself as a path to include directories
set(CMAKE_INCLUDE_CURRENT_DIR ON)
 
# Create a variable called helloworld_SOURCES containing all .cpp files:
set(helloworld_SOURCES helloworld.cpp main.cpp)
 
# For a large number of source files you can create it in a simpler way
# using file() function:
# file(GLOB hellworld_SOURCES *.cpp)
 
# Create an executable file called helloworld from sources:
add_executable(helloworld ${helloworld_SOURCES})

Now you create a shadow build directory (eg. build/) and build your project, as shown with the commands below:

$ mkdir build
$ cd build
$ cmake ..
$ make

That’s it! This finishes the first part of a series of useful tips about using CMake as the build system from basic to complex projects. If you need further information, please have a look at the tutorial website.

Hi again,
Since my previous post, we’ve been using the QAnimationState class together with the convenience method addAnimateTransition() to get animated transitions between states. Now the API’s got even cleaner and easier to understand, you don’t have to use a special state in order to associate animated transitions to it any longer ;) I’ve updated the Qt’s documentation about the animation framework, you can read it below:Animations and States

When using a state machine, we can associate an animation to a transition between states using a QSignalTransition or QEventTransition class. These classes are both derived from QAbstractTransition, which defines the convenience function addAnimation() that enables the appending of one or more animations triggered when the transition occurs.

We also have the possibility to associate properties with the states rather than setting the start and end values ourselves. Below is a complete code example that animates the geometry of a QPushButton.

QPushButton *button = new QPushButton("Animated Button");button->show();
 
QStateMachine *machine = new QStateMachine;
 
QState *state1 = new QState(machine->rootState());
state1->assignProperty(button, "geometry", QRect(0, 0, 100, 30));
 
machine->setInitialState(state1);
 
QState *state2 = new QState(machine->rootState());
state2->assignProperty(button, "geometry", QRect(250, 250, 100, 30));
 
QSignalTransition *transition1 = state1->addTransition(button,SIGNAL(clicked()), state2);
transition1->addAnimation(new QPropertyAnimation(button, "geometry"));
 
QSignalTransition *transition2 = state2->addTransition(button,SIGNAL(clicked()), state1);
transition2->addAnimation(new QPropertyAnimation(button, "geometry"));
 
machine->start();
You can find the most up-to-date documentation about the Animation Framework and State Machine framework here: http://doc.trolltech.com/4.6-snapshot/index.html

Sending patches using git-email

If you work on a project that uses GIT as repository, you should probably need a simple way to send your patches to others in a simple, clean way. For this, I’ve started (for a while now) using a very cool tool called git-send-email. For Ubuntu users, It is available on the git-email package (sudo apt-get install git-email) and provides a way to send patches through email to others. See HOWTO below:

  1. Install ‘git-email’ package:
  2. $ sudo apt-get install git-email
  1. Add these options to ~/.gitconfig:
  2. [sendemail]
    smtpserver = "yourmailserver.com"
    smtpuser = "user"
    smtppass = "abc123"
  1. Now suppose you have a local patch that needs reviews/acks. Pick up
    its hash with ‘git log -n 2′:
  2. $ git log -n2
    commit a268d86e547dffe73c9f7b4633913ffdf91b1a8e[..]
    commit bf14b2f140fc84a57f61c7f59efae294b2a9a1df[..]
  1. Pick up commit hashes and create a formal patch file using ‘git format-patch -C ..’:
  2. $ git format-patch -C bf14b2f140fc84a57f61c7f59efae294b2a9a1df..a268d86e547dffe73c9f7b4633913ffdf91b1a8e

    A new file 0001-COMMIT-SOMETHING.patch is now created. Note: If you want to pick the last patch you’ve commited locally, you can easy this step by doing the following:

    $ git format-patch -n

    Where n is the number of last patches you want to pick (e.g. 1).

  1. Almost there! Now send your patch to mail list using ‘git send-email’:
  2. $ git send-email --to "mail@list.com" 0001-COMMIT-SOMETHING.patch

Done!

Sending patches using git-email

If you work on a project that uses GIT as repository, you should probably need a simple way to send your patches to others in a simple, clean way. For this, I’ve started (for a while now) using a very cool tool called git-send-email. For Ubuntu users, It is available on the git-email package (sudo apt-get install git-email) and provides a way to send patches through email to others. See HOWTO below:
  1. Install ‘git-email’ package:
  2. $ sudo apt-get install git-email
  1. Add these options to ~/.gitconfig:
  2. [sendemail]smtpserver = "yourmailserver.com"smtpuser = "user"smtppass = "abc123"
  1. Now suppose you have a local patch that needs reviews/acks. Pick up
    its hash with ‘git log -n 2′:
  2. $ git log -n2commit a268d86e547dffe73c9f7b4633913ffdf91b1a8e[..]commit bf14b2f140fc84a57f61c7f59efae294b2a9a1df[..]
  1. Pick up commit hashes and create a formal patch file using ‘git
    format-patch -C ..‘:
  2. $ git format-patch -C bf14b2f140fc84a57f61c7f59efae294b2a9a1df..a268d86e547dffe73c9f7b4633913ffdf91b1a8e

    A new file 0001-COMMIT-SOMETHING.patch is now created. Note: If you want to pick the last patch you’ve commited locally, you can easy this step by doing the following:

    $ git format-patch -n

    Where n is the number of last patches you want to pick (e.g. 1).

  1. Almost there! Now send your patch to mail list using ‘git send-email’:
  2. $ git send-email --to "mail@list.com" 0001-COMMIT-SOMETHING.patch

Done!

Hi again!
I finally got time to upgrade my personal laptop (Acer 3050 series) to Ubuntu Hardy (was Edgy). On Edgy I was using ndiswrapper in union with Atheros AR5BXB63 Windows XP driver in order to get wi-fi working.
Now, on Ubuntu Hardy, I’ve found a way to get it running using madwifi! By default, Ubuntu Hardy recognizes the wi-fi card but it doesn’t get it working, so we need to compile and install a modified madwifi snapshot containing AR5007 models support.

Procedures are below:

1. Go to System > Administration > Hardware Drivers

2. Disable the following options:

  • Atheros Hardware Access Layer (HAL)
  • Support for Atheros 802.11 wireless LAN cards.

3. Reboot your system

4. After reboot, open a terminal and issue the following:

$ sudo apt-get install build-essential$ wget http://snapshots.madwifi.org/special/madwifi-ng-r3366+ar5007.tar.gz$ tar xfz madwifi-ng-r3366+ar5007.tar.gz$ cd madwifi-ng-r2756+ar5007$ make$ sudo make install$ sudo modprobe ath_pci

Update: For updated releases please visit http://snapshots.madwifi.org/special

5. Done! If everything went well, your wi-fi is ready to use! In order to verify it, you can issue the following:

$ ifconfig wifi0wifi0     Link encap:UNSPEC  HWaddr 00-19-7E-3F-59-55-00-00-00-00-00-00-00-00-00-00      UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1      RX packets:12151 errors:0 dropped:0 overruns:0 frame:1786      TX packets:2676 errors:0 dropped:0 overruns:0 carrier:0      collisions:0 txqueuelen:199      RX bytes:3036377 (2.8 MB)  TX bytes:407225 (397.6 KB)      Interrupt:18

See you on next tutorial! Thanks to UbuntuGeek for helping me out with this!

Powered by WordPress | Theme: Motion by 85ideas.