How to structure a codebase

Started by
10 comments, last by codingPractices 7 years, 4 months ago

I currently have a folder "C++" and within it a bunch of projects. It looks a little like this (obviously I haven't named them Project1 etc.):

C++

Project1

Project2

Project3

Now this used to work fine up until I started having the need to use a class that I made from another project. I thought of copy-pasting the class but this wouldn't work as if I updated the original class, the copied ones wouldn't be updated. Also, I'd have to guess in which project I made the class in. Then I thought of calling it from the other project itself but then if I were to package the project it wouldn't work as it wouldn't include the classes from external folders (at per my knowledge).

The only other thing I can think of is within my "C++" folder I have a folder named something like "Codebase", where I store all the classes and the like, and another folder called "Projects" or something and keep "Project1", "Project2" etc. in there and call the classes from the codebase (thus solving the problem where I can't find where a specific class I made is). However, again, I don't know packaging the final product would work. How do you, or professionals, people on GitHub etc. do it?

Advertisement

Code shared across projects is what is generally called a 'library'. This might often be managed completely separately and distributed just as a header file and a .lib file, so that you can link it into your own projects without using the source code. Within an organisation, it might be more common to manage each library as a project, and each program brings together a bunch of projects together. (e.g. Visual Studio allows for multiple projects in one solution.)

To begin with, it's usually perfectly fine just to have your shared code in its own directory, and just refer to it from other projects whenever you need to. When it comes to 'packaging' there's usually nothing to consider, because all the relevant code gets compiled into your executable regardless of where the source code came from. With other languages, this isn't necessarily the case, but that's not a problem you have (yet).

This is a problem that pretty much every no-suck revision control system can solve for you.

Import the externals you need from the repo, and there you go. Original is modified and committed, the other projects using it are updated as well. You can (and probably should) make the shared code explicitly a "library", but this is not strictly necessary. It's much nicer, though.

But... you are not using a revision control system? Shame on you. Shame, shame, shame. (No, really... you absolutely want to use one, not just for this purpose.)

1. So when I call the class from another directory it would still be packaged automatically despite the code being somewhere else?

2. How exactly would I tell in "main.cpp" that it's a lbrary?

1. Classes aren't 'called' or 'packaged' in C++. That's not how the language works. The compiler doesn't care where the files live, providing it can find them.

2. This question doesn't make sense. If you're asking "how do I designate a certain part of my code as a library" then that depends what sort of library you're making. At this stage, I don't recommend you attempt to make anything explicitly into a library, and just keep your shared code in a shared directory.

I'm not sure this is an issue where a revision control system helps, but it would complicate matters a lot.

main.cpp


#include "/home/neel/MEGA/Code/Test/OtherProject/MyClass.h"
#include <iostream>
using namespace std;

int main(){
    cout << "come on\n";
    MyClass myClassObject;
    myClassObject.myFunction();
}

It includes the file but when I instantiate it it says "undefined reference to MyClass::myFunction()"

Here's the header and source file included in a different folder:

MyClass.h


#ifndef MYCLASS_H
#define MYCLASS_H

class MyClass{
    public:
        void myFunction();
};

#endif

MyClass.cpp


#include "MyClass.h"
#include <iostream>
using namespace std;

void MyClass::myFunction(){
    cout << "hello bob\n";
}
You need to tell the compiler where to look for include directories. For g++, it looks like you want the -I compiler option.

The #include will locate the header file, but the implementation of the class is presumably in a .cpp file, and that doesn't appear to be referenced in your project. Without that, it can't access the actual code for that class and can't build the final executable.

If you're using Visual C++, ensure both those files are in your project, the header and the source file. If you're using a different compiler, how to do this will differ.

To clarify, I use Gedit and g++ with Terminal (basically I don't use an IDE)

You need to tell the compiler where to look for include directories. For g++, it looks like you want the -I compiler option.

So do I keep all the code the same and then just change the command from Terminal or?

The #include will locate the header file, but the implementation of the class is presumably in a .cpp file, and that doesn't appear to be referenced in your project. Without that, it can't access the actual code for that class and can't build the final executable.

If you're using Visual C++, ensure both those files are in your project, the header and the source file. If you're using a different compiler, how to do this will differ.

Using g++, how would I do this?

Depends on what IDE you are using. With g++ you pass both the directories where libraries can be found (-L (large L)), the directories where header files can be found (-I (large 'i')), and what libraries you want to link against (-l (small 'L' - no, I'm not kidding)).

Most IDEs handle that for you, though - or makefiles.

If you are going to use libraries, make sure they are static not dynamic, and you'll save yourself ten weeks of headaches.

I organize my code like this:


Projects/                                 //(doesn't need to be language specific!)
Projects/StrangerFlames/
Projects/StrangerFlames/Common/           //My "Common" library (a static library). Really needs to be broken up into sub-libraries when I have time.
Projects/StrangerFlames/CommonTests/      //Test cases for Common. Ostensibly.
Projects/StrangerFlames/Engine/           //The game logic itself.
Projects/StrangerFlames/Platforms/          
Projects/StrangerFlames/Platforms/Desktop/                  //Builds the .exe for Win/Mac/Linux PCs.
Projects/StrangerFlames/Platforms/DesktopWithEditor/        //Builds the .exe for Win/Mac/Linux PCs, but includes the built-in Editor.

Ofcourse, Projects/StrangerFlames/ is in a repo (I use Mercurial (aka 'hg') with the free BitBucket service, but git (and the free GitHub service) is more popular).

The common library is under the StrangerFlames repo, but at present I don't mind. If I work on another project, I don't want to be afraid of making changes that'll break StrangerFlames, so I want a full copy of the depedencies as part of the StrangerFlames repo. In the future I'll probably make it be its own repo, though.

This topic is closed to new replies.

Advertisement