GCC: Difference between revisions

From EMC23 - Satellite Of Love
Jump to navigation Jump to search
mNo edit summary
mNo edit summary
Line 66: Line 66:


  g++ main.cpp -Wl,--start-group -lbase-lib -lchild-lib -Wl,--end-group
  g++ main.cpp -Wl,--start-group -lbase-lib -lchild-lib -Wl,--end-group
= Separate Compilation Tutorial =
All of the programs that we have looked at to this point have been contained within a single file. This is the exception rather than the rule. As programs become larger, it is important to spread them across files of a reasonable size. In this lesson we will look at why this is important, and how it can be done.
Compiling Files
Up to this point, whenever you wanted to compile a program you compiled the file displayed in an Emacs buffer. The Compile This File... option of Emacs' Compile menu (or equivalently, M-x compile) is a handy feature when your entire program is contained with one file. It is, of course, possible to compile a file completely independently of Emacs.
Download hello.c. It is a simple program that prints out ``Hello world'', and you can compile and run it without ever displaying it in Emacs. To compile it, go to a Unix Shell window, connect to the directory into which you downloaded the program, and enter the following command:
gcc -Wall -g -c hello.c
This command will result in a new file being created. Use the ls command to list your directory. What file is there that wasn't before?
Click here for the answer
At this point you still don't have an executable program that you can run. The next step is to link the object file to produce such an executable. To do this, type the following into your UNIX Shell window:
gcc -o hello hello.o -lm
Linking hooks up your compiled code with some additional C-specific code. Once again, a new file has been created in your directory. List the directory. What new file do you find?
Click here for the answer
Now that you have an executable you can run it in the familiar way. Simply type ``hello'' into the UNIX Shell window.
To summarize, the steps involved in compiling, linking, and running a program are:
    Compile the ``.c'' file containing the source code with a command such as
    gcc -Wall -g -c hello.c
    The -c in the command is important--it tells C to produce an object file called (in this case) ``hello.o''. The -Wall part is optional but is strongly encouraged--it tells C to produce all possible warning messages. A warning message will usually lead you to a bug in your program. The -g tells the compiler to include information needed by the debugger.
    Link the ``.o'' file to produce an executable with a command such as
    gcc -o hello hello.o -lm
    The -o hello in the command is important--it tells C what to name the executable. The -lm part tells C to link in the math libraries. If your program doesn't use any of the match functions from ``math.h'', you can leave this part out.
    Run the executable in the usual way.
    If your entire program is contained within a single file, you can do the compilation and linking in one step by entering the command
    gcc -Wall -g -o hello hello.c -lm
This is exactly what Emacs does when it compiles a program for you. We have been careful to this point to do the compilation in two separate steps so that you will be able to deal with programs made up of more than one file. We will explore this topic further in the next section.
Multiple Files
Consider the idea of dividing programs into more than one file. By that we mean putting the various functions that make up the program into more than one file.
Try to think of some reasons why this might be a good idea.
Click here for some possible answers
Now let's take a look at a program divided into more than one file. Download main.c and help.c and view them in Emacs. Notice that main.c makes use of the two functions defined in ``help.c''.
Is there any way that you can compile this program from Emacs? Try compiling ``main.c'' this way. What happens?
Click here for the answer
Now try compiling the buffer containing ``help.c''. What happens?
Click here for the answer
Compiling Multiple Files
Based upon what you already know, what do you suppose would be the procedure for compiling, linking, and running the program that we've spread across two files here? Think about it carefully before you look at the answer.
Click here for the answer
Now do it yourself. Compile, link, and run the program.
When you've succeeded in doing that, try the following experiment. Modify the main program slightly to call the two functions in the opposite order. What do you think will be involved in recompiling, linking, and running the new version of the program?
Click here for the answer
Compile, link, and run your modified program. (Don't forget to save ``main.c'' before you do so!)
Declaring Functions
There's still a problem remaining. Whenever you compile ``main.c'', the compiler complains that ``sum'' and ``product'' are undeclared functions. Even so, the linker succeeds in putting together an executable. Why should we worry about the compiler warning if we can get an executable program anyway?
Click here for an answer
It is actually not too difficult to fix up this problem. Simply add the following two lines to ``main.c'' up above the main procedure.
int sum (int n);
int product (int n);
Where have you seen these lines before?
Click here for the answer
Save ``main.c'' and rebuild the executable. If you've done everything correctly, the errors should go away.
Include Files
This is a clumsy way to go about declaring functions that are implemented in a separate file. Can you think of some problems?
Click here for an answer
Here's how we can deal with both of these problems. Create a new file that contains nothing but the declarations of the functions in ``help.c''. In fact, we have already created just such a file: download help.h and take a look at it. What is in there in addition to the declarations?
Click here for the answer
Now, modify ``main.c'' by eliminating the declarations you added, and replacing them with the line
#include "help.h"
As you probably recall, this is a direction to the compiler to behave as if the contents of the file ``help.h'' were actually typed in here. Notice that we have surrounded the name of the file with quotes instead of angle brackets as is the case with, for example, stdio.h. Why?
Click here for the answer
Save ``main.c'' and compile, link, and run it. How does this address problem (1) identified above?
Click here for the answer
However, we still haven't addressed issue (2). There is nothing to stop us from modifying the declarations in ``help.h'', rendering it inconsistent with ``help.c''.
Fortunately, there's a way to deal with this problem too. Put the line
#include "help.h"
at the top of ``help.c''. Now save ``help.c'' and rebuild the executable. You should encounter no errors.
Now edit ``help.c'' again by changing one of the declarations. For example, change ``sum'' so that it takes a float as an argument instead of an int. Save and recompile ``help.c''. What happens?
Click here for the answer
Summary
To summarize, here is the suggested procedure for dealing with multiple-file programs in C.
    For each file ``file.c'' containing functions that will be used elsewhere, create a file ``file.h'' containing the header information and comments for those functions.
    Put the line
    #include "file.h"
    near the beginning of ``file.c''. This way, the compiler will warn you if the two sets of declarations ever become different.
    Put the line
    #include "file.h"
    near the beginning of all files that use the functions in ``file.c''. This way, the complier will warn you if you use the functions incorrectly.
You can then separately compile the ``.c'' files, and then link together to create an executable. In the next lesson we will look at Makefiles, which provide a more convenient way of compiling and linking multiple file programs.


= Compiling C and C++ Programs =
= Compiling C and C++ Programs =

Revision as of 10:32, 5 September 2021

Compiling with GCC[edit]

Example[edit]

Assuming a single source file named main.cpp, the command to compile and link an non-optimized executable is as follows (Compiling without optimization is useful for initial development and debugging, although -Og is officially recommended for newer GCC versions).

g++ -o app -Wall main.cpp -O0

To produce an optimized executable for use in production, use one of the -O options (see: -O1, -O2, -O3, -Os, -Ofast):

g++ -o app -Wall -O2 main.cpp

If the -O option is omitted, -O0, which means no optimizations, is used as default (specifying -O without a number resolves to -O1).

Alternatively, use optimization flags from the O groups (or more experimental optimizations) directly. The following example builds with -O2 optimization, plus one flag from the -O3 optimization level:

g++ -o app -Wall -O2 -ftree-partial-pre main.cpp

To produce a platform-specific optimized executable (for use in production on the machine with the same architecture), use:

g++ -o app -Wall -O2 -march=native main.cpp

Either of the above will produce a binary file that can be run with .\app.exe on Windows and ./app on Linux, Mac OS, etc.

The -o flag can also be skipped. In this case, GCC will create default output executable a.exe on Windows and a.out on Unix-like systems. To compile a file without linking it, use the -c option:

g++ -o file.o -Wall -c file.cpp

This produces an object file named file.o which can later be linked with other files to produce a binary:

g++ -o app file.o otherfile.o

More about optimization options can be found at gcc.gnu.org. Of particular note are -Og (optimization with an emphasis on debugging experience -- recommended for the standard edit-compile-debug cycle) and -Ofast (all optimizations, including ones disregarding strict standards compliance).

The -Wall flag enables warnings for many common errors and should always be used. To improve code quality it is often encouraged also to use -Wextra and other warning flags which are not automatically enabled by -Wall and -Wextra.

If the code expects a specific C++ standard, specify which standard to use by including the -std= flag. Supported values correspond to the year of finalization for each version of the ISO C++ standard. As of GCC 6.1.0, valid values for the std= flag are c++98/c++03, c++11, c++14, and c++17/c++1z. Values separated by a forward slash are equivalent.

g++ -std=c++11 <file>

GCC includes some compiler-specific extensions that are disabled when they conflict with a standard specified by the -std= flag. To compile with all extensions enabled, the value gnu++XX may be used, where XX is any of the years used by the c++ values listed above.

The default standard will be used if none is specified. For versions of GCC prior to 6.1.0, the default is -std=gnu++03; in GCC 6.1.0 and greater, the default is -std=gnu++14.

Note that due to bugs in GCC, the -pthread flag must be present at compilation and linking for GCC to support the C++ standard threading functionality introduced with C++11, such as std::thread and std::wait_for. Omitting it when using threading functions may result in no warnings but invalid results on some platforms. Linking with libraries:

Use the -l option to pass the library name:

g++ main.cpp -lpcre2-8
  1. pcre2-8 is the PCRE2 library for 8bit code units (UTF-8)

If the library is not in the standard library path, add the path with -L option:

g++ main.cpp -L/my/custom/path/ -lmylib

Multiple libraries can be linked together:

g++ main.cpp -lmylib1 -lmylib2 -lmylib3

If one library depends on another, put the dependent library before the independent library:

g++ main.cpp -lchild-lib -lbase-lib

Or let the linker determine the ordering itself via --start-group and --end-group (note: this has significant performance cost):

g++ main.cpp -Wl,--start-group -lbase-lib -lchild-lib -Wl,--end-group



Separate Compilation Tutorial[edit]

All of the programs that we have looked at to this point have been contained within a single file. This is the exception rather than the rule. As programs become larger, it is important to spread them across files of a reasonable size. In this lesson we will look at why this is important, and how it can be done.

Compiling Files

Up to this point, whenever you wanted to compile a program you compiled the file displayed in an Emacs buffer. The Compile This File... option of Emacs' Compile menu (or equivalently, M-x compile) is a handy feature when your entire program is contained with one file. It is, of course, possible to compile a file completely independently of Emacs.

Download hello.c. It is a simple program that prints out ``Hello world, and you can compile and run it without ever displaying it in Emacs. To compile it, go to a Unix Shell window, connect to the directory into which you downloaded the program, and enter the following command:

gcc -Wall -g -c hello.c

This command will result in a new file being created. Use the ls command to list your directory. What file is there that wasn't before?

Click here for the answer

At this point you still don't have an executable program that you can run. The next step is to link the object file to produce such an executable. To do this, type the following into your UNIX Shell window:

gcc -o hello hello.o -lm

Linking hooks up your compiled code with some additional C-specific code. Once again, a new file has been created in your directory. List the directory. What new file do you find?

Click here for the answer

Now that you have an executable you can run it in the familiar way. Simply type ``hello into the UNIX Shell window.

To summarize, the steps involved in compiling, linking, and running a program are:

   Compile the ``.c file containing the source code with a command such as
   gcc -Wall -g -c hello.c
   The -c in the command is important--it tells C to produce an object file called (in this case) ``hello.o. The -Wall part is optional but is strongly encouraged--it tells C to produce all possible warning messages. A warning message will usually lead you to a bug in your program. The -g tells the compiler to include information needed by the debugger.
   Link the ``.o file to produce an executable with a command such as
   gcc -o hello hello.o -lm
   The -o hello in the command is important--it tells C what to name the executable. The -lm part tells C to link in the math libraries. If your program doesn't use any of the match functions from ``math.h, you can leave this part out.
   Run the executable in the usual way.
   If your entire program is contained within a single file, you can do the compilation and linking in one step by entering the command
   gcc -Wall -g -o hello hello.c -lm

This is exactly what Emacs does when it compiles a program for you. We have been careful to this point to do the compilation in two separate steps so that you will be able to deal with programs made up of more than one file. We will explore this topic further in the next section.

Multiple Files

Consider the idea of dividing programs into more than one file. By that we mean putting the various functions that make up the program into more than one file.

Try to think of some reasons why this might be a good idea.

Click here for some possible answers

Now let's take a look at a program divided into more than one file. Download main.c and help.c and view them in Emacs. Notice that main.c makes use of the two functions defined in ``help.c.

Is there any way that you can compile this program from Emacs? Try compiling ``main.c this way. What happens?

Click here for the answer

Now try compiling the buffer containing ``help.c. What happens?

Click here for the answer

Compiling Multiple Files

Based upon what you already know, what do you suppose would be the procedure for compiling, linking, and running the program that we've spread across two files here? Think about it carefully before you look at the answer.

Click here for the answer

Now do it yourself. Compile, link, and run the program.

When you've succeeded in doing that, try the following experiment. Modify the main program slightly to call the two functions in the opposite order. What do you think will be involved in recompiling, linking, and running the new version of the program?

Click here for the answer

Compile, link, and run your modified program. (Don't forget to save ``main.c before you do so!)

Declaring Functions

There's still a problem remaining. Whenever you compile ``main.c, the compiler complains that ``sum and ``product are undeclared functions. Even so, the linker succeeds in putting together an executable. Why should we worry about the compiler warning if we can get an executable program anyway?

Click here for an answer

It is actually not too difficult to fix up this problem. Simply add the following two lines to ``main.c up above the main procedure.

int sum (int n); int product (int n);

Where have you seen these lines before?

Click here for the answer

Save ``main.c and rebuild the executable. If you've done everything correctly, the errors should go away.

Include Files

This is a clumsy way to go about declaring functions that are implemented in a separate file. Can you think of some problems?

Click here for an answer

Here's how we can deal with both of these problems. Create a new file that contains nothing but the declarations of the functions in ``help.c. In fact, we have already created just such a file: download help.h and take a look at it. What is in there in addition to the declarations?

Click here for the answer

Now, modify ``main.c by eliminating the declarations you added, and replacing them with the line

  1. include "help.h"

As you probably recall, this is a direction to the compiler to behave as if the contents of the file ``help.h were actually typed in here. Notice that we have surrounded the name of the file with quotes instead of angle brackets as is the case with, for example, stdio.h. Why?

Click here for the answer

Save ``main.c and compile, link, and run it. How does this address problem (1) identified above?

Click here for the answer

However, we still haven't addressed issue (2). There is nothing to stop us from modifying the declarations in ``help.h, rendering it inconsistent with ``help.c.

Fortunately, there's a way to deal with this problem too. Put the line

  1. include "help.h"

at the top of ``help.c. Now save ``help.c and rebuild the executable. You should encounter no errors.

Now edit ``help.c again by changing one of the declarations. For example, change ``sum so that it takes a float as an argument instead of an int. Save and recompile ``help.c. What happens?

Click here for the answer

Summary

To summarize, here is the suggested procedure for dealing with multiple-file programs in C.

   For each file ``file.c containing functions that will be used elsewhere, create a file ``file.h containing the header information and comments for those functions.
   Put the line
   #include "file.h"
   near the beginning of ``file.c. This way, the compiler will warn you if the two sets of declarations ever become different.
   Put the line
   #include "file.h"
   near the beginning of all files that use the functions in ``file.c. This way, the complier will warn you if you use the functions incorrectly.

You can then separately compile the ``.c files, and then link together to create an executable. In the next lesson we will look at Makefiles, which provide a more convenient way of compiling and linking multiple file programs.















Compiling C and C++ Programs[edit]

gcc is the GNU C Compiler and g++ is the GNU C++ compiler. Below are several examples that show how to use g++ to compile C++ programs. Example 1: Compiling a simple program Consider the following example: Let "hello.C" be a file that contains the following C++ code.

 #include "iostream.h"
 int main() 
 {
   cout << "Hello\n";
 } 

The standard way to compile this program is with the command

 g++ hello.C -o hello 

This command compiles hello.C into an executable program named "hello" that you run by typing './hello' at the command line. It does nothing more than print the word "hello" on the screen. Alternatively, the above program could be compiled using the following two commands.

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

The end result is the same, but this two-step method first compiles hello.C into a machine code file named "hello.o" and then links hello.o with some system libraries to produce the final program "hello". In fact the first method also does this two-stage process of compiling and linking, but the stages are done transparently, and the intermediate file "hello.o" is deleted in the process.

Frequently used compilation options

C and C++ compilers allow for many options for how to compile a program, and the examples below demonstrate how to use many of the more commonly used options. In each example, "myprog.C" contains C++ source code for the executable "myprog". In most cases options can be combined, although it is generally not useful to use "debugging" and "optimization" options together.

Compile myprog.C so that myprog contains symbolic information that enables it to be debugged with the gdb debugger.

   g++ -g myprog.C -o myprog

Have the compiler generate many warnings about syntactically correct but questionable looking code. It is good practice to always use this option with gcc and g++.

   g++ -Wall myprog.C -o myprog

Generate symbolic information for gdb and many warning messages.

   g++ -g -Wall myprog.C -o myprog

Generate optimized code on a Linux machine.

   g++ -O myprog.C -o myprog

Compile myprog.C when it contains Xlib graphics routines.

   g++ myprog.C -o myprog -lX11

If "myprog.c" is a C program, then the above commands will all work by replacing g++ with gcc and "myprog.C" with "myprog.c". Below are a few examples that apply only to C programs.

Compile a C program that uses math functions such as "sqrt".

   gcc myprog.C -o myprog -lm

Compile a C program with the "electric fence" library. This library, available on all the Linux machines, causes many incorrectly written programs to crash as soon as an error occurs. It is useful for debugging as the error location can be quickly determined using gdb. However, it should only be used for debugging as the executable myprog will be much slower and use much more memory than usual.

   gcc -g myprog.C -o myprog -lefence


Example 2: Compiling a program with multiple source files If the source code is in several files, say "file1.C" and "file2.C", then they can be compiled into an executable program named "myprog" using the following command:

 g++ file1.C file2.C -o myprog 

The same result can be achieved using the following three commands:

 g++ -c file1.C
 g++ -c file2.C
 g++ file1.o file2.o -o myprog 

The advantage of the second method is that it compiles each of the source files separately. If, for instance, the above commands were used to create "myprog", and "file1.C" was subsequently modified, then the following commands would correctly update "myprog".

 g++ -c file1.C
 g++ file1.o file2.o -o myprog 

Note that file2.C does not need to be recompiled, so the time required to rebuild myprog is shorter than if the first method for compiling myprog were used. When there are numerous source file, and a change is only made to one of them, the time savings can be significant. This process, though somewhat complicated, is generally handled automatically by a makefile.