Skip to content

The GCC Command Line – Part 1

July 8, 2011

 

Introduction

The GCC compiler has probably the most complex command line of any tool ever written. There are literally thousands of options available, depending on how you installed and/or built the thing. This article (and the ones that follow) shows you how to use the handful of these many options that you really need for day-to-day C++ and C programming. To follow this article, you will need to have installed GCC – for instructions on how to do this on Windows, see here (if you are on Linux, it’s probably installed already), and be able to use a command line and a text editor.

Note that this tutorial is applicable to both Windows (it was written on Windows), and to Linux and other UNIX-like operating systems, except that I use Windows paths in the examples – Linux users should mentally transpose back-slashes to forward-slashes, and omit drive letters!

Hello World

Let’s start with the canonical C++ “Hello World” program. Fire up a command line prompt, start notepad (or your favourite text editor) and enter this code:

#include <iostream>
using namespace std;
int main() {
    cout << "hello world" << endl;
}

save it as “hello.cpp”, and compile it with the GCC command:

$ g++ hello.cpp

Note from now on I will use ‘$’ to indicate the command prompt – your actual command prompt will almost certainly be something else.

Assuming no syntax errors, GCC will silently compile and link your code. If you look at the directory you are working in, you will find a new file called “a.exe”. This is the executable – you can run it:

$ a
hello world

Hurrah! But why has GCC called the executable “a.exe”? Why not, say, “hello.exe”? Well, years ago, when men were men and beards were beards, UNIX compilers produced an executable output file called “a.out”, because it was the output from the assembler (maybe – history gets a bit hazy here), and the GCC compiler has stuck with it, although on Windows it has to be called “a.exe”. However, most people would like a more meaningful name for the executable, and the first GCC command-line option that people learn is -o, which names the executable:

$ g++ hello.cpp -o hello
$ hello
hello world

Under Windows, there is no need to tack on the “.exe” extension. You could also supply a path, which would write the executable at that path.

GCC is mostly not sensitive to the order of its options (we’ll see later in this series that sometimes it is) and is not sensitive to spaces between the option and it’s parameter. So these are all equivalent:

$ g++ hello.cpp -o hello
$ g++ -o hello hello.cpp
$ g++ -ohello hello.cpp

My personal preference is to make the -o option the very last on the command line.

Remember:

  • Use -o to specify the output executable.

g++ versus gcc

Up until now we have compiled our C++ code with what you may think of as the GCC C++ compiler, called “g++”. What happens if we compile it with what you may think of as the C compiler, which is called “gcc”? Well, you get a lot of error messages:

$ gcc hello.cpp -o hello
C:\Users\neilb\AppData\Local\Temp\cc8IToAX.o:hello.cpp:(.text+0x19): undefined reference to `std::cout'

I’ve actually trimmed all error messages except the first. One thing to notice here – these are not messages from the compiler. Whenever you see “undefined reference” in an error message, it means the error comes from the linker. In other words, GCC has correctly compiled the C++ code in our program, but has failed to link it with the correct C++ libraries. This is because neither “g++” nor “gcc” are really the C++ or C compilers. They are actually drivers for the compiler, the assembler and the linker – you might like to think of them as sophisticated batch programs or shell scripts which manage the whole compilation process. Given a source file, they both do the same thing – if the extension is .cpp, compile it as a C++ file, if the extension is .c, compile it as a C file (you can use other extensions, but don’t). Then, at the link phase, they do something different – g++ links in the C++ libraries, while gcc links in the C libraries. As things like “cout” are in the C++ libraries only, you get the linker errors.

Remember:

  • Always compile C++ programs with g++ and not gcc.

-Wall – the most important option

Let’s modify our hello.cpp program – we’ll keep the same file name:

#include
using namespace std;
int main() {
    int x;
    cout << "x is " << x << endl;
}

if you compile and run this using the command line we’ve used so far, g++ compiles it without complaint, and you get (or at least I get) this output:

x is 2130567168

What has happened in here is that a variable called “x” has been created. As it is an automatic (stack) variable, there is no initialisation to zero, as would be the case if it was a static variable, and we don’t (as we should have done) provide an initialisation:

int x = 0;         // would be right
int x = 42;        // so would this
int x = rand();    // or this, if we really wanted a random value

it ends up containing some random stuff. We then output it, and … at the point we output the uninitialised variable, the program has moved into the realm of what both C++ and C call “undefined behaviour”. When your program is in this realm (from which it is impossible to escape), its behaviour is completely unpredictable. Using an uninitialised variable in any way puts your program into this state. and if you haven’t worked it out by now, we don’t want to be here!

So how to avoid it? Well, the GCC compiler has an awful tendency to assume that the programmer knows what he or she is doing, despite the fact that he or she mostly doesn’t. Instead of turning all warnings about things like uninitialised variables on by default, GCC tends to turn them off. But you can turn them on:

$ g++ -Wall hello.cpp -o hello
hello.cpp: In function 'int main()':
hello.cpp:5:21: warning: 'x' is used uninitialized in this function

Now we get a warning about the uninitialised variable. This is good – we want the compiler to spot every problem, no matter how minor (and this isn’t a minor one), that it can spot.

The -Wall option would appear to warn you about all errors that do not cause compilation to abort. In fact, it only warns about some. There are a lot of other warning options – I recommend you use at least:

$ g++ -Wall -Wextra -pedantic hello.cpp -o hello

Rather than describe in detail what these (and the many other -W options do), I strongly recommend you take a look at the GCC documentation at http://gcc.gnu.org/onlinedocs – if you are serious about using GCC, you really need to read this stuff. However, it’s worth pointing out that the -pedantic option effectively turns off all sorts of GCC extensions that are enabled by default, turning them into warnings or errors. If you intend your code to be at all portable, you should use -pedantic.

Remember:

  • Use -Wall -Wextra -pedantic every time you compile a C++ program

The second article in this series covers how to use GCC to do separate compilation and link with libraries.

About these ads
Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: