Como os Programas Go São Estruturados: Pacotes, main e a Toolchain
O Go organiza o código-fonte em pacotes, compila-os em arquivos objeto e os vincula em um único binário estático.
Busque em todas as páginas da documentação
O Go organiza o código-fonte em pacotes, compila-os em arquivos objeto e os vincula em um único binário estático.
Entender esse pipeline ajuda você a posicionar main, raciocinar sobre importações e depurar falhas de compilação sem adivinhar.
main, compilada pela toolchain Go em um único executável sem um runtime separado para distribuir.main, build cache, linking.go build ou decidir onde init e main pertencem.go.mod, modo workspace, vendoring, compilação cruzada e o layout da biblioteca padrão.Arquivos de código-fonte Go pertencem a exatamente um pacote, declarado no topo de cada arquivo com package foo.
O nome do pacote geralmente é o último segmento do import path (por exemplo, import "net/http" usa o pacote http), mas não precisa corresponder ao nome do diretório em casos raros como package main.
Apenas o pacote main produz um executável.
Ele deve definir func main() como o ponto de entrada do processo.
Todos os outros pacotes são bibliotecas: eles compilam para um arquivo de biblioteca (.a) que o linker combina no binário final.
Um módulo é a unidade de versionamento.
O arquivo go.mod na raiz do repositório nomeia o caminho do módulo (por exemplo, example.com/myapp) e fixa as versões das dependências.
Os caminhos de importação dentro do seu módulo começam com esse caminho de módulo mais o caminho do diretório abaixo dele.
Pense no layout como uma pequena linha de produção:
arquivos .go --> compilador go --> arquivos .a --> linker --> binário único
A toolchain Go (comando go) orquestra compilação, linkagem, testes e download de módulos.
Você raramente invoca gc ou ld diretamente.
Quando você executa go build, a ferramenta resolve o grafo de módulos a partir de go.mod, percorre as importações a partir do seu pacote main e compila cada pacote necessário.
Os resultados vão para o build cache em $GOPATH/pkg ou no cache de módulos, para que pacotes inalterados pulem a recompilação.
Identificadores exportados começam com uma letra maiúscula; nomes minúsculos são privados do pacote.
Essa regra é imposta pelo compilador, não por modificadores de acesso no código.
O linker realiza a eliminação de código morto em nível de função para código inalcançável, o que mantém os binários menores do que vincular todos os símbolos de forma ingênua.
// cmd/myapp/main.go - entrada executável
package main
import "example.com/myapp/internal/server"
func main() {
server.Run()
}Diretórios internal/ são especiais: o compilador rejeita importações de example.com/myapp/internal/... de fora da árvore example.com/myapp.
Isso lhe dá um limite imposto para código não público.
Funções init em um pacote são executadas antes de main, na ordem de dependência, e são principalmente para registro ou configuração única.
O uso excessivo de init torna a ordem de inicialização difícil de raciocinar.
go test compila arquivos de teste (*_test.go) no mesmo pacote (ou package foo_test para testes black-box) e vincula um binário de teste que executa funções Test*.
As mesmas regras de grafo de pacotes se aplicam.
Workspaces (go.work) permitem que múltiplos módulos compilem juntos durante o desenvolvimento local sem publicar pseudo-versões.
Use-os quando você edita uma biblioteca e seu consumidor em paralelo.
Compilação cruzada define GOOS e GOARCH; o Go ainda gera um binário estático por padrão na maioria das plataformas.
Builds habilitados para CGO vinculam código C e complicam a compilação cruzada porque precisam de uma toolchain C correspondente.
| Abordagem | Força | Fraqueza | Melhor Ajuste |
|---|---|---|---|
| Monorepo, um módulo | Importações simples, um go.mod | Módulos grandes podem desacelerar CI | Pequenas equipes, produto único |
| Módulo de biblioteca + módulo de app | Limites claros de release | Necessário replace/workaround local | Bibliotecas compartilhadas entre produtos |
Pacotes internal/ | Privacidade imposta pelo compilador | Não pode compartilhar com importadores externos | Auxiliares específicos do aplicativo |
Vendoring (vendor/) | Builds offline reproduzíveis | Manutenção manual ou go mod vendor | Air-gapped ou auditoria rigorosa |
Imagens de contêiner para Go frequentemente copiam apenas go.mod, go.sum e o código-fonte, executam go build -o /app e distribuem uma imagem scratch ou distroless porque o binário não precisa de JVM ou interpretador.
Hooks de observabilidade (pprof, trace) compilam no mesmo binário via importações em branco ou registro explícito em main.
package main e importações renomeadas (import http "net/http") quebram esse padrão.go run pula a etapa de compilação - Ele compila para um binário temporário e o executa; não é um interpretador.unsafe ainda podem acessar dados.go.mod ainda registra as versões.Um módulo é uma unidade versionada declarada em go.mod (geralmente um repositório).
Um pacote é uma unidade de compilação dentro desse módulo (geralmente um diretório de arquivos .go).
Em um pacote chamado main, tipicamente sob cmd/<nome_app>/main.go em projetos maiores.
Apenas um pacote main é vinculado por executável.
O caminho do módulo em go.mod atua como um prefixo globalmente único para que go get possa buscar código de hosts VCS como GitHub ou seu forge privado.
Ele mescla arquivos de biblioteca compilados, resolve símbolos, aplica eliminação de código morto e escreve um executável nativo para o sistema operacional e arquitetura de destino.
Todas as funções init em pacotes importados são executadas primeiro, na ordem de dependência, e então main.main é executado.
Múltiplas funções init em um único arquivo são executadas na ordem do código-fonte.
Ciclos de importação são rejeitados em tempo de compilação.
Refatore tipos compartilhados em um terceiro pacote ou estreite interfaces para quebrar o ciclo.
Go trata caminhos de importação .../internal/... como privados para a árvore pai acima de internal.
Módulos externos não podem importá-los.
Builds puramente Go são vinculados estaticamente por padrão.
Importações de CGO ou certos wrappers de syscall podem puxar bibliotecas dinâmicas dependendo da plataforma e das tags de build.
Os resultados compilados dos pacotes são chaveados por hashes de código-fonte e flags.
Pacotes inalterados reutilizam arquivos .a em cache em vez de recompilar.
cmd/ contém múltiplos pacotes main (ferramentas CLI, workers) enquanto o código da biblioteca permanece importável na raiz do módulo ou sob pkg/ por convenção.
Go seleciona a versão mínima que satisfaz todos os requisitos (MVS).
Você vê uma versão em go.mod, a menos que use replace para exceções.
Módulos substituíram GOPATH para gerenciamento de dependências.
GOPATH ainda define os locais padrão do cache de módulos e artefatos de build, mas você não coloca código-fonte lá para trabalho normal baseado em módulos.
Versões de Stack: Esta página foi escrita para Go 1.26.x (padrão Green Tea GC, modernizadores go fix - verifique o patch na compilação), chi (última versão - verifique na compilação), gin (última versão - verifique na compilação), echo (última versão - verifique na compilação), google.golang.org/grpc (última versão - verifique na compilação), sigs.k8s.io/controller-runtime (última versão - verifique na compilação), kubebuilder (última versão - verifique na compilação), tinygo (última versão - verifique os alvos de placa na compilação), wazero (última versão - verifique na compilação) e golangci-lint (última versão - verifique o conjunto de linters na compilação).
Revisado por Chris St. John·Última atualização: 18 de jul. de 2026