Pregunta

Tengo un archivo make que compila y luego llama a otro archivo make. Dado que este makefile llama a más makefiles que hacen el trabajo, realmente no cambia. Por lo tanto, sigue pensando que el proyecto está construido y actualizado.

dnetdev11 ~ # make
make: `release' is up to date.

¿Cómo fuerzo el makefile para reconstruir el objetivo?

clean = $(MAKE) -f ~/xxx/xxx_compile.workspace.mak clean


build = svn up ~/xxx                                                       \
        $(clean)                                                                \
        ~/cbp2mak/cbp2mak -C ~/xxx ~/xxx/xxx_compile.workspace        \
        $(MAKE) -f ~/xxx/xxx_compile.workspace.mak $(1)                    \


release:
        $(build )

debug:
        $(build DEBUG=1)

clean:
        $(clean)

install:
        cp ~/xxx/source/xxx_utility/release/xxx_util /usr/local/bin
        cp ~/xxx/source/xxx_utility/release/xxxcore.so /usr/local/lib

Nota: nombres eliminados para proteger a los inocentes

Edición: Versión final fija:

clean = $(MAKE) -f xxx_compile.workspace.mak clean;


build = svn up;                                         \
        $(clean)                                        \
        ./cbp2mak/cbp2mak -C . xxx_compile.workspace;   \
        $(MAKE) -f xxx_compile.workspace.mak    $(1);   \


.PHONY: release debug clean install

release:
        $(call build,)

debug:
        $(call build,DEBUG=1)

clean:
        $(clean)

install:
        cp ./source/xxx_utillity/release/xxx_util /usr/bin
        cp ./dlls/Release/xxxcore.so /usr/lib
¿Fue útil?

Solución

Puede declarar que uno o más de sus objetivos son falso .

  

Un objetivo falso es uno que no es realmente el nombre de un archivo; más bien   es solo un nombre para que una receta se ejecute cuando haces un explícito   solicitud. Hay dos razones para usar un objetivo falso: para evitar un   entrar en conflicto con un archivo del mismo nombre y mejorar el rendimiento.

     

...

     

Un objetivo falso no debe ser un requisito previo de un archivo de destino real; Si   es, su receta se ejecutará cada vez que make vaya a actualizar eso   expediente. Mientras un objetivo falso nunca sea un prerrequisito de un verdadero   objetivo, la receta de destino falso se ejecutará solo cuando el falso   objetivo es un objetivo específico

Otros consejos

El conmutador -B para crear, cuya forma larga es --always-make , le dice a make que ignore las marcas de tiempo y haga las objetivos Esto puede anular el propósito de usar make, pero puede ser lo que necesita.

Un truco que solía estar documentado en un manual de Sun para make es utilizar un objetivo (inexistente) '.FORCE'. Puede hacer esto creando un archivo, force.mk, que contenga:

.FORCE:
$(FORCE_DEPS): .FORCE

Luego, suponiendo que su archivo MAKE existente se llame makefile , puede ejecutar:

make FORCE_DEPS=release -f force.mk -f makefile release

Dado que .FORCE no existe, todo lo que dependa de él estará desactualizado y reconstruido.

Todo esto funcionará con cualquier versión de make ; en Linux, tiene GNU Make y, por lo tanto, puede usar el objetivo .PHONY como se discutió.

También vale la pena considerar por qué make considera que la publicación está actualizada. Esto podría deberse a que tiene un comando touch release entre los comandos ejecutados; podría deberse a que existe un archivo o directorio llamado 'release' que existe y no tiene dependencias, por lo que está actualizado. Luego está la razón real ...

Alguien más sugirió .PHONY que es definitivamente correcto. .PHONY debe usarse para cualquier regla para la cual una comparación de fecha entre la entrada y la salida no sea válida. Como no tiene ningún objetivo con el formato output: input , ¡debe usar .PHONY para TODOS!

Dicho todo esto, probablemente debería definir algunas variables en la parte superior de su archivo MAKE para los diversos nombres de archivo, y definir reglas de creación reales que tengan secciones de entrada y salida para que pueda usar los beneficios de make, es decir, que ¡En realidad solo compila las cosas que son necesarias para hacer copias!

Editar: ejemplo agregado. Sin probar, pero así es como haces .PHONY

.PHONY: clean    
clean:
    $(clean)

Si recuerdo correctamente, 'make' usa marcas de tiempo (hora de modificación del archivo) para determinar si un objetivo está actualizado o no. Una forma común de forzar una reconstrucción es actualizar esa marca de tiempo, usando el comando 'tocar'. Puede intentar invocar 'touch' en su makefile para actualizar la marca de tiempo de uno de los objetivos (tal vez uno de esos sub-makefiles), lo que podría forzar a Make a ejecutar ese comando.

Esta técnica simple permitirá que el makefile funcione normalmente cuando no se desea forzar. Crea un nuevo objetivo llamado fuerza al final de tu makefile . El objetivo force tocará un archivo del que depende tu objetivo predeterminado. En el siguiente ejemplo, he agregado toque myprogram.cpp . También agregué una llamada recursiva a make . Esto hará que el objetivo predeterminado se realice cada vez que escriba make force .

yourProgram: yourProgram.cpp
       g++ -o yourProgram yourProgram.cpp 

force:
       touch yourProgram.cpp
       make

Probé esto y funcionó para mí

agregue estas líneas a Makefile

clean:
    rm *.o output

new: clean
    $(MAKE)     #use variable $(MAKE) instead of make to get recursive make calls

guardar y ahora llamar

make new 

y recompilará todo de nuevo

¿Qué pasó?

1) 'nuevas' llamadas limpias. 'clean' do 'rm' que elimina todos los archivos de objetos que tienen la extensión de '.o'.

2) 'nuevas' llamadas 'make'. 'make' ve que no hay archivos '.o', por lo que crea todos los '.o' nuevamente. entonces el vinculador vincula todo el archivo .o en una salida ejecutable

Buena suerte

De acuerdo con Miller Recursivo hacer que se considere perjudicial debe evitar llamar a $ (HACER) ! En el caso que muestres, es inofensivo, porque esto no es realmente un makefile, solo un script de envoltura, que podría haber sido escrito en Shell. Pero dices que continúas así en niveles de recursión más profundos, por lo que probablemente te encuentres con los problemas que se muestran en ese ensayo revelador.

Por supuesto, con GNU es difícil evitarlo. Y a pesar de que son conscientes de este problema, es su forma documentada de hacer las cosas.

OTOH, makepp fue creado como una solución para este problema . Puede escribir sus makefiles en un nivel por directorio, sin embargo, todos se agrupan en una vista completa de su proyecto.

Pero los archivos make anteriores son escritos recursivamente. Así que hay una solución alternativa donde $ (MAKE) no hace nada más que canalizar las solicitudes secundarias al proceso de makepp principal. Solo si haces cosas redundantes o, lo que es peor, contradictorias entre tus submakes, debes solicitar --traditional-recursive-make (que por supuesto rompe esta ventaja de makepp). No conozco tus otros makefiles, pero si están bien escritos, las reconstrucciones necesarias de makepp deberían suceder automáticamente, sin la necesidad de ningún truco sugerido por otros.

Si no necesita conservar ninguna de las salidas que ya compiló correctamente

nmake /A 

reconstruye todo

En realidad depende de cuál es el objetivo. Si es un objetivo falso (es decir, el objetivo NO está relacionado con un archivo), debe declararlo como .PHONY.

Sin embargo, si el objetivo no es un objetivo falso pero solo quieres reconstruirlo por algún motivo (un ejemplo es cuando usas la macro de preprocesamiento __TIME__), debes usar el esquema FORCE que se describe en las respuestas aquí.

Ya se mencionó, pero pensé que podría agregar al uso de touch

Si touch todos los archivos fuente que se van a compilar, el comando touch cambia las marcas de tiempo de un archivo a la hora del sistema al touch El comando fue ejecutado.

La marca de tiempo del archivo fuente es lo que make utiliza para " saber " un archivo ha cambiado y debe volver a compilarse

Por ejemplo: si el proyecto era un proyecto c ++, entonces toque * .cpp , luego ejecute make nuevamente, y make debería recompilar todo el proyecto.

make clean elimina todos los archivos de objetos ya compilados.

En mi sistema Linux (Centos 6.2), hay una diferencia significativa entre declarar el objetivo .PHONY y crear una dependencia falsa en FORCE, cuando la regla realmente crea un archivo que coincide con el objetivo. Cuando el archivo debe ser regenerado cada vez, se requieren ambos la FUERZA de dependencia falsa en el archivo, y .PHONY para la dependencia falsa.

mal:

date > $@

derecha:

FORCE
    date > $@
FORCE:
    .PHONY: FORCE
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top