Como esto es para Unix, los ejecutables no tienen extensiones.
Una cosa a tener en cuenta es que root-config
es una utilidad que proporciona la compilación correcta y las banderas de enlace; y las bibliotecas adecuadas para crear aplicaciones contra root. Eso es solo un detalle relacionado con la audiencia original de este documento.
Hazme bebe
o nunca olvidas la primera vez que te hicieron
Una discusión introductoria sobre make y cómo escribir un simple makefile
¿Qué es hacer? ¿Y por qué debería importarme?
La herramienta llamada Make es un administrador de dependencia de compilación. Es decir, se encarga de saber qué comandos deben ejecutarse en qué orden tomar su proyecto de software de una colección de archivos fuente, archivos de objetos, bibliotecas, encabezados, etc., etc., algunos de los cuales pueden haber cambiado recientemente --- y convertirlos en una versión correcta y actualizada del programa.
En realidad, también puedes usar Make para otras cosas, pero no voy a hablar de eso.
Un archivo trivial
Suponga que tiene un directorio que contiene:, tool
tool.cc
tool.o
support.cc
support.hh
y support.o
que depende root
y se supone que debe compilarse en un programa llamado tool
, y suponga que ha estado pirateando los archivos de origen (lo que significa que el existente tool
está desactualizado) y desea compilar el programa.
Para hacer esto usted mismo podría
Compruebe si support.cc
o support.hh
es más reciente que support.o
, y si es así, ejecute un comando como
g++ -g -c -pthread -I/sw/include/root support.cc
Verifique si support.hh
o tool.cc
son más nuevos que tool.o
, y si es así, ejecute un comando como
g++ -g -c -pthread -I/sw/include/root tool.cc
Compruebe si tool.o
es más nuevo que tool
, y si es así, ejecute un comando como
g++ -g tool.o support.o -L/sw/lib/root -lCore -lCint -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lTree -lRint \
-lPostscript -lMatrix -lPhysics -lMathCore -lThread -lz -L/sw/lib -lfreetype -lz -Wl,-framework,CoreServices \
-Wl,-framework,ApplicationServices -pthread -Wl,-rpath,/sw/lib/root -lm -ldl
¡Uf! ¡Qué lío! Hay mucho que recordar y varias posibilidades de cometer errores. (Por cierto, los detalles de las líneas de comando que se muestran aquí dependen de nuestro entorno de software. Estos funcionan en mi computadora).
Por supuesto, puede ejecutar los tres comandos cada vez. Eso funcionaría, pero no se adapta bien a una pieza sustancial de software (como DOGS que toma más de 15 minutos compilar desde cero en mi MacBook).
En su lugar, podría escribir un archivo llamado makefile
así:
tool: tool.o support.o
g++ -g -o tool tool.o support.o -L/sw/lib/root -lCore -lCint -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lTree -lRint \
-lPostscript -lMatrix -lPhysics -lMathCore -lThread -lz -L/sw/lib -lfreetype -lz -Wl,-framework,CoreServices \
-Wl,-framework,ApplicationServices -pthread -Wl,-rpath,/sw/lib/root -lm -ldl
tool.o: tool.cc support.hh
g++ -g -c -pthread -I/sw/include/root tool.cc
support.o: support.hh support.cc
g++ -g -c -pthread -I/sw/include/root support.cc
y solo escribe make
en la línea de comando. Que realizará los tres pasos que se muestran arriba automáticamente.
Las líneas no indentadas aquí tienen la forma "destino: dependencias" y le dicen a Make que los comandos asociados (líneas sangradas) deben ejecutarse si alguna de las dependencias es más nueva que el objetivo. Es decir, las líneas de dependencia describen la lógica de lo que debe reconstruirse para acomodar los cambios en varios archivos. Si support.cc
cambia eso significa que support.o
debe ser reconstruido, pero tool.o
puede dejarse solo. Cuando los support.o
cambios tool
deben ser reconstruidos.
Los comandos asociados con cada línea de dependencia se activan con una pestaña (ver más abajo) que debe modificar el objetivo (o al menos tocarlo para actualizar el tiempo de modificación).
Variables, reglas incorporadas y otras cosas
En este punto, nuestro archivo MAKE simplemente está recordando el trabajo que debe realizarse, pero aún así teníamos que resolver y escribir todos y cada uno de los comandos necesarios en su totalidad. No tiene por qué ser así: Make es un lenguaje poderoso con variables, funciones de manipulación de texto y una gran cantidad de reglas incorporadas que pueden hacernos esto mucho más fácil.
Hacer variables
La sintaxis para acceder a una variable make es $(VAR)
.
La sintaxis para asignar a una variable Make es: VAR = A text value of some kind
(o VAR := A different text value but ignore this for the moment
).
Puede usar variables en reglas como esta versión mejorada de nuestro archivo MAKE:
CPPFLAGS=-g -pthread -I/sw/include/root
LDFLAGS=-g
LDLIBS=-L/sw/lib/root -lCore -lCint -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lTree -lRint \
-lPostscript -lMatrix -lPhysics -lMathCore -lThread -lz -L/sw/lib -lfreetype -lz \
-Wl,-framework,CoreServices -Wl,-framework,ApplicationServices -pthread -Wl,-rpath,/sw/lib/root \
-lm -ldl
tool: tool.o support.o
g++ $(LDFLAGS) -o tool tool.o support.o $(LDLIBS)
tool.o: tool.cc support.hh
g++ $(CPPFLAGS) -c tool.cc
support.o: support.hh support.cc
g++ $(CPPFLAGS) -c support.cc
que es un poco más legible, pero aún requiere mucho tipeo
Hacer funciones
GNU make admite una variedad de funciones para acceder a la información del sistema de archivos u otros comandos del sistema. En este caso, estamos interesados en $(shell ...)
qué se expande a la salida de los argumentos y $(subst opat,npat,text)
qué reemplaza todas las instancias de opat
con npat
en el texto.
Aprovechar esto nos da:
CPPFLAGS=-g $(shell root-config --cflags)
LDFLAGS=-g $(shell root-config --ldflags)
LDLIBS=$(shell root-config --libs)
SRCS=tool.cc support.cc
OBJS=$(subst .cc,.o,$(SRCS))
tool: $(OBJS)
g++ $(LDFLAGS) -o tool $(OBJS) $(LDLIBS)
tool.o: tool.cc support.hh
g++ $(CPPFLAGS) -c tool.cc
support.o: support.hh support.cc
g++ $(CPPFLAGS) -c support.cc
que es más fácil de escribir y mucho más legible.
Darse cuenta de
- Todavía estamos indicando explícitamente las dependencias para cada archivo de objeto y el ejecutable final
- Hemos tenido que escribir explícitamente la regla de compilación para ambos archivos fuente
Reglas implícitas y de patrones
En general, esperaríamos que todos los archivos fuente de C ++ se traten de la misma manera, y Make proporciona tres formas de decir esto:
- reglas de sufijo (consideradas obsoletas en GNU make, pero mantenidas por compatibilidad con versiones anteriores)
- reglas implícitas
- reglas de patrón
Las reglas implícitas están integradas, y algunas se discutirán a continuación. Las reglas de patrón se especifican en una forma como
%.o: %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -c $<
lo que significa que los archivos de objetos se generan a partir de los archivos fuente de C ejecutando el comando que se muestra, donde la variable "automática" se $<
expande al nombre de la primera dependencia.
Reglas incorporadas
Make tiene una gran cantidad de reglas integradas que significan que, muy a menudo, un proyecto puede compilarse con un archivo MAKE muy simple.
La regla incorporada de creación de GNU para archivos fuente C es la que se muestra arriba. Del mismo modo, creamos archivos de objetos a partir de archivos fuente de C ++ con una regla como $(CXX) -c $(CPPFLAGS) $(CFLAGS)
.
Los archivos de un solo objeto se vinculan utilizando $(LD) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS)
, pero esto no funcionará en nuestro caso, porque queremos vincular varios archivos de objeto.
Variables utilizadas por las reglas integradas
Las reglas integradas utilizan un conjunto de variables estándar que le permiten especificar información del entorno local (como dónde encontrar los archivos de inclusión ROOT) sin volver a escribir todas las reglas. Los más propensos a ser interesantes para nosotros son:
CC
- el compilador de C para usar
CXX
- el compilador de C ++ para usar
LD
- el enlazador para usar
CFLAGS
- bandera de compilación para archivos fuente C
CXXFLAGS
- banderas de compilación para archivos fuente C ++
CPPFLAGS
- indicadores para el preprocesador c (normalmente incluyen rutas de archivo y símbolos definidos en la línea de comando), utilizados por C y C ++
LDFLAGS
- banderas de enlace
LDLIBS
- bibliotecas para vincular
Un Makefile Básico
Al aprovechar las reglas incorporadas, podemos simplificar nuestro archivo MAKE para:
CC=gcc
CXX=g++
RM=rm -f
CPPFLAGS=-g $(shell root-config --cflags)
LDFLAGS=-g $(shell root-config --ldflags)
LDLIBS=$(shell root-config --libs)
SRCS=tool.cc support.cc
OBJS=$(subst .cc,.o,$(SRCS))
all: tool
tool: $(OBJS)
$(CXX) $(LDFLAGS) -o tool $(OBJS) $(LDLIBS)
tool.o: tool.cc support.hh
support.o: support.hh support.cc
clean:
$(RM) $(OBJS)
distclean: clean
$(RM) tool
También hemos agregado varios objetivos estándar que realizan acciones especiales (como limpiar el directorio de origen).
Tenga en cuenta que cuando se invoca make sin argumento, usa el primer objetivo encontrado en el archivo (en este caso, todos), pero también puede nombrar el objetivo para obtener cuál es el que hace que make clean
eliminar los archivos de objeto en este caso.
Todavía tenemos todas las dependencias codificadas.
Algunas mejoras misteriosas
CC=gcc
CXX=g++
RM=rm -f
CPPFLAGS=-g $(shell root-config --cflags)
LDFLAGS=-g $(shell root-config --ldflags)
LDLIBS=$(shell root-config --libs)
SRCS=tool.cc support.cc
OBJS=$(subst .cc,.o,$(SRCS))
all: tool
tool: $(OBJS)
$(CXX) $(LDFLAGS) -o tool $(OBJS) $(LDLIBS)
depend: .depend
.depend: $(SRCS)
$(RM) ./.depend
$(CXX) $(CPPFLAGS) -MM $^>>./.depend;
clean:
$(RM) $(OBJS)
distclean: clean
$(RM) *~ .depend
include .depend
Darse cuenta de
- ¡Ya no hay líneas de dependencia para los archivos fuente!?!
- Hay alguna magia extraña relacionada con .depend y depend
- Si lo hace
make
a continuación, ls -A
se ve un archivo con el nombre .depend
que contiene las cosas que se parecen a las líneas de dependencia maquillaje
Otra lectura
Conozca errores y notas históricas
El idioma de entrada para Make es sensible al espacio en blanco. En particular, las líneas de acción que siguen a las dependencias deben comenzar con una pestaña . Pero una serie de espacios puede tener el mismo aspecto (y, de hecho, hay editores que convertirán silenciosamente las pestañas en espacios o viceversa), lo que da como resultado un archivo Make que se ve bien y aún no funciona. Esto se identificó como un error al principio, pero (según la historia ) no se solucionó, porque ya había 10 usuarios.
(Esto fue copiado de una publicación wiki que escribí para estudiantes de posgrado de física).