El siguiente Makefile crea un ejecutable llamado prog
de las fuentes prog1.c, prog2.c, prog3.c and main.c
. prog
está vinculado contra libmystatlib.a
y libmydynlib.so
que también están construidos desde la fuente. Además, prog
utiliza la biblioteca libstuff.a
en stuff/lib
y su encabezado en stuff/include
. El Makefile por defecto construye un objetivo autorización, pero ofrece también un objetivo de depuración:
#Makefile
CC = gcc
CPP = g++
RANLIB = ar rcs
RELEASE = -c -O3
DEBUG = -c -g -D_DEBUG
INCDIR = -I./stuff/include
LIBDIR = -L./stuff/lib -L.
LIBS = -lstuff -lmystatlib -lmydynlib
CFLAGS = $(RELEASE)
PROGOBJS = prog1.o prog2.o prog3.o
prog: main.o $(PROGOBJS) mystatlib mydynlib
$(CC) main.o $(PROGOBJS) $(LIBDIR) $(LIBS) -o prog
debug: CFLAGS=$(DEBUG)
debug: prog
mystatlib: mystatlib.o
$(RANLIB) libmystatlib.a mystatlib.o
mydynlib: mydynlib.o
$(CPP) -shared mydynlib.o -o libmydynlib.so
%.o: %.c
$(CC) $(CFLAGS) $(INCDIR) $< -o [email protected]
%.o: %.cpp
$(CPP) $(CFLAGS) $(INCDIR) -fPIC $< -o [email protected]
Aquí es una CMakeLists.txt
que hace (casi) exactamente lo mismo, con algunos comentarios para subrayar la similitudes con el Makefile:
#CMakeLists.txt
cmake_minimum_required(VERSION 2.8) # stuff not directly
project(example) # related to building
include_directories(${CMAKE_SOURCE_DIR}/stuff/include) # -I flags for compiler
link_directories(${CMAKE_SOURCE_DIR}/stuff/lib) # -L flags for linker
set(PROGSRC prog1.c prog2.c prog3.c) # define variable
add_executable(prog main.c ${PROGSRC}) # define executable target prog, specify sources
target_link_libraries(prog mystatlib mydynlib stuff) # -l flags for linking prog target
add_library(mystatlib STATIC mystatlib.c) # define static library target mystatlib, specify sources
add_library(mydynlib SHARED mydynlib.cpp) # define shared library target mydynlib, specify sources
#extra flags for linking mydynlib
set_target_properties(mydynlib PROPERTIES POSITION_INDEPENDENT_CODE TRUE)
#alternatively:
#set_target_properties(mydynlib PROPERTIES COMPILE_FLAGS "-fPIC")
En este sencillo ejemplo, las diferencias más importantes son:
CMake rec reconoce qué compiladores usar para qué tipo de fuente. Además, invoca la secuencia correcta de comandos para cada tipo de destino. Por lo tanto, allí no hay una especificación explícita de comandos como $ (CC) ..., $ (RANLIB) ... y así sucesivamente.
Todos los indicadores comunes de compilador/enlazador que se ocupan de la inclusión de archivos de encabezado, bibliotecas, etc. son reemplazados por comandos independientes de plataforma/sistema de compilación.
indicadores de depuración se incluyen ya sea estableciendo la variable de CMAKE_BUILD_TYPE de "depuración", o pasándolo a CMake cuando se invoca el programa: cmake -DCMAKE_BUILD_TYPE:STRING=Debug
.
CMake también ofrece la inclusión independiente de la plataforma del distintivo '-fPIC' (a través de la propiedad POSITION_INDEPENDENT_CODE) y muchos otros. Aún así, se pueden implementar ajustes más oscuros a mano en CMake así como también en un Makefile (usando COMPILE_FLAGS
y propiedades similares). Por supuesto, CMake realmente comienza a brillar cuando las bibliotecas de terceros (como OpenGL) se incluyen de manera portátil.
El proceso de compilación tiene un paso si utiliza un archivo Makefile, es decir, escribiendo make
en la línea de comandos.Para CMake, hay dos pasos: primero, necesita configurar su entorno de compilación (ya sea escribiendo cmake <source_dir>
en su directorio de compilación o ejecutando algún cliente de GUI). Esto crea un Makefile o algo equivalente, según el sistema de compilación que elija (por ejemplo, make en Unixes o VC++ o MinGW + Msys en Windows). El sistema de compilación se puede pasar a CMake como un parámetro; sin embargo, CMake realiza elecciones predeterminadas razonables según la configuración de su sistema. En segundo lugar, realiza la compilación real en el sistema de compilación seleccionado.
Las fuentes y las instrucciones de construcción están disponibles en https://github.com/rhoelzel/make_cmake.
+1 Esta es una buena pregunta; cuando comencé con 'cmake', yo también quería esto. Pero dudo que lo encuentres porque las capacidades no coinciden tan bien entre sí. Si intentas que 'cmake' actúe como' make', te volverás loco, en serio. Lo mejor es comenzar de cero. Las cosas que son triviales en 'make' están bastante involucradas en' cmake', y viceversa. –
@ ErnestFriedman-Hill ¿tiene más detalles al respecto? Entonces 'make' y' cmake' son tan distintos que deberían verse más como herramientas complementarias en lugar de competir. –
@Shurane - cmake no construye nada en sí mismo; crea Makefiles (y otros scripts de construcción similares), que luego ejecuta. Por lo tanto, cada vez que escriba archivos cmake, debe pensar si un comando debe aplicarse durante el tiempo de generación o durante el tiempo de compilación. Algunas acciones, por ejemplo, copiar un conjunto de archivos comodín en tiempo de compilación, son bastante complicadas, en comparación con el '' cp * .x $ (OUTDIR) '" que escribirías en un Makefile. Quizás la parte más molesta para mí es que los Makefiles generados son, por diseño, completamente no portables e inflexibles (continuación) –