---
title: "Zig como Compilador C/C++: zig cc e zig c++ sem Setup"
url: "https://ziglang.com.br/artigos/zig-compilador-c-cpp-toolchain/"
markdown_url: "https://ziglang.com.br/artigos/zig-compilador-c-cpp-toolchain.MD"
description: "Como usar o Zig como compilador C/C++ com zig cc e zig c++: cross-compile dependências, substitua GCC, Clang e MSVC e monte builds C/C++ sem configurar toolchain."
date: "2026-06-26"
author: ""
---

# Zig como Compilador C/C++: zig cc e zig c++ sem Setup

Como usar o Zig como compilador C/C++ com zig cc e zig c++: cross-compile dependências, substitua GCC, Clang e MSVC e monte builds C/C++ sem configurar toolchain.


Quem já tentou compilar um projeto C/C++ decente em mais de um sistema operacional conhece a dor: instalar GCC no Linux, MinGW no Windows, toolchain da Apple no macOS, configurar `sysroot`, brigar com versão de glibc e ainda assim depender de um CI que nem sempre reproduz a máquina local. O que poucos desenvolvedores percebem é que **o próprio Zig já é um compilador C e C++ completo e portátil**.

Os comandos `zig cc` e `zig c++` são invólucros drop-in sobre o Clang/LLVM que vêm embutidos no próprio binário do Zig, acompanhados das libc de cross-compilação (musl, mingw-w64, glibc e variantes). Isso transforma o Zig em uma toolchain C/C++ que você baixa uma vez e usa para compilar projetos existentes em praticamente qualquer alvo, sem instalar SDK por plataforma.

Este guia mostra como usar o Zig como compilador C/C++ no dia a dia: compilar código C/C++ legado, substituir GCC/Clang/MSVC em pipelines, cross-compilar dependências sem sysroot e integrar tudo aos seus projetos Zig. Ele complementa o guia de [cross-compilation com Zig](/artigos/zig-cross-compilation-guia/), o material de [interoperabilidade com C](/artigos/zig-interoperabilidade-c/) e o [build system do Zig](/tutoriais/zig-build-system/). A ideia central é a mesma: menos setup, mais previsibilidade.

## O que é `zig cc` e por que isso importa

O binário oficial do Zig inclui o Clang, o LLD (linker) e os fontes das libc que ele sabe compilar. Quando você executa `zig cc`, o Zig age como um compilador C que aceita a maior parte das flags que você já conhece (`-O`, `-I`, `-L`, `-l`, `-D`, `-std=c11`), mas com uma vantagem estrutural: ele resolve libc, headers e linker automaticamente para o alvo escolhido.

A consequência prática é enorme para quem trabalha com C/C++ e sistemas:

- um único download substitui GCC, Clang, MinGW e partes do fluxo de MSVC;
- cross-compilar para Windows a partir do Linux (ou o contrário) não exige instalar toolchain adicional;
- o CI fica reproduzível porque a toolchain viaja junto com o projeto;
- dependências em C/C++ de um projeto Zig podem ser construídas com a mesma ferramenta que já cuida do resto.

Antes de qualquer benchmark ou recurso avançado, esse é o ganho real: **previsibilidade**. O mesmo `zig cc 0.14.1` produz o mesmo binário na sua máquina, na do colega e no runner do CI.

## `zig cc` versus `zig c++` versus `zig build`

São três coisas diferentes e vale separar antes de continuar:

| Comando | Para que serve | Quando usar |
|---|---|---|
| `zig cc` | Compila código C (drop-in para `gcc`/`clang`) | Projetos C, dependências em C, scripts de build |
| `zig c++` | Compila código C++ (drop-in para `g++`/`clang++`) | Projetos C++, bibliotecas que precisam de C++ |
| `zig build` | Orquestra um projeto Zig via `build.zig` | Quando o projeto principal é em Zig |

A confusão comum é achar que `zig build` é a única forma de usar o Zig. Ele é o caminho para projetos nativamente em Zig, mas `zig cc`/`zig c++` existem justamente para a base enorme de código C e C++ que já existe no mundo. Se você está construindo um projeto Zig, use `zig build`; se está compilando algo em C/C++ que já existe, use `zig cc` ou `zig c++`.

## Compilando um projeto C existente

Comece pelo caso mais simples: um programa em C que precisa virar binário.

```bash
# main.c
# #include <stdio.h>
# int main(void) { printf("olá do zig cc\n"); return 0; }

zig cc main.c -o app
./app
```

Sem Makefile, sem `configure`, sem instalar nada além do próprio Zig. Para algo um pouco maior, com vários arquivos e includes:

```bash
zig cc -O2 -std=c11 -Iinclude src/main.c src/parser.c src/io.c -lm -o app
```

As flags são as mesmas que você usaria com GCC ou Clang. É exatamente por isso que a substituição costuma ser tão direta em projetos legados: a interface é compatível.

## Substituindo GCC, Clang e MSVC com `CC=zig cc`

A maneira mais limpa de adotar o Zig como compilador em um projeto C/C++ existente não é reescrever o build, e sim **apontar as variáveis de ambiente** para o Zig. Makefiles, CMake, Autotools e Meson em geral respeitam `CC`, `CXX`, `LD` e afins.

```bash
export CC="zig cc"
export CXX="zig c++"

make            # agora compila com o Zig como compilador
cmake -B build && cmake --build build
```

Em CMake, às vezes é preciso também passar o linker:

```bash
cmake -B build \
  -DCMAKE_C_COMPILER="zig" -DCMAKE_C_COMPILER_ARG1="cc" \
  -DCMAKE_CXX_COMPILER="zig" -DCMAKE_CXX_COMPILER_ARG1="c++"
```

O detalhe do `ARG1` aparece porque alguns sistemas de build esperam um executável único (`zig`) e o `cc`/`c++` vira argumento. Para quem está saindo do CMake, vale revisar o roteiro de [migrar CMake para build.zig](/tutoriais/migrar-cmake-para-build-zig/); a diferença é que aqui a ideia é manter o CMake e só trocar a toolchain, não o sistema de build.

## Cross-compilação C/C++ sem configurar sysroot

Aqui mora o recurso que mais economiza tempo. O Zig embute as libc necessárias para cross-compilar, então um único comando compila para um alvo diferente sem que você precise baixar toolchain, `sysroot` ou headers extras.

```bash
# Linux → Windows (sem instalar MinGW)
zig cc main.c -target x86_64-windows-gnu -o app.exe

# Linux/macOS → Linux com musl (binário estável, portável)
zig cc main.c -target x86_64-linux-musl -o app

# Qualquer SO → macOS (ABI arm64)
zig cc main.c -target aarch64-macos-none -o app

# Linux → ARM Linux (comum em embarcados/Raspberry Pi)
zig cc main.c -target aarch64-linux-gnu -o app
```

O formato do `-target` é `<cpu>-<os>-<libc>`. Para alvos sem libc (bare metal, firmware), use `-none`. Isso conversa diretamente com o material de [sistemas embarcados e IoT](/artigos/zig-embarcados-iot/) e com o guia de [cross-compilation para FreeBSD e NetBSD](/artigos/zig-cross-compilation-freebsd-netbsd/): a mesma toolchain que gera seu binário de servidor gera o firmware e o binário de desktop.

Um cuidado importante: cross-compilar funciona bem quando o projeto depende apenas de libc padrão e bibliotecas estáticas que você também compila. Se o projeto liga dinamicamente contra bibliotecas de sistema do alvo (uma `libfoo.so` específica), você ainda precisa dessas bibliotecas. O `zig cc` resolve headers e libc embutidos, não magicamente baixa dependências de terceiros.

## Compilando dependências C/C++ para um projeto Zig

Na prática, muitos projetos Zig dependem de bibliotecas em C. O fluxo natural é compilar essas dependências com o mesmo `zig cc` que já cuida do resto, garantindo que alvo, ABI e libc batam. O artigo sobre [dependências e `build.zig.zon`](/artigos/zig-dependencias-build-zig-zon-guia-pratico/) trata de pacotes Zig; aqui o foco é dependência em C.

No `build.zig`, adicione fontes C diretamente ao seu passo de build:

```zig
const exe = b.addExecutable(.{
    .name = "meuapp",
    .root_module = b.createModule(.{
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    }),
});

// Compila um arquivo C com a mesma toolchain/alvo do projeto.
exe.root_module.addCSourceFile(.{
    .file = b.path("vendor/mini.c"),
    .flags = &.{ "-std=c11", "-O2" },
});

// Caso precise de headers do projeto C.
exe.root_module.addIncludePath(b.path("vendor/include"));
```

Se a dependência é maior e usa o próprio `configure`/`Makefile`, a abordagem é rodar esse build apontando `CC=zig cc` para o `target` desejado e depois ligar o `.a`/`.lib` gerado ao seu executável Zig com `exe.linkLibrary(...)` ou `exe.addObject`. O ganho é que uma única toolchain compila a dependência e o código Zig no mesmo alvo, sem desalinhamento de ABI.

## O que já vem embutido (e o que não vem)

É honesto separar expectativas. Junto com `zig cc`, você já tem:

- **Clang/LLVM** para C, C++ e Objective-C;
- **LLD** como linker integrado;
- **libc de cross-compilação**: musl, mingw-w64, glibc (várias versões) e suporte limitado a MSVC;
- headers de libc para os alvos suportados.

O que o `zig cc` **não** resolve sozinho:

- bibliotecas de terceiros (`libssl`, `libcurl`, `libpq` etc.) precisam ser compiladas ou obtidas para o alvo;
- SDKs proprietários ainda exigem instalação em alguns casos (alguns alvos macOS e o `windows-msvc` têm restrições);
- sanitizers e ferramentas de debugging avançadas nem sempre têm paridade total com Clang standalone.

Para integração com banco de dados, por exemplo, você continua precisando da libpq do alvo — veja o guia de [PostgreSQL com libpq em produção](/artigos/zig-postgresql-libpq-producao/). O `zig cc` encurta o caminho da toolchain, mas não substitui planejar suas dependências.

## CI/CD com zero setup de toolchain

Em pipelines de CI, o ganho é imediato. Em vez de instalar `gcc-multilib`, `mingw-w64`, versão específica de `clang` e cache de `sysroot`, você baixa um tarball do Zig e tem tudo. Para releases multiplataforma, combine com o roteiro de [GitHub Actions para Zig](/artigos/zig-github-actions-release-multiplataforma/):

```bash
# matriz de alvos, mesma toolchain
for target in \
  x86_64-linux-musl \
  aarch64-linux-gnu \
  x86_64-windows-gnu \
  x86_64-macos-none; do
  zig cc src/main.c -target "$target" -o "app-$target"
done
```

Cada binário sai da mesma execução, do mesmo runner, com a mesma versão de Zig. Isso reduz drásticamente a categoria inteira de bugs "funciona na minha máquina, quebra no CI".

## Quando não usar `zig cc`

Nem toda situação pede o Zig como compilador C/C++. Evite trocar quando:

- o projeto já tem toolchain validada e auditada e não há demanda de cross-compilação;
- você precisa de um recurso específico de MSVC (como algumas opções de linker do Windows) que ainda não tem paridade;
- o time depende de sanitisadores/profilers que exigem o Clang standalone ou GCC com versão específica;
- a integração depende fortemente de um SDK proprietário que o Zig não cobre.

A regra prática: use `zig cc` quando o objetivo for **portabilidade e reprodutibilidade**, especialmente com cross-compilação. Se o objetivo for explorar recursos experimentais de um compilador específico, mantenha esse compilador.

## Checklist antes de padronizar a toolchain

Antes de adotar `zig cc` como compilador C/C++ padrão do projeto, confira:

- a versão do Zig está fixada no projeto e no CI (via `build.zig.zon` ou cache de download);
- os alvos necessários (`-target`) foram testados de verdade, não assumidos;
- as dependências em C/C++ são compiladas com o mesmo `CC=zig cc` do alvo;
- os binários de release rodam nos sistemas alvo (principalmente Windows e macOS);
- o `CMake`/`Makefile` está passando o linker corretamente quando necessário;
- há um fallback documentado caso um alvo deixe de ser suportado;
- o tamanho do binário e o uso de sanitizers foram checados para builds de debug;
- o time sabe que `zig cc` e `zig build` são coisas diferentes.

## Perguntas frequentes

**`zig cc` é o Clang?** Sim, por baixo dos panos é o Clang/LLVM, com LLD e libc gerenciados pelo próprio Zig. A vantagem é o empacotamento e a resolução automática de libc por alvo.

**Preciso instalar o MinGW para gerar `.exe`?** Não. Com `-target x86_64-windows-gnu`, o Zig usa o mingw-w64 embutido. Para `-windows-msvc`, há suporte, mas com mais ressalvas.

**`zig cc` compila C++?** Para C++ use `zig c++`. Ele linka a libc++ corretamente. Para projetos mistos, geralmente basta definir `CXX=zig c++`.

**Isso substitui o GCC em distros Linux?** Para compilar seus projetos, sim. Para gerenciar pacotes do sistema, não — a toolchain de pacotes do seu SO segue sendo a fonte de verdade do sistema.

**Funciona para firmware/embarcados?** Sim, é um dos pontos fortes. Para alvos bare metal e RTOS, combine com o conteúdo sobre [firmware no ESP32 com FreeRTOS](/artigos/zig-esp32-freertos-firmware/).

## Próximos passos

Se você vai padronizar o Zig como toolchain C/C++, leia também o guia de [cross-compilation](/artigos/zig-cross-compilation-guia/), a [interoperabilidade com C](/artigos/zig-interoperabilidade-c/) e como [migrar um projeto C para Zig](/artigos/migrar-projeto-c-para-zig/). Para comparar com outra linguagem de sistemas que também precisa de uma toolchain C/C++ para dependências nativas, veja como o tema aparece em <a href="https://rustlang.com.br/artigos/rust-para-embarcados/" target="_blank" rel="noopener noreferrer" onclick="umami.track('portfolio-site-click', { destination: 'rustlang.com.br' })">Rust para embarcados</a>: a diferença é que o Rust delega o C para o compilador do sistema (via crate `cc`), enquanto o Zig já embute o compilador e as libc de cross-compilação — o que costuma eliminar boa parte da configuração por plataforma.
