A07 - Encontrando e usando dependências

Questão

  • Como posso usar o CMake para detectar e usar as dependências do meu projeto?

Objetivos

  • Aprender como usar find_package.

  • Saiba quais outras alternativas de detecção existem.

A grande maioria dos projetos de software não acontece no vácuo: eles terão dependências de frameworks e bibliotecas existentes. Uma boa documentação instruirá seus usuários a garantir que eles sejam satisfeitos em seu ambiente de programação. O sistema de compilação é o local apropriado para verificar se essas pré-condições são atendidas e se seu projeto pode ser construído corretamente. Neste episódio, mostraremos alguns exemplos de como detectar e usar dependências em seu sistema de compilação CMake.

Encontrando dependências

O CMake oferece uma família de comandos para encontrar artefatos instalados em seu sistema:

  • find_file para recuperar o caminho completo para um arquivo.

  • find_library para encontrar uma biblioteca, compartilhada ou estática.

  • find_package para encontrar e carregar configurações de um projeto externo.

  • find_path para encontrar o diretório que contém um arquivo.

  • find_program para encontrar um executável.

A principal ferramenta para a descoberta de dependência é find_package, que cobrirá suas necessidades em quase todos os casos de uso.

você deve somente usar os outros comandos da família find_ em circunstâncias muito especiais e restritas. Por quê?

  1. Para uma grande variedade de dependências comuns, os módulos Find<PackageName>.cmake enviados com o CMake funcionam perfeitamente e são mantidos pelos desenvolvedores do CMake. Isso elimina o fardo de programar seus próprios módulos de detecção de dependência.

  2. find_package irá configurar alvos importados: alvos definidos fora do seu projeto que podem ser usados com seus próprios alvos. As propriedades nos destinos importados definem requisitos de uso para as dependências. Um comando como:

    target_link_libraries(your-target
      PUBLIC
        imported-target
      )
    

    definirá flags de compilador, definições, diretórios de inclusão e bibliotecas de links de imported-target para your-target e para todos os outros destinos em seu projeto que usarão your-target.

Esses dois pontos simplificam enormemente a detecção de dependência e uso consistente em um projeto de várias pastas.

Usando find_package

Ao tentar a detecção de dependência com find_package, você deve certificar-se de que:

  • Um modulo Find<PackageName>.cmake exista,

  • Quais componentes, se houver, ele fornece e

  • Quais destinos importados ele configurará.

Uma lista completa de Find<PackageName>.cmake pode ser encontrada na interface de linha de comando: .. code-block:: bash

$ cmake –help-module-list | grep “Find”

Exercício 23: Usando MPI

Neste exercício, você tentará compilar um programa “Hello, world” que usa a interface de passagem de mensagens (MPI).

  1. Verifique se existe um módulo FindMPI.cmake na biblioteca de módulos embutida.

  2. Familiarize-se com seus componentes e as variáveis e destinos importados que ele define.

O projeto base está em source/code/day-2/23_mpi-cxx.

  1. Compile o arquivo de origem em um executável.

  2. Vincule para o destino importado MPI.

  3. Invoque uma compilação detalhada e observe como o CMake compila e vincula.

Um exemplo funcional está na subpasta solution.

Alternativas: scripts Config e pkg-config

O que fazer quando não há um módulo Find<PackageName>.cmake embutido para um pacote do qual você depende? Os desenvolvedores de pacotes podem já estar preparados para ajudá-lo:

  • Eles disponibilizam o arquivo específico do CMake <PackageName>Config.cmake que descreve como o destino importado deve ser usada pelo seu pacote. Neste caso, você precisa apontar o CMake para a pasta que contém o arquivo Config usando a variável especial <PackageName>_DIR:

    $ cmake -S. -Bbuild -D<PackageName>_DIR=/folder/containing/<PackageName>Config.cmake
    
  • Eles incluem um arquivo .pc, que, em plataformas do tipo Unix, pode ser detectado com o utilitário pkg-config. Você pode então aproveitar o pkg-config através do CMake:

    # find pkg-config
    find_package(PkgConfig REQUIRED)
    # ask pkg-config to find the UUID library and prepare an imported target
    pkg_search_module(UUID REQUIRED uuid IMPORTED_TARGET)
    # use the imported target
    if(TARGET PkgConfig::UUID)
      message(STATUS "Found libuuid")
    endif()
    

Esta foi a estratégia adotada em A05 - Compilação, vinculação e execução ao testar o uso da biblioteca UUID.

Resumo

  • O CMake possui um rico ecossistema de módulos para encontrar dependências de software. Eles são chamados de Find<package>.cmake.

  • Os módulos Find<package>.cmake são usados através de find_package(<package>).

  • Você também pode usar a ferramenta clássica do Unix pkg-config

    para encontrar dependências de software, mas isso não é tão robusto quanto os módulos Find<package> nativos do CMake.

Footnotes