Tutorial MUD, part 1: Environment setup

In this first part of making Tutorial MUD,I will set up the build environment and create a set of makefile that will be used to build the server.

To start things off, you will always find the code in its GitHub repository. Each article here will be having its own tag in the repository, so you can easily follow along the progress in these articles and find the code easily in the repository. Paragraphs and steps in these articles might have intermediate tags, but there will always be a “part-1” or “part-3” tag that will be set for the code at the end of the article.

Directory structure

How to set up the directories might not be high up on the priority list, but it has to be done. For a simple project such as this it will be pretty simple:

  • A root folder, containing a README file, a Makefile and the actual source filder.
  • A source folder, containing all source and header files, and a Makefile to build the source.
  • A library folder, which will contain the world-files and other files used by the server.

If you look in the repository at tag pre-part-1-directories you will see the layout. It’s very simple but still enough to split the source files from the world files.

The first source

The first source file will be the file containing the main function, and it will start out as a basically empty source file. I will also add a master header file, that will be included in all sources in the server. These can be found under the tag pre-part-1-empty-sources.

The source file:

[codesyntax lang=”cpp”]

#include "tm.h"

int main(int argc, char *argv[])
{
}

[/codesyntax]

Header file:

[codesyntax lang=”cpp”]

#ifndef __TM_H__
#define __TM_H__

#endif // __TM_H__

[/codesyntax]

The makefiles

Having just one or two source files, it’s still quite easy to build the project for hand, but our project will contain quite a lot of source files. This is where the command make comes in; It reads a special file, Makefile, and with the help of that can automatically call the commands needed to compile and link a project.

A Makefile has something called targets and dependencies. A target depends on one or more dependencies. Both targets and dependencies are normal files, and make uses the modification time-stamps on the dependencies to check if the target should be built or not. If a target doesn’t exist, or if its modification time-stamp is earlier than those of any of the dependencies, then the commands for that target is executed. A simple rule, as it is called, can look like this:

[codesyntax lang=”make”]

tutorialmud: main.o
	g++ main.o -o tutorialmud

[/codesyntax]

The above snippet tells make that is the file tutorialmud doesn’t exist, or if the file main.o has been modified after tutorialmud, then run the command g++ with the given parameters.

At the moment a Makefile containing the above will be enough to build the project as it is now. However, to support a larger number of files it might be hard to edit the file in several places to add these files, especially if one file has to be removed. It’s very easy to do the change in one place but forget it in another. This is where Makefile variables comes in. You put a list of all object files in a variable, and reference that variable in the rule.

[codesyntax lang=”make”]

OBJFILES = main.o

tutorialmud: $(OBJFILES)
	g++ $(OBJFILES) -o tutorialmud

[/codesyntax]

Using variables is actually good, say we want to change the flags to the compiler or the linker, instead of trying to look for correct rule in the Makefile, just have them all in a variable at the top:

[codesyntax lang=”make”]

OBJFILES = main.o

CXXFLAGS =
LDFLAGS  =

LD       = g++
CXX      = g++

tutorialmud: $(OBJFILES)
	$(LD) $(LDFLAGS) $(OBJFILES) -o tutorialmud

[/codesyntax]

But what about if you want to change the name of the finished program? If we change it in ome place we might forgot to change it in another, so better put that in a variable to.

[codesyntax lang=”make”]

TARGET   = tutorialmud

$(TARGET): $(OBJFILES)
	$(LD) $(LDFLAGS) $(OBJFILES) -o $(TARGET)

[/codesyntax]

As you can see there are variable for the compiler flags (CXXFLAGS) and linker flags (LDFLAGS). Lets put some good to have flags into them.

[codesyntax lang=”make”]

CXXFLAGS = -Wall -Wextra -std=c++0x -pipe -g
LDFLAGS  = -g

[/codesyntax]

Lets have a look at what these flags mean:

  • -Wall add lots of warnings to the build, very good to have to find suspect pieces of code.
  • -Wextra add even more warnings.
  • -std=c++0x tells the compiler to allow new C++11 functionality.
  • -pipe is used to chain the different programs of the compiler into a pipe. The compilation will generally be faster, but will also use more memory.
  • -g is used to add debugging information, very necessary if there is a problem and you need to use a debugger to find it.

The warning options will make the compiler warn us that the parameters argc and argv to the main function are unused. Don’t worry about this warning for now, we will soon start using those arguments.

Now we actually have enough in the Makefile to build the MUD Server, no matter how many source files you add to it. There are some other problems though, like for instance what if you want to clean up the temporary object files? This can of course be done with the rm command (rm *.o), but it is customary to put this in the Makefile as well.

[codesyntax lang=”make”]

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

[/codesyntax]

The above snippet contains two targets: First a target called .PHONY, and the a target to actually remove the object files. .PHONY is used to tell make that its dependencies are not real files. So adding this will stop make from searching for a file called “clean”.

Another problem is that if make is run without arguments, it uses the first target in the Makefile. We can either make sure that the top-most target is always the correct, and add new ones below, or we add a new top-target.

[codesyntax lang=”make”]

.PHONY: default
default: all

.PHONY: all
all: $(TARGET)

[/codesyntax]

The above contains two new targets: First the default top target, and a target named all whose purpose it is to make all other targets. The all target is common in makefiles.

The complete Makefile will look like this:

[codesyntax lang=”make”]

TARGET   = tutorialmud

OBJFILES = main.o

CXXFLAGS = -Wall -Wextra -std=c++0x -pipe -g
LDFLAGS  = -g

LD       = g++
CXX      = g++

.PHONY: default
default: all

.PHONY: all
all: $(TARGET)

$(TARGET): $(OBJFILES)
	$(LD) $(LDFLAGS) $(OBJFILES) -o $(TARGET)

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

[/codesyntax]

Telling git to ignore files

This Makefile works wonderfully, and easily add new files or flags to it. But when you have built your program, and checks the repository status with git status, you will notice it tells you that the object files and the program are untracked. That’s exactly what we want, we don’t want git to track any temporary or generated files, so we need to tell git what files to ignore. This is done with a special file called .gitignore, and should be in the top-level folder of the repository.

[codesyntax]

*.o
src/tutorialmud

[/codesyntax]

The above tells git to ignore files ending in .o and src/tutorialmud.

That’s it for now. If you followed this you should have a small program that run, but is not very interesting, together with a pretty good Makefile to build the program. It can all be found in the repository, with the part-1 tag.

In the next part we shall start writing some functions to log output from the server.

3 Replies to “Tutorial MUD, part 1: Environment setup”

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.