Monthly Archive for July, 2010

Simple C++ project with Make

Once a while some colleague of mine is in deep need of Makefiles for compiling some C/C++ code. Although I normally suggest to use Autoconf/Automake or CMake, not everybody is interested in learning how to use those tools. Furthermore, sometimes is just more handy to start writing the code immediately, instead of writing/copying/modifying configuration files.

So, since I believe I dedicated several hours of my life in explaining the mysteries of GNU Make, I decided to spend some time and showing how Make can be use to automagically compile all you need with no extra time spent in writing the Makefile itself.

How it works

The main idea is that you might want to code a small library in C/C++ and write a few executables that rely on the library. I will describe how a Makefile can be used to automatically compile the library without any need of adding the files one by one to the Makefile itself. Once you have downloaded and uncompressed the archive, you will see the following file layout:

bintemplate/
|-- both.cpp
|-- chicken.cpp
|-- eagle.cpp
|-- lib/
|-- Makefile
`-- src/
    |-- Bird.cpp
    |-- Bird.hpp
    |-- Chicken.cpp
    |-- Chicken.hpp
    |-- Eagle.cpp
    `-- Eagle.hpp

The src/ directory contains all the files that are needed to compile the library, so both the included ones (.hpp) and the non-included ones (.cpp). The lib/ directory will contain the library once it will be compiled.
The small capitals .cpp files are the executables that will be linked against the library.
In this example, the project contains tree C++ classes (Bird.*pp, Chicken.*pp and Eagle.*pp) and tree executables (both.cpp, chicken.cpp, eagle.cpp).

As explained later on, the Makefile will compile automatically in the library all the src/*.*pp files and will compile and link against the library all the *.cpp in the root folder. This means that, if you want to add a new class or a new include, or a new executable, you simply create the file at his place, and you call make. Let’s now see how it is possible.

Makefile

Let’s now take a look at the Makefile itself, chunk-by-chunk.

1
2
3
4
5
6
7
8
9
10
# 2010-07-27  Michele Tavella <tavella.michele@gmail.com>
 
PROJECT=bintemplate
VERSION=v0.0.1
AUTHOR=Michele Tavella <tavella.michele@gmail.com>
 
CC=g++
CFLAGS=-Wall -O2
LDFLAGS=-lm 
CTAGS=ctags -R --c++-kinds=+p --fields=+iaS --extra=+q

The first few lines define the project name and version, the compiler, the compiler options, some libraries we normally want to link against and the parameters to build the tags.

12
13
14
15
LOCAL_PATH=~/Paths/playback
CONFIG_CFLAGS=-I$(LOCAL_PATH)/include
CONFIG_LDPATH=-L$(LOCAL_PATH)/lib
CONFIG_LDFLAGS= -lpthread -lstdc++ -Wl,--rpath -Wl,$(LOCAL_PATH)/lib/

The second block is a little more tricky. I always install libraries, headers etc. in a local folder (LOCAL_PATH). This allows me to have different directories with different releases of one or a set of libraries (this becomes very handy when you work on several projects at the same time). BTW, if you have some libraries installed in some weird place, modify lines 13-14 accordingly, otherwise simply remove whatever is on the right of the “=” character. Line 15 specifies the LDFLAGS needed to link against the correct libraries, in this case libpthread and libstrc++.

17
18
19
20
21
22
SRC=src
LIB=lib
LIB_INC=$(wildcard $(SRC)/*.hpp)
LIB_SRC=$(wildcard $(SRC)/*.cpp)
BIN_SRC=$(wildcard *.cpp)
TARGET_LIB=$(LIB)/$(PROJECT).a

Lines 17-18 define the location of the src/ and the lib/ directories, while lines 19-21 use the Make wildcard command to generate a list of the files required to build the library (src/*.*pp) and the files required to build the executables (*.cpp), as it was discusses in the previous section.

24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
.PHONY: library libraryo binaries binarieso
 
default: library binaries
 
binaries: binarieso $(BIN_SRC:.cpp=)
 
binarieso: $(BIN_SRC:.cpp=.o)
 
library: libraryo
	ar r $(TARGET_LIB) $(LIB_SRC:.cpp=.o)
 
libraryo: $(LIB_SRC:.cpp=.o)
 
%.o : %.cpp
	$(CC) -c $(CFLAGS) $(CONFIG_CFLAGS) -I$(SRC) \
            $(CONFIG_LDPATH) $< -o $@ $(CONFIG_LDFLAGS) $(LDFLAGS) 
 
.o:
	$(CC) $(CONFIG_CFLAGS) $(CONFIG_LDPATH) \
            $*.o -o $* $(TARGET_LIB) $(LDFLAGS) $(CONFIG_LDFLAGS)

To understand this chunk, you need to know a little about Make. The main idea is that we define the targets (phony or not) and the rules needed to first compile the library and then to compile the binaries.

45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
.PHONY: tags install clean info edit
 
clean:
	@echo "[Makefile] Cleaning..."
	@rm -fv $(TARGET_LIB)
	@rm -fv $(BIN_SRC:.cpp=)
	@rm -fv $(BIN_SRC:.cpp=.o)
	@rm -fv $(LIB_SRC:.cpp=.o)
	@rm -fv core*
	@rm -fv vgcore*
	@rm -fv tags
 
install:
	@echo "[Makefile] Running installation"
	@cp -v $(BIN_SRC:.cpp=) $(LOCAL_PATH)/bin
 
tags:
	@echo "[Makefile] Building tags"
	@$(CTAGS) $(LOCAL_PATH)/include/ $(SRC)/ .
 
info:
	@echo "[Makefile] Info:"
	@echo "  Project:   $(PROJECT)"
	@echo "  Version:   $(VERSION)" 
	@echo "  Author:    $(AUTHOR)"
	@echo "  Lib:       $(TARGET_LIB)"
	@echo "  Bin:       $(TARGET_BIN)"
	@echo "  Src:       $(LIB_SRC)"
	@echo "  Inc:       $(LIB_INC)"
 
edit:
	@echo "[Makefile] Editing:"
	@gvim -geom 175x60 -O2 $(LIB_INC) $(LIB_SRC) $(BIN_SRC)

Lines 45-73 define all the phony targets (command, in Make jargon) that I use to make my life easier.

Example

Once you extracted the archive, you can run

make

to compile the libraries and the executables, or similarly you can run:

make clean

to remove all the .o and .a files. Assuming you have GVim and exuberant-ctags installed, you can try to play around with all the other phony targets I briefly discussed above.

Download

bintemplate.tar.bz2 – 2010-07-27

To-do

1. Make phony rules not-phony
2. Improve overall, many important details are missing

Online BCI demo on TED

BCI technology has far to go, and we solvently demo our prototypes for the media or during public events. We know that our prototypes work well, but once we go online in front of the audience, it is the subject that carries on the most complex task (that is, not getting stressed). If things work out of the box, we are generally happy but we are not surprised.

Tan Le is the head of Emotiv Systems, a company that inspires a few doubts among some of my colleagues. She gave a speech on TED:

“Tan Le’s astonishing new computer interface reads its user’s brainwaves, making it possible to control virtual objects, and even physical electronics, with mere thoughts (and a little concentration). She demos the headset, and talks about its far-reaching applications.”

Nothing against Emotiv Systems, but I believe we should be really careful in building up false expectations, specially if the technology is targeting people with disabilities. By the way, she did not promise too much and she demoed some kind of application using mental-state. It is interesting how surprised she was when everything was working more or less properly! Body language sometimes tells you more than what you would think.

On dogs and employees

Back in the days I had a serious problem as a dog owner. The problem was related to the fact that when I was not in my flat, Tito kept jumping and sleeping on the couch. This sucks in several ways. Saliva and hair are usually transferred to your clothes and removing them is incredibly painful. Furthermore, during daytime Tito has to stay home by himself. Tito knew that the couch was forbidden, but guess what happened when I was not home…

By the way, at that time I wrote a dummy Python/OpenCV script to detect brown moving objects (read: dogs) moving on a brighter background (read: the couch). In case of detection, a sound with my voice was played. I have to admit that the thing was working generally well, specially because in a couple of days Tito became really afraid of the couch. I guess the whole trick was done by the dog earing my voice without seeing (smelling?) me.

By the way, this is an example of the detection:

A couple of days ago I was asked by one of my usual contractors if it was possible to use a webcam to detect whether a person is in front of the computer. The whole idea is have a page in the intranet that tells everybody if you are in your office or not. Although I believe that this kind of stuff is generally evil, I started reading this Face Detection using OpenCV howto. It looks like everything is more or less there, so it’s an easy job that can be carried on with the rest.

I will suggest to my contractor to play a track with the voice of the CEO as soon as the employee leaves his computer.