2010-08-03 6 views
5

Ho un progetto il cui makefile usa funzionalità esclusive di GNU Make. Purtroppo, ci sono piattaforme che dobbiamo supportare dove GNU make non è ancora il default quando si esegue make.Rilevamento (non-) GNU Make quando qualcuno esegue `make`

Uno dei miei colleghi è stato morso da questo, quando un'implementazione non-GNU ha silenziosamente fallito la creazione del nostro codice correttamente (ha espanso una variabile automatica in una stringa vuota). Voglio evitare che ciò accada di nuovo, generando invece un messaggio di errore esplicito.

Cosa posso scrivere in un Makefile per distinguere la marca GNU dalla marca non GNU, stampare un errore chiaro e uscire?

Ho già capito una soluzione a rinominare il mio vero makefile per GNUmakefile, e mettendo un piccolo stub in Makefile, ma preferirei qualcosa di più diretto.

Le risposte da Beta e Dan Moulding guardare veramente bello e semplice, ma su AIX 6.1, l'attuazione make non possono gestire una di esse:

$ cat testmake 

foo: 
     touch foo 

ifeq ($(shell $(MAKE) -v | grep GNU),) 
$(error this is not GNU Make) 
endif 

ifeq "${MAKE_VERSION}" "" 
$(info GNU Make not detected) 
$(error ${MIN_MAKE_VER_MSG}) 
endif 


$ /usr/bin/make -f testmake 
"testmake", line 5: make: 1254-055 Dependency line needs colon or double colon operator. 
"testmake", line 6: make: 1254-055 Dependency line needs colon or double colon operator. 
"testmake", line 7: make: 1254-055 Dependency line needs colon or double colon operator. 
"testmake", line 8: make: 1254-055 Dependency line needs colon or double colon operator. 
"testmake", line 11: make: 1254-055 Dependency line needs colon or double colon operator. 
"testmake", line 12: make: 1254-055 Dependency line needs colon or double colon operator. 
"testmake", line 13: make: 1254-055 Dependency line needs colon or double colon operator. 
make: 1254-058 Fatal errors encountered -- cannot continue. 

mi imbatto in problemi simili su entrambi i arcaico e moderno versioni (Solaris 8 & 10) di marca Sun. Quello è meno critico, ma sarebbe bello da gestire.

+0

Quale versione di GNU è in esecuzione? – bta

+0

Sei corretto. L'approccio che avevo preso si basava troppo su GNUisms, quindi potrebbe non funzionare * affatto * con implementazioni non-GNU di make. Ora dubito che ci sia un modo portatile per raggiungere il tuo obiettivo usando solo un Makefile (cioè senza ricorrere a uno script di shell o ad altre risorse esterne). Ho annullato la mia risposta. –

risposta

2

Non conosco alcuna funzionalità interna che sia assolutamente unica per GNUMake, ma qui c'è un kludge: chiama "make -v" e analizza l'output per "GNU" (poiché sembra improbabile che un make non GNU avrebbe MAKE insieme ad un GNU Make):

ifeq ($(shell $(MAKE) -v | grep GNU),) 
$(error this is not GNU Make) 
endif 

EDIT:
come Dan Dare la forma, sto iniziando a vedere la dimensione reale di questo problema. Come scritto, richiede un Makefile sintatticamente corretto in tutte le versioni di Make. Non ho accesso a Sun Make (e non riesco a trovare manuali per questo), quindi non so se questo è possibile, o come scriverlo se lo è, o come testarlo se lo facessi.

Ma posso suggerire un approccio che potrebbe funzionare. Forse qualcosa di simile può essere reso universale:

default: 
    ./runGNUMake.pl 

Ecco, questo è tutto il makefile. Quindi scrivi lo script runGNUMake in Perl (o bash, o qualunque cosa ti piaccia) che farà qualcosa come il mio "make -v" kludge e poi stamperà il messaggio di errore o eseguirà "make -f realMakefile".

+0

Avevo pensato di farlo in uno script esterno che era già in esecuzione, ma non avevo pensato di inserirlo nel makefile stesso. – Novelocrat

+0

Non funziona su AIX 6.1 :-( – Novelocrat

+0

Novelocrat: in realtà? Come fa a mancare, un Make non GNU ha un 'MAKE' che sembra essere impostato su un Make di GNU, oppure fa apparire un Make di GNU non-GNU? (Suppongo che potremmo chiamare rispettivamente "falso positivo" e "falso negativo") – Beta

6

Come osservato, GNU make i controlli per GNUmakefile prima makefile o Makefile, ho usato una correzione banale, come lei ha descritto, un default (decoy) Makefile che causa un errore/avviso:

default: 
    @echo "This requires GNU make, run gmake instead" 
    exit 70 

Il GNU make documentation consiglia di utilizzare il nome GNUmakefile quando lo Makefile è specifico per GNU, quindi questa è la mia soluzione preferita.

Sulle piattaforme in cui il codice nativo make preferisce un diverso nome Makefile, è possibile eseguire una variazione su questo, ad es.su FreeBSD ho l'esca sopra nel BSDmakefile che viene usato in preferenza su Makefile (impedendo così al sistema make di manomettere la mia build). AFAICT AIX o Solaris make non hanno un nome alternativo che è possibile utilizzare in questo modo.

Un problema con un wrapper Makefile che tenta di chiamare GNU make sta passando tutti gli argomenti.

un test apparentemente portatile (finora, ho trovato a lavorare su un mix di antico OSF1, BSD e Solaris) è possibile utilizzare SOMETHING=$(shell ...) per rilevare se GNU make è in esecuzione, le versioni non saranno GNU non impostare SOMETHING . A causa di deferred evaluation of variables, non è possibile utilizzare questo come facilmente come previsto. Questo si basa sull'implementazione che gestisce silenziosamente i nomi delle macro con spazi espansi con $() (ad esempio, tratta $(shell foo) come nome variabile/macro anziché function, anche se un'assegnazione a tale nome in quell'implementazione causerebbe un errore).

L'unico modo portatile è possibile stampare un evidente errore di è quello di avere un obiettivo fittizio che viene sempre eseguito, utilizzando il trucco di cui sopra:

GNUMAKE=$(shell echo GNUMAKE) 

default: gnumake all 

gnumake: 
     @[ "$(GNUMAKE)" = "GNUMAKE" ] || { echo GNU make required ; exit 70; } 

Questo presuppone di avere un POSIX sh shell.

(ho visto le prove che ispezionano $(MAKE) -v falliscono quando entrambi sistema e GNU fanno sono chiamati "make", il sistema make cospira contro di voi e invoca GNU make ... Avreste bisogno di un po 'di attenzione la verifica delle variabili d'ambiente PATH, MAKE ed eventualmente SHELL per gestire ogni caso.)