Cómo hacer un Makefile SIMPLE C ++

303

Estamos obligados a usar un Makefile para unir todo para nuestro proyecto, pero nuestro profesor nunca nos mostró cómo hacerlo.

Sólo tengo un archivo, a3driver.cpp. El controlador importa una clase desde una ubicación "/user/cse232/Examples/example32.sequence.cpp",.

Eso es. Todo lo demás está contenido con el .cpp.

¿Cómo haría para crear un Makefile simple que crea un ejecutable llamado a3a.exe?

Acontecer
fuente
99
.EXE así que definitivamente es Windows. Pensándolo bien ... el camino es estilo Unix. Probablemente usando Mingw-32.
Nathan Osman
2
Suspiro. Supongo que tienes que aprender lo básico de cada comercio, incluso si nunca los usarás. Solo tengo que entender cómo funcionan las cosas. Sin embargo, es muy probable que siempre se desarrolle en un IDE, como Eclipse. Obtendrá una respuesta aquí para su caso simple de una línea y hay muchos tutoriales web, pero si desea un conocimiento en profundidad, no puede vencer al libro de O'reilly (lo mismo para la mayoría de los temas s / w). amazon.com/Managing-Projects-Make-Nutshell-Handbooks/dp/… Elija una copia de segunda mano de amazon, half.com, betterworldbooks eBay
Mawg dice que reinstale a Monica el
2
El enlace publicado por @Dennis ahora está muerto, pero el mismo material se puede encontrar en esta página de archive.org .
Guilherme Salomé
Prefiero las ideas de esta persona. ( hiltmon.com/blog/2013/07/03/… ) La estructura del proyecto puede modificarse fácilmente para adaptarse. Y también estoy de acuerdo en que el tiempo del desarrollador debe gastarse en otras cosas que no sean automake / autoconf. Estas herramientas tienen su lugar, pero quizás no para proyectos internos. Estoy construyendo un script que producirá una estructura de proyecto de este tipo.
Daisuke Aramaki el
@ GuilhermeSalomé Gracias, creo que este es el mejor tutorial simple y completo.
Hareen Laks

Respuestas:

561

Como esto es para Unix, los ejecutables no tienen extensiones.

Una cosa a tener en cuenta es que root-configes 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.hhy support.oque depende rooty 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 toolestá desactualizado) y desea compilar el programa.

Para hacer esto usted mismo podría

  1. Compruebe si support.cco support.hhes más reciente que support.o, y si es así, ejecute un comando como

    g++ -g -c -pthread -I/sw/include/root support.cc
  2. Verifique si support.hho tool.ccson más nuevos que tool.o, y si es así, ejecute un comando como

    g++ -g  -c -pthread -I/sw/include/root tool.cc
  3. Compruebe si tool.oes 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 makefileasí:

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 makeen 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.cccambia eso significa que support.odebe ser reconstruido, pero tool.opuede dejarse solo. Cuando los support.ocambios tooldeben 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 opatcon npaten 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

  1. Todavía estamos indicando explícitamente las dependencias para cada archivo de objeto y el ejecutable final
  2. 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:

  1. reglas de sufijo (consideradas obsoletas en GNU make, pero mantenidas por compatibilidad con versiones anteriores)
  2. reglas implícitas
  3. 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 cleaneliminar 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

  1. ¡Ya no hay líneas de dependencia para los archivos fuente!?!
  2. Hay alguna magia extraña relacionada con .depend y depend
  3. Si lo hace makea continuación, ls -Ase ve un archivo con el nombre .dependque 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).

dmckee --- gatito ex moderador
fuente
99
Este método para generar dependencias es obsoleto y realmente dañino. Consulte Generación avanzada de autodependencia .
Maxim Egorushkin
55
-pthreadEl indicador hace gccque se definan las macros necesarias, -D_REENTRANTes innecesario.
Maxim Egorushkin
8
@jcoe Realiza un pase de preprocesador adicional innecesario para generar dependencias. Al hacer un trabajo innecesario, simplemente disipa el calor derritiendo los polos de hielo y, a mayor escala, se acerca a la muerte por calor de nuestro universo.
Maxim Egorushkin
2
Probablemente "dañino" es demasiado, pero dado que las fases u objetivos explícitos de generación de dependencia están desactualizados ya que, como mínimo, el CCG 3, realmente creo que todos deberíamos superarlos. bruno.defraine.net/techtips/makefile-auto-dependencies-with-gcc/…
hmijail llora a los resigneados el
2
Realmente, la respuesta aceptada no debe depender de un software muy específico ( root-config). Debería proponerse una alternativa más general con la misma capacidad, en caso de existir, o simplemente dejarla fuera. No voté en contra debido a la lista y explicación de las macros make más utilizadas.
diodo verde
56

Siempre pensé que era más fácil de aprender con un ejemplo detallado, así que así es como pienso en los makefiles. Para cada sección, tiene una línea que no está sangrada y muestra el nombre de la sección seguida de dependencias. Las dependencias pueden ser otras secciones (que se ejecutarán antes de la sección actual) o archivos (que si se actualizan harán que la sección actual se ejecute nuevamente la próxima vez que se ejecute make).

Aquí hay un ejemplo rápido (tenga en cuenta que estoy usando 4 espacios donde debería estar usando una pestaña, Stack Overflow no me deja usar pestañas):

a3driver: a3driver.o
    g++ -o a3driver a3driver.o

a3driver.o: a3driver.cpp
    g++ -c a3driver.cpp

Cuando escriba make, elegirá la primera sección (a3driver). a3driver depende de a3driver.o, por lo que irá a esa sección. a3driver.o depende de a3driver.cpp, por lo que solo se ejecutará si a3driver.cpp ha cambiado desde la última vez que se ejecutó. Suponiendo que se haya ejecutado (o que nunca se haya ejecutado), compilará a3driver.cpp en un archivo .o, luego volverá a a3driver y compilará el ejecutable final.

Como solo hay un archivo, incluso podría reducirse a:

a3driver: a3driver.cpp
    g++ -o a3driver a3driver.cpp

La razón por la que mostré el primer ejemplo es que muestra el poder de los makefiles. Si necesita compilar otro archivo, simplemente puede agregar otra sección. Aquí hay un ejemplo con un secondFile.cpp (que se carga en un encabezado llamado secondFile.h):

a3driver: a3driver.o secondFile.o
    g++ -o a3driver a3driver.o secondFile.o

a3driver.o: a3driver.cpp
    g++ -c a3driver.cpp

secondFile.o: secondFile.cpp secondFile.h
    g++ -c secondFile.cpp

De esta manera, si cambia algo en secondFile.cpp o secondFile.h y vuelve a compilar, solo volverá a compilar secondFile.cpp (no a3driver.cpp). O, alternativamente, si cambia algo en a3driver.cpp, no volverá a compilar secondFile.cpp.

Avíseme si tiene alguna pregunta al respecto.

También es tradicional incluir una sección llamada "all" y una sección llamada "clean". "all" generalmente compilará todos los ejecutables y "clean" eliminará "artefactos de compilación" como archivos .o y los ejecutables:

all: a3driver ;

clean:
    # -f so this will succeed even if the files don't exist
    rm -f a3driver a3driver.o

EDITAR: No me di cuenta de que estás en Windows. Creo que la única diferencia es cambiar el -o a3drivera -o a3driver.exe.

Brendan Long
fuente
El código absoluto que estoy tratando de usar es: p4a.exe: p4driver.cpp g ++ -o p4a p4driver.cpp PERO, me dice "falta el separador". Estoy usando TAB, pero todavía me dice eso. ¿Alguna idea?
Suceda el
2
Por lo que puedo decir, ese mensaje de error solo aparece si tienes espacios. Asegúrese de que no tiene ninguna línea que comience con espacios (espacio + tab dará ese error). Eso es lo único en lo que puedo pensar ...
Brendan Long
Nota para futuros editores: StackOverflow no puede procesar pestañas incluso si las edita en la respuesta, así que no intente "arreglar" mi nota al respecto.
Brendan Long el
35

¿Por qué a todos les gusta enumerar los archivos fuente? Un simple comando de búsqueda puede encargarse de eso fácilmente.

Aquí hay un ejemplo de un simple Makefile de C ++. Simplemente colóquelo en un directorio que contenga .Carchivos y luego escriba make...

appname := myapp

CXX := clang++
CXXFLAGS := -std=c++11

srcfiles := $(shell find . -name "*.C")
objects  := $(patsubst %.C, %.o, $(srcfiles))

all: $(appname)

$(appname): $(objects)
    $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $(appname) $(objects) $(LDLIBS)

depend: .depend

.depend: $(srcfiles)
    rm -f ./.depend
    $(CXX) $(CXXFLAGS) -MM $^>>./.depend;

clean:
    rm -f $(objects)

dist-clean: clean
    rm -f *~ .depend

include .depend
lodo frito
fuente
2
Una razón para no buscar automáticamente los archivos fuente es que uno puede tener diferentes objetivos de compilación que necesitan diferentes archivos.
hmijail llora a los despedidos el
Acordó @hmijail, así como submódulos que contienen una tonelada de fuentes / encabezados que no desea compilar / vincular ... y, sin duda, muchas otras circunstancias en las que la búsqueda / uso exhaustivo no es adecuado.
Ingeniero
¿Por qué usar "shell find" y no "wildcard" en su lugar?
Nolan
1
@Nolan para encontrar archivos de origen en un árbol de directorio de origen
AlejandroVD
13

Tenías dos opciones.

Opción 1: makefile más simple = NO MAKEFILE.

Cambie el nombre de "a3driver.cpp" a "a3a.cpp", y luego en la línea de comando escriba:

nmake a3a.exe

Y eso es. Si está utilizando GNU Make, use "make" o "gmake" o lo que sea.

Opción 2: un archivo MAKE de 2 líneas.

a3a.exe: a3driver.obj
    link /out:a3a.exe a3driver.obj
Ninguno
fuente
3
Esta sería una excelente respuesta si no presupusiera tantas cosas sobre los detalles del entorno del OP. Sí, están en Windows, pero eso no significa que estén usando nmake. La linklínea de comando también se ve muy específica para un compilador particular, y al menos debe documentar cuál.
tripleee
6

Su archivo Make tendrá una o dos reglas de dependencia dependiendo de si compila y vincula con un solo comando, o con un comando para la compilación y uno para el enlace.

La dependencia es un árbol de reglas que se ve así (tenga en cuenta que la sangría debe ser una TAB):

main_target : source1 source2 etc
    command to build main_target from sources

source1 : dependents for source1
    command to build source1

No debe haber una línea en blanco después de que los comandos para un objetivo, y debe no ser una línea en blanco antes de los comandos. El primer objetivo en el archivo MAKE es el objetivo general, y otros objetivos se construyen solo si el primer objetivo depende de ellos.

Entonces su archivo MAKE se verá más o menos así.

a3a.exe : a3driver.obj 
    link /out:a3a.exe a3driver.obj

a3driver.obj : a3driver.cpp
    cc a3driver.cpp
John Knoeller
fuente
6

Sugiero (tenga en cuenta que la sangría es una TAB):

tool: tool.o file1.o file2.o
    $(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $@

o

LINK.o = $(CXX) $(LDFLAGS) $(TARGET_ARCH)
tool: tool.o file1.o file2.o

La última sugerencia es un poco mejor ya que reutiliza las reglas implícitas de GNU Make. Sin embargo, para que funcione, un archivo fuente debe tener el mismo nombre que el ejecutable final (es decir: tool.cy tool).

Aviso, no es necesario declarar fuentes. Los archivos de objetos intermedios se generan mediante una regla implícita. En consecuencia, esto Makefilefunciona para C y C ++ (y también para Fortran, etc.).

Observe también, por defecto, el uso de Makefile $(CC)como el vinculador. $(CC)no funciona para vincular archivos de objetos C ++. Modificamos LINK.osolo por eso. Si desea compilar código C, no tiene que forzar el LINK.ovalor.

Claro, también puede agregar sus indicadores de compilación con variable CFLAGSy agregar sus bibliotecas LDLIBS. Por ejemplo:

CFLAGS = -Wall
LDLIBS = -lm

Una nota al margen: si tiene que usar bibliotecas externas, sugiero usar pkg-config para configurar correctamente CFLAGSy LDLIBS:

CFLAGS += $(shell pkg-config --cflags libssl)
LDLIBS += $(shell pkg-config --libs libssl)

El lector atento notará que esto Makefileno se reconstruye correctamente si se cambia un encabezado. Agregue estas líneas para solucionar el problema:

override CPPFLAGS += -MMD
include $(wildcard *.d)

-MMDpermite construir archivos .d que contienen fragmentos de Makefile sobre dependencias de encabezados. La segunda línea solo los usa.

Por supuesto, un Makefile bien escrito también debe incluir cleany distcleanreglas:

clean:
    $(RM) *.o *.d

distclean: clean
    $(RM) tool

Aviso, $(RM)es el equivalente de rm -f, pero es una buena práctica no llamar rmdirectamente.

La allregla también es apreciada. Para que funcione, debería ser la primera regla de su archivo:

all: tool

También puede agregar una installregla:

PREFIX = /usr/local
install:
    install -m 755 tool $(DESTDIR)$(PREFIX)/bin

DESTDIRestá vacío por defecto. El usuario puede configurarlo para instalar su programa en un sistema alternativo (obligatorio para el proceso de compilación cruzada). Los mantenedores de paquetes para distribución múltiple también pueden cambiar PREFIXpara instalar su paquete /usr.

Una última palabra: no coloque los archivos fuente en subdirectorios. Si realmente desea hacer eso, manténgalo Makefileen el directorio raíz y use rutas completas para identificar sus archivos (es decir subdir/file.o).

Para resumir, su Makefile completo debería verse así:

LINK.o = $(CXX) $(LDFLAGS) $(TARGET_ARCH)
PREFIX = /usr/local
override CPPFLAGS += -MMD
include $(wildcard *.d)

all: tool
tool: tool.o file1.o file2.o
clean:
    $(RM) *.o *.d
distclean: clean
    $(RM) tool
install:
    install -m 755 tool $(DESTDIR)$(PREFIX)/bin
Jérôme Pouiller
fuente
Cerca del final: ¿No debería haber líneas vacías entre las reglas? La respuesta de John Knoeller afirmó que.
Peter Mortensen el
Ninguna de las implementaciones makeque conozco (GNU Make y BSD Make) necesitan líneas vacías entre las reglas. Sin embargo, existen toneladas de makeimplementaciones con sus propios errores ^ Wspecificities.
Jérôme Pouiller
5

Solía respuesta de friedmud . Investigué esto por un tiempo, y parece ser una buena manera de comenzar. Esta solución también tiene un método bien definido para agregar indicadores de compilación. Respondí nuevamente, porque hice cambios para que funcionara en mi entorno, Ubuntu y g ++. Más ejemplos de trabajo son el mejor maestro, a veces.

appname := myapp

CXX := g++
CXXFLAGS := -Wall -g

srcfiles := $(shell find . -maxdepth 1 -name "*.cpp")
objects  := $(patsubst %.cpp, %.o, $(srcfiles))

all: $(appname)

$(appname): $(objects)
    $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $(appname) $(objects) $(LDLIBS)

depend: .depend

.depend: $(srcfiles)
    rm -f ./.depend
    $(CXX) $(CXXFLAGS) -MM $^>>./.depend;

clean:
    rm -f $(objects)

dist-clean: clean
    rm -f *~ .depend

include .depend

Los makefiles parecen ser muy complejos. Estaba usando uno, pero estaba generando un error relacionado con no vincular en las bibliotecas de g ++. Esta configuración resolvió ese problema.

VectorVortec
fuente