Versão mínima
Aqui está a primeira linha de cada CMakeLists.txt
, que é o nome requerido do arquivo CMake procura:
cmake_minimum_required(VERSION 3.1)
Deixemos mencionar um pouco da sintaxe do CMake. O nome do comandocmake_minimum_required
é insensível a maiúsculas e minúsculas, portanto a prática comum é usar minúsculas. 1 O VERSION
é uma palavra-chave especial para esta função. E o valor da versão segue a palavra-chave. Como em qualquer lugar deste livro, basta clicar no nome do comando para ver a documentação oficial, e usar o menu suspenso para alternar a documentação entre as versões CMake.
Esta linha é especial! 2 A versão do CMake também ditará as políticas,que definem as mudanças de comportamento. Então, se você definir minimum_required
para VERSION2.8
, você terá o comportamento de link errado no MacOS, por exemplo, mesmo nas versões mais recentes do CMake. Se você definir para 3.3 ou menos, você terá o comportamento incorreto dos símbolos errados, etc. Uma lista de políticas e versões está disponível empolicies.
Starting in CMake 3.12, isto suporta um intervalo, como VERSION 3.1...3.15
;isto significa que você suporta tão baixo quanto 3.1 mas também o testou com as configurações da nova política até 3.15. Isto é muito mais agradável em usuários que precisam das apostas, e devido a um truque na sintaxe, é retrocompatível com versões mais antigas do CMake (embora rodando CMake 3.1-3.11 irá apenas definir a versão 3.1 das políticas neste exemplo, uma vez que essas versões não tratavam isso de forma especial). Novas versões das políticas tendem a ser mais importantes para os usuários de MacOS e Windows, que normalmente também têm uma versão muito recente do CMake.
Isso é o que novos projetos devem fazer:
cmake_minimum_required(VERSION 3.7...3.20)if(${CMAKE_VERSION} VERSION_LESS 3.12) cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})endif()
Se a versão do CMake for menor que 3.12, o bloco if será verdadeiro, e a política será definida para a versão atual do CMake. Se o CMake for 3.12 ou superior, o ifblock será falso, mas a nova sintaxe em cmake_minimum_required
será berespectada e isto continuará a funcionar corretamente!
WARNING: O modo servidor CMake do MSVC tinha originalmente um bug na leitura deste formato, então se você precisa suportar construções Windows sem linha de comando para versões antigas do MSVC, você vai querer fazer isso em vez disso:
cmake_minimum_required(VERSION 3.7)if(${CMAKE_VERSION} VERSION_LESS 3.20) cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})else() cmake_policy(VERSION 3.20)endif()
Se você realmente precisa definir um valor baixo aqui, você pode usarcmake_policy
para aumentar condicionalmente o nível da política ou definir uma política específica. Por favor, pelo menos faça isso para seus usuários macOS!
Configurando um projeto
Agora, cada arquivo CMake de nível superior terá a próxima linha:
project(MyProject VERSION 1.0 DESCRIPTION "Very nice project" LANGUAGES CXX)
Agora vemos ainda mais sintaxe. Strings são citadas, espaço em branco não importa, e o nome do projeto é o primeiro argumento (posicional). Todos os argumentos de palavras-chave aqui são opcionais. A versão define um monte de variáveis, comoMyProject_VERSION
e PROJECT_VERSION
. As linguagens são C
, CXX
,Fortran
, ASM
, CUDA
(CMake 3.8+), CSharp
(3.8+), e SWIFT
(CMake3.15+ experimental). C CXX
é o padrão. No CMake 3.9, DESCRIPTION
foi adicionado para definir uma descrição do projeto, também. A documentação paraproject
pode ser útil.
Você pode adicionar comentários com o caractere #
. CMake tem uma sintaxe inline para comentários também, butit é raramente usado.
Não há realmente nada de especial sobre o nome do projeto. Nenhum alvo é adicionado neste ponto.
Fazer um executável
Embora as bibliotecas sejam muito mais interessantes, e vamos gastar a maior parte do nosso tempo com elas, vamos começar com um simples executável.
add_executable(one two.cpp three.h)
Existem várias coisas para desempacotar aqui. one
é tanto o nome do arquivo executável gerado, como o nome do alvo CMake criado (você vai ouvir muito mais sobre alvos em breve, eu prometo). A lista de arquivos fonte vem a seguir, e você pode listar quantos você quiser. O CMake é inteligente, e só irá compilar extensões de arquivos fonte. Os cabeçalhos serão, para a maioria das intenções e propósitos, ignorados; a única razão para listá-los é para fazê-los aparecer em IDEs. Os alvos aparecem como pastas em muitas IDEs. Mais sobre o sistema de compilação geral e alvos está disponível em buildsystem.
Fazer uma biblioteca
Fazer uma biblioteca é feito com add_library
, e é quase tão simples:
add_library(one STATIC two.cpp three.h)
Você pode escolher um tipo de biblioteca, STATIC, SHARED, ou MODULE. Se você deixar essa escolha de fora, o valor de BUILD_SHARED_LIBS
será usado para escolher entre STATIC e SHARED.
Como você verá nas seções seguintes, muitas vezes você precisará fazer um alvo fictício, ou seja, um onde nada precisa ser compilado, por exemplo, para uma biblioteca somente de cabeçalho. Isso é chamado de biblioteca INTERFACE, e é outra escolha; a única diferença é que ela não pode ser seguida por nomes de arquivos.
Você também pode fazer uma biblioteca ALIAS
com uma biblioteca existente, que simplesmente lhe dá um novo nome para um alvo. O único benefício disto é que você pode fazer bibliotecas com ::
no nome (que você verá mais tarde). 3
Os alvos são seus amigos
Agora especificamos um alvo, como adicionamos informações sobre ele? Por exemplo, talvez ele precise de um diretório include:
target_include_directories(one PUBLIC include)
target_include_directories
adiciona um diretório include a um alvo. PUBLIC
não significa muito para um executável; para uma biblioteca, permite ao CMake saber que qualquer alvo que se ligue a este alvo deve também precisar de um directório de include. Outras opções são PRIVATE
(afetam somente o alvo atual, não dependências), e INTERFACE
(somente necessário para dependências).
Podemos então encadear alvos:
add_library(another STATIC another.cpp another.h)target_link_libraries(another PUBLIC one)
target_link_libraries
é provavelmente o comando mais útil e confuso no CMake. Ele pega um alvo (another
) e adiciona uma dependência se um alvo for dado. Se nenhum alvo desse nome (one
) existe, então ele adiciona um link para uma biblioteca chamada one
no seu caminho (daí o nome do comando). Ou você pode dar-lhe um caminho completo para uma biblioteca. Ou um linker flag. Apenas para adicionar um pouco de confusão final, o clássico CMake permitiu-lhe saltar a selecção de palavras-chave de PUBLIC
, etc. Se isto foi feito em um alvo, você receberá um erro se tentar misturar estilos mais abaixo na cadeia.
Focus no uso de alvos em toda parte, e palavras-chave em toda parte, e você ficará bem.
Targets podem ter incluído diretórios, bibliotecas vinculadas (ou alvos vinculados), opções de compilação, definições de compilação, características de compilação (veja o capítulo C++11), e mais. Como você verá nos dois capítulos incluindo os capítulos de projetos, você pode frequentemente obter alvos (e sempre fazer alvos) para representar todas as bibliotecas que você usa. Mesmo coisas que não são bibliotecas verdadeiras, como o OpenMP, podem ser representadas com alvos. É por isso que o CMake Moderno é ótimo!
Dive in
Veja se você pode seguir o seguinte arquivo. Ele faz uma biblioteca C++11 simples e um programa usando-o. Sem dependências. Discutirei mais opções padrão de C++ mais tarde, usando o sistema CMake 3.8 por enquanto.
cmake_minimum_required(VERSION 3.8)project(Calculator LANGUAGES CXX)add_library(calclib STATIC src/calclib.cpp include/calc/lib.hpp)target_include_directories(calclib PUBLIC include)target_compile_features(calclib PUBLIC cxx_std_11)add_executable(calc apps/calc.cpp)target_link_libraries(calc PUBLIC calclib)
1. Neste livro, evitarei principalmente mostrar-lhe a maneira errada de fazer as coisas; você pode encontrar muitos exemplos disso online. Mencionarei alternativas ocasionalmente, mas estas não são recomendadas a menos que sejam absolutamente necessárias; muitas vezes elas estão lá apenas para ajudá-lo a ler código CMake antigo.
2. Você verá às vezes
FATAL_ERROR
aqui, que era necessário para suportar boas falhas ao executar isso no CMake <2.6, o que não deve ser mais um problema.
3. A sintaxe
::
foi originalmente destinada aINTERFACE IMPORTED
bibliotecas, que eram explicitamente supostas serem bibliotecas definidas fora do projeto atual. Mas, por causa disso, a maioria dos comandostarget_*
não funcionam emIMPORTED
bibliotecas, tornando-as difíceis de configurar você mesmo. Portanto, não use a palavra-chaveIMPORTED
por enquanto, e use um alvoALIAS
em seu lugar; estará tudo bem até que você comece a exportar alvos. Esta limitação foi corrigida no CMake 3.11.