C++ files organisation

Started by
11 comments, last by BitMaster 9 years, 9 months ago

I have been coding C++ for more than a year now and I just realized that the way I package my project is very different from how all the C++ open source projects package their projects.
Most of the C++ projects package in such a way that it looks like this

project
|_ include
|_ src

while I usually store them in deep folder structures.
project
|_folder A
|_ sub folder A
|_ sub folder B
|_ folder B

When I learn a language, I want to embrace it fully and not just use it like another language. But before I migrate some of my projects, I thought I asked, what are the advantages/disadvantages to doing either way ? I know my way probably came from back when I just started programming and Java has a really deep folder structure. Do anyone do the same as I ?

Check out my blog at zwodahs.github.io and zwodahs.itch.io/

Advertisement

Putting header files into a include folder has the advantage that you have all interfaces to your modules in a single place, like /usr/include and /usr/local/include on UNIX style systems. To make the software available to others, maybe as a library gives you a more simple way to find the header files to the libraries.

But at the end I suspect that it is up to your personal feeling about how to handle header files.

They are not mutually exclusive. You can have a main src or include folder which then branches off into a deep (but not too deep) file tree, with your modules neatly organized in separate files and folders. This is what I tend to do myself. In any case, if you are not designing a library or other code that could be reused by people other than you, I would just use whatever works best for you, such organizational concerns are not usually a major problem except to grumpy packagers used to doing things "their way" smile.png . Probably many of the large open source projects that you have seen have bureaucratic or architectural requirements (by virtue of being very large, or having lots of users and contributors) that would be very inappropriate in a smaller project, so many of the things you see in them would seem very strange from your perspective (though src/include is not really among them, but just saying). I don't think there is a widely accepted standard in C++ anyway, as long as your build system does not grow uncontrollably in complexity underneath you, you should not worry about it too much. C++ doesn't have a universal style guide that almost everybody follows like Java or C# do, far from that.

Some styles I've seen are "headers in include, source code in src", "only public headers in include, private headers and source code in src", "everything in src", "code dump with no folders at all (perhaps with e.g. a visual studio solution which already encodes the folder structure)", and so on... to be fair I do mostly C and not much C++, and I am personally not too comfortable with the idea of putting actual implementation code inside an "include" folder like a lot of the C++ projects seem to be doing with the advent of header-only libraries and templates (yes, I know it's not strictly required if you forward declare the different templated types you'll be using, but few bother to do that). But it's really no big deal - we are not machines, and can adapt when things don't go 100% as we expect. Really, it just goes to show that there is really no consensus on the right way to do it.

In any case, I can give a few insights on what I expect from a freshly checked out code repository:

* as a user (for libraries and other)

- is there an obvious build/install script (e.g. a solution file for visual studio for windows, a makefile or cmake/scons/autohell script for linux, a codeblocks project, etc..)?

- if not, is there a readme or install.txt I can look at?

- no? well, I don't know how to use it, if it's small enough and license permitting I might copy the source and headers inside my own code.. provided I can find them, e.g. an include or src folder

- if not, I give up and check out another library

* as a developer (contributing/etc)

- if the build system is a bit complex or there are things I should know or configuration options, are there notes about that somewhere? (not needed for small programs or obvious instructions e.g. a plain makefile)

- is it easy to build the software after changing code? does it make sure to always rebuild what needs to be (and, preferably, only what needs to be)?

- does it build out of source, or at least doesn't spew .o/.obj files everywhere in the source folder?

- are there tests I can run after making nontrivial changes?

As long as your project package provides these things, I don't see any problem. I've certainly seen far worse and I'm sure others have too.

“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”

Nested source layout seems to have two problems:

1) Includes may have to still be relative i.e #include "../../player/LeftHand.h" which may get a little bit messy and a pain if you decide to move the project structure.
2) At work when we used Unity we had an issue with locating scripts (quickly). A location that makes sense to one person does not to another. We decided to have all game script files in the same directory, all library scripts in their own directory. So much easier.

Note that Visual Studio provides structures in the IDE call "filters". Even though these appear to be nested, they only point to files which are all in the same directory. This may be the best of both worlds.

I recommend nesting source only if they are unique to a lib or .exe such as

mygame
- bin
  - game.exe
- lib
  - libplatform.a
  - libnetcode.a
  - libimageloader.a
- src
  - platform
    - *.cpp *.h
  - game
    - *.cpp *.h
  - netcode
    - *.cpp *.h
  - imageloader
    - *.cpp *.h
And then -Isrc/platform -Isrc/netcode -Isrc/imageloader so that library headers can be included using < >.
http://tinyurl.com/shewonyay - Thanks so much for those who voted on my GF's Competition Cosplay Entry for Cosplayzine. She won! I owe you all beers :)

Mutiny - Open-source C++ Unity re-implementation.
Defile of Eden 2 - FreeBSD and OpenBSD binaries of our latest game.
Personally I'm never putting my headers into a different directory. The only point to do that would be for publishing just the headers for a library I want to publish, but I would rather use CMake or some other build tool to copy the relevant headers from the source directory to a published include directory when needed.

1) Includes may have to still be relative i.e #include "../../player/LeftHand.h" which may get a little bit messy and a pain if you decide to move the project structure.

I would suggest to not include files relative to the location of the source file or whatever, that is just asking for trouble in my opinion. Always include files from a base relative directory (e.g. project root, or more likely the "include" folder) and the problem disappears.

“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”

Using relative includes is a good choice to prevent many -I<include dir> compiler parameters. This way you can go inside a subdir with sources and start the compiler/make in there without thinking about where you are and how your compiler include parameter must look.

But... in fact it is awesome to handle if you move a module around.

Because I use UML with a code generator that produces the include statements I do not think about the positioning. It is always right and works, even if I move around the modules in the model.

Wow that is a lot of feedback :P. Thanks a lot.

I will think about this more before converting my projects.


1) Includes may have to still be relative i.e #include "../../player/LeftHand.h" which may get a little bit messy and a pain if you decide to move the project structure.

I would suggest to not include files relative to the location of the source file or whatever, that is just asking for trouble in my opinion. Always include files from a base relative directory (e.g. project root, or more likely the "include" folder) and the problem disappears.

So instead of relative includes, what would be a good way if I don't want a centralized include folder ?

I have this problem recently when I was reorganizing my files and I need to update quite a few of the includes.

Check out my blog at zwodahs.github.io and zwodahs.itch.io/

I work with oodles of free software projects. I've seen plenty with a separate includes/ directory and many that have them combined. I've seen many with a deep or broad hierarchy and the same with everything dumped into a single subdirectory. Technically it makes no difference and there is no de facto or de jure standard, it's entirely up to the taste of the most vocal or dominant developer.

Since packaging project source inevitably means installing into a staging directory, that isn't relevant. Since installing means copying out of the sources into an installation directory, that's not relevant.

What is relevant is when someone comes along to try and read and understand the code, it's a lot easier when there isn't a separate include/ directory in the project, and the header and other sources files are all combined in one hierarchy. I've noticed the most vocal proponents of the separate include/ hierarchy tend to be those who spend no time maintaining other people's code. There is also no argument that in larger projects readability is improved by namespacing components into separate subdirectories and all include references are relative to the top of the hierarchy. If each component produces a static convenience library (or, if required, a shared library) that also makes your unit testing easier.

Stephen M. Webb
Professional Free Software Developer

Using relative includes is a good choice to prevent many -I<include dir> compiler parameters. This way you can go inside a subdir with sources and start the compiler/make in there without thinking about where you are and how your compiler include parameter must look.


I would avoid relative includes if at all possible and rather use something like CMake to generate my makesfiles then.

This topic is closed to new replies.

Advertisement