C++ Usar Bibliotecas Externas

A biblioteca padrão do C++ é grande, mas não tem tudo: não comprime arquivos, não desenha janelas, não conversa com bancos de dados. Para isso existem milhares de bibliotecas externas, código pronto, testado e gratuito, escrito por outras pessoas. Usar uma em C++ dá um pouco mais de trabalho do que em outras linguagens, porque a biblioteca precisa chegar em duas etapas: os cabeçalhos na compilação e o código já compilado na ligação. Nesta aula você vai entender essas duas partes, instalar bibliotecas pelo apt, ligá-las com -l e deixar o pkg-config e o CMake encontrarem tudo por você.

Você vai aprender
  • A diferença entre bibliotecas header-only e compiladas.
  • Como achar e instalar uma biblioteca pelo apt, e por que o pacote certo termina em -dev.
  • Como compilar e ligar com -l (exemplo real: a zlib, com -lz), e por que a posição do -l importa.
  • Como o pkg-config descobre as opções certas.
  • Como o CMake faz isso com find_package.
  • O que são os gerenciadores de pacotes vcpkg e Conan.

Os comandos desta aula foram executados na máquina fictícia da Ana (usuária ana, computador notebook), um Ubuntu 26.04 com o g++ 15.2 e o CMake 4.2. Nela, a biblioteca de compressão zlib já está instalada (com o pacote de desenvolvimento), e a biblioteca de formatação fmt não está; os exemplos com a fmt instalada estão marcados como ilustrativos.


A ideia: comprar pronto

A Ana quer pôr um bolo de casamento no cardápio da lojinha. Ela pode fazer tudo do zero, ou comprar a massa pronta de uma confeitaria e só montar. Uma biblioteca é isso: alguém já fez a parte difícil (e testou muito), e você só usa.

Em C++, uma biblioteca chega de um destes dois jeitos:

Header-only ("só cabeçalho")Compilada
O que vemsó arquivos .h, com todo o código dentro (funções inline, templates)arquivos .h (as declarações) e um arquivo binário (.so ou .a no Linux) com o código já compilado
Na compilação#include#include
Na ligaçãonadaé preciso pedir a biblioteca: -l…
Vantagemfácil: copie o arquivo para a pasta e prontocompila rápido (o código pesado já está pronto)
Exemplosdoctest, nlohmann/json, a maior parte do Boostzlib, SQLite, OpenSSL, Qt, fmt (que também tem um modo header-only)

Você já usou uma header-only na aula Testes Automatizados: a doctest é um único arquivo doctest.h, baixado para a pasta do projeto. E se lembra das duas partes de um projeto com vários arquivos (Arquivos .h e .cpp)? Uma biblioteca compilada é a mesma coisa, só que o .cpp foi compilado por outra pessoa e você recebe o resultado pronto.


1. Header-only: só incluir

Uma biblioteca header-only é simplesmente um .h com tudo dentro. Para ver como é por dentro, a Ana escreveu uma bem pequena, para mostrar preços em reais:

#pragma once
// moeda.h: uma "biblioteca" header-only. Tudo está aqui; não há nada para ligar.
#include <format>
#include <string>

namespace moeda {

inline std::string reais(double valor) {
    std::string texto = std::format("{:.2f}", valor);   // por exemplo, "27.50"
    for (char& c : texto) {
        if (c == '.') {
            c = ',';
        }
    }
    return "R$ " + texto;
}

}

Repare nos ingredientes: #pragma once, um namespace próprio (para não colidir com nomes de quem usa) e funções inline (para poderem ser incluídas por vários .cpp sem o erro "múltiplas definições"). É exatamente o que as bibliotecas header-only de verdade fazem, só que com milhares de linhas.

Experimente: a aba moeda.h é a biblioteca, e o main.cpp só a inclui. Rode. Depois acrescente à biblioteca uma função inline std::string centavos(int c) que devolve reais(c / 100.0) e use-a no main com moeda::centavos(1990).

#include <iostream>
#include "moeda.h"

int main() {
    std::cout << "Pão: " << moeda::reais(0.75) << '\n';
    std::cout << "Total: " << moeda::reais(27.5) << '\n';
}
#pragma once
// moeda.h: uma "biblioteca" header-only. Tudo está aqui; não há nada para ligar.
#include <format>
#include <string>

namespace moeda {

inline std::string reais(double valor) {
    std::string texto = std::format("{:.2f}", valor);   // por exemplo, "27.50"
    for (char& c : texto) {
        if (c == '.') {
            c = ',';
        }
    }
    return "R$ " + texto;
}

}

2. Instalar uma biblioteca compilada pelo apt

No Ubuntu, as bibliotecas mais conhecidas estão no repositório de pacotes, prontas para instalar com o apt (veja o Instalar no Linux). Cada biblioteca costuma vir em dois pacotes:

PacoteExemploO que trazQuem precisa
a biblioteca (runtime)libfmt10só o binário .soquem roda programas que usam a biblioteca
o de desenvolvimento, terminado em -devlibfmt-devos cabeçalhos .h, o .so para ligar, o arquivo do pkg-config e o do CMakequem compila programas com a biblioteca: você

Procurar e conferir

Para achar o nome do pacote, use apt-cache search. A opção --names-only procura só nos nomes, e o ^ quer dizer "começando com":

$ apt-cache search --names-only '^libfmt'
libfmt-dev - fast type-safe C++ formatting library -- development files
libfmt-doc - fast type-safe C++ formatting library -- documentation
libfmt-ocaml - OCaml Format pretty-printer combinators (runtime)
libfmt-ocaml-dev - OCaml Format pretty-printer combinators (development)
libfmt10 - fast type-safe C++ formatting library -- library
$ apt-cache show libfmt-dev | grep -E '^(Description|Homepage)' | head -3
Homepage: https://fmt.dev/
Description-en: fast type-safe C++ formatting library -- development files
Description-md5: 7963a4ca548a609af43ee9bd78ee3acd

Os dois libfmt-ocaml são de outra linguagem, com nome parecido: leia a descrição. O que interessa é o libfmt-dev ("arquivos de desenvolvimento"). Para saber se ele está instalado e qual versão viria, use apt-cache policy:

$ apt-cache policy libfmt-dev
libfmt-dev:
  Instalado: (nenhum)
  Candidato: 10.1.1+ds1-4build1
  Tabela de versão:
     10.1.1+ds1-4build1 500
        500 http://archive.ubuntu.com/ubuntu resolute/universe amd64 Packages
Instalado: (nenhum)
Não está instalado.
Candidato: 10.1.1+ds1-4build1
A versão que o apt install instalaria: a fmt 10.1.1 (o resto é a numeração do pacote no Ubuntu).
resolute/universe
Vem do repositório universe do Ubuntu 26.04 (codinome resolute), mantido pela comunidade.

Compare com a zlib, que a Ana já tem:

$ apt-cache policy zlib1g-dev
zlib1g-dev:
  Instalado: 1:1.3.dfsg+really1.3.1-1ubuntu3.1
  Candidato: 1:1.3.dfsg+really1.3.1-1ubuntu3.1
  Tabela de versão:
 *** 1:1.3.dfsg+really1.3.1-1ubuntu3.1 500
        500 http://archive.ubuntu.com/ubuntu resolute-updates/main amd64 Packages
        500 http://security.ubuntu.com/ubuntu resolute-security/main amd64 Packages
        100 /var/lib/dpkg/status
     1:1.3.dfsg+really1.3.1-1ubuntu3 500
        500 http://archive.ubuntu.com/ubuntu resolute/main amd64 Packages

Os *** marcam a versão instalada (a zlib 1.3.1, com uma atualização de segurança).

Ver o que seria instalado, sem instalar

apt-get -s install faz uma simulação (-s): mostra o que aconteceria, sem mudar nada e sem pedir senha. É um bom hábito antes de instalar:

$ apt-get -s install libfmt-dev
NOTA: Esta é apenas uma simulação!
      apt-get precisa de privilégios de root para execução real.
      Lembre-se também de que a trava está desativada e,
      portanto, não dependa da relevância para a situação real atual!
Lendo listas de pacotes...
Construindo árvore de dependências...
Lendo informação de estado...
Resolvendo dependências...
Os pacotes adicionais a seguir serão instalados:
  libfmt10
Pacotes sugeridos:
  libfmt-doc
Os NOVOS pacotes a seguir serão instalados:
  libfmt-dev libfmt10
0 pacotes atualizados, 2 pacotes novos instalados, 0 a serem removidos e 12 não atualizados.
Inst libfmt10 (10.1.1+ds1-4build1 Ubuntu:26.04/resolute [amd64])
Inst libfmt-dev (10.1.1+ds1-4build1 Ubuntu:26.04/resolute [amd64])
Conf libfmt10 (10.1.1+ds1-4build1 Ubuntu:26.04/resolute [amd64])
Conf libfmt-dev (10.1.1+ds1-4build1 Ubuntu:26.04/resolute [amd64])

Pedindo o libfmt-dev, o apt traz junto o libfmt10 (a biblioteca em si), como explicado na tabela acima. As linhas Inst (instalar) e Conf (configurar) são o plano. Para instalar de verdade: sudo apt install libfmt-dev.

O que tem dentro de um pacote -dev

O dpkg -L lista os arquivos de um pacote instalado. Filtrando os que interessam, da zlib:

$ dpkg -L zlib1g-dev | grep -E '\.(h|so|a|pc)$'
/usr/include/zconf.h
/usr/include/zlib.h                                   « o cabeçalho que você inclui
/usr/lib/x86_64-linux-gnu/libz.a                      « a biblioteca estática
/usr/lib/x86_64-linux-gnu/pkgconfig/zlib.pc           « o arquivo do pkg-config
/usr/share/doc/zlib1g-dev/examples/gzlog.h
/usr/share/doc/zlib1g-dev/examples/zran.h
/usr/lib/x86_64-linux-gnu/libz.so                     « a biblioteca compartilhada

O zlib.h está em /usr/include, uma das pastas onde o #include <…> procura (lembra da lista em O Pré-processador?). Por isso basta #include <zlib.h>, sem -I.


3. Compilar e ligar com -l

A zlib é a biblioteca de compressão por trás do formato .gz, do PNG e de boa parte da internet. A Ana a usou para ver quanto uma lista de compras repetida encolhe:

#include <iostream>
#include <string>
#include <vector>
#include <zlib.h>

int main() {
    std::string texto;
    for (int i = 0; i < 50; ++i) {
        texto += "pão, leite, café; ";
    }

    uLongf tamanho = compressBound(texto.size());
    std::vector<Bytef> comprimido(tamanho);
    int resultado = compress(comprimido.data(), &tamanho,
                             reinterpret_cast<const Bytef*>(texto.data()), texto.size());
    if (resultado != Z_OK) {
        std::cout << "Erro ao comprimir: " << resultado << '\n';
        return 1;
    }

    std::cout << "zlib versão " << zlibVersion() << '\n';
    std::cout << "Original:   " << texto.size() << " bytes\n";
    std::cout << "Comprimido: " << tamanho << " bytes\n";
}
#include <zlib.h>
As declarações da zlib: as funções compress, compressBound, zlibVersion e os tipos uLongf e Bytef (números e bytes, nos nomes que a zlib usa).
compressBound(texto.size())
"No pior caso, quantos bytes a versão comprimida pode ter?" Usado para reservar espaço no vector.
compress(destino, &tamanho, origem, tamanhoOrigem)
Comprime. A zlib é uma biblioteca em C, que trabalha com bytes e ponteiros: o reinterpret_cast<const Bytef*> diz "trate as letras do texto como bytes", e o &tamanho deixa a função escrever no tamanho quantos bytes realmente usou.
Z_OK
A constante que a zlib devolve quando deu certo. Bibliotecas em C avisam erros assim, por um número.

Compilando do jeito de sempre:

$ g++ -std=c++23 -Wall -Wextra zip.cpp -o zip
/usr/bin/x86_64-linux-gnu-ld.bfd: /tmp/ccdRfd5K.o: na função "main":
zip.cpp:(.text+0x6e): referência não definida para "compressBound"
/usr/bin/x86_64-linux-gnu-ld.bfd: zip.cpp:(.text+0xd9): referência não definida para "compress"
/usr/bin/x86_64-linux-gnu-ld.bfd: zip.cpp:(.text+0x152): referência não definida para "zlibVersion"
collect2: error: ld returned 1 exit status

A compilação passou: o zlib.h foi achado e declarou as funções. Quem falhou foi a ligação: é o undefined reference ("referência não definida") de Compilar Vários Arquivos. O corpo das funções está no libz.so, e ninguém pediu ao ligador para olhar lá. É para isso que serve o -l:

$ g++ -std=c++23 -Wall -Wextra zip.cpp -o zip -lz
$ ./zip
zlib versão 1.3.1
Original:   1000 bytes
Comprimido: 38 bytes

Mil bytes (50 repetições de 20 bytes; o ã e o é ocupam 2 bytes cada em UTF-8) viraram 38: texto repetido comprime muito bem.

-lz
-l (de library, "biblioteca") seguido do nome curto da biblioteca, colado. O ligador transforma -lz em libz.so (ou libz.a): põe lib na frente e a extensão no fim. Do mesmo jeito, -lfmt procura libfmt.so e -lsqlite3 procura libsqlite3.so.
a posição: no fim
Depois dos arquivos que usam a biblioteca. Veja o porquê logo abaixo.

Os arquivos que o -lz pode encontrar:

$ ls /usr/lib/x86_64-linux-gnu/libz.*
/usr/lib/x86_64-linux-gnu/libz.a
/usr/lib/x86_64-linux-gnu/libz.so
/usr/lib/x86_64-linux-gnu/libz.so.1
/usr/lib/x86_64-linux-gnu/libz.so.1.3.1
ArquivoTipoComo funciona
libz.so (shared object)biblioteca compartilhada (dinâmica)o programa guarda só uma referência; a biblioteca é carregada quando ele roda. Um programa menor, e todos os programas do sistema usam a mesma cópia (e recebem as atualizações de segurança dela). É a escolhida por padrão.
libz.a (archive)biblioteca estáticaum pacote de arquivos .o, copiados para dentro do programa na ligação. O programa fica maior, mas não depende de nada na hora de rodar.
libz.so.1, libz.so.1.3.1a mesma .so, com a versão no nomeatalhos (links) para a versão instalada

O comando ldd lista as bibliotecas compartilhadas de que um programa precisa para rodar:

$ ldd ./zip | grep libz
	libz.so.1 => /usr/lib/x86_64-linux-gnu/libz.so.1 (0x0000788107b45000)

(O número entre parênteses é o endereço onde ela foi carregada na memória, que muda a cada execução.) É por isso que existe o pacote zlib1g, sem -dev: quem só roda o zip precisa do libz.so.1, não dos cabeçalhos.

O -l no lugar errado
$ g++ -std=c++23 -Wall -Wextra -lz zip.cpp -o zip2
/usr/bin/x86_64-linux-gnu-ld.bfd: /tmp/ccMg9oec.o: na função "main":
zip.cpp:(.text+0x6e): referência não definida para "compressBound"
/usr/bin/x86_64-linux-gnu-ld.bfd: zip.cpp:(.text+0xd9): referência não definida para "compress"
/usr/bin/x86_64-linux-gnu-ld.bfd: zip.cpp:(.text+0x152): referência não definida para "zlibVersion"
collect2: error: ld returned 1 exit status

O que aconteceu: o -lz está lá, mas antes do zip.cpp. O ligador lê o comando da esquerda para a direita. Quando chegou na zlib, ainda ninguém tinha pedido nada dela (o zip.cpp vem depois), e ele a deixou de lado. Quando o zip.cpp pediu as funções, a zlib já tinha ficado para trás.

Como resolver: as bibliotecas vão depois dos arquivos que as usam; na dúvida, no fim do comando. É a exceção à regra "a ordem não importa", que vale para .cpp e .o.

"não foi possível localizar -lzlib"
$ g++ -std=c++23 -Wall -Wextra zip.cpp -o zip -lzlib
/usr/bin/x86_64-linux-gnu-ld.bfd: não foi possível localizar -lzlib: Arquivo ou diretório inexistente
collect2: error: ld returned 1 exit status

O que significa: o ligador procurou libzlib.so e libzlib.a, que não existem (em inglês: cannot find -lzlib). O nome do -l é o do arquivo (libz), não o do projeto (zlib).

Como resolver: descubra o nome do arquivo com dpkg -L pacote-dev ou, melhor, pergunte ao pkg-config (próxima seção). Se o erro for com o nome certo, falta instalar o pacote -dev.

Biblioteca não instalada: "fatal error: fmt/core.h"

A Ana tentou um exemplo da fmt sem ter o libfmt-dev:

$ g++ -std=c++23 -Wall -Wextra ola.cpp -o ola -lfmt
ola.cpp:1:10: fatal error: fmt/core.h: Arquivo ou diretório inexistente
    1 | #include <fmt/core.h>
      |          ^~~~~~~~~~~~
compilation terminated.

O que significa: o erro acontece antes de chegar no -lfmt: o cabeçalho não existe em nenhuma pasta do sistema. (O fmt/ no nome quer dizer que os cabeçalhos da fmt ficam numa subpasta, /usr/include/fmt/.)

Como resolver: sudo apt install libfmt-dev. Se a biblioteca foi instalada em outro lugar (compilada à mão, por exemplo), indique as pastas: -I para os cabeçalhos e -L para os binários, como em g++ … -I/opt/fmt/include … -L/opt/fmt/lib -lfmt.


4. pkg-config: "quais opções essa biblioteca precisa?"

Cada biblioteca tem as suas manias: uma precisa de -I com uma pasta especial, outra de duas -l, outra de uma opção de compilação. Decorar isso não dá. O pkg-config é um programa que guarda essas receitas: cada pacote -dev instala um arquivo .pc (como o zlib.pc que apareceu no dpkg -L), e você pergunta:

$ pkg-config --modversion zlib
1.3.1
$ pkg-config --cflags --libs zlib
 -lz
--modversion
A versão instalada.
--cflags
As opções de compilação (por exemplo, -I…). A zlib não precisa de nenhuma, porque o cabeçalho está em /usr/include; por isso só sai um espaço.
--libs
As opções de ligação: -lz.

O truque é pôr a pergunta dentro do comando do g++ com $( … ) (a "substituição de comando" do terminal, que troca o trecho pela saída dele):

$ g++ -std=c++23 -Wall -Wextra zip.cpp -o zip3 $(pkg-config --cflags --libs zlib)
$ ./zip3 | head -1
zlib versão 1.3.1

Assim, o comando funciona para qualquer biblioteca com .pc, sem você saber os detalhes. Para ver quantas o sistema conhece: pkg-config --list-all (na máquina da Ana, 84). Se o pacote não estiver instalado:

$ pkg-config --libs fmt
Package fmt was not found in the pkg-config search path.
Perhaps you should add the directory containing `fmt.pc'
to the PKG_CONFIG_PATH environment variable
Package 'fmt' not found
$ echo $?
1

"O pacote fmt não foi encontrado." O conselho sobre o PKG_CONFIG_PATH só serve para bibliotecas instaladas fora do lugar padrão; aqui, falta mesmo o sudo apt install libfmt-dev, que instala o fmt.pc. Depois disso, o mesmo comando daria as opções da fmt.

Com a fmt instalada, o exemplo dela compilaria assim (ilustrativo: a fmt não está instalada na máquina da Ana):

#include <fmt/core.h>

int main() {
    fmt::print("Olá, {}! Você tem {} itens.\n", "Ana", 3);
}
$ g++ -std=c++23 -Wall -Wextra ola.cpp -o ola $(pkg-config --cflags --libs fmt)     « ilustrativo
$ ./ola
Olá, Ana! Você tem 3 itens.

A fmt foi a inspiração do std::format e do std::print, que entraram na biblioteca padrão no C++20 e no C++23. Com o g++ 15 e -std=c++23, você já tem quase tudo isso sem biblioteca externa. Muitos projetos ainda usam a fmt por terem nascido antes, ou para compiladores mais antigos.


5. No CMake: find_package

No CMake, a pergunta "onde está a biblioteca e como ligo?" é feita com find_package ("encontre o pacote"), e a ligação, com o target_link_libraries que você já conhece:

cmake_minimum_required(VERSION 3.25)
project(Zip LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

find_package(ZLIB REQUIRED)

add_executable(zip zip.cpp)
target_link_libraries(zip PRIVATE ZLIB::ZLIB)
find_package(ZLIB REQUIRED)
Procura a zlib no sistema. REQUIRED ("obrigatório"): se não achar, pare com erro. O nome (ZLIB, em maiúsculas) é o que a documentação da biblioteca indica.
ZLIB::ZLIB
Um alvo importado, criado pelo find_package, que carrega tudo o que a biblioteca precisa: pastas de cabeçalhos, o arquivo para ligar e opções. O :: no nome é a marca desses alvos.
$ cmake -B build -G Ninja
-- The CXX compiler identification is GNU 15.2.0
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found ZLIB: /usr/lib/x86_64-linux-gnu/libz.so (found version "1.3.1")
-- Configuring done (0.4s)
-- Generating done (0.0s)
-- Build files have been written to: /home/ana/cpp/libs/build
$ cmake --build build
[1/2] Building CXX object CMakeFiles/zip.dir/zip.cpp.o
[2/2] Linking CXX executable zip
$ ./build/zip
zlib versão 1.3.1
Original:   1000 bytes
Comprimido: 38 bytes

Repare na linha -- Found ZLIB: ("encontrei a zlib"), com o caminho e a versão. Para a fmt, o CMakeLists.txt seria igual, com find_package(fmt REQUIRED) e target_link_libraries(ola PRIVATE fmt::fmt). Sem o libfmt-dev, a configuração para assim:

$ cmake -B build -G Ninja
«… detecções do compilador …»
CMake Error at CMakeLists.txt:6 (find_package):
  By not providing "Findfmt.cmake" in CMAKE_MODULE_PATH this project has
  asked CMake to find a package configuration file provided by "fmt", but
  CMake did not find one.

  Could not find a package configuration file provided by "fmt" with any of
  the following names:

    fmtConfig.cmake
    fmt-config.cmake

  Add the installation prefix of "fmt" to CMAKE_PREFIX_PATH or set "fmt_DIR"
  to a directory containing one of the above files.  If "fmt" provides a
  separate development package or SDK, be sure it has been installed.


-- Configuring incomplete, errors occurred!

A mensagem é longa, mas a última frase é a que importa: "se o fmt tem um pacote de desenvolvimento separado, confira se ele está instalado". O fmtConfig.cmake que o CMake procurou vem dentro do libfmt-dev. Depois do sudo apt install libfmt-dev, a configuração passaria, mostrando a fmt encontrada (ilustrativo).


6. Gerenciadores de pacotes: vcpkg e Conan

O apt resolve bem no Linux, mas tem limites: a versão é a que o Ubuntu escolheu (a fmt 10.1, enquanto o projeto pode querer outra), e não existe no Windows nem no macOS. Para isso surgiram os gerenciadores de pacotes próprios do C++:

FerramentaDe quemComo funciona
vcpkgMicrosoft (livre, multiplataforma)você lista as bibliotecas num arquivo vcpkg.json; o vcpkg baixa e compila cada uma, e o CMake as encontra pelo mesmo find_package
ConanJFrog (livre, multiplataforma)você lista as bibliotecas num conanfile.txt ou conanfile.py; ele baixa versões já compiladas quando existem e gera os arquivos para o CMake
FetchContent do CMakeo próprio CMakeo CMakeLists.txt baixa o código da biblioteca (do GitHub, por exemplo) e a compila junto com o projeto

Para projetos de estudo no Linux, o apt basta. Quando o projeto precisar rodar em vários sistemas ou de versões exatas, vale aprender um desses.

Antes de escolher uma biblioteca
  • A biblioteca padrão já faz? std::format, std::filesystem, std::chrono, <random>… cobrem muita coisa.
  • Está viva? Atualizações recentes, documentação, gente usando.
  • A licença permite o seu uso? MIT, BSD, zlib e Boost são bem permissivas.
  • Está no apt, no vcpkg ou no Conan? Isso facilita muito a vida.

Referência

ComandoO que faz
apt-cache search --names-only '^lib…'procura pacotes pelo nome
apt-cache policy pacoteinstalado? qual versão viria?
apt-get -s install pacotesimula a instalação
sudo apt install pacote-devinstala a biblioteca para desenvolvimento
dpkg -L pacotelista os arquivos de um pacote instalado
g++ … arquivo.cpp -o prog -lnomeliga com libnome.so (o -l depois dos arquivos)
-I pasta / -L pastapasta extra de cabeçalhos / de bibliotecas
pkg-config --cflags --libs nomeas opções certas para a biblioteca
ldd ./progas bibliotecas compartilhadas de que o programa precisa
find_package(Nome REQUIRED)(CMake) procura a biblioteca
target_link_libraries(prog PRIVATE Nome::Nome)(CMake) liga com ela
MensagemFaseCausa
fatal error: x.h: Arquivo ou diretório inexistentecompilaçãopacote -dev não instalado, ou falta -I
referência não definida para / undefined reference toligaçãofaltou o -l, ou ele está antes dos arquivos
não foi possível localizar -lx / cannot find -lxligaçãonome errado no -l, pacote não instalado, ou falta -L
Package x was not found in the pkg-config search pathpkg-configpacote -dev não instalado
Could not find a package configuration file provided by "x"CMakepacote -dev não instalado

Exercícios

1. O nome do -l

O arquivo da biblioteca SQLite se chama libsqlite3.so. Complete a opção de ligação:

g++ -std=c++23 -Wall -Wextra banco.cpp -o banco

2. Perguntar ao pkg-config

Complete para obter as opções de compilação e de ligação da zlib:

pkg-config zlib

3. Qual pacote instalar para compilar programas com a fmt?

4. g++ -lz zip.cpp -o zip dá referência não definida para "compress", mas g++ zip.cpp -o zip -lz funciona. Por quê?

5. O que caracteriza uma biblioteca header-only?

Missão final: da fmt para a biblioteca padrão

Missão: o editor do guia não tem a fmt instalada, como a máquina da Ana. Rode e veja o fatal error do cabeçalho que não existe (o Clang diz 'fmt/core.h' file not found, "arquivo não encontrado"). Depois troque a fmt pela biblioteca padrão do C++23, que tem a mesma ideia: o cabeçalho <print> e a função std::print (com {} no lugar de cada valor). A saída deve ser Olá, Ana! Você tem 3 itens.

#include <fmt/core.h>

int main() {
    fmt::print("Olá, {}! Você tem {} itens.\n", "Ana", 3);
}
#include <print>

int main() {
    std::print("Olá, {}! Você tem {} itens.\n", "Ana", 3);
}

Resumo

  • Uma biblioteca header-only é só .h: copie e inclua. Uma compilada tem .h (para compilar) e .so/.a (para ligar).
  • No Ubuntu, instale o pacote -dev (sudo apt install libfmt-dev). Antes, confira com apt-cache policy e simule com apt-get -s install.
  • Ligue com -lnome (procura libnome.so), depois dos arquivos: g++ zip.cpp -o zip -lz. Sem ele: undefined reference ("referência não definida").
  • pkg-config --cflags --libs nome dá as opções certas; use dentro do comando com $( … ).
  • No CMake: find_package(Nome REQUIRED) + target_link_libraries(prog PRIVATE Nome::Nome).
  • vcpkg, Conan e o FetchContent do CMake trazem bibliotecas em qualquer sistema e com a versão que você escolher.