Saída CMake / diretório de compilação

116

Eu sou muito novo no CMake, li alguns tutoriais sobre como usá-lo e escrevi algumas complicadas 50 linhas de script CMake para fazer um programa para 3 compiladores diferentes. Isso provavelmente conclui todo o meu conhecimento no CMake.

Agora meu problema é que tenho algum código-fonte, cuja pasta não quero mexer / mexer quando fizer o programa. Quero que todos makeos arquivos e pastas CMake e de saída sejam incluídos ../Compile/, então mudei algumas variáveis ​​em meu script CMake para isso e funcionou por algum tempo quando fiz algo assim no meu laptop:

Compile$ cmake ../src
Compile$ make

Onde com isso eu tive uma saída limpa na pasta em que estou agora, que é exatamente o que estou procurando.

Agora mudei para outro computador, recompilei o CMake 2.8.11.2 e estou quase de volta à estaca zero! Ele sempre compila a coisa na srcpasta onde meu CMakeLists.txtestá localizado.

A parte em que escolho o diretório em meu script CMake é esta:

set(dir ${CMAKE_CURRENT_SOURCE_DIR}/../Compile/)
set(EXECUTABLE_OUTPUT_PATH ${dir} CACHE PATH "Build directory" FORCE)
set(LIBRARY_OUTPUT_PATH ${dir} CACHE PATH "Build directory" FORCE)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${dir})
set(CMAKE_BUILD_FILES_DIRECTORY ${dir})
set(CMAKE_BUILD_DIRECTORY ${dir})
set(CMAKE_BINARY_DIR  ${dir})
SET(EXECUTABLE_OUTPUT_PATH ${dir})
SET(LIBRARY_OUTPUT_PATH ${dir}lib)
SET(CMAKE_CACHEFILE_DIR ${dir})

E agora sempre termina com:

-- Build files have been written to: /.../src

Estou esquecendo de algo?

The Quantum Physicist
fonte
4
Há pouca necessidade de definir todas as variáveis ​​que você está definindo. O CMake os define para padrões razoáveis. Você definitivamente não deve modificar CMAKE_BINARY_DIRou CMAKE_CACHEFILE_DIR. O que acontece se você remover todas essas set()chamadas e apenas fazer cd Compile; rm -rf *; cmake ../src?
Angew não está mais orgulhoso de SO,
5
Basicamente, contanto que você esteja fora do diretório de origem ao executar o CMake, ele não modificará o diretório de origem, a menos que sua CMakeList explicitamente o faça.
Angew não está mais orgulhoso de SO,
@Angew Obrigado pela dica, que é surpreendente! Removi todas essas linhas e usei apenas cmake ../src e funcionou perfeitamente! Isso é tão surpreendente porque eu tentei antes quando estava aprendendo o CMake e não funcionou. Por favor, coloque sua resposta em uma resposta oficial para dar a você a marca de verificação grande :)
The Quantum Physicist
1
O que me salvou foi a observação de @Adam Bowen de que "você não pode criar uma compilação fora do código-fonte para um diretório de origem com uma compilação in-source"
Aur Saraf

Respostas:

60

Há pouca necessidade de definir todas as variáveis ​​que você está definindo. O CMake os define para padrões razoáveis. Você definitivamente não deve modificar CMAKE_BINARY_DIRou CMAKE_CACHEFILE_DIR. Trate-os como somente leitura.

Primeiro remova o arquivo de cache problemático existente do diretório src:

cd src
rm CMakeCache.txt
cd ..

Em seguida, remova todos os set()comandos e faça:

cd Compile
rm -rf *
cmake ../src

Contanto que você esteja fora do diretório de origem ao executar o CMake, ele não modificará o diretório de origem, a menos que sua CMakeList explicitamente o faça.

Depois de fazer isso funcionar, você pode ver onde o CMake coloca as coisas por padrão e, apenas se não estiver satisfeito com os locais padrão (como o valor padrão de EXECUTABLE_OUTPUT_PATH), modifique apenas aqueles de que precisa. E tentar expressá-las em relação a CMAKE_BINARY_DIR, CMAKE_CURRENT_BINARY_DIR, PROJECT_BINARY_DIRetc.

Se você olhar a documentação do CMake, verá variáveis ​​particionadas em seções semânticas. Exceto em circunstâncias muito especiais, você deve tratar todos aqueles listados em "Variáveis ​​que fornecem informações" como somente leitura dentro de CMakeLists.

Angew não está mais orgulhoso de SO
fonte
2
Comecei a usar cmake com compilações no diretório src ... essa técnica falhou inicialmente. Depois de excluir todos os arquivos / caches de compilação do cmake no diretório src, essa técnica funcionou. Obrigado!
Avi Tevet
18
Talvez seja melhor não aconselhar o uso rm -rf *. Não é bonito se cd Compilefalhar ...
Romano
2
@Roman Eu considero esses exemplos de linha de comando praticamente um pseudo-código. É menos prolixo e mais exato do que digitar "entre no diretório Compile, exclua tudo lá e execute o CMake com um caminho para o diretório de origem". Eu presumo bom senso básico e julgamento por parte do leitor.
Angew não está mais orgulhoso de SO
@AviTevet: Acho que essa é a resposta correta. Se houver arquivos de cache do cmake de uma chamada anterior do cmake dentro do diretório de origem, você não fará com que o cmake escolha outro diretório para os arquivos gerados, a menos que exclua todos os antigos do diretório de origem. Comportamento bastante quebrado por CMake na minha opinião. Por que você não escreve outra resposta?
Jo So
113

Parece que você quer uma compilação fora do código-fonte . Existem algumas maneiras de criar uma compilação fora do código-fonte.

  1. Faça o que você estava fazendo, corra

    cd /path/to/my/build/folder
    cmake /path/to/my/source/folder

    o que fará com cmake para gerar uma árvore de construção em /path/to/my/build/folderpara a árvore de origem em /path/to/my/source/folder.

    Depois de criá-lo, o cmake lembra onde está a pasta de origem - para que você possa executar novamente o cmake na árvore de construção com

    cmake /path/to/my/build/folder

    ou mesmo

    cmake .

    se o seu diretório atual já for a pasta de construção.

  2. Para CMake 3.13 ou posterior, use essas opções para definir as pastas de origem e de construção

    cmake -B/path/to/my/build/folder -S/path/to/my/source/folder
  3. Para CMake mais antigo, use algumas opções não documentadas para definir as pastas de origem e de compilação :

    cmake -B/path/to/my/build/folder -H/path/to/my/source/folder

    que fará exatamente a mesma coisa que (1), mas sem a dependência do diretório de trabalho atual.

O CMake coloca todas as suas saídas na árvore de construção por padrão, então a menos que você esteja usando liberalmente ${CMAKE_SOURCE_DIR}ou ${CMAKE_CURRENT_SOURCE_DIR}em seus arquivos cmake, ele não deve tocar em sua árvore de código-fonte .

A maior coisa que pode dar errado é se você gerou anteriormente uma árvore de construção em sua árvore de código-fonte (ou seja, você tem uma construção de código-fonte ). Depois de fazer isso, a segunda parte de (1) acima começa e o cmake não faz nenhuma alteração na origem ou nos locais de compilação. Portanto, você não pode criar uma compilação fora do código-fonte para um diretório de origem com uma compilação in-source . Você pode consertar isso facilmente removendo (no mínimo) CMakeCache.txtdo diretório de origem. Existem alguns outros arquivos (principalmente no CMakeFilesdiretório) que o CMake gera que você deve remover também, mas eles não farão com que o cmake trate a árvore de origem como uma árvore de construção.

Uma vez que compilações fora do código-fonte são frequentemente mais desejáveis ​​do que compilações in-source, você pode querer modificar seu cmake para exigir compilações fora da fonte:

# Ensures that we do an out of source build

MACRO(MACRO_ENSURE_OUT_OF_SOURCE_BUILD MSG)
     STRING(COMPARE EQUAL "${CMAKE_SOURCE_DIR}"
     "${CMAKE_BINARY_DIR}" insource)
     GET_FILENAME_COMPONENT(PARENTDIR ${CMAKE_SOURCE_DIR} PATH)
     STRING(COMPARE EQUAL "${CMAKE_SOURCE_DIR}"
     "${PARENTDIR}" insourcesubdir)
    IF(insource OR insourcesubdir)
        MESSAGE(FATAL_ERROR "${MSG}")
    ENDIF(insource OR insourcesubdir)
ENDMACRO(MACRO_ENSURE_OUT_OF_SOURCE_BUILD)

MACRO_ENSURE_OUT_OF_SOURCE_BUILD(
    "${CMAKE_PROJECT_NAME} requires an out of source build."
)

A macro acima vem de um módulo comumente usado chamado MacroOutOfSourceBuild. Existem inúmeras fontes para MacroOutOfSourceBuild.cmakeno google, mas não consigo encontrar o original e é curto o suficiente para incluir aqui na íntegra.

Infelizmente, o cmake geralmente grava alguns arquivos no momento em que a macro é chamada, portanto, embora ele vá impedi-lo de realmente executar a compilação, você ainda precisará excluir CMakeCache.txte CMakeFiles.

Você pode achar útil definir os caminhos em que binários, bibliotecas compartilhadas e estáticas são gravados - nesse caso, veja como faço para fazer a saída cmake em um diretório 'bin'? (isenção de responsabilidade, eu tenho a resposta mais votada para essa pergunta ... mas é como eu sei sobre isso).

Adam Bowen
fonte
Na verdade, a opção de definir a pasta de origem é -S, não-H
smac89
@ smac89 Obrigado! Parece que eles os documentaram no 3.13 - Eu atualizei a resposta para refletir o CMake moderno.
Adam Bowen
8

Transformando meu comentário em uma resposta:

Caso alguém tenha feito o que eu fiz, que foi começar colocando todos os arquivos de compilação no diretório de origem:

cd src
cmake .

cmake vai colocar um monte de arquivos de compilação e arquivos de cache ( CMakeCache.txt, CMakeFiles, cmake_install.cmake, etc) no srcdir.

Para mudar para uma compilação fora do código-fonte, tive que remover todos esses arquivos. Então eu poderia fazer o que @Angew recomendou em sua resposta:

mkdir -p src/build
cd src/build
cmake ..
Avi Tevet
fonte
7

No CMake Wiki :

CMAKE_BINARY_DIR se você estiver compilando no código-fonte, é o mesmo que CMAKE_SOURCE_DIR, caso contrário, este é o diretório de nível superior de sua árvore de compilação

Compare essas duas variáveis ​​para determinar se a compilação fora da fonte foi iniciada

damkrat
fonte
6

Você não deve confiar em um nome de diretório de construção embutido em seu script, portanto, a linha com ../Compiledeve ser alterada.

É porque deve caber ao usuário compilar.

Em vez disso, use uma das variáveis ​​predefinidas: http://www.cmake.org/Wiki/CMake_Useful_Variables (procure CMAKE_BINARY_DIRe CMAKE_CURRENT_BINARY_DIR)

Michał Walenciak
fonte
2
isso é exatamente o que eu estava procurando - CMAKE_CURRENT_BINARY_DIRnormalmente falaria sobre o caminho de compilação binário atual. Possivelmente, pode ser usado para definir as compilações libs / bin dependentes.
parasrish