C Program Compilation steps & Example with GCC Linux

GCC (GNU Compiler Collection)

1. A Brief History and Introduction to GCC

GCC, formerly for “GNU C Compiler”, has grown over times to support many languages such as C (gcc), C++ (g++), Objective-C, Objective-C++, Java (gcj), Fortran (gfortran), Ada (gnat), Go (gccgo), OpenMP, Cilk Plus, and OpenAcc. It is now referred to as "GNU Compiler Collection". The mother site for GCC is http://gcc.gnu.org/. The current version is GCC 7.3, released on 2018-01-25.

GCC is a key component of so-called “GNU Toolchain”, for developing applications and writing operating systems. The GNU Toolchain includes:

  1. GNU Compiler Collection (GCC): a compiler suite that supports many languages, such as C/C++ and Objective-C/C++.
  2. GNU Make: an automation tool for compiling and building applications.
  3. GNU Binutils: a suite of binary utility tools, including linker and assembler.
  4. GNU Debugger (GDB).
  5. GNU Autotools: A build system including Autoconf, Autoheader, Automake and Libtool.
  6. GNU Bison: a parser generator (similar to lex and yacc).

GCC is portable and run in many operating platforms. GCC (and GNU Toolchain) is currently available on all Unixes. They are also ported to Windows (by Cygwin, MinGW and MinGW-W64). GCC is also a cross-compiler, for producing executables on different platform.

GCC Versions

The various GCC versions are:

  • GCC version 1 (1987): Initial version that support C.
  • GCC version 2 (1992): supports C++.
  • GCC version 3 (2001): incorporating ECGS (Experimental GNU Compiler System), with improve optimization.
  • GCC version 4 (2005):
  • GCC version 5 (2015):
  • GCC Version 6 (2016):
  • GCC Version 7 (2017):

C++ Standard Support

There are various C++ standards:

  • C++98
  • C++11 (aka C++0x)
  • C++14 (aka C++1y)
  • C++17 (aka C++1z)
  • C++2a (next planned standard in 2020)

The default mode is C++98 for GCC versions prior to 6.1, and C++14 for GCC 6.1 and above. You can use command-line flag -std to explicitly specify the C++ standard. For example,

  • -std=c++98, or -std=gnu++98 (C++98 with GNU extensions)
  • -std=c++11, or -std=gnu++11 (C++11 with GNU extensions)
  • -std=c++14, or -std=gnu++14 (C++14 with GNU extensions), default mode for GCC 6.1 and above.
  • -std=c++17, or -std=gnu++17 (C++17 with GNU extensions), experimental.
  • -std=c++2a, or -std=gnu++2a (C++2a with GNU extensions), experimental.

2 Installing GCC on Unixes

3 Installing GCC on Mac OS X

$ gcc --version
......
Target: x86_64-apple-darwin14.5.0 // 64-bit target codes
Thread model: posix

4 Installing GCC on Windows

  • Cygwin GCC: Cygwin is a Unix-like environment and command-line interface for Microsoft Windows. Cygwin is huge and includes most of the Unix tools and utilities. It also included the commonly-used Bash shell.
  • MinGW: MinGW (Minimalist GNU for Windows) is a port of the GNU Compiler Collection (GCC) and GNU Binutils for use in Windows. It also included MSYS (Minimal System), which is basically a Bourne shell (bash).
  • MinGW-W64: a fork of MinGW that supports both 32-bit and 64-bit windows.

Various GCCs under Cygwin

There are many GCCs under Cygain/MinGW. To differentiate these variations, you need to understand the followings:

  • Windows/Intel uses these instruction sets: x86 is a 32-bit instruction set; i868 is a 32-bit enhanced version of x86; x86_64 (or amd64) is a 64-bit instruction set.
  • 32-bit compilers/programs can run on 32-bit or 64-bit (backward compatible) Windows, but 64-bit compiler can only run on 64-bit Windows.
  • 64-bit compilers may produce target of 32-bit or 64-bit.
  • If you use Cygwin’s GCC, the target could be native Windows or Cygwin. If the target is native Windows, the code can be distributed and run under Windows. However, if the target is Cygwin, to distribute, you need to distribute Cygwin runtime environment (cygwin1.dll). This is because Cygwin is a Unix emulator under Windows.

MinGW-W64 Target 32/64-bit Native Windows

The MinGW-W64 (a fork of MinGW, available at http://mingw-w64.org/doku.php) supports target of both 32-bit and 64-bit native Windows. You can install “MinGW-W64” under “Cygwin” by selecting these packages (under “devel” category):

  • mingw64-x86_64-gcc-core: 64-bit C compiler for target of native 64-bit Windows. The executable is "x86_64-w64-mingw32-gcc".
  • mingw64-x86_64-gcc-g++: 64-bit C++ compiler for target of native 64-bit Windows. The executable is "x86_64-w64-mingw32-g++".
  • mingw64-i686-gcc-core: 64-bit C compiler for target of native 32-bit Windows. The executable is "i686-w64-mingw32-gcc".
  • mingw64-i686-gcc-g++: 64-bit C++ compiler for target of native 32-bit Windows. The executable is "i686-w64-mingw32-g++".

Notes:

  • I suggest you install “mingw64-x86_64-gcc-core" and "mingw64-x86_64-gcc-g++" to provide native 64-bit Windows codes, but skip "mingw64-i686-gcc-core" and "mingw64-i686-gcc-g++", unless you need to produce 32-bit Windows applications.
  • For JNI (Java Native Interface) in 64-bit Java, you need to use “x86_64-w64-mingw32-gcc" or "x86_64-w64-mingw32-g++" to produce 64-bit native Windows code.

Run the executables and check the versions:

// Target 64-bit native Windows
$ x86_64-w64-mingw32-gcc --version
x86_64-w64-mingw32-gcc (GCC) 6.4.0
$ x86_64-w64-mingw32-gcc -v
Using built-in specs.
COLLECT_GCC=x86_64-w64-mingw32-gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-w64-mingw32/6.4.0/lto-wrapper.exe
Target: x86_64-w64-mingw32
Configured with: .....
Thread model: posix
gcc version 6.4.0 (GCC)
$ x86_64-w64-mingw32-g++ --version
x86_64-w64-mingw32-g++ (GCC) 6.4.0
// Target 32-bit native Windows
$ i686-w64-mingw32-gcc --version
i686-w64-mingw32-gcc (GCC) 6.4.0
$ i686-w64-mingw32-g++ --version
i686-w64-mingw32-g++ (GCC) 6.4.0

Other GCCs in Cygwin

Other GCC packages in Cygwin are:

  • gcc-core, gcc-g++: Basic 64-bit C/C++ compiler target 64-bit Cygwin. You probably should install these two packages too. However, to distribute the code produced, you need to distribute Cygwin Runtime Environment (cygwin1.dll). This is because Cygwin is a Unix emulator under Windows.
  • cygwin32-gcc-core, cygwin32-gcc-g++: Older 32-bit C/C++ compiler for target 32-bit Cygwin (Obsoleted by gcc-code and gcc-g++?).
  • mingw-gcc-core, mingw-gcc-g++: Older MinGW 32-bit C/C++ compiler for 32-bit Windows (Obsoleted by MinGW-W64 packages?).

5 Post Installation

You could display the version of GCC via --version option:

$ gcc --version
gcc (GCC) 6.4.0
$ g++ --version
g++ (GCC) 6.4.0

More details can be obtained via -v option, for example,

$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-cygwin/6.4.0/lto-wrapper.exe
Target: x86_64-pc-cygwin
Configured with: ......
Thread model: posix
gcc version 6.4.0 (GCC)
$ g++ -v
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-cygwin/6.4.0/lto-wrapper.exe
Target: x86_64-pc-cygwin
Configured with: ......
Thread model: posix
gcc version 6.4.0 (GCC)

Help

You can get the help manual via the --help option. For example,

$ gcc --help

Man Pages

You can read the GCC manual pages (or man pages) via the man utility:

$ man gcc
// or
$ man g++
// Press space key for next page, or 'q' to quit.

Reading man pages under CMD or Bash shell can be difficult. You could generate a text file via:

$ man gcc | col -b > gcc.txt

The col utility is needed to strip the backspace. (For Cygwin, it is available in "Utils", "util-linux" package.)

Alternatively, you could look for an online man pages, e.g., http://linux.die.net/man/1/gcc.

The GCC man pages are kept under “usr/share/man/man1".

$ whereis gcc
gcc: /usr/bin/gcc.exe /usr/lib/gcc /usr/share/man/man1/gcc.1.gz

6 Getting Started

Compile/Link a Simple C Program — hello.c

Below is the Hello-world C program hello.c:

1 // hello.c
2 #include <stdio.h>
3
4 int main() {
5 printf("Hello, world!\n");
6 return 0;
7 }

To compile the hello.c:

> gcc hello.c
// Compile and link source file hello.c into executable a.exe (Windows) or a (Unixes)

The default output executable is called "a.exe" (Windows) or "a.out" (Unixes and Mac OS X).

To run the program:

// (Windows) In CMD shell
> a

// (Unixes / Mac OS X) In Bash Shell - include the current path (./)
$ chmod a+x a.out
$ ./a.out

Notes for Unixes and Bash Shell:

  • In Bash shell, the default PATH does not include the current working directory. Hence, you need to include the current path (./) in the command. (Windows include the current directory in the PATH automatically; whereas Unixes do not - you need to include the current directory explicitly in the PATH.)
  • You also need to include the file extension, if any, i.e., "./a.out".
  • In Unixes, the output file could be "a.out" or simply "a". Furthermore, you need to assign executable file-mode (x) to the executable file "a.out", via command "chmod a+x filename" (add executable file-mode "+x" to all users "a+x").

To specify the output filename, use -o option:

// (Windows) In CMD shell
> gcc -o hello.exe hello.c
// Compile and link source file hello.c into executable hello.exe
> hello
// Execute hello.exe under CMD shell

// (Unixes / Mac OS X) In Bash shell
$ gcc -o hello hello.c
$ chmod a+x hello
$ ./hello

NOTE for Unixes:

  • In Unixes, we typically omit the .exe file extension (meant for Windows only), and simply name the output executable as hello (via command "gcc -o hello hello.c".
  • You need to assign executable file mode via command "chmod a+x hello".

Compile/Link a Simple C++ Program - hello.cpp

1 // hello.cpp
2 #include <iostream>
3 using namespace std;
4
5 int main() {
6 cout << "Hello, world!" << endl;
7 return 0;
8 }

You need to use g++ to compile C++ program, as follows. We use the -o option to specify the output file name.

// (Windows) In CMD shell
> g++ -o hello.exe hello.cpp
// Compile and link source hello.cpp into executable hello.exe
> hello
// Execute under CMD shell
// (Unixes / Mac OS X) In Bash shell
$ g++ -o hello hello.cpp
$ chmod a+x hello
$ ./hello

More GCC Compiler Options

A few commonly-used GCC compiler options are:

$ g++ -Wall -g -o Hello.exe Hello.cpp
  • -o: specifies the output executable filename.
  • -Wall: prints "all" Warning messages.
  • -g: generates additional symbolic debuggging information for use with gdb debugger.

Compile and Link Separately

The above command compile the source file into object file and link with other object files and system libraries into executable in one step. You may separate compile and link in two steps as follows:

// Compile-only with -c option
> g++ -c -Wall -g Hello.cpp
// Link object file(s) into an executable
> g++ -g -o Hello.exe Hello.o

The options are:

  • -c: Compile into object file "Hello.o". By default, the object file has the same name as the source file with extension of ".o" (there is no need to specify -o option). No linking with other object files or libraries.
  • Linking is performed when the input file are object files “.o" (instead of source file ".cpp" or ".c"). GCC uses a separate linker program (called ld.exe) to perform the linking.

Compile and Link Multiple Source Files

Suppose that your program has two source files: file1.cpp, file2.cpp. You could compile all of them in a single command:

> g++ -o myprog.exe file1.cpp file2.cpp

However, we usually compile each of the source files separately into object file, and link them together in the later stage. In this case, changes in one file does not require re-compilation of the other files.

> g++ -c file1.cpp
> g++ -c file2.cpp
> g++ -o myprog.exe file1.o file2.o

Compile into a Shared Library

To compile and link C/C++ program into a shared library (".dll" in Windows, ".so" in Unixes), use -shared option. Read "Java Native Interface" for example.

7. GCC Compilation Process

GCC compiles a C/C++ program into executable in 4 steps. For example, a “gcc -o hello.exe hello.c" is carried out as follows:

  1. Pre-processing: via the GNU C Preprocessor (cpp.exe), which includes the headers (#include) and expands the macros (#define).
> cpp hello.c > hello.i

The resultant intermediate file “hello.i" contains the expanded source code.

2. Compilation: The compiler compiles the pre-processed source code into assembly code for a specific processor.

> gcc -S hello.i

The -S option specifies to produce assembly code, instead of object code. The resultant assembly file is "hello.s".

3. Assembly: The assembler (as.exe) converts the assembly code into machine code in the object file "hello.o".

> as -o hello.o hello.s

4. Linker: Finally, the linker (ld.exe) links the object code with the library code to produce an executable file "hello.exe".

> ld -o hello.exe hello.o ...libraries...

Verbose Mode (-v)

You can see the detailed compilation process by enabling -v (verbose) option. For example,

> gcc -v -o hello.exe hello.c

Electronic Engineer who loves programming