Directorio de salida / compilación de CMake

115

Soy bastante nuevo en CMake, y leí algunos tutoriales sobre cómo usarlo, y escribí algunas complicadas 50 líneas de script de CMake para hacer un programa para 3 compiladores diferentes. Esto probablemente concluye todo mi conocimiento en CMake.

Ahora mi problema es que tengo un código fuente, cuya carpeta no quiero tocar / con la que no quiero tocar cuando hago el programa. Quiero que todos makelos archivos y carpetas de CMake y de salida entren ../Compile/, así que cambié algunas variables en mi script de CMake para eso, y funcionó durante algún tiempo cuando hice algo como esto en mi computadora portátil:

Compile$ cmake ../src
Compile$ make

Donde con eso tuve una salida limpia en la carpeta en la que estoy ahora, que es exactamente lo que estoy buscando.

Ahora me mudé a otra computadora y volví a compilar CMake 2.8.11.2, ¡y casi he vuelto al punto de partida! Siempre compila la cosa en la srccarpeta donde CMakeLists.txtse encuentra mi .

La parte donde elijo el directorio en mi script CMake es 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})

Y ahora siempre termina con:

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

¿Me estoy perdiendo de algo?

El físico cuántico
fuente
4
Hay poca necesidad de configurar todas las variables que está configurando. CMake los establece en valores predeterminados razonables. Definitivamente no debe modificar CMAKE_BINARY_DIRo CMAKE_CACHEFILE_DIR. ¿Qué sucede si eliminas todas estas set()llamadas y simplemente lo haces cd Compile; rm -rf *; cmake ../src?
Angew ya no está orgulloso de SO
5
Básicamente, siempre que esté fuera del directorio de origen cuando ejecute CMake, no modificará el directorio de origen a menos que su CMakeList se lo indique explícitamente.
Angew ya no se enorgullece de SO
@Angew ¡Gracias por el consejo, que es sorprendente! Eliminé todas esas líneas y usé cmake ../src ¡y funcionó como un encanto! Esto es tan sorprendente porque lo probé antes cuando estaba aprendiendo CMake por primera vez y no funcionó. Por favor, ponga su respuesta en una respuesta oficial para darle la gran marca de verificación :)
The Quantum Physicist
1
Lo que me salvó fue el comentario de @Adam Bowen de que "no se puede crear una compilación fuera de la fuente para un directorio de fuente con una compilación en la fuente"
Aur Saraf

Respuestas:

60

Hay poca necesidad de configurar todas las variables que está configurando. CMake los establece en valores predeterminados razonables. Definitivamente no debe modificar CMAKE_BINARY_DIRo CMAKE_CACHEFILE_DIR. Trátelos como de solo lectura.

Primero elimine el archivo de caché problemático existente del directorio src:

cd src
rm CMakeCache.txt
cd ..

Luego elimine todos los set()comandos y haga:

cd Compile
rm -rf *
cmake ../src

Siempre que esté fuera del directorio de origen cuando ejecute CMake, no modificará el directorio de origen a menos que su CMakeList se lo indique explícitamente.

Una vez que tenga esto funcionando, puede ver dónde CMake coloca las cosas de forma predeterminada, y solo si no está satisfecho con las ubicaciones predeterminadas (como el valor predeterminado de EXECUTABLE_OUTPUT_PATH), modifique solo las que necesita. Y tratar de expresarlas en relación con CMAKE_BINARY_DIR, CMAKE_CURRENT_BINARY_DIR, PROJECT_BINARY_DIRetc.

Si observa la documentación de CMake, verá variables divididas en secciones semánticas. Excepto en circunstancias muy especiales, debe tratar todas las que se enumeran en "Variables que proporcionan información" como de solo lectura dentro de CMakeLists.

Angew ya no está orgulloso de SO
fuente
2
Empecé a usar cmake con builds en el directorio src ... esta técnica falló inicialmente. Una vez que eliminé todos los archivos / cachés de compilación de cmake en el directorio src, esta técnica funcionó. ¡Gracias!
Avi Tevet
18
Tal vez sea mejor no aconsejar el uso rm -rf *. No es bonito si cd Compilefalla ...
Roman
2
@Roman Considero que tales ejemplos de línea de comandos son prácticamente un pseudocódigo. Es menos detallado y más exacto que escribir "ingrese al directorio Compile, elimine todo lo que hay allí y luego ejecute CMake con una ruta al directorio de origen". Asumo sentido común básico y juicio por parte del lector.
Angew ya no está orgulloso de SO
@AviTevet: Creo que esta es la respuesta correcta. Si hay archivos de caché de cmake de una invocación de cmake anterior dentro del directorio de origen, no conseguirá que cmake elija otro directorio para los archivos generados, a menos que elimine todos los antiguos del directorio de origen. Comportamiento bastante roto por CMake en mi opinión. ¿Por qué no escribe otra respuesta?
Jo So
112

Parece que desea una compilación fuera de origen . Hay un par de formas de crear una compilación fuera de código fuente.

  1. Haz lo que estabas haciendo, corre

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

    lo que hará que cmake para generar un árbol de construcción en /path/to/my/build/folderel árbol de fuentes en /path/to/my/source/folder.

    Una vez que lo haya creado, cmake recuerda dónde está la carpeta de origen, por lo que puede volver a ejecutar cmake en el árbol de compilación con

    cmake /path/to/my/build/folder

    o incluso

    cmake .

    si su directorio actual ya es la carpeta de compilación.

  2. Para CMake 3.13 o posterior, use estas opciones para configurar las carpetas de origen y compilación

    cmake -B/path/to/my/build/folder -S/path/to/my/source/folder
  3. Para CMake más antiguo, use algunas opciones no documentadas para configurar las carpetas de origen y compilación :

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

    que hará exactamente lo mismo que (1), pero sin depender del directorio de trabajo actual.

CMake coloca todas sus salidas en el árbol de compilación de forma predeterminada, por lo que, a menos que esté usando generosamente ${CMAKE_SOURCE_DIR}o ${CMAKE_CURRENT_SOURCE_DIR}en sus archivos cmake, no debería tocar su árbol de fuentes .

Lo más importante que puede salir mal es si ha generado previamente un árbol de compilación en su árbol de fuentes (es decir, tiene una compilación en la fuente ). Una vez que haya hecho esto, la segunda parte de (1) anterior entra en acción y cmake no realiza ningún cambio en las ubicaciones de origen o compilación. Por lo tanto, no puede crear una compilación fuera de origen para un directorio de origen con una compilación en origen . Puede solucionar esto con bastante facilidad eliminando (como mínimo) CMakeCache.txtdel directorio de origen. Hay algunos otros archivos (principalmente en el CMakeFilesdirectorio) que genera CMake que también debe eliminar, pero estos no harán que cmake trate el árbol de origen como un árbol de compilación.

Dado que las compilaciones fuera de la fuente son a menudo más deseables que las compilaciones en la fuente, es posible que desee modificar su cmake para requerir compilaciones fuera de la fuente:

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

La macro anterior proviene de un módulo de uso común llamado MacroOutOfSourceBuild. Hay numerosas fuentes MacroOutOfSourceBuild.cmakeen Google, pero parece que no puedo encontrar el original y es lo suficientemente corto como para incluirlo aquí en su totalidad.

Desafortunadamente, cmake generalmente ha escrito algunos archivos en el momento en que se invoca la macro, por lo que, aunque evitará que realice la compilación, aún deberá eliminar CMakeCache.txty CMakeFiles.

Puede que le resulte útil establecer las rutas en las que se escriben los binarios, las bibliotecas compartidas y estáticas, en cuyo caso, vea cómo puedo convertir la salida de cmake en un directorio 'bin'. (descargo de responsabilidad, tengo la respuesta más votada sobre esa pregunta ... pero así es como lo sé).

Adam Bowen
fuente
En realidad, la opción para configurar la carpeta de origen es -S, no-H
smac89
@ smac89 ¡Gracias! Parece que los documentaron en 3.13. Actualicé la respuesta para reflejar el CMake moderno.
Adam Bowen
8

Convirtiendo mi comentario en una respuesta:

En caso de que alguien hiciera lo que yo hice, que fue comenzar poniendo todos los archivos de compilación en el directorio de origen:

cd src
cmake .

cmake pondrá un montón de archivos de generación y archivos de caché ( CMakeCache.txt, CMakeFiles, cmake_install.cmake, etc.) en el srcdirectorio.

Para cambiar a una compilación fuera de origen, tuve que eliminar todos esos archivos. Entonces podría hacer lo que @Angew recomendó en su respuesta:

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

A partir de CMake Wiki :

CMAKE_BINARY_DIR si está compilando en la fuente, esto es lo mismo que CMAKE_SOURCE_DIR, de lo contrario, este es el directorio de nivel superior de su árbol de compilación

Compare estas dos variables para determinar si se inició la compilación fuera de origen

Damkrat
fuente
6

No debe confiar en un nombre de directorio de compilación codificado en su script, por lo que ../Compiledebe cambiar la línea con .

Es porque el usuario debe decidir dónde compilar.

En lugar de eso, use una de las variables predefinidas: http://www.cmake.org/Wiki/CMake_Useful_Variables (busque CMAKE_BINARY_DIRy CMAKE_CURRENT_BINARY_DIR)

Michał Walenciak
fuente
2
esto es exactamente lo que estaba buscando CMAKE_CURRENT_BINARY_DIR, normalmente diría sobre la ruta de construcción binaria actual. Posiblemente se pueda usar para configurar las versiones de bibliotecas / bin dependientes.
parasrish