C/C++ program compilation under Linux system

Article directory

  • Introduction
  • C program compilation
    • Generate an executable program from a single source file
    • Executable program generated from multiple source files
    • Source files generate object files
    • Compile preprocessing
    • generate assembly code
    • Build a static library
    • build shared library
  • C++ program compilation
    • Generate an executable program from a single source file
    • Executable program generated from multiple source files
    • Source files generate object files
    • Compile preprocessing
    • generate assembly code
    • Build a static library

Introduction

On the Linux operating system, GCC is a modern collection of compilers that can be used to compile several programming languages, including C and C++ Language.

By using the GCC compiler, you can write efficient, safe and reliable programs. For C programs, it is recommended to use gcc for compilation, but for C ++ programs, it is recommended to use g ++ strong> . If you need to build large-scale C programs and manage source files, you can use makefile and the make tool for this task.

  • Makefile is a text file that contains targets, dependencies, and commands to execute. Multiple targets can be created and specify dependencies and command sequences according to program complexity.

  • The Make command can automatically build a program, it will read the Makefile and generate the necessary commands to ensure that the target dependencies are followed without having to manually enter a series of compilation commands.

Therefore, when faced with large C programs, using makefile and make tools can significantly improve the efficiency and convenience of compilation, and reduce the occurrence of common errors and problems.

The process of compiling a C program mainly includes four stages: compilation preprocessing, compilation optimization, assembly, link.

  • In the compilation preprocessing stage, the compiler will read the preprocessing commands in the source program (for example, macro definition commands, conditional compilation instructions, header file inclusion instructions, etc.) and special symbols (for example, appearing in the source program LINE is interpreted as the current line number expressed in decimal; FILE is interpreted as the file name of the currently compiled source program, and it is replaced with the corresponding content, and the header file is added at the same time definitions in , etc.).

  • In the compilation and optimization stage, the compiler will translate the code into corresponding assembly code after confirming that all instructions conform to the grammatical rules through lexical analysis and syntax analysis, and perform optimization processing. There are two ways to optimize, one is optimization for the code itself (for example, deletion of common expressions, loop optimization, code extraction, deletion of useless code assignment, etc.), and the other is instruction optimization for computer hardware (for example, Adjust and optimize the instructions according to the characteristics of the machine hardware execution instructions, reduce the length of the object code, improve the execution efficiency, etc.).

  • In the assembly stage, the compiler will produce an assembly file, and then convert it into a sequence of target machine instructions through the assembler to generate a corresponding target file. The target file generally contains at least a code segment and a data segment.

  • In the linking phase, the linker will link multiple object files together, resolve symbolic references, and generate an executable. According to different connection methods, link libraries can be divided into static link and dynamic link. In static linking, the code of the function will be copied directly into the final executable file; in dynamic linking, the code of the function is placed in the shared object, and the name of the shared object and a small amount of Key Information.

C program compilation

Single source file generates executable program

Take the following simple C program as an example, the code of the program is as follows:

/* hello.c */
#include <stdio.h>

int main(int argc,char *argv[])
{<!-- -->
printf("Hello cqupthao!\\
");
return 0;
}

The easiest and most direct way to compile the above code into an executable program is to save the code as a file hello.c , and execute the following command in the corresponding directory:

gcc hello.c -Wall

The GCC compiler can identify it as a C source code file by checking the suffix of the file specified in the command line (GCC default action: compile the source code file to generate an object file, link the object file to obtain an executable program, delete the object file, and the compiler The file name of the default executable program a.out).

Enter a command of the following format in a terminal to have it run and display the results:

./a.out

## result
Hello cqupthao!

You can use the option -o to specify the executable program that generates the specified file name. For example, enter the following command to generate an executable program named hello:

gcc hello.c -o hello -Wall

Enter the following command format in the terminal to make it run and display the result:

./hello

## result
Hello cqupthao!

Note: If the compiler needs to use the math.h library and other standard libraries that are not called by GCC by default, the option -lm should be used.

Multiple source files generate executable programs

When multiple source code files are compiled, the GCC compiler will automatically perform the link operation. For example, a file program named hellomain.c calls the sayhello() function of a file program named sayhello.c, the code of the program is as follows :

/* hellomain.c */
void sayhello(void);

int main(int argc,char *argv[])
{<!-- -->
sayhello();
return 0;
}

The following program code is stored in the sayhello() function defined by the program in the file named sayhello.c:

/* sayhello.c */
#include <stdio.h>

void sayhello()
{<!-- -->
printf("Hello cqupthao!\\
");
}

To compile the two files into object files and link them into an executable program hello, and delete the object file, enter the command in the following format:

gcc hellomain.c sayhello.c -o hello -Wall

Enter the following command format in the terminal to make it run and display the result:

./hello

## result
Hello cqupthao!

Source file generates object file

When the option -c is used during compilation, GCC will compile the source code file, but will not link the object file to generate an executable file. At the same time, the program can save the generated target files to the disk to facilitate subsequent operations and debugging.

In this case, GCC’s default output file name is the same as the source code file name, but the suffix is changed to .o , indicating that this is an object file, that is, a binary file that is not linked. Thus, when compiling a large C program, multiple source files can be compiled separately into object files, which are then combined at the link stage to produce the final executable.

For example, to generate an object file named hello.o, enter a command in the following format:

gcc -c hello.c -Wall

The option -o can be used to generate an object file with the specified filename. For example, entering the following command will produce an object file named sayhello.o:

gcc -c hello.c -o sayhello.o -Wall

When building an object library or generating a series of object files for later linking, you can generate the corresponding object file name hello.o , callhello.o and sayhello.o object files, enter commands in the following format:

gcc -c hello.c callhello.c sayhello.c -Wall

## result
hello.o callhello.o sayhello.o

Compile preprocessing

The option -E instructs the compiler to do only preprocessing for compilation. For example, to preprocess the source file hello.c and list the result on standard output, enter a command in the following format:

gcc -E hello.c

The option -o is used to direct the preprocessed code to a C source file that does not need to be preprocessed and has a suffix of .i. For example, enter the command in the following format :

gcc -E hello.c -o hello.i

Generate assembly code

The option -S instructs the compiler to generate assembly language code and then exit. For example, to generate the assembly language file hello.s from the C source code file hello.c , enter the command in the following format:

gcc -S hello.c

The form of assembly language depends on the target platform of the compiler. If multiple source code files are compiled, each file will generate a corresponding assembly code module.

Build a static library

A static library is a set of files with the suffix .o generated by the compiler, which are compiled from the same source code library. Static linking of code, in contrast to dynamic libraries, means that when the program runs, all dependencies are linked and copied, so all necessary code is included in the executable.

In this way, dynamic link errors can be avoided when the program is running, and the performance loss of the dynamic link library can be eliminated. In addition, static libraries are portable and self-contained because they are not dependent on a specific version of the operating system or computer hardware.

Another name of the static library is the archive file (archive), because it is actually a series of .o File archives, to build a library, first compile the object modules required in the library. For example, the file names of the following two programs are firsthello.c and secondhello.c respectively, and their source codes are as follows:

/* firsthello.c */
#include <stdio.h>

void firsthello()
{<!-- -->
        printf("This is the first hello!\\
");
}
/* secondhello.c */
#include <stdio.h>

void secondhello()
{<!-- -->
printf("This is the second hello!\\
");
}

Before using the static library, you need to compile the source code files that need to be compiled into object files (suffix .o), and then use the ar command to package them into an archive File (also called static library file, the suffix is .a). For example, to compile these two source code files into object files, enter commands in the following format:

gcc -c firsthello.c secondhello.c -Wall

Under the Linux system, the ar tool is usually used to manage and create archive files. ar with the parameter -r can create a new library and save the object file insert. The argument -r will create a new library if it does not exist, adding (by replacing if necessary) the object module to the archive. For example, to create a static library named libhello.a that contains the two object modules in this example, enter a command of the form:

ar -r libhello.a firsthello.o secondhello.o

Call these two functions in the library, write a program named uselib.c, the code of the program is as follows:

/* uselib.c */
void firsthello(void);
void secondhello(void);

int main(int argc,char *argv[])
{<!-- -->
firsthello();
second hello();
return 0;
}

Programs can be compiled and linked with a single command by specifying the library on the command line, as follows:

gcc uselib.c libhello.a -o uselib -Wall

Enter the following command format in the terminal to make it run and display the result:

./uselib

## result
This is the first hello!
This is the second hello!

The naming convention of the static library starts with lib and the suffix is .a, for example, libhello.a, this naming convention is widely used in In various operating systems and programming languages, in the Linux system, all system libraries use this naming convention. The compiler provides the -l option to specify the library file name that needs to be linked, and you can specify the library name in the command line by shorthand, similar to -l form. For example, in the above command, use -lhello to point to the libhello.a static library, and link the library with the uselib.c file Link to generate executable file uselib.

It should be noted that the compiler will search for the libhello.a library file from the default system library directory. If the library file exists in a specific directory, you can use the full path name or relative pathname to specify the location of the library file. If you specify a specific path name, you can use the absolute path or relative path format to express. For example, assuming the libhello.a library file is stored in the lib directory under the current directory, the following command can be used:

gcc twohellos.c -L./lib -lhello -o twohellos -Wall

In this command, the -L./lib option specifies that the library file is in the lib directory under the current directory, and the -lhello option refers to the >libhello.a static library file, so the compiler will search for libhello.a static library file in the specified directory, so as to realize the link operation.

Build shared library

Shared library (shared library), also known as dynamic link library (dynamic library), is a collection of object files generated by the compiler in a special way. During the compilation process, all addresses (including variable references and function calls) in the object file module are relative rather than absolute, which enables the shared library to be dynamically loaded when the program is running and supports simultaneous use by multiple processes. Thereby saving memory space and realizing code reuse.

Unlike static libraries, shared libraries are not linked into the final execution file, but are loaded into memory when the program runs. Therefore, the shared library has better portability and reusability, and can be shared and used in different applications, thereby better realizing code reuse.

To build a shared library, you first need to compile the object file (.o file). For example, in the following example, we compile the two source code files sharedfirst.c and sharedsecond.c, and generate the target file sharedfirst.o and sharedsecond.o:

/* sharedfirst.c */
#include <stdio.h>

void sharedfirst()
{<!-- -->
printf("This is the first hello from a shared library!\\
");
}
/* sharedsecond.c */
#include <stdio.h>

void sharedsecond()
{<!-- -->
printf("This is the second hello from a shared library!\\
");
}

To compile the above two source code files into object files, enter the command in the following format:

gcc -c -fpic sharedfirst.c sharedsecond.c -Wall

The option -c tells the compiler to generate only .o object files. The option -fpic causes the generated object modules to take floating (relocatable) addresses.

The following gcc command builds the object files into a shared library named hello.so:

gcc -shared shellofirst.o shellosecond.o -o hello.so

When compiling a shared library, there is no obvious entry point function, such as the main() function, that is called when the program runs, so you need to use the option -shared to tell the compiler Create a shared library instead of an executable. This option tells the compiler not to link according to the entry address agreed by the operating system, but to treat the compiled object file collection as a shared object.

Since the compiler can recognize the file extension .c and know how to compile it into an object file, the compilation step can be omitted, and the two source code files can be directly compiled and linked by a command in the following formatsharedfirst.c and sharedsecond.c, and build them into a shared library libshello.so. In this case, the compiler automatically compiles the source files into object files and links those object files as shared libraries:

gcc -fpic -shared sharedfirst.c sharedsecond.c -o hello.so -Wall

Write a program file named uessharedlib.c to call the main program of the two functions in the shared library. The code of the program is as follows:

/* usesharedlib.c */
void sharedfirst(void);
void sharedsecond(void);

int main(int argc,char *argv[])
{<!-- -->
sharedfirst();
sharedsecond();
return 0;
}

The program can be compiled and linked with the shared library with the following commands:

gcc usesharedlib.c hello.so -o usesharedlib -Wall

Running it must allow it to locate the shared library hello.so , because the functions in the library are loaded when the program is running. It should be noted that the current working directory may not be in the search path of the shared library, so you need to use the following command line to set the environment variable LD_LIBRARY_PATH:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./

Enter the following command format in the terminal to make it run and display the result:

./usesharedlib

## result
This is the first hello from a shared library!
This is the second hello from a shared library!

C++ program compilation

Single source file generates executable program

Let's take a simple C++ program as an example, the code of the program is as follows:

/* hello.cpp */
#include <iostream>

int main(int argc,char *argv[])
{<!-- -->
    std::cout << "Hello cqupthao!" << std::endl;
    return(0);
}

The program uses cout defined in the header file iostream to write a simple string to the standard output. The most simple and direct way to compile the above code into an executable program is Save the code as a file hello.cpp, and execute the following command in the corresponding directory:

g++ hello.cpp -Wall

The compiler g++ recognizes a file specified on the command line as a C++ source code file by examining its suffix. The default action of the compiler: Compile the source code file to generate the object file, link the object file and the functions in the libstdc++ library to get the executable program and delete the object file. By default, the compiler does not specify the file name of the executable program a.out , and the following form can be entered in the terminal to make it run and display the result:

./a.out

## result
Hello cqupthao!

You can use the option -o to specify the executable program that generates the specified file name. For example, enter the following command to generate an executable program named hello:

g++ hello.cpp -o hello -Wall

Enter the following command format in the terminal to make it run and display the result:

./hello

## result
Hello cqupthao!

Note: g++ is a special version that sets gcc's default language to C++, and it automatically uses the C++ standard library instead of the C standard library when linking.

By following the naming convention of the source code and specifying the name of the corresponding library, it is feasible to use gcc to compile and link the C++ program. For example, enter the command in the following format:

gcc hello.cpp -lstdc + + -o hello -Wall

Enter the following command format in the terminal to make it run and display the result:

./hello

## result
Hello cqupthao!

Option -l (ell) transforms the name following it to the name of the library by adding the prefix lib and the suffix .a to the name of the library libstdc + + .a , then it looks for the library in the standard library path. The compilation process and output files of gcc are exactly the same as those of g++.

On most systems, GCC installs a program called c++, which is equivalent to g++. For example, enter a command in the following format:

c++ hello.cpp -o hello -Wall

Enter the following command format in the terminal to make it run and display the result:

./hello

## result
Hello cqupthao!

Multiple source files generate executable programs

If multiple source files are specified in the g++ command, they will all be compiled and linked into a single executable. For example, the following header file named speak.h contains the definition of a class with only one function. The code of the program is as follows:

/* speak.h */
#include <iostream>

class Speak
{<!-- -->
    public:
        void sayHello(const char *);
};

The following program code lists the contents of the file speak.cpp, which contains the function body of the sayHello() function:

/* speak.cpp */
#include "speak.h"

void Speak::sayHello(const char *str)
{<!-- -->
    std::cout << "Hello " << str << "\\
";
}

Write a program named hellospeak.cpp that uses the Speak class. The code of the program is as follows:

/* hellospeak.cpp */
#include "speak.h"

int main(int argc,char *argv[])
{<!-- -->
    Speak speak;
    speak.sayHello("cqupthao!");
    return(0);
}

To compile and link the above two source code files into a single executable program, enter the command in the following format:

g++ hellospeak.cpp speak.cpp -o hellospeak -Wall

Enter the following command format in the terminal to make it run and display the result:

./hellospeak

## result
Hello cqupthao!

Note: #include "speak.h" is included in speak.cpp, which means to search the system header Before the file directory, the file “speak.h” will be searched in the current directory, and it is in this directory, so it does not need to be specified in the command.

Source file generates object file

When compiling, you can use the option -c to tell the compiler to compile the source code but not to execute the link. The output result is an object file. The default name of the file is the same as the source code file name, but its suffix is changed to .o . For example, a command of the following format will compile the source file hellospeak.cpp and generate the object file hellospeak.o:

g++ -c hellospeak.cpp -Wall

g++ recognizes .o files and passes them as input files to the linker. For example, entering a command of the following form will compile source files into object files and link them into a single executable program:

g++ -c hellospeak.cpp -Wall
g++ -c speak.cpp -Wall
g++ hellospeak.o speak.o -o hellospeak

Enter the following command format in the terminal to make it run and display the result:

./hellospeak

## result
Hello cqupthao!

The option -o can be used not only to name executable files, but also to name other files output by the compiler. For example, the following command produces the exact same executable as above, except that the intermediate object files have different names:

g + + -c hellospeak.cpp -o hellotmp.o -Wall
g++ -c speak.cpp -o speaktmp.o -Wall
g++ hellotmp.o speaktmp.o -o hellospeak

Enter the following command format in the terminal to make it run and display the result:

./hellospeak

## result
Hello cqupthao!

Compile preprocessing

The option -E causes g++ to execute no other actions after the source code has been processed by the compiling preprocessor. For example, to preprocess the source file hellospeak.cpp and display the result on standard output, enter a command in the following format:

g++ -E hellospeak.cpp

The suffix of the preprocessed file is .ii , which can be generated by the -o option, for example, enter the command in the following format:

gcc -E hellospeak.cpp -o hellospeak.ii

Generate assembly code

The option -S instructs the compiler to compile the program into assembly language, output the assembly language code and then end. For example, to generate the assembly language file hellospeak.s from the C++ source file hellospeak.cpp, enter the command in the following format:

g++ -S hellospeak.cpp

The form of assembly language depends on the target platform of the compiler. If multiple source code files are compiled, each file will generate a corresponding assembly code module.

Build a static library

A static library is a collection of object files generated by a compiler. When linking a program, it is the same whether to use the object file in the library or the object file in the directory. The members in the library include ordinary functions, class definitions, object instances of the class, and so on. Another name for a static library is an archive file, and the tool for managing this archive file is called ar .

For example, create two object modules and use them to generate a static library. Write a program with a header file named say.h that contains the prototype of the function sayHello() and the definition of the class Say. The code of the program is as follows :

/* say.h */
#include <iostream>

void sayhello(void);

class Say {<!-- -->
    private:
        char *string;
    public:
        Say(char *str)
        {<!-- -->
            string = str;
        }
        void sayThis(const char *str)
        {<!-- -->
            std::cout << str << " from a static library!\\
";
        }
        void sayString(void);
};

The following program named say.cpp is the source code of one of the two object files that need to be added to the static library. It contains the sayString( ) The definition body of the function and the declaration of an instance librarysay of the class Say, the code of the program is as follows:

/* say.cpp */
#include "say.h"

void Say::sayString()
{<!-- -->
    std::cout << string << "\\
";
}
 
Say librarysay("Library instance of Say!");

The program whose source file name is sayhello.cpp is the source code of the second object file that needs to be added to the static library, it contains the definition of the function sayhello(), the program The code is as follows:

/* sayhello.cpp */
#include "say.h"

void sayhello()
{<!-- -->
    std::cout << "The hello from a static library!\\
";
}

A command sequence of the following format compiles a source code file into an object file, and the command ar stores it in the library:

g++ -c sayhello.cpp -Wall
g++ -c say.cpp -Wall
ar -r libsay.a sayhello.o say.o

Write a main program saymain.cpp to call the corresponding program code in the library libsay.a:

/* saymain.cpp */
#include "say.h"

int main(int argc,char *argv[])
{<!-- -->
    extern Say librarysay;
    Say localsay = Say("Local instance of Say!");
    sayhello();
    librarysay.sayThis("howdy");
    librarysay.sayString();
    localsay.sayString();
    return(0);
}

The program can be compiled and linked using commands of the form:

g++ saymain.cpp libsay.a -o saymain

Enter the following command format in the terminal to make it run and display the result:

./saymain

## result
The hello from a static library!
howdy from a static library!
Library instance of Say!
Local instance of Say!
  • Reference book: "Linux Embedded C Development" (by Huaqing Yuanjian)
syntaxbug.com © 2021 All Rights Reserved.