Sempre que criamos um arquivo com definições de funções personalizadas, por exemplo, utils.c
e seu arquivo de cabeçalho correspondente utils.h
contendo as declarações de função, preciso compilar o utils.c
arquivo junto com o código do driver em que estou usando, com um comando como gcc driver.c utils.c -o my_exe
.
Então, qual instrução compila os arquivos C padrão, cujos arquivos de cabeçalho incluímos como stdio.h
?
A compilação é um processo de três etapas: pré-processamento, compilação e vinculação.
gcc driver.c utils.c -o my_exe
é uma abreviação de:Que é compilar o driver, compilar os utilitários e então vincular tudo.
Ainda menos claro aqui é que as inclusões são copiadas para os arquivos C para compilação. Os passos a seguir dividem ainda mais para mostrar o pré-processamento que manipula o código nos arquivos de cabeçalho:
gcc driver.o utils.o -o my_exe
Também é possível alterar as bibliotecas de inclusão, por exemplo,-lm
para incluir a biblioteca matemática padrão (libm.a ou libm.so). Bibliotecas são apenas código-fonte C pré-compilado (código objeto ou.o
) em um arquivo contêiner.As bibliotecas padrão (como em
stdlib.h
estdio.h
) sãolibc.so
(oulibc.a
). Você não precisa vinculá-las explicitamente, mas pode fazê-lo se quiser.Então
gcc driver.o utils.o -o my_exe
se tornagcc driver.o utils.o -o my_exe -lc
Você pode pré-compilar seu código da mesma maneira para vinculação posterior:
Ao compilar,
gcc driver.c utils.c -o my_exe
ele pulará a criação dos arquivos .o correspondentes e, como as alterações de driver.c e utils.c são necessárias na saída final, você precisa executar este comando sempre que houver alguma alteração em qualquer um desses arquivos. Como mencionado na resposta anterior, o arquivo C padrão é compilado como uma biblioteca estática ou dinâmica, e estas serão criadas pelo proprietário do pacote correspondente e estarão disponíveis para o usuário como parte de qualquer pacote do sistema operacional, por exemplo, libc-dev.Para evitar a compilação quando não houver modificações em um arquivo específico, você pode usar o Makefile, que cria um arquivo ".o" intermediário, algo como
Na maioria das implementações C, o código-fonte da biblioteca C padrão foi preparado para você e empacotado em arquivos de “biblioteca”.
O código-fonte da biblioteca padrão é compilado ou montado em módulos de objetos, e esses módulos de objetos são inseridos em arquivos de biblioteca estáticos ou dinâmicos. Arquivos de biblioteca são, em grande parte, apenas coleções de módulos de objetos.
O GCC e o Clang incluem a biblioteca padrão por padrão ao vincular. (Há algumas complicações nisso, como o fato de algumas implementações exigirem uma
-lm
opção adicional para incluir as rotinas matemáticas da biblioteca padrão.) O comandogcc
orclang
(e algumas outras variantes, comog++
) é, na verdade, um "front-end" que chama o compilador e/ou o montador e/ou o vinculador conforme necessário para os argumentos que você passa. Se você der a-v
opção, eles mostrarão os comandos que executam, e o comando link incluirá um ou mais arquivos de biblioteca.Isso é o que acontece quando você inclui
#include <stdio.h>
(adiciona funções de entrada/saída comoprintf
), para gerenciamento de memória#include <stdlib>
, manipulação de strings#include <string.h>
etc... você diz ao compilador para copiar as declarações paraprintf
,scanf
etc... essas funções estão nos arquivos de cabeçalho, comostdio.h
,stdlib
etc... o código para esses arquivos já está compilado, eles são parte da biblioteca GNU C.você tenta verbose onde esses arquivos estão localizados
gcc -v your_program.c -o your_program
a saída ficaria assim
aqui você pode ver três fases:
Compilação de seus
.c
arquivos em.o
arquivos de objeto, por meio de chamadas paracc1
eas
.Vinculação desses arquivos de objeto, além dos arquivos de inicialização (
Scrt1.o
,crti.o
,crtn.o
) e das bibliotecas de tempo de execução C pré-construídas (bibliotecas de suporte do GCC e a biblioteca padrão C).O resultado é seu executável final.
No seu dump detalhado, a linha-chave está enterrada na invocação
collect2
/ld
:… -plugin-opt=-pass-through=-lc … -lc …
Esse
-lc
é o sinalizador do vinculador que informa:Você não compila
stdio.c
(nem qualquer um dos.c
códigos-fonte da glibc) sozinho. A biblioteca C é fornecida como arquivos pré-compilados (libc.a
) e objetos compartilhados (libc.so
), e os drivers GCC são passados automaticamente-lc
em tempo de link para que todas as suas<stdio.h>
declarações sejam resolvidas em código real na libc.uma boa leitura seria https://www.gnu.org/software/libc/manual/html_node/Header-Files.html e Como funciona o processo de compilação/vinculação?
Os arquivos C padrão já estão compilados e fazem parte da biblioteca stdc++ e de outras bibliotecas vinculadas a ela. No meu caso, estava lá em
Um teste de exemplo para verificar se a
.so
contém uma função ou não. Acabei de verificar seprintf
está presente nestelibstdc++.so.6
.Cada versão do gcc tem uma versão correspondente
libstdc++.so
, por isso não é possível executar um executável criado com uma versão superior do gcc em uma versão inferior. Ele não possui os símbolos de tempo de execução necessários.