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?


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.


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).


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 ..

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


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)


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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.