Respostas:
Ao escrever scripts do CMake, você precisa saber muito sobre a sintaxe e como usar variáveis no CMake.
Strings usando set()
:
set(MyString "Some Text")
set(MyStringWithVar "Some other Text: ${MyString}")
set(MyStringWithQuot "Some quote: \"${MyStringWithVar}\"")
Ou com string()
:
string(APPEND MyStringWithContent " ${MyString}")
Lista usando set()
:
set(MyList "a" "b" "c")
set(MyList ${MyList} "d")
Ou melhor com list()
:
list(APPEND MyList "a" "b" "c")
list(APPEND MyList "d")
Listas de nomes de arquivos:
set(MySourcesList "File.name" "File with Space.name")
list(APPEND MySourcesList "File.name" "File with Space.name")
add_excutable(MyExeTarget ${MySourcesList})
set()
Comando CMakestring()
Comando CMakelist()
Comando CMakePrimeiro, existem as "Variáveis normais" e o que você precisa saber sobre seu escopo:
CMakeLists.txt
eles são definidos em e tudo chamado de lá ( add_subdirectory()
, include()
, macro()
e function()
).add_subdirectory()
e function()
são especiais, porque abrem seu próprio escopo.
set(...)
lá são visíveis apenas e elas fazem uma cópia de todas as variáveis normais do nível de escopo de onde são chamadas (chamadas de escopo pai).set(... PARENT_SCOPE)
function(xyz _resultVar)
configuraçãoset(${_resultVar} 1 PARENT_SCOPE)
include()
ou macro()
scripts modificará variáveis diretamente no escopo de onde elas são chamadas.Segundo, existe o "Cache de Variáveis Globais". O que você precisa saber sobre o cache:
CMakeCache.txt
arquivo no diretório de saída binária.Os valores no cache podem ser modificados no aplicativo GUI do CMake antes de serem gerados. Portanto, eles - em comparação com variáveis normais - têm a type
e a docstring
. Normalmente, não uso a GUI, portanto, set(... CACHE INTERNAL "")
defino meus valores globais e persistentes.
Observe que o INTERNAL
tipo de variável de cache implicaFORCE
Em um script do CMake, você só pode alterar as entradas de cache existentes se usar a set(... CACHE ... FORCE)
sintaxe. Esse comportamento é utilizado, por exemplo, pelo próprio CMake, porque normalmente não força as entradas de cache e, portanto, você pode predefini-lo com outro valor.
cmake -D var:type=value
, just cmake -D var=value
ou with cmake -C CMakeInitialCache.cmake
.unset(... CACHE)
.O cache é global e você pode configurá-los praticamente em qualquer lugar nos scripts do CMake. Mas eu recomendo que você pense duas vezes sobre onde usar as variáveis de cache (são globais e persistentes). Normalmente, prefiro a sintaxe set_property(GLOBAL PROPERTY ...)
e set_property(GLOBAL APPEND PROPERTY ...)
para definir minhas próprias variáveis globais não persistentes.
Para evitar armadilhas, você deve saber o seguinte sobre variáveis:
find_...
comandos - se bem-sucedidos - gravam seus resultados como variáveis em cache "para que nenhuma chamada procure novamente"set(MyVar a b c)
é "a;b;c"
e set(MyVar "a b c")
é"a b c"
list()
comando para lidar com listasfunctions()
vez de, macros()
porque você não deseja que suas variáveis locais apareçam no escopo pai.project()
e enable_language()
. Portanto, pode ser importante definir algumas variáveis antes que esses comandos sejam usados.Às vezes, apenas variáveis de depuração ajudam. O seguinte pode ajudá-lo:
printf
estilo antigo de depuração usando o message()
comando Existem também alguns módulos prontos para uso fornecidos com o próprio CMake: CMakePrintHelpers.cmake , CMakePrintSystemInformation.cmakeCMakeCache.txt
arquivo no diretório de saída binário. Esse arquivo é gerado mesmo se a geração real do seu ambiente de criação falhar.cmake --trace ...
para ver o processo completo de análise do CMake. Essa é a última reserva, porque gera muita produção.$ENV{...}
e escrever set(ENV{...} ...)
variáveis de ambiente$<...>
são avaliadas apenas quando o gerador do CMake grava o ambiente make (é comparado com variáveis normais que são substituídas "no local" pelo analisador)${${...}}
você pode dar nomes de variáveis em uma variável e referenciar seu conteúdo.if()
comando)
if(MyVariable)
você pode verificar diretamente uma variável para true / false (não é necessário aqui para o anexo ${...}
)1
, ON
, YES
, TRUE
, Y
, ou um número diferente de zero.0
, OFF
, NO
, FALSE
, N
, IGNORE
, NOTFOUND
, a cadeia vazia, ou termina no sufixo -NOTFOUND
.if(MSVC)
, mas pode ser confusa para alguém que não conhece esse atalho de sintaxe.set(CMAKE_${lang}_COMPILER ...)
if()
comandos. Aqui está um exemplo onde CMAKE_CXX_COMPILER_ID
é "MSVC"
e MSVC
é "1"
:
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
é verdade, porque avalia como if("1" STREQUAL "1")
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
é falso, porque avalia como if("MSVC" STREQUAL "1")
if(MSVC)
cmake_policy(SET CMP0054 NEW)
como "apenas interpretar if()
argumentos como variáveis ou palavras-chave quando não estiver entre aspas".option()
comando
ON
ou OFF
permitem uma manipulação especial, como por exemplo, dependênciasoption
o set
comando. O valor atribuído option
é realmente apenas o "valor inicial" (transferido uma vez para o cache durante a primeira etapa da configuração) e posteriormente deve ser alterado pelo usuário através da interface gráfica do usuário do CMake .${MyString}
leva a um monte de erros para "se houver argumentos ...", como o erro CMake perto de se: "se houver argumentos" seguidos de parênteses, "NÃO", "IGUAIS" e similares .
if (MyString ...)
lo (se for o seu código dando o aviso).
${MyString}
e substituímos por MyString
(ou acredito que removemos todas). Ainda sem alegria: Build 372 . A porcaria nem vem do nosso código. Parece vir do CMake. A linha 283 é if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
.
Aqui estão alguns exemplos básicos para começar rápido e sujo.
Definir variável:
SET(INSTALL_ETC_DIR "etc")
Usar variável:
SET(INSTALL_ETC_CROND_DIR "${INSTALL_ETC_DIR}/cron.d")
Definir variável:
SET(PROGRAM_SRCS
program.c
program_utils.c
a_lib.c
b_lib.c
config.c
)
Usar variável:
add_executable(program "${PROGRAM_SRCS}")
if ("${MyString}" ...)
Eu sou avisos vendo:Policy CMP0054 is not set: Only interpret if() arguments as variables or keywords when unquoted
. Consulte, por exemplo, Build 367 . Alguma ideia?