Structure of a multiplatform source tree

Here's a sample directory tree for a product that can be built for two different operating systems (QNX 4 and Neutrino), on two CPU platforms (x86 and ARM):

Figure 1. Source tree for a multiplatform project.

We'll talk about the names of the directory levels shortly. At each directory level is a Makefile file that the make utility uses to determine what to do in order to make the final executable.

However, if you examine the makefiles, you can see that most of them simply contain:

include recurse.mk

Why do we have makefiles at every level? Because make can recurse into the bottommost directory level (the variant level in the diagram). That's where the actual work of building the product occurs. This means that you could type make at the topmost directory, and it would go into all the subdirectories and compile everything. Or you could type make from a particular point in the tree, and it would compile only what's needed from that point down.

We'll discuss how to cause make to compile only certain parts of the source tree, even if invoked from the top of the tree, in the "Advanced topics" section.

Note: When deciding where to place source files, as a rule of thumb you should place them as high up in the directory tree as possible. This not only reduces the number of directory levels to traverse when looking for source, but also encourages you to develop source that's as generic as possible (i.e. that isn't specific to the OS, CPU, or board). Lower directory levels are reserved for more and more specific pieces of source code.

If you look at the source tree that we ship, you'll notice that we follow the directory structure defined above, but with a few shortcuts. We'll cover those shortcuts in the "Advanced Topics" section.