Tips for the CS 6410 labs (courtesy of courtesy of MIT's 6.824 class)


Introduction

The CS 6410 labs require you to program C/C++ on Linux/UNIX machines. This document should help you on your way with reading manual pages, compiling C/C++ programs, and understanding Makefiles that we will provide you with.

Finding and reading manual pages

If you need to find information on Unix commands, system calls, configuration files, etc., then man is your friend. For example,

% man socket

gives you the man page for the socket system call. (man man gives you the manual page for man itself.) Note that it may be necessary to specify which section of the manual you wish to read. For example, man read may yield the man page for the wrong read---the shell read rather than the read system call. If this is the case, try man 2 read. In this case, 2 specifies the manual section; there are 8 sections. You can find relevant man pages (and what section they are in) using man -k. For example,

% man -k read

shows a one-line description for each man page that has the word ``read'' in the description.

Compiling and linking simple programs

A compiler takes one or more source files and produces object files that contain machine code. Object files contain machine code and usually have a .o extension. C source files usually have a .c extension and g++ files usually have a .C or .cc extension. Object files may have undefined symbols (names of functions or global variables); linking object files into an executable resolves these undefined symbols. Note that one of the object files must have a main() function to create an executable.

Object files can be linked together to form an executable, provided that one (and only one) of the object files defines a main() function.

An executable is similar to an object file in that it contains machine code, but an executable contains some additional bits that allow the operating system to start the program and run it.

Compiling a source file into the equivalent object file is done using g++ -c. For example:

% g++ -c hello.C -o hello.o

The -c flag indicates pure compilation without linking. Even if hello.C defines main(), the resulting hello.o is not executable. To compile a source file into an executable, omit the -c flag:

% g++ hello.C -o hello

This creates an executable hello. Note that g++ will bark at you if you try to create an executable without a definition of main().

Note that all these examples assume you are compiling g++ files. Use gcc instead of g++ if you are compiling plain old C files.

Multiple object files can be linked together into one executable. Suppose we have the following files:

common.h

#ifndef __COMMON_H
#define __COMMON_H
void hello();
void bye();
#endif // __COMMON_H

hello.C

#include <stdio.h>

#include "common.h"
void hello() {
  printf("hello!\n");
}

bye.C

#include <stdio.h>
#include "common.h"
void bye() {
  printf("bye!\n");
}

main.C


#include "common.h"
int main() {
  hello();
  bye();
}

To turn these files into a working executable, do:

% g++ main.C hello.C bye.C -o hellobye

This compiles main.C, bye.C, and hello.C and links them together into an executable called hellobye. The header file common.h declares---but does not define---hello() and bye() so that the compiler can compile main.C, without knowing the details of their implementation.

Linking is only possible when no two object files try to define C or g++ functions or global variables with the same name. For example, try declaring a variable int foo in both hello.C and bye.C. Compiling each file separately is no problem, but linking fails with a multiple definition of `foo' error. The same is true for functions. Depending on what you want, you can avoid this problem in one of a number of ways:

Using libraries

While doing the CS 6410 labs you probably won't need to create your own libraries, but the Makefile you get from us will cause your files to be linked with some of our libraries. This section gives a quick overview on how to create and use libraries.

You can create a small library using hello.o and bye.o by doing:

% ar cru libhellobye.a hello.o bye.o

This creates a library libhellobye.a. Now we can recompile and relink main.C with this new library.

% g++ main.C -L. -lhellobye -o hellobye

This compiles main.C and links the result with libhellobye.a into an executable called hellobye. The -lname flag tells g++ to search for a library called libname.a. The -Ldir flags tells g++ to add directory dir to the search path when looking for a library. In our case, libhellobye.a is in the current directory, hence -L..

Makefiles

While doing the CS 6410 labs you probably won't need to create your own Makefiles from scratch, because we will give them to you. However, you may need to modify them. This section gives a quick overview of what a Makefile is and how it is used.

A Makefile is used in conjuction with GNU make and describes how different source and header files in a project relate and how to compile and link them. A Makefile usually bears the meaningful name Makefile and its contents are probably roughly similar to this example:

Makefile

hellobye : libhellobye.a main.o
        g++ main.o -L. -lhellobye -o hellobye

libhellobye.a : hello.o bye.o
        ar cru libhellobye.a hello.o bye.o
# this command puts hello.o and bye.o in a library libhellobye.a

hello.o : hello.C common.h
        g++ -c hello.C -o hello.o

bye.o : bye.C common.h
        g++ -c bye.C -o bye.o

main.o : main.C common.h
        g++ -c main.C -o main.o

clean :
        rm -f *.a *.o hellobye

This Makefile has 6 sections. Each section describes a dependency on the first line and some action on the second. A dependency consists of a target file (before the colon) and prerequisite files (after the colon). Lines starting with # are comments.

When you run make, it will execute a target's action if any of the prerequisite files have been modified since the target was last modified. make executes the action in much the same way as if you had typed it to the shell. make only tries to make sure that the very first target in the Makefile is up to date. However, if the first target depends on other targets, make may end up executing multiple actions.

The first section in the Makefile above states that the file hellobye depends on libhellobye.a and main.o. If either libhellobye.a or main.o is newer than hellobye, then hellobye is rebuilt. Building the whole project is now as simple as typing

# make

If you write your Makefile correctly, make will only compile and link those parts of a project that have changed since the last make. If your project is big and the full compile/link process takes a long time, then make is your friend. It saves time.

Notice that the last section in this Makefile is not a real dependency, but allows the user to conveniently call

# make clean

to remove all object files, the library, and the executable.

Makefiles can get pretty complicated, but this introduction should be sufficient for your CS 6410 needs.

Version Control

You may find it useful to keep track of different versions of your work as you progress. A version control system allows you to checkpoint your work and may help you track down regressions in your code. The change log tracked by the VCS can serve to remind you what your intention was in making a particular change days or weeks afterwards.

You can easily install popular version control systems (CVS, Subversion, Git, and darcs) on the EC2 machines (e.g. on debian based distributions like Ubuntu type apt-get install cvs). If you are familiar with one of these systems, you are welcome to use it. If you are interested in learning one, you should be able to start relatively quickly. There are massive amounts of documentation for each of these tools available online.


For questions or comments, contact the TA.
Back to the CS 6410 home.