Desde que aprendí acerca -j He usado -j8 alegremente. El otro día estaba compilando una instalación atlas y la marca falló. Finalmente lo rastreé hasta que las cosas se hicieron fuera de orden, y funcionó bien una vez que volví a la marca única. Esto me pone nervioso ¿Qué tipo de condiciones debo tener en cuenta al escribir mis propios archivos make para evitar hacer algo inesperado con make -j?GNU de make
Respuesta
pienso hacer -j respetará las dependencias que se especifiquen en el Makefile; es decir, si especifica que objA depende de objB y objC, make no comenzará a trabajar en objA hasta que objB y objC estén completos.
Lo más probable es que su Makefile no especifique el orden de operaciones necesario estrictamente, y es solo suerte que funcione para usted en el caso de un solo hilo.
Eso es correcto. Trabajo en una base de código de aproximadamente 20 millones de líneas, principalmente en C con un poco de C++. Se divide en cientos de componentes, aproximadamente la mitad de los cuales usan marca y la mitad usan mermelada. Siempre hago compilaciones paralelas con la opción -j; de lo contrario, las construcciones tomarían horas. Jam genera sus propias dependencias, por lo que los componentes que lo usan siempre tienen éxito. Pero los componentes que usan makefiles construidos a mano se ahogan ocasionalmente, invariablemente debido a dependencias inadecuadas. –
He visto mucho en la web que '-j' se refiere a la cantidad de CPU con las que desea compilar. He realizado una prueba en mi máquina de 8 núcleos y 'make 'funciona hasta e incluyendo' -j8' (más allá de eso es 100% de uso en todos los núcleos, similar a '-j8'). En cada incremento de entero, vería otro uso del núcleo aumentar aproximadamente en un * 100% *. ¿Diría que es una buena regla general para saber qué especificar como su valor '-j'? – Jacksonkr
La única buena regla que conozco es hacer un "make clean; time make -jn" en su programa, con varios valores de (n), y ver cuánto tiempo tarda cada compilación, y luego ir con la configuración completada en la menor cantidad de tiempo Hay demasiadas variables (velocidad de la CPU, velocidad de la RAM, tamaño de la RAM, velocidad del disco duro, sobrecarga del proceso del sistema operativo, etc.) para poder hacer generalizaciones útiles. –
En pocas palabras - asegurarse de que sus dependencias son correctos y completos.
Si está utilizando una marca de un solo subproceso, puede ignorar ciegamente las dependencias implícitas entre los destinos. Al usar la función paralela no puede confiar en las dependencias implícitas. Todos deberían hacerse explícitos. Esta es probablemente la trampa más común. Particularmente si se utilizan objetivos .phony como dependencias.
This enlace es una buena guía sobre algunos de los problemas con la marca paralela.
+1 Para el buen enlace. Ahora siento que puedo confiar en make -j también y cómo solucionar problemas cuando surgen. Bien vale la pena leer. –
Si usted tiene un make recursivo, las cosas pueden romper bastante fácilmente. Si no está haciendo una marca recursiva, siempre que sus dependencias sean correctas y completas, no debería tener ningún problema (salvo un error en la marca). Consulte Recursive Make Considered Harmful para obtener una descripción mucho más completa de los problemas con la marca recursiva.
He aquí un ejemplo de un problema que me encontré cuando empecé a usar compilaciones paralelas. Tengo un objetivo llamado "nuevo" que utilizo para reconstruir el objetivo desde cero (una compilación "nueva"). En el pasado, codifiqué el objetivo "nuevo" simplemente indicando "limpiar" y luego "compilar" como dependencias.
build: ## builds the default target
clean: ## removes generated files
fresh: clean build ## works for -j1 but fails for -j2
que funcionó bien hasta que empecé a usar compilaciones paralelas, pero con compilaciones paralelas, que intenta hacer ambas cosas "limpia" y "construir" al mismo tiempo. Así que cambié la definición de "nuevo" de la siguiente manera para garantizar el orden correcto de las operaciones.
fresh:
$(MAKE) clean
$(MAKE) build
Esto es fundamentalmente solo una cuestión de especificar las dependencias correctamente. El truco es que las construcciones paralelas son más estrictas sobre esto que las compilaciones de subprocesos únicos. Mi ejemplo demuestra que una lista de dependencias para un objetivo dado no necesariamente indica el orden de ejecución.
Recursive make, yuk !. La forma correcta de decir para hacer _porfavor siempre se limpia antes de que build_ sea, por supuesto, 'build: clean'. – bobbogo
@bobbogo: no quiero hacer siempre la limpieza antes de compilar, eso es innecesario en la mayoría de los casos. El objetivo "nuevo" que describí es básicamente un simple script que ejecuta un "make clean" seguido de "make build" (para esos raros momentos en que quiero hacer eso). No veo ningún daño al ejecutar make recursivamente en este escenario. – nobar
¿Qué le parece protegerlo con un condicional: 'ifeq ($ (MAKECMDGOALS), nuevo); construir: limpio; endif' (reemplazar el punto y coma por las líneas nuevas)? – eriktous
Es una buena idea tener una prueba automatizada para probar la opción -j de TODOS los archivos make. Incluso los mejores desarrolladores tienen problemas con la opción -j de make. Los problemas más comunes son los más simples.
myrule: subrule1 subrule2
echo done
subrule1:
echo hello
subrule2:
echo world
En la fabricación normal, verá hola -> mundo -> hecho. Con make -j 4, es posible que vea mundo -> hola -> hecho
Donde he visto que esto suceda la mayoría es con la creación de directorios de salida.Por ejemplo:
build: $(DIRS) $(OBJECTS)
echo done
$(DIRS):
[email protected] -p [email protected]
$(OBJECTS):
$(CC) ...
Acabo de pensar que agregaría a la respuesta de subsetbrew ya que no muestra el efecto claramente. Sin embargo, agregar algunos comandos de suspensión sí lo hace. Bueno, funciona en Linux.
A continuación, se ejecuta make muestra diferencias con:
- hacen
- hacen -j4
all: toprule1
toprule1: botrule2 subrule1 subrule2
@echo toprule 1 start
@sleep 0.01
@echo toprule 1 done
subrule1: botrule1
@echo subrule 1 start
@sleep 0.08
@echo subrule 1 done
subrule2: botrule1
@echo subrule 2 start
@sleep 0.05
@echo subrule 2 done
botrule1:
@echo botrule 1 start
@sleep 0.20
@echo "botrule 1 done (good prerequiste in sub)"
botrule2:
@echo "botrule 2 start"
@sleep 0.30
@echo "botrule 2 done (bad prerequiste in top)"
- 1. Depuración GNU make
- 2. GNU make cheat-sheet
- 3. BSD Make y GNU Make makefile compatible
- 4. Completo tutorial gnu make/gcc
- 5. ejecutando grep desde GNU make
- 6. Boost bjam versus GNU make
- 7. GNU make: objetivo limpio depende de incluye
- 8. evitar la duplicación de GNU Make reglas
- 9. Speedup GNU make build process - Paralelismo?
- 10. GNU Make convertir espacios a dos puntos
- 11. ¿Vale la pena aprender GNU Make?
- 12. Opción GNU make --jobs en QMAKE
- 13. GNU make: ¿invertir el éxito del subproceso?
- 14. ¿Por qué GNU make eliminar un archivo
- 15. elementos de unión de una lista de GNU Make
- 16. reglas de patrón multi-comodín de GNU make
- 17. Creando varios archivos de encabezado precompilados utilizando GNU make
- 18. GNU make diferencias en las declaraciones de variables múltiples líneas
- 19. GNU make: La extracción de argumento para -j dentro Makefile
- 20. equivalente portátil de GNU make% -style pattern rules
- 21. ¿Cómo invoco una macro make de GNU creada usando define?
- 22. Variables automáticas en las pruebas de condicionales: GNU Make
- 23. GNU Make: Cómo llamar $ (comodín) dentro de $ (eval)
- 24. Cómo analizar el rendimiento de GNU Make files
- 25. ¿Cuáles son algunos buenos recursos para GNU Make?
- 26. Especificando la ruta en makefile (GNU make en Windows)
- 27. ¿Cómo obtengo $ (error ...) para trabajar condicionalmente en GNU Make?
- 28. GNU make: objetivos múltiples en una sola regla
- 29. GNU Make: cómo unir la lista y separarla con separador?
- 30. Unix find with GNU Make para actualizar automáticamente los archivos
¿Estás seguro de que es hacer de culpa? Escribir makefiles correctos es propenso a errores. –
Meh, incluso los archivos makefiles generados por autotools tienen errores. Intente compilar GCC con -j2 o superior. – LiraNuna