Step 1: Project Setup

Read time: 14 minutes (3719 words)

By now you should be aware that every project you create should live in a folder named after that project. Furthermore, that project should immediately be placed under Git management! No exceptions!

Warning

Never take one project and morph it into another one. You may regret that later. You will remember that you did something cool in that first project only to discover you wrecked that project when you moved on. I have every project I wrote during two years in the Texas State CS graduate program (including my thesis project, the biggest Python program I have written!) on a backup HD. It is fun to resurrect some of those and run them again, even after 15 years!

The Project Folder

For this project, you should have already cloned your new repository for Lab2. The result is a new folder named “Lab2-CPU-Factory-username”. Personally, I hate names like that. I would rather keep names short, and to the point. We can fix that:

$ cd cosc2325
$ mv lab2-cpu-factory-username cpu-factory

Git does not care what the project folder name is, it only cares about what is inside of that folder. Furthermore, when you clone something, you can pick some other name by adding that name after the URL:

$ git clone https://githib.com/ACC-COSC2325-003-SP19/lab2-cpu-factory-rblack42 cpu-factory

Now the working repository folder is named cpu-factory.

Let’s write some simple code:

src/main.cpp
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#include <iostream>
#include "version.h"

int main(int argc, char *argv[]) {
    std::cout 
        << "CPU Factory"
        << " Version: "
        << version
        << std::endl;
}

Notice that I placed this code file in a new subdirectory named src. I will use this directory to hold all code that interacts with a human. This is the primary application code, and this is the entry point for our simulator program. In our testing, we will not try to test the complete application. That can be a hard thing to do. We will focus on testing the components of this application. We do not have any of those yet.

Versions

It is very common to include a version number in your project. You have seen this in action: Windows 7, Windows 8, etc. This is the third evolution of this simulator project, so I gave it a version number of “3.0”. Rather than place that in main.cpp, I pulled it out and placed it in a header file.

All header files we create for this project will be stored in a directory named include. That will make it easy to find them later.

include/version.h
1
2
3
4
#include <string>

// current project version number
const std::string version = "3.0";

Test It!

We have written enough code to try running it. Since the code so far is just a minor variation of “Hello, World!” it better run!

$ g++ -o test src/main.cpp
src/main.cpp:2:10: fatal error: 'version.h' file not found
#include "version.h"
         ^~~~~~~~~~~
1 error generated.

Well, that is annoying. We “included” a header file, but the compiler cannot find it. We could fix this by specifying the correct path to that file, but that clutters up the code and makes it hard to change later. Instead, let’s just tell the compiler where to look for it:

$ g++ -o test -I include src/main.cpp

That -I option tells the compiler to look here if it cannot find a header file anywhere else.

Since the compiler exited with no errors, we should be able to run our code:

$ ./test
CPU Factory Version: 3.0

All this proves is that we can build a really simple C++ program. At the very least, that proves that our development tools are properly set up! This is not the kind of testing we want to do, and testing the complete application is not what we will do either.

Too Much Typing

At this point in our project, we are ready for a cool new tool, one that will save you a ton of typing on the command line!

You need to read the notes on using Make one of the oldest and still most powerful build tools in all od programming. There are new contenders to the throne, but understanding Make will make to a better developer.

With that background, this Makefile should not be too scary:

Makefile
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
TARGET = demo
SSRCS	= $(wildcard src/*.cpp)
LSRCS	= $(wildcard lib/*.cpp)
OBJS	= $(SSRCS:.cpp=.o) $(LSRCS:.cpp=.o)
CFLAGS	= -I include -std=c++11

.PHONY: all
all:	$(TARGET)

$(TARGET):	$(OBJS)
	g++ -o $@ $^

%.o:	%.cpp
	g++ -c $(CFLAGS) -o $@ $<

.PHONY: run
run:	$(TARGET)
	./$(TARGET)

.PHONY: clean
clean:
	rm -f $(TARGET) $(OBJS)

Warning

Copy-and-paste at your own peril! The web does not honor tab characters. Make is extremely pick about tabs, so your copied Makefile will not work until you get those tabs back in where they belong. gVim can help you if you edit the file with the right name. gVim knows where tabs belong!

With this file added to your project, you should be able to do this:

$ make clean
rm -f demo src/main.o
$ make
g++ -c -I include -std=c++11 -o src/main.o src/main.cpp
g++ -o demo src/main.o
$ make run
./demo
CPU Factory Version: 3.0

Looks like we have a decent start! Now for some real code!