Compilação e linkagem com GCC/G++
Tags: cpp, gcc, linux, programming
Published: 2022-01-12 12:58:52

O GCC é a sigla para **GNU Compiler Collections** e trata-se de um compilador usado em linguagens como C/C++. O trabalho principal de um compilador é transformar um código-fonte em um código binário executável a nível de linguagem de máquina. E é com ele também que se faz a associação com bibliotecas externas (linkagem), geração de códigos para debugging e também arquivos objeto.

Neste resumido artigo será mostrado algum dos comandos mais básicos do GCC (foco em C++, logo o comando usado é o `g++`) para geração de arquivos usados na criação de um executável. A principal fonte e também leitura recomendada é o manual do programa que pode ser acessado pelo comando `man gcc`, ou de forma resumida com `gcc --help`.

### Uso básico do GCC

Ao passar um arquivo para o compilador, as etapas a serem executadas são as seguintes:

- Preprocessamento
- Compilação e assembly
- Linkagem

É possível parar o processo em uma dessa etapas caso se queira e assim gerar arquivos intermediários.

### Parar após preprocessamento

Nesta etapa, ocorre, por exemplo, a inclusão dos arquivos de cabeçalho indicados com a diretiva `#include` e também a substituição das macros (`#define`), além da inclusão de códigos que passam pelos blocos condicionais (`#if`, `#ifdef`, `#ifndef`, etc) entre outra operaçôes. 

O resultado é um arquivo ainda com cara de `C++` porém com dezenas de milhares ou mais de linhas de código pois inclui as definições de todos os arquivos externos (arquivos `*.h`). Convencionalmente, a extensão desse arquivo é `.ii`.

Para gerar o arquivo pós-preprocessamento usa-se a opção `-E` (é preciso indicar um arquivo de saída, ou então será usado o console).

```bash
g++ -E arquivo.cpp -o arquivo.ii
```

### Parar após a compilação

No processo de compilação, o código fonte é transformado em código assembly (extensão `.s`) porém, ainda em formato texto (pode ser visualizado num editor comum). 

Para se obter esse arquivo passa-se a opção `-S`. O arquivo de entrada pode ser tanto um `.cpp` quanto um `.ii`.

```bash
g++ -S arquivo.ii -o arquivo.s
```

### Parar após o assembler

Após a compilação, é gerado um código em assembly mas no formato texto, no entanto, o executável precisa estar no formato binário e para isso é preciso passar pelo etapa do assembler que vai gerar um arquivo binário, porém ainda não executável.

No ambiente Linux, esse arquivo é chamado de arquivo objeto e tem extensão (`.o`), ele contém os símbolos (assunto para outro post) do programa já no formato binário.

Para se chegar nesse arquivo pode se passar qualquer formato anterior com a opção `-c`. Essa opção também é conhecida como "compilar sem linkar", pois é a única etapa pendente para se chegar no executável final.

```bash
g++ -c arquivo.s -o arquivo.o
```

### Adicionar informações para debugging

O debugger do GCC/++ é o **gdb** e para ser usado precisa que o executável contenha informações adicionais no executável final. Para incluir essas informações passa-se a opção `-g`.

```bash
g++ -cg arquivo.cpp -o arquivod.o
```

### Linkagem

Caso se queira compilar e linkar com as bibliotecas, não é necessário passar a opção `-c`. Entende-se que o compilador irá passar por todas as etapas, incluindo a última que é a linkagem com os dependências externas.

Uma vez compilados os arquivos `.cpp` e gerados arquivos `.o`, para se obter o binário executável é necessário passar pelo processo de linkagem.

Para isso passam-se os arquivos compilados `.o` e a lista de bibliotecas com a opção `-l` e nome da lib, sem o prefixo `lib` (por exemplo, `-lGL` para linkar com a `libGL`). Caso seja necessário linkar com uma lib dinâmica (`.so`) que não esteja no sistema, pode-se passar o endereço dessa lib com a opção `-L`. Para linkar com uma lib estática (`.a`), passa-se o arquivo junto dos demais arquivos compilados `.o`.

É importante indicar o arquivo binário final com a opção de output `-o`.

```bash
g++ arquivo.o -lGL another_lib.a -o program
```

### Conclusão

Aqui foram mostradas, por alto, alguns dos comandos mais básicos na geração de arquivos do GCC na hora de compilar e gerar o programa,. Há mais opções úteis quando se tem uma ferramenta tão poderosa assim que pretendo trazer em outro post, como otimizações para gerar programas mais eficientes (porém com compilação mais lenta) e até indicação de qual standard usar (c++11, c++14, etc.).