aboutsummaryrefslogtreecommitdiff
path: root/README.md
blob: 08793bfd55877106a5beac1763d1e5d5b691a71a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# A Simple C++ Project Structure

One of the things I need is a bunch of blazingly fast [daemons](https://en.wikipedia.org/wiki/Daemon_(computing)) to capture market information and trade data. I prototyped them in Ruby to see what comes down the line, **but I have the need, the need for speed.** Which means I need a UNIX C or C++ framework.

### The Project Folder Tree

**Note:** I’m not making these to go outside my company, so the full GNU C++ standard project is overkill. Much of what follows does conform to the basics of their standard C++ project design though.

If you come from a web development background, and ended up learning C++ for some fortunate reason you must have ended up at this point at some point of time. Now if you are like most authentic coders, you must have started digging to see what experienced coders do to structure their code. Ironically even though C++ is really old and mature, the docs that are available out there are not very appealing to the current generation of coders who have been reading web framework docs which are easy to understand and follow. I don’t know why people have not taken such an initiative for C++. But truth be told, it is **not an easy language to learn.**

![Simple Cpp Folders](/images/simple-cpp-folders.jpg)

In the web, these kind of tasks are usually automated. Third party libraries are also managed and added/removed by package managers ( Something that the C++ ecosystem lacks ). This gives you an opportunity to take full control of your project, and best of all, learn how things work under the hood. I will try to keep things as detailed as possible. There are two things C++ coders are concerned with while working on a massive project —

1. Maintaining a project structure
1. Dealing with third party libraries

In this article we will be concerned with the former. We will also talk about **CMake,** a tool that will be used to bind the project together.

So let us now get to the meat of this article — **The project structure.** After reading a few docs and consulting a few good coders, I have come to an sturdy project structure that shall avoid confusion and should keep your code clean and clutter free. Here is the layout, let us break it down one by one.

```
Project_name
  |
  |---- CMakeLists.txt
  |
  |---- include
  |       |
  |       |---- Project_name
  |                 |
  |                 |---- public_header(s).h
  |
  ---- src
  |     |
  |     |---- private_header(s).h
  |     |
  |     |---- code(s).cpp
  |
  |
  |---- libs
  |       |
  |       |---- A
  |       |
  |       |---- B
  |
  |
  |---- tests
  ```

**Note:** Basically what we are making is a library which you might use directly or might be used as a third party library by some one else. The key idea is to separate the public header files from the private ones, ie. you need to have some kind of control over which functions people using your library can invoke and which ones are strictly from internal use.

**1. include/**

By convention, include directory is for header files, but modern practice suggests that include directory must strictly contain headers that need to be **exposed publicly.** A thing to note here is the use of another directory inside the include directory. What is even more interesting is that it has a name same as that of your project. The reason to do this is to give a sense of specification when someone tries to use your library. Thus to use your library, one has to use the code

`#include <Project_Name/public_header.h>`

instead of

`#include <public_header.h>`

which basically makes it look kind of generalized.

**2. src/**

This directory basically contains all the **source code** and the **header files** that are for internal use only. All the code that you library/project consists of must go in here.

**3. libs/**

This directory consists all the **third party libraries** that are need by your project. Usually if you look into any of the third party libraries present here, they would be following a similar structure that you are using for your project.

A point to note is there are two ways of using third party libraries in C++ — **static** and **dynamic.** This lib directory is only for static ones. We will discuss more on this later in a separate article ( Part 4 of this series).

**4. test/**

As the name suggests, code for unit testing is kept in this directory.

**5. bin/**

The **output executables** go here, both for the app and for any tests and spikes.

**6. build/**

This folder contains all object files, and is removed on a **clean.**

**7. doc/** *or docs/**

Any notes, like my assembly notes and configuration files, are here. I decided to create the development and production config files in here instead of in a separate **config** folder as they “document” the configuration.

**8. spike/**

 I often write smaller classes or files to test technologies or ideas, and keep them around for future.

**9. CMakeList.txt**

This file is basically a configuration file that tells **CMake** what to do. We will talk in detail on CMakeList.txt in Part 2 of this series. Keep in mind that CMake is not a build system, but a build system generator. To understand this statement, you must know the difference between **Make** and **CMake.** We will get to this when we talk about CMake in the next article.

**10. .gitignore**

Since I use **git** for source code control, the **.gitignore** file is:

```
# Ignore the build and lib dirs
build
lib/*

# Ignore any executables
bin/*

# Ignore Mac specific files
.DS_Store
```

**11. Makefile**

I do not need the extra effort or platform independence of [autotools](https://en.wikipedia.org/wiki/GNU_Build_System). These are great for users, but suck up developer time to make them work. Instead, I opted for a simple yet flexible and generic makefile (see notes below):

```
#
# TODO: Move `libmongoclient.a` to /usr/local/lib so this can work on production servers
#
 
CC := g++ # This is the main compiler
# CC := clang --analyze # and comment out the linker last line for sanity
SRCDIR := src
BUILDDIR := build
TARGET := bin/runner
 
SRCEXT := cpp
SOURCES := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT))
OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.o))
CFLAGS := -g # -Wall
LIB := -pthread -lmongoclient -L lib -lboost_thread-mt -lboost_filesystem-mt -lboost_system-mt
INC := -I include

$(TARGET): $(OBJECTS)
  @echo " Linking..."
  @echo " $(CC) $^ -o $(TARGET) $(LIB)"; $(CC) $^ -o $(TARGET) $(LIB)

$(BUILDDIR)/%.o: $(SRCDIR)/%.$(SRCEXT)
  @mkdir -p $(BUILDDIR)
  @echo " $(CC) $(CFLAGS) $(INC) -c -o $@ $<"; $(CC) $(CFLAGS) $(INC) -c -o $@ $<

clean:
  @echo " Cleaning..."; 
  @echo " $(RM) -r $(BUILDDIR) $(TARGET)"; $(RM) -r $(BUILDDIR) $(TARGET)

# Tests
tester:
  $(CC) $(CFLAGS) test/tester.cpp $(INC) $(LIB) -o bin/tester

# Spikes
ticket:
  $(CC) $(CFLAGS) spikes/ticket.cpp $(INC) $(LIB) -o bin/ticket

.PHONY: clean
```

Notes on the Makefile:

* The **TODO** at the top reminds me that I am using a different version of a library in development and it must be removed before deployment.

* The **TARGET** is the main executable of the project, in this case `bin/runner`. Type **make** and this is what gets built.

* I’m using **g++** because it’s the same on Mac OS X and on the production Linux boxes.

* If I uncomment the **clang** line, I get a failed link as the libraries are incompatible (or comment out the last line under **$(TARGET):).** But then I get the benefit of a **clang static** analyzer run help me make my code better, well worth it.

* I use the fewest number of compiler **CFLAGS** when developing as possible, optimization happens later.

* The **SOURCES** list is dynamic, I don’t want to manually have to maintain this list as I program. Anything in the src folder will be included in the compile as long as it has a **SRCEXT** extension.

* The **OBJECTS** list is also dynamic and uses a Makefile trick to build the list based on available sources.

* The **LIB** in this case uses a local library for [MongoDB](https://www.mongodb.com/) as I am testing it, but uses the default [homebrew](https://brew.sh/) or [yum](http://yum.baseurl.org/) installed libraries for boost. I normally do not use boost, but Mongo needs it.

* The **INC** ensures all headers in the **include** folder are accessible.

* I like to see the commands that run, hence the multitude of **@echo's.**

* Since there are so few of them, I manually add spikes and test builds as a new Makefile target, see the **ticket:** target for example.

* The **.PHONY** clean is brilliant, it nukes the build folder and the main executable. It does not clean spike or test executables though.

**Aside: Why separate the includes and the sources?** This is fundamentally not necessary for most of my expected projects as they will be stand-alone daemons. But I do expect to build a few shared libraries for these daemons, and having the **include** files separate makes them easier to deploy later on. So I may as well get into the practice of keeping them separate.

**12. Retro Programming**

So the retro `code-compile-run` loop looks like this:

* Code in TextMate 2.

* ⌘⇥ to a terminal and **make.**

* ⌘⇥ Fix any errors in TextMate 2.

* ⌘⇥ to a terminal and **make** again until it compiles.

Type `bin\runner` params in terminal to run the application. **Tip: Use shell** `!` **expansion:** `!b` alone means that I have to type even less to run the last executable with the same parameter list.

There is nothing fancy about this setup, but that is the whole point. A simple, retro environment for simple retro C++ programs.

Once you understand what CMake does and how all this comes together to generate your final binary, every thing will be crystal clear and you shall have no problem building a new project from scratch.

> “You can’t trust code that you did not totally create yourself” — Ken Thompson