@embedFile em Zig
O @embedFile incorpora o conteúdo de um arquivo diretamente no binário compilado, em tempo de compilação. Retorna um ponteiro para um array de bytes constante. Ideal para incluir recursos como arquivos de texto, SQL, HTML, imagens ou certificados sem dependências externas em runtime.
Sintaxe
@embedFile(comptime path: []const u8) *const [N]u8
Parâmetros
- path (
[]const u8, comptime): Caminho do arquivo relativo ao diretório do arquivo-fonte atual, ou relativo a um caminho de include configurado no build.zig.
Valor de retorno
Retorna *const [N]u8 — ponteiro para array de bytes constante, onde N é o tamanho do arquivo em bytes. O compilador determina N automaticamente.
Exemplos práticos
Exemplo 1: Incorporar arquivo de texto
const std = @import("std");
// Incorpora o conteúdo de "versao.txt" no binário
const versao = @embedFile("versao.txt");
pub fn main() void {
std.debug.print("Versão: {s}\n", .{versao});
std.debug.print("Tamanho: {} bytes\n", .{versao.len});
}
Exemplo 2: SQL embutido
const std = @import("std");
const sql_criar_tabela = @embedFile("sql/criar_tabela.sql");
const sql_inserir = @embedFile("sql/inserir.sql");
fn executarSQL(conexao: anytype, query: []const u8) !void {
try conexao.exec(query);
}
pub fn main() !void {
// As queries SQL são compiladas no binário
// Não precisa carregar arquivos em runtime
std.debug.print("Query de criação ({} bytes):\n{s}\n", .{
sql_criar_tabela.len,
sql_criar_tabela,
});
}
Exemplo 3: Dados binários (certificado, imagem)
const std = @import("std");
const certificado_raiz = @embedFile("certs/ca-bundle.crt");
const icone = @embedFile("assets/icone.png");
pub fn main() void {
std.debug.print("Certificado: {} bytes\n", .{certificado_raiz.len});
std.debug.print("Ícone: {} bytes\n", .{icone.len});
// Os dados estão disponíveis como slices de bytes
// Prontos para uso sem I/O de arquivo
if (std.mem.startsWith(u8, icone, &[_]u8{ 0x89, 'P', 'N', 'G' })) {
std.debug.print("Formato: PNG confirmado\n", .{});
}
}
Casos de uso comuns
- Queries SQL: Incorporar arquivos
.sqlpara executar sem carregar do disco. - Templates HTML: Incluir templates de página no binário do servidor.
- Certificados TLS: Embutir certificados raiz sem dependência do sistema.
- Shaders: Incluir shaders GLSL/HLSL compilados no binário.
- Dados de teste: Incorporar fixtures de teste diretamente no binário de testes.
- Assets: Imagens, ícones e fontes para aplicações self-contained.
Como @embedFile funciona internamente
O compilador Zig lê o arquivo em tempo de compilação e inclui seu conteúdo como dados estáticos na seção .rodata (ou equivalente) do binário. O arquivo se torna parte do executável — não há leitura de disco em runtime. O caminho do arquivo é resolvido relativamente ao arquivo-fonte que contém o @embedFile.
// Em src/main.zig:
const dados = @embedFile("../assets/config.json");
// Resolve para: assets/config.json relativo ao projeto
Vantagens e desvantagens
Vantagens:
- Binário auto-contido — sem arquivos externos para distribuir
- Zero overhead de I/O em runtime — dados já estão em memória
- Erro em tempo de compilação se o arquivo não existir
- Os dados são imutáveis (
*const [N]u8) — proteção de memória
Desvantagens:
- Aumenta o tamanho do binário
- Não é possível atualizar os dados sem recompilar
- Dados grandes podem aumentar o tempo de link
Trabalhando com o tipo retornado
@embedFile retorna *const [N]u8 — um ponteiro para array. Ele pode ser coercido para vários tipos:
const dados = @embedFile("arquivo.bin");
// Como slice de bytes (mais comum)
const slice: []const u8 = dados;
// Como string (se o arquivo for texto UTF-8)
const texto: [:0]const u8 = dados; // só se terminar com \0
// O tamanho é conhecido em comptime
const tamanho = dados.len; // comptime_int
std.debug.print("Tamanho: {} bytes\n", .{dados.len});
Configurando caminhos de include no build.zig
Para usar @embedFile com arquivos fora da árvore do código-fonte, configure caminhos adicionais no build.zig:
pub fn build(b: *std.Build) void {
const exe = b.addExecutable(.{ /* ... */ });
// Adicionar diretório de assets ao caminho de busca de @embedFile
exe.addAnonymousModule("assets", .{
.root_source_file = b.path("assets/root.zig"),
});
// Ou usar addObjectFile para incluir recursos
b.installArtifact(exe);
}
Comparação com alternativas
| Abordagem | Em runtime | Tamanho binário | Atualizável sem recompilar |
|---|---|---|---|
@embedFile | Não | Maior | Não |
std.fs.readFile | Sim | Menor | Sim |
| Variável de ambiente | Sim | Menor | Sim |
| Argumento CLI | Sim | Menor | Sim |
Use @embedFile quando portabilidade e auto-contenção são prioridade. Use std.fs para dados que mudam frequentemente.
Erros comuns
Caminho incorreto: O caminho é relativo ao arquivo-fonte, não ao diretório de trabalho. Se o arquivo não for encontrado, o compilador emite um erro claro em tempo de compilação — uma das vantagens sobre std.fs.readFile.
Tentar modificar os dados: O array retornado é const — qualquer tentativa de modificar os bytes resultará em erro de compilação. Se precisar de uma cópia mutável, copie para um buffer:
const dados_const = @embedFile("template.html");
var buffer: [dados_const.len]u8 = undefined;
@memcpy(&buffer, dados_const);
// Agora buffer é mutável
Perguntas Frequentes
@embedFile funciona com arquivos binários (imagens, fontes)?
Sim, completamente. @embedFile trata o arquivo como sequência de bytes brutos — não há interpretação de encoding. Funciona igualmente para texto UTF-8, PNG, PDF, ELF, ou qualquer formato binário.
Existe um limite de tamanho para @embedFile?
Não há limite imposto pelo Zig, mas arquivos muito grandes aumentam o tamanho do binário e o tempo de link. Para arquivos de muitos megabytes, considere usar std.fs com leitura em runtime.
Posso usar @embedFile em testes?
Sim. É uma forma elegante de incluir fixtures de teste sem depender de paths relativos que podem quebrar dependendo de onde os testes são executados.
Builtins relacionados
- @import — Importa módulos Zig (não dados binários)
- @compileError — Gera erro se arquivo não existir
- @src — Informações de localização no código-fonte