views:

442

answers:

8

I have been learning C++ in school to create small command-line programs.

However, I have only built my projects with IDEs, including VS08 and QtCreator.

I understand the process behind building a project: compile source to object code, then link them into an executable that is platform specific (.exe, .app, etc). I also know most projects also use make to streamline the process of compiling and linking multiple source and header files.

The thing is, although IDEs do all this under the hood, making life very easy, I don't really know what is really happening, and feel that I need to get accustomed to building projects the "old fashioned way": from the command line, using the tool chain explicitly.

I know what Makefiles are, but not how to write them.
I know what gcc does, but not how to use it.
I know what the linker does, but not how to use it.

What I am looking for, is either an explanation, or link to a tutorial that explains, the workflow for a C++ project, from first writing the code up to running the produced executable.

I would really like to know the what, how, and why of building C++.

(If it makes any difference, I am running Mac OS X, with gcc 4.0.1 and make 3.81)

Thanks!

A: 

compiler takes a cpp and turns into an object file which contains native code and some information about that native code

a linker takes the object files and lays out an excutable using the extra information in the object file.... it finds all the references to the same things and links them up, and makes and image useful for the operating system to know how to load all the code into memory.

check out object file formats to get a better understanding of what the compiler produces

http://en.wikipedia.org/wiki/Object_file (different compilers use different formats)

also check out (for gcc)

http://pages.cs.wisc.edu/~beechung/ref/gcc-intro.html on what you type at the command line

Keith Nicholas
wish people would leave a comment why they down vote
Keith Nicholas
I am not the downvoter, but I am guessing it could be because the asker said he knew what was being done, but not how to write the Makefile or do the operations on the command line, so you were answering the wrong question.
Justin Smith
The original downvote was because you simply repeated what I said I already knew (what the linker and compiler do). The object file link was not useful and did not help answer my question at all. I did undo the downvote because the gcc link is a very good resource, but still not all I was looking for.
Austin Hyde
Don't be discouraged @Keith, it's just airmiles points. It's the karma that's real. ;)
wilhelmtell
+11  A: 

A simple example is often useful to show the basic procedure, so:

Sample gcc usage to compile C++ files:

$ g++ -c file1.cpp                 # compile object files
[...]
$ g++ -c file2.cpp
[...]
$ g++ -o program file1.o file2.o   # link program
[...]
$ ./program                        # run program

To use make to do this build, the following Makefile could be used:

# main target, with dependencies, followed by build command (indented with <tab>)
program: file1.o file2.o
    g++ -o program file1.o file2.o

# rules for object files, with dependencies and build commands
file1.o: file1.cpp file1.h
    g++ -c file1.cpp

file2.o: file2.cpp file2.h file1.h
    g++ -c file2.cpp

Sample Makefile usage:

$ make                              # build it
[...]
$ ./program                         # run it

For all the details you can look at the Gnu make manual and GCC's documentation.

sth
Very important note for the makefile: tabs are explicitly noted, and are part of the syntax, and are not treated the same way as spaces. This leads to all sorts of headaches - makefiles are best edited in a text editor that can show the difference between a tab and a space explicitly.
Justin Smith
When you build explicitly with g++ in all but the most trivial cases you have to link with g++ too. This as opposed to linking with ld, as you may with C code. The reason is that in C++ the linker must know stuff that only the compiler knows, stuff that isn't normally found in object code. And for this, the C++ compiler needs to talk to the linker. So link with g++, and g++ will call under the hood ld in the appropriate way.
wilhelmtell
+4  A: 

I know what Makefiles are, but not how to write them.

The make syntax is horrible, but the GNU make docs aren't bad. The main syntax is:

<target> : <dependency> <dependency> <dep...>
<tab>    <command>
<tab>    <command>

Which defines commands to build the target from the given dependencies.

Reading docs and examples is probably how most people learn makefiles, as there are many flavors of make with their own slight differences. Download some projects (pick something known to work on your system, so you can actually try it out), look at the build system, and see how they work.

You should also try building a simple make (strip out a bunch of the harder features for your first version); I think this is one case where that will give you a much better grasp on the situation.

I know what gcc does, but not how to use it.

Again, man g++, info pages, and other documentation is useful, but the main use when you call it directly (instead of through a build system) will be:

g++ file.cpp -o name            # to compile and link
g++ file.cpp other.cpp -o name  # to compile multiple files and link as "name"

You can also write your own shell script (below is my ~/bin/c++ simplified) to incorporate $CXXFLAGS so you won't forget:

#!/bin/sh
g++ $CXXFLAGS "$@"

You can include any other option as well. Now you can set that environment variable ($CXXFLAGS, the standard variable for C++ flags) in your .bashrc or similar, or redefine it in a particular session, for working without a makefile (which make does do just fine, too).

Also use the -v flag to see details on what g++ does, including...

I know what the linker does, but not how to use it.

The linker is what takes the object files and links them, as I'm sure you know, but g++ -v will show you the exact command it uses. Compare gcc -v file.cpp (gcc can work with C++ files) and g++ -v file.cpp to see the difference in linker commands that often causes the first to fail, for example. Make also shows the commands as it runs them by default.

You are better off not using the linker directly, because it is much simpler to use either gcc or g++ and give them specific linker options if required.

Roger Pate
+2  A: 

Just to throw this out there, the complete gcc documentation can be found here: http://www.delorie.com/gnu/docs/gcc/gcc_toc.html

Dan
And a pretty good makefile tutorial can be found here: http://mrbook.org/tutorials/make/
Dan
+11  A: 

Compiling

Let's say you want to write a simple 'hello world' application. You have 3 files, hello.cpp hello-writer.cpp and hello-writer.h, the contents being

// hello-writer.h
void WriteHello(void);

// hello-writer.cpp
#include "hello-writer.h"
#include <stdio>
void WriteHello(void){
    std::cout<<"Hello World"<<std::endl;
}

// hello.cpp
#include "hello-writer.h"
int main(int argc, char ** argv){
    WriteHello();
}

The *.cpp files are converted to object files by g++, using the commands

g++ -c hello.cpp -o hello.o
g++ -c hello-writer.cpp -o hello-writer.o

The -c flag skips the linking for the moment. To link all the modules together requires running

g++ hello.o hello-writer.o -o hello

creating the program hello. If you need to link in any external libraries you add them to this line, eg -lm for the math library. The actual library files would look something like libm.a or libm.so, you ignore the suffix and the 'lib' part of the filename when adding the linker flag.

Makefile

To automate the build process you use a makefile, which consists of a series of rules, listing a thing to create and the files needed to create it. For instance, hello.o depends on hello.cpp and hello-writer.h, its rule is

hello.o:hello.cpp hello-writer.h
     g++ -c hello.cpp -o hello.o # This line must begin with a tab.

If you want to read the make manual, it tells you how to use variables and automatic rules to simplify things. You should be able to just write

hello.o:hello.cpp hello-writer.h

and the rule will be created automagically. The full makefile for the hello example is

all:hello
hello:hello.o hello-writer.o
    g++ hello.o hello-writer.o -o hello
hello.o:hello.cpp hello-writer.h
    g++ -c hello.cpp -o hello.o
hello-writer.o:hello-writer.cpp hello-writer.h
    g++ -c hello-writer.cpp -o hello-writer.o

Remember that indented lines must start with tabs. Not that not all rules need an actual file, the all target just says create hello. It is common for this to be the first rule in the makefile, the first being automatically created when you run make.

With all this set up you should then be able to go to a command line and run

$ make
$ ./hello
Hello World

More advanced Makefile stuff

There are also some useful variables that you can define in your makefile, which include

  • CXX: c++ compiler
  • CXXFLAGS: Additional flags to pass to the compiler (E.g include directories with -I)
  • LDFLAGS: Additional flags to pass to the linker
  • LDLIBS: Libraries to link
  • CC: c compiler (also used to link)
  • CPPFLAGS: preprocessor flags

Define variables using =, add to variables using +=.

The default rule to convert a .cpp file to a .o file is

$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $< -o $@

where $< is the first dependancy and $@ is the output file. Variables are expanded by enclosing them in $(), this rule will be run with the pattern hello.o:hello.cpp

Similarly the default linker rule is

$(CC) $(LDFLAGS) $^ -o $@ $(LDLIBS)

where $^ is all of the prerequisites. This rule will be run with the pattern hello:hello.o hello-writer.o. Note that this uses the c compiler, if you don't want to override this rule and are using c++ add the library -lstdc++ to LDLIBS with the line

LDLIBS+=-lstdc++

in the makefile.

Finally, if you don't list the dependancies of a .o file make can find them itself, so a minimal makefile might be

LDFLAGS=-lstdc++
all:hello
hello:hello.o hello-writer.o

Note that this ignores the dependancy of the two files on hello-writer.h, so if the header is modified the program won't be rebuilt. If you're interested, check the -MD flag in the gcc docs for how you can automatically generate this dependancy.

Final makefile

A reasonable final makefile would be

// Makefile
CC=gcc
CXX=g++
CXXFLAGS+=-Wall -Wextra -Werror
CXXFLAGS+=-Ipath/to/headers
LDLIBS+=-lstdc++ # You could instead use CC = $(CXX) for the same effect 
                 # (watch out for c code though!)

all:hello                                   # default target
hello:hello.o hello-world.o                 # linker
hello.o:hello.cpp hello-world.h             # compile a module
hello-world.o:hello-world.cpp hello-world.h # compile another module
    $(CXX) $(CXXFLAGS) -c $< -o $@          # command to run (same as the default rule)
                                            # expands to g++ -Wall ... -c hello-world.cpp -o hello-world.o
Scott Wales
great answer, +1
Paul Nathan
Could you update your answer with what the final Makefile looks like, implementing the rules and variables you mention?
Austin Hyde
@Austin This makefile uses the implicit make rules and links using `gcc`. You can also define your own rules if you need to, check the gnu make manual.
Scott Wales
Your post brought back memory of the olden days.
Yada
A: 

You might also look into Autoproject, which sets up automake and autoconf files, which makes it easier for people to compile your packages on different platforms: http://packages.debian.org/unstable/devel/autoproject

pib
A: 

I like this quirky intro to building a hello world program with gcc, Linux-based but the command-line stuff should work fine on OS/X. In particular, it walks you through making some common mistakes and seeing the error messages.

Holy Compilers, Robin, the darn thing worked!

Andy Dent
A: 

This is what has helped me to learn the autoconf, automake, ...:

http://www.bioinf.uni-freiburg.de/~mmann/HowTo/automake.html

It is a nice tutorial progresses from a simple helloworld to more advanced structures with libraries etc.

fikovnik