CMake package guidelines (Português)

From ArchWiki
Status de tradução: Esse artigo é uma tradução de CMake package guidelines. Data da última tradução: 2020-04-27. Você pode ajudar a sincronizar a tradução, se houver alterações na versão em inglês.
Diretrizes de pacotes do Arch

32-bitCLRCMakeCrossDKMSEclipseElectronFonteFree PascalGNOMEGoHaskellJavaKDEKernelLispMesonMinGWNode.jsNonfreeOCamlPerlPHPPythonRRubyRustShellVCSWebWine

Este documento abrange padrões e diretrizes sobre como escrever PKGBUILDs para software que usa CMake.

Introdução

Do site do CMake:

O CMake é uma família de ferramentas de código aberto e de plataforma cruzada, projetada para criar, testar e empacotar software. O CMake é usado para controlar o processo de compilação de software usando arquivos simples de configuração independentes de plataforma e compilador e gerar makefiles e espaços de trabalho nativos que podem ser usados no ambiente do compilador de sua escolha.

Uso típico

O uso típico consiste em executar o comando cmake e depois executar o comando de construção. O comando cmake geralmente define alguns parâmetros, verifica as dependências necessárias e cria os arquivos de compilação, deixando o software pronto para ser compilado por outras ferramentas como make e ninja.

Comportamentos indesejados do CMake

Devido às suas próprias características internas para gerar os arquivos de compilação, às vezes o CMake pode se comportar de maneiras indesejadas. Sendo assim, algumas etapas devem ser observadas ao escrever PKGBUILDs para software baseado no CMake.

Carência de suporte à variável de ambiente CPPFLAGS

O CMake não possui suporte à variável de ambiente CPPFLAGS. Essa variável contém sinalizadores (opções) de preprocessador C/C++ que são passados para o compilador no momento da compilação e são definidos no arquivo de configuração do makepkg. Como o CMake não possui suporte a ela, todos os sinalizadores definidos nesta variável não serão passados para o compilador.

Atualmente, CPPFLAGS contém apenas o sinalizador -D_FORTIFY_SOURCE=2. Este é um sinalizador de proteção e é importante por motivos de segurança, pois pode evitar tipos específicos de ataques que podem ocorrer em estouros de buffer exploráveis. Para mais detalhes sobre este sinalizador, consulte feature_test_macros(7).

Os desenvolvedores do CMake estão cientes dessa situação, pois há um antigo relatório de erro[1][2] foi aberto (em 2012) no rastreador de erros do CMake e ainda não foi resolvido. Enquanto isso não for resolvido, os empacotadores devem manipular manualmente a passagem do CPPFLAGS para o CMake a nível de empacotamento.

Corrigindo o problema de CPPFLAGS

Isso pode ser corrigido anexando CPPFLAGS a CFLAGS e/ou CXXFLAGS, pois eles são analisados pelo CMake. Você pode usar export para anexar CPPFLAGS diretamente em CFLAGS/CXXFLAGS antes de executar o CMake. Por exemplo:

PKGBUILD
build() {
    export CFLAGS+=" ${CPPFLAGS}"
    export CXXFLAGS+=" ${CPPFLAGS}"
    cmake <opções>
    <outros comandos>
}

Isso afetará todos os comandos que usam CFLAGS/CXXFLAGS posteriormente. Existem outras possibilidades que preservam o CFLAGS/CXXFLAGS, como usar as opções do CMake -DCMAKE_C_FLAGS="${CFLAGS} ${CPPFLAGS}" e/ou -DCMAKE_CXX_FLAGS="${CXXFLAGS} ${CPPFLAGS}".

Alguns poucos projetos de software codificam -D_FORTIFY_SOURCE=2 em seus arquivos CMake. Se esse for o caso e se você tiver certeza de que -D_FORTIFY_SOURCE=2 está sendo usado, anexando CPPFLAGS a CFLAGS/CXXFLAGS não é necessário, mas geralmente não há problema em fazer isso como regra geral. Isso evitará que o pacote perca o suporte para -D_FORTIFY_SOURCE=2 se o upstream o remover do código-fonte em versões futuras e você não perceber, reduzindo o trabalho de atualização do pacote.

Nota:
  • Não é ideal misturar CPPFLAGS em CFLAGS/CXXFLAGS, mas é melhor do que permitir que o pacote seja compilado sem o importante sinalizador de proteção.
  • Ao usar o export, não esqueça o espaço após o operador do shell +=. Caso contrário, o comando do compilador falhará na execução porque produzirá uma opção inválida.
  • Nem todo software exigirá o acréscimo de CPPFLAGS a CFLAGS e CXXFLAGS. Programas diferentes exigirão apenas CFLAGS, apenas CXXFLAGS ou ambos, e isso dependerá do software upstream em questão. Em caso de dúvida, o uso de ambos geralmente não dói. Você pode usar apenas o necessário, se tiver certeza.

CMake pode substituir automaticamente o sinalizador padrão de otimização do compilador

É muito comum ver pessoas executando o CMake com a opção -DCMAKE_BUILD_TYPE=Release. Alguns projetos upstream, mesmo inadvertidamente, incluem essa opção em suas instruções de compilação, mas isso produz um comportamento indesejado.

Cada tipo de compilação faz com que o CMake anexe automaticamente um conjunto de sinalizadores a CFLAGS e CXXFLAGS. Ao usar o tipo de compilação comum Release, ele anexa automaticamente o sinalizador de otimização -O3[3] do compilador, e isso substitui o sinalizador padrão do Arch Linux que atualmente é -O2 (definido no arquivo de configuração do makepkg). Isso é indesejável, pois se desvia do nível de otimização direcionada do Arch Linux.

Notas sobre -O3

O uso de -O3 não garante que o software tenha um desempenho melhor e, às vezes, pode até atrasar o programa. Também pode quebrar o software em algumas situações. Há uma boa razão pela qual os desenvolvedores do Arch Linux escolhem -O2 como o nível de otimização de destino e devemos continuar com ele. A menos que você saiba exatamente o que está fazendo, ou se o upstream explicitamente disser ou implicar que -O3 é necessário, devemos evitar usá-lo em nossos pacotes.

Corrigindo a substituição automática do sinalizador de otimização

Corrigir isso de uma maneira 100% garantida não é uma questão simples devido à flexibilidade do CMake. Observe que não há solução padrão que possa ser aplicada a todos os casos. Nesta seção serão objeto de discussão as possíveis soluções e alguns pontos que devem ser observados.

O tipo de compilação padrão do CMake é None e não anexa nenhum sinalizador a CFLAGS e CXXFLAGS por padrão, então simplesmente omitir a opção CMAKE_BUILD_TYPE pode funcionar, pois será padronizada como None. Mas observe que a omissão desta opção não garante a correção do problema, pois muitos projetos de software configuram automaticamente o tipo de construção como Release (ou outro tipo) nos arquivos CMake, se CMAKE_BUILD_TYPE não estiver definido na linha de comando.

Como o tipo de compilação padrão None não anexa nenhum sinalizador a CFLAGS e CXXFLAGS por padrão, usando a opção -DCMAKE_BUILD_TYPE=None também pode funcionar. De um modo geral, usar a opção -DCMAKE_BUILD_TYPE=None é melhor do que omitir o uso de CMAKE_BUILD_TYPE. Ele abordará o caso quando o upstream definir automaticamente o tipo de compilação como Release quando CMAKE_BUILD_TYPE for omitido, ele não anexará nenhum sinalizador por padrão e é incomum ver o software configurando sinalizadores indesejados para o tipo de compilação None.

Mas, infelizmente, as coisas não são tão simples como usar apenas -DCMAKE_BUILD_TYPE=None para corrigir isso. Ao usar o tipo de compilação None para corrigir o problema de -O3, pode-se cair em outro problema. É uma prática comum para muitos projetos de software definir alguns sinalizadores de compilador necessários para o tipo de compilação Release nos arquivos CMake (por exemplo, como definir as variáveis do CMake CMAKE_C_FLAGS_RELEASE e CMAKE_CXX_FLAGS_RELEASE). Esse software pode quebrar ou se comportar mal quando compilado sem esses sinalizadores definidos pelo upstream, se você usar o tipo de compilação None. Para determinar se estão faltando alguns sinalizadores, é necessário examinar os arquivos do CMake ou comparar a saída de make VERBOSE=1 para os tipos de compilação None e Release. O que fazer se o tipo de compilação None fizer com que alguns sinalizadores definidos pelo upstream sejam perdidos? Nesse caso, você pode estar no meio de duas situações problemáticas, porque se você usar o tipo de compilação Release, poderá usar o sinalizador indesejado -O3 e se usar o tipo de compilação None, você perderá alguns sinalizadores definidos a montante necessários. Não existe uma maneira padrão de resolver essa situação e ela deve ser analisada caso a caso. Se o upstream definir -O2 para o tipo de compilação Release, você poderá usar -DCMAKE_BUILD_TYPE=Release (veja abaixo). Caso contrário, o patch dos arquivos do CMake pode ser uma solução.

Alguns poucos projetos de software codificam -O2 para o tipo de compilação Release em seus arquivos CMake e, portanto, -DCMAKE_BUILD_TYPE=Release pode ser configurado com segurança nesse caso se você tiver certeza de que -O2 é o nível de otimização que está sendo usado.

Atenção:
  • Alguns softwares podem falhar ao usar o tipo de compilação None. Teste o software ao usar o tipo de compilação None para verificar se ele irá quebrar ou perder funcionalidades.
  • Alguns softwares podem funcionar apenas com o tipo de compilação Release. Você precisará experimentar e testar o software.

Verificando as correções

Você pode verificar se as correções estão sendo usadas corretamente pelo CMake, ativando o modo detalhado da ferramenta de compilação. Por exemplo, ao usar make (que é o padrão do CMake), isso pode ser feito adicionando VERBOSE=1 a ele (como make VERBOSE=1). Isso permitirá que make produza os comandos do compilador que estão sendo executados. Você pode então executar makepkg e examinar a saída para ver se o compilador está usando os sinalizadores -D_FORTIFY_SOURCE=2 e -O2. Se vários sinalizadores de otimização estiverem sendo exibidos em cada linha de comando, o último sinalizador na linha será o usado pelo compilador (significa que -O2 precisa ser o último sinalizador de otimização para ser eficaz).

Diretórios de prefixo e instalação de biblioteca

O prefixo padrão do Arch Linux /usr pode ser especificado pela opção do CMake -DCMAKE_INSTALL_PREFIX=/usr. Isso geralmente é necessário porque muitos softwares padrão instalam arquivos no prefixo /usr/local.

Alguns projetos upstream configuram seus arquivos CMake para instalar bibliotecas no diretório /usr/lib64. Se esse for o caso, você poderá configurar corretamente o diretório de instalação da biblioteca como /usr/lib usando a opção CMake -DCMAKE_INSTALL_LIBDIR=lib.

Dicas e truques

Especificando diretórios

Desde a versão 3.13 do CMake, existe uma opção -B que cria automaticamente o diretório de compilação. Isso evita a criação do diretório de compilação por um comando mkdir (ou install) separado. A opção -S especifica o diretório fonte (onde procurar por um arquivo CMakeLists.txt) e evita a necessidade de usar cd na árvore de fontes antes executando cmake. Combinadas, essas duas opções são uma maneira conveniente de especificar os diretórios de compilação e de fontes. Por exemplo, para criar um programa chamado foo:

PKGBUILD
build() {
    <comando(s) de exportação>
    cmake -B build -S "foo-${pkgver}" [outras_opções_cmake]
    make -C build
}

Reduzindo possíveis saídas indesejadas

A opção -Wno-dev do CMake suprimirá a saída de alguns avisos destinados apenas aos desenvolvedores do projeto upstream que gravam os arquivos CMakeLists.txt. A remoção desses avisos torna a saída do CMake mais suave e reduz a carga de examiná-la. Como regra geral, esses avisos geralmente podem ser ignorados com segurança pelos empacotadores.

Removendo referências a RPATH inseguro de binários

Às vezes, os binários resultantes podem conter referências não seguras em RPATH. Isso pode ser verificado executando Namcap no pacote compilado e consiste em um problema de segurança que deve ser corrigido. Há uma boa chance de corrigir isso usando as opções do CMake CMAKE_SKIP_INSTALL_RPATH=YES ou CMAKE_SKIP_RPATH=YES. Você precisa experimentar os dois e ver o que funcionará no software em questão (não é necessário usar as duas opções).

Obtendo todas as opções disponíveis do CMake

Para obter todas as opções "visíveis" do CMake disponíveis para um projeto de software, execute cmake -LAH na árvore de origem (onde está localizado o arquivo principal CMakeLists.txt).

Se você deseja salvar a saída para referência posterior, você pode redirecioná-la para um arquivo:

$ cmake -LAH >options.txt 2>&1

Modelo

Aqui está um modelo geral para a função build() que serve como ponto de partida para pacotes baseados no CMake. Supondo que o pacote seja nomeado foo, ele é baseado em C e C++ e que não define nenhum sinalizador de compilador necessário para o tipo de compilação Release nos arquivos CMake:

PKGBUILD
build() {
    export CFLAGS+=" ${CPPFLAGS}"
    export CXXFLAGS+=" ${CPPFLAGS}"
    cmake -B build -S "foo-${pkgver}" \
        -DCMAKE_BUILD_TYPE='None' \
        -DCMAKE_INSTALL_PREFIX='/usr' \
        -Wno-dev
    make -C build
}

Não se esqueça de colocar o cmake em makedepends.

Pacotes exemplos

Veja também