Diferencia entre usar Makefile y CMake para compilar el código

288

Codifico en C / C ++ y uso un Makefile (GNU) para compilar el código. Puedo hacer lo mismo con CMake y obtener un MakeFile. Sin embargo, ¿cuál es la diferencia entre usar Makefile y CMake para compilar el código?

rish
fuente
2
cmake también puede producir archivos para usar ninja
Bћовић

Respuestas:

403

Make (o más bien un Makefile) es un sistema de compilación: controla el compilador y otras herramientas de compilación para compilar su código.

CMake es un generador de sistemas de construcción. Puede producir Makefiles, puede producir archivos de compilación Ninja, puede producir proyectos KDEvelop o Xcode, puede producir soluciones de Visual Studio. Desde el mismo punto de partida, el mismo archivo CMakeLists.txt. Entonces, si tiene un proyecto independiente de la plataforma, CMake es una forma de hacerlo también independiente del sistema de compilación.

Si tiene desarrolladores de Windows acostumbrados a los desarrolladores de Visual Studio y Unix que confían en GNU Make, CMake es (una) de las formas de hacerlo.

Siempre recomendaría usar CMake (u otro generador de sistema de compilación, pero CMake es mi preferencia personal) si pretende que su proyecto sea multiplataforma o ampliamente utilizable. CMake también proporciona algunas características interesantes como detección de dependencias, administración de interfaz de biblioteca o integración con CTest, CDash y CPack.

El uso de un generador de sistema de compilación hace que su proyecto esté más preparado para el futuro. Incluso si ahora es GNU-Make-only, ¿qué sucede si luego decide expandirse a otras plataformas (ya sea Windows o algo incrustado), o simplemente quiere usar un IDE?

Angew ya no está orgulloso de SO
fuente
55
@rish Sí, esa es la esencia. Sin embargo, tenga en cuenta que hay más formas de programar en Linux que Makefiles; consulte, por ejemplo, QtCreator, KDEvelop, Ninja. Para cada uno de estos, es "crear un proyecto y mantenerlo sincronizado con el Makefile" o "volver a ejecutar CMake". Y, como se menciona en la respuesta, CMake también tiene otra funcionalidad, como el descubrimiento de dependencias (p find_package(). Ej. ) O el soporte de pruebas / empaquetado.
Angew ya no está orgulloso de SO
3
Leí que CMake no puede crear archivos MAKE no recursivos. ¿Sigue siendo cierto?
Maxim Egorushkin
1
@Angew No recursivo es cuando make se invoca una vez con el árbol de dependencia del proyecto completo. A diferencia de lo recursivo cuando un archivo MAKE de nivel superior invoca archivos MAKE de subproyectos en cierto orden.
Maxim Egorushkin
3
Esta es una debilidad importante de CMake: GNU make tiene sus arrugas, pero si te tomas el tiempo de aprenderlo, es extremadamente potente y versátil, y funciona en una enorme cantidad de plataformas. No tener un árbol de dependencia completo para analizar es una falla importante, solo google para 'hacer recursivo hacer que se considere dañino'.
Erik Alapää
1
@ ErikAlapää Leeré el artículo en detalle, pero a primera vista, parecen estar hablando de marcas recursivas donde la profundidad de la recursión depende de los datos (es decir, depende de la profundidad del directorio de origen, etc.). Ese no es el caso con CMake: la profundidad total de las invocaciones siempre es 3, independientemente de la estructura del proyecto. Es solo que algunos bits se delegan en un submakefile en lugar de todos en uno, pero no refleja la estructura del proyecto de ninguna manera. Además, los submakefiles no son realmente "autónomos", por lo que no sufren el problema de dependencia excesiva / insuficiente.
Angew ya no está orgulloso de SO
39

La afirmación de que CMake es un "generador de compilación" es un error común.

No es técnicamente incorrecto; solo describe CÓMO funciona, pero NO LO que hace.

En el contexto de la pregunta, hacen lo mismo: toman un montón de archivos C / C ++ y los convierten en binarios.

Entonces, ¿cuál es la verdadera diferencia?

  • CMake es mucho más de alto nivel. Está diseñado para compilar C ++, para el cual escribe mucho menos código de compilación, pero también puede usarse para compilaciones de propósito general. maketambién tiene algunas reglas C / C ++ incorporadas, pero en su mayoría son inútiles.

  • CMakerealiza una compilación de dos pasos: genera un script de compilación de bajo nivel en ninjao en makemuchos otros generadores, y luego lo ejecuta. Todas las piezas de script de shell que normalmente se acumulan Makefilesolo se ejecutan en la etapa de generación. Por lo tanto, CMakeconstruir puede ser un orden de magnitud más rápido.

  • La gramática de CMakees mucho más fácil de soportar para herramientas externas que las de make .

  • Una vez que makeconstruye un artefacto, olvida cómo se construyó. ¿De qué fuentes se creó, qué indicadores del compilador? CMakelo rastrea, te lo makedeja a ti. Si una de las fuentes de la biblioteca se eliminó desde la versión anterior de Makefile, makeno la reconstruirá.

  • Moderno CMake(comenzando con la versión 3.algo) funciona en términos de dependencias entre "objetivos". Un objetivo sigue siendo un único archivo otput (lamentablemente), pero puede tener dependencias transitivas ("público" / "interfaz" en términos de CMake). Estas dependencias transitivas pueden exponerse u ocultarse de los paquetes dependientes. CMakegestionará directorios para usted también. Con make, estás atascado en un nivel de archivo por archivo y administrar directorios a mano.

Podrías codificar algo makeusando archivos de bandera para cubrir los dos últimos vacíos, pero estás solo. makecontiene un lenguaje completo de Turing (incluso dos, a veces tres contando Guile ), y todos ellos son horribles.

Para ser honesto, esto es lo que CMakey maketienen en común - sus lenguas son bastante horrible:

  • No tienen tipos;
  • sin matrices, solo cadenas separadas por espacios, escapando así del infierno;
  • normalmente pasa argumentos a funciones estableciendo variables globales; (esto se está abordando en CMake moderno: las variables pueden tener espacios de nombres ahora; un objetivo es un espacio de nombres para sus propiedades)
  • la referencia a una variable indefinida se ignora silenciosamente por defecto;

para empezar.

Pero en CMaketi escribes muchas menos líneas de código.

Victor Sergienko
fuente
1
Aquí hay buena información, pero un comentario es completamente incorrecto: cmake tiene un tipo LIST ya que con las funciones LIST adecuadas, lo cual es crucial para muchas tareas del sistema de compilación, una pequeña diferencia: cmake.org/cmake/help/git-master/command /list.html
resolviendoJ
No lo llamaría "completamente" incorrecto, pero gracias por la corrección.
Victor Sergienko