📜 ⬆️ ⬇️

Unix as IDE: Compile

Under Unix, there are many compilers and interpreters, but here we will discuss only gcc as a means of compiling C code, and briefly touch on using perl as an example interpreter.

Gcc



GCC is a set of compilers with a very respectable age and distributed under the GPL license. It is known as a tool for working with C and C ++ programs. A free license and widespread prevalence on Unix-like systems have become the key to its continued popularity, although there are more modern alternatives using LLVM infrastructure, such as Clang .

The main gcc executable file is best presented not as a compiler in the usual sense, but as a layer of abstraction over a multitude of individual programming tools that perform code parsing, compilation, linking and other actions. This means that using it you can not just get a working binary from C code, but explore in detail all the steps of this complex process, and if necessary adjust it to fit your needs.
')
Here I will not discuss the use of make-files, although they will certainly be needed for any project more difficult than in a single file. Makefile I touch in the next article on the automation of the assembly.

Compiling and building object code



The object code is compiled with this command:

$ gcc -c example.c -o example.o 


If the code is correct, an unlinked binary object file named example.o will be created in the current folder, or problems will be reported. You can look inside the received file and see its contents in assembly language like this:

 $ objdump -D example.o 


Alternatively, you can ask gcc to immediately show the final assembly code with the -S parameter:

 $ gcc -c -S example.c -o example.s 


The output of the assembler code can be useful to combine with the output of the source itself, which can be achieved by typing:

 $ gcc -c -g -Wa,-a,-ad example.c > example.lst 


Preprocessor



The C preprocessor ( cpp ) is commonly used to include header files and define macros. This is a standard part of the gcc compilation process, but you can view the code it generates by calling cpp directly:

 $ cpp example.c 


The source code will be displayed in the final form, ready for compilation, with macros replaced and substitution of included external files.

Linking objects



One or several object files can be linked to the corresponding executable file:

 $ gcc example.o -o example 


In this example, gcc just calls ld , the GNU linker. The command will create an executable file named example .

Compilation, assembly and linking



All of the above can be done in one step with the command:

 $ gcc example.c -o example 


This method is simpler, but compiling objects separately gives some performance gain: you do not need to compile unchanged code, but we'll talk about this in the next article.

Include external files and bind



C files and header files can be explicitly included in the compilation using the -l option:

 $ gcc -I/usr/include/somelib.h example.c -o example 


Similarly, if the code needs to be dynamically linked to an already compiled system library, available in one of the system folders ( /lib or /usr/lib ), for example, ncurses , this can be achieved using the -l option :

 $ gcc -lncurses example.c -o example 


If in the process of compiling external links a lot, it makes sense to add them to the environment variables:

 $ export CFLAGS=-I/usr/include/somelib.h $ export CLIBS=-lncurses $ gcc $CFLAGS $CLIBS example.c -o example 


By the way, the Makefile is then created to save us from worrying about such trifles.

Compilation plan



To see the details of the gcc internal kitchen, you can add the -v option , and the compilation plan will be output to the standard error output stream:

 $ gcc -v -c example.c -o example.o 


If there is no need to generate object or executable files, then for accuracy you can use - ### :

 $ gcc -### -c example.c -o example.o 


It is very useful to see what actions gcc takes without our knowledge, in addition, so we can identify unwanted steps during compilation.

Advanced error reporting



It is possible to add the -Wall and / or -pedantic keys so that gcc warns us about cases that are not necessarily errors, but can be:

 $ gcc -Wall -pedantic -c example.c -o example.o 


It is convenient to include such options in the Makefile or in the definition of a makeprg for Vim , as they are perfectly combined with the quickfix window, and help to write readable, compatible and error-free code.

Profiling the compilation process



You can enable the -time option so that gcc displays the execution time of each step in the output text:

 $ gcc -time -c example.c -o example.o 


Optimization



Gcc has optimization keys, indicating that you can ask it to create more efficient object code and related binaries by increasing the compile time. I consider -O2 as the golden mean for the released code:

 gcc -O1 gcc -O2 gcc -O3 


Like any Bash command, all this can be invoked directly from Vim:

 :!gcc % -o example 


Interpreters



The approach to interpreted code in Unix-systems is different. In my examples I will use Perl, but the same principles apply for code, for example, in Python or Ruby.

Inline code



You can string Perl-code directly to the interpreter in any of the following ways: The first is probably the easiest and most common way to work with Perl ; the second uses the heredoc syntax, and the third is the classic Unix pipeline.

 $ perl -e 'print "Hello world.\n";' $ perl <<<'print "Hello world.\n";' $ echo 'print "Hello world.\n";' | perl 


Of course, in everyday life we ​​store the code in a file that can be called directly like this:

 $ perl hello.pl 


You can check the syntax of the code without executing it with the -c option :

 $ perl -c hello.pl 


Sometimes you want to use the script like any binary executable, without worrying about what it represents. To do this, the script adds the first line to the so-called " shebang ", indicating the path to the interpreter, which should be transferred to the execution of the file.

 #!/usr/bin/env perl print "Hello, world.\n"; 


The script can then set the attribute of the executable file by calling chmod . It is also considered good practice to rename a file, removing extensions, since it is now considered almost a real executable file:

 $ mv hello{.pl,} $ chmod +x hello 


Then the file can be called directly without an interpreter:

 $ ./hello 


This whole kitchen works so well that many standard Linux system utilities, such as adduser , are actually Perl or Python scripts.

In the next post I will talk about the methods of working with make to build projects that are comparable to the usual IDE.

To be continued...

Unix as IDE: Introduction
Unix as IDE: Files
Unix as IDE: Working with Text
Unix as IDE: Compile

Source: https://habr.com/ru/post/151314/


All Articles