2010-02-24 10 views
6

Sto vivendo un problema estremamente strano in una nuova installazione di OSX 10.4.11 + Xcode 2.5. L'ho ridotto ad un caso di test minimale. Ecco test.cpp:g ++ fallisce misteriosamente solo se un file .h si trova in una determinata directory

#include "macros.h" 

int main (void) 
{ 
    return 1; 
} 

Ed ecco macros.h:

#ifndef __JUST_TESTING__ 
#define __JUST_TESTING__ 

template<typename T> void swap (T& pT1, T& pT2) 
{ 
    T pTmp = pT1; 
    pT1 = pT2; 
    pT2 = pTmp; 
} 

#endif //__JUST_TESTING__ 

Questo compila e funziona bene se entrambi i file sono nella stessa directory. TUTTAVIA, se metto macros.h in/usr/include/gfc2 (è parte di una libreria personalizzata che uso io) e cambiare il # include nel test.cpp, la compilazione non riesce con questo errore:

/usr/include/gfc2/macros.h:4: error: template with C linkage 

ho ricercato quell'errore e la maggior parte dei commenti indicano una "C esterna penzolante", che non sembra affatto il caso.

Sono a perdita completa qui. È g ++ per qualche ragione supponendo che tutto in /usr/include/gfc2 sia C anche se è incluso da un file .cpp che non dice extern "C" da nessuna parte?

Qualche idea?

EDIT: Non compilare se uso il percorso completo nella #include, vale a dire #include "/usr/include/gfc2/macros.h"

EDIT2: Non è inclusa l'intestazione sbagliata. Ho verificato questo utilizzando cpp, g++ -E, e la ridenominazione macros.h a foobarmacros.h

+0

Questo è un totale, senza speranza, disinformato da un milione di anni fa al buio, ma provare a rimuovere la "c" dal nome della directory. :) – datageist

+0

Prova a pubblicare i risultati di "set | grep -i include" qui. –

+0

@datageist - Grazie, ma non ha fatto la differenza. Stranamente, si compila se io includo il suo percorso completo. Hmmm ... – ggambett

risposta

7

G ++ potrebbe effettivamente essere supponendo che tutto in/usr/include è C. provare a compilare il codice con -E e studiare i marcatori di linea nell'output preprocessore:

g++ -E test.cpp | grep '^#' 

è probabile che tu vedi cose come

# 1 "/usr/include/gfc2/macros.h" 1 3 4 

il 4 è il preprocessore alludendo a G ++ che dovrebbe avvolgere tutto in extern "C", sulla supposizione che gli antichi file header della vostra piattaforma in/usr/include anteriori C++. Vedere Preprocessor Output nel manuale CPP.

In questi giorni G ++ ignora questo suggerimento, perché la maggior parte delle intestazioni C della piattaforma non è più antica. Vedere la macro target NO_IMPLICIT_EXTERN_C nel manuale GCC Internals. Ma può darsi che questa vecchia versione di Xcode abbia GCC configurato senza NO_IMPLICIT_EXTERN_C e quindi è ascoltando il suggerimento del preprocessore. (Questo è impostato quando GCC stesso è costruito - Non penso che ci sia un interruttore della riga di comando per sovrascriverlo.)

Potrebbe essere possibile aggirare il problema avvolgendo il contenuto del file di intestazione in extern "C++".

+0

Per coincidenza avevo appena trovato questo thread, che dice essenzialmente lo stesso che dici: http://www.pixelglow.com/lists/archive/macstl-dev/2005-February/000015.html Quindi sembra che sia un compilatore " caratteristica "dopotutto. È un sollievo, anche se stavo impazzendo! – ggambett

+0

Vedere anche http://www.cocoabuilder.com/archive/xcode/247374-headers-in-usr-include.html#247468 – ggambett

+0

http://www.cocoabuilder.com/archive/xcode/247374- intestazioni- il collegamento in-usr-include.html è interessante: ha avuto successo con "extern" C++ "' (ed è davvero standard: vedi 7.5/3); e quando ha commentato tutti i riferimenti a "# XX", ciò che stava realmente facendo stava cancellando tutti gli "4" suggerimenti del preprocessore. Questa è effettivamente una funzione * utile * quando si esegue il porting di GCC su una piattaforma di un fornitore privo di errori con intestazioni solo C spezzate. Sì, parlo per l'amara esperienza! Tuttavia la vera risposta è quella di correggere le intestazioni di sistema e attivare 'NO_IMPLICIT_EXTERN_C', come sembra che Apple abbia fatto da allora. –

0

Beh, sembra davvero strano ...

Come si chiama XCode g ++? Non penso che g ++ decida spontaneamente che un file include ha il collegamento C solo perché si trova in una directory diversa. Hai provato a compilare il tuo progetto a mano? Prova "g ++ main.cpp -I/usr/include/gfc2 /". Se questo risolve il tuo problema, allora non è g ++. Forse XCode precompila le intestazioni?

+0

In effetti sto usando il compilatore della riga di comando, più precisamente g ++ -o test test.cpp – ggambett

+0

Hai provato a rinominare "macros.h" in "macros.hpp"? – neverlord

+0

sì. Stesso errore :( – ggambett

0

non avete provato a cambiare il file test.cpp a tutti, ma invece quando si compila anche dire:

-I/usr/include/gfc2/ 
+0

Grazie!Funziona, ma lo inserisco nella categoria "workaround". Piuttosto risolvo la causa principale, dal momento che questo codice esatto ha funzionato per sempre su Linux, Mac e Windows, quindi sono abbastanza sicuro che sia un problema con questa particolare installazione. – ggambett

+0

(Per completezza,) Il motivo per cui questo funziona è che l'intestazione proviene ora dalla normale directory denominata in questa opzione, piuttosto che dallo speciale built-in '/ usr/include'. Dato che l'intestazione non proviene da una directory speciale, il preprocessore non mette i flag '4' sui suoi marcatori di riga, quindi G ++ non è tentato di inserirlo in" extern "C" '. (Vedi la mia risposta sopra per una spiegazione di queste bandiere) –

1

questo v'è un salto nel buio, ma è un altro file chiamato macros.h da qualche parte sotto /usr/include o nella tua installazione GCC? GCC ha una funzionalità per il wrapping delle intestazioni, chiamato #include_next, che potrebbe essere la causa del tuo problema.

Una cosa che puoi fare per disambiguare il tuo macros.h da qualsiasi altro macros.h nel percorso di inclusione è includerlo come gfc2/macros.h. In questo modo, il compilatore cercherà tutte le directory nel percorso di inclusione per una sottodirectory denominata gfc2 contenente un file denominato macros.h, riducendo la possibilità di una collisione. Inoltre, impedisce di dover aggiungere /usr/include/gfc2 al percorso di inclusione.

BTW, #include "file.h" cerca prima la directory corrente. Per saltare questo e andare dritto al percorso di inclusione, utilizzare #include <file.h>:

#include <stdio.h> 
#include <gfc2/macros.h> 

Un altro approccio è quello di scegliere un nome di file che è più probabile che sia unico, come gfc2macros.h.

+0

Ho pensato anche a questo, ma l'output di cpp conferma che g ++ sta prelevando le macro corrette.h (oltre al fatto che il messaggio di errore contiene il percorso completo del mio file). Non ci sono altri macros.h in/usr/include. – ggambett

+0

Hai eseguito 'cpp' o hai eseguito' g ++ -E'? g ++ potrebbe aggiungere directory al percorso di inclusione predefinito, quindi il risultato potrebbe non essere lo stesso. – bk1e

0

Si può vedere dove g ++ è alla ricerca di include con il flag verbose:

g++ -v -o test test.cpp 

e questo basta eseguire il preprocessore e mostrare ciò che è effettivamente incluso nel file e compilato:

g++ -E test.cpp | less 

Se i file errati vengono inclusi (o l'intestazione viene incapsulata in un'altra, come suggerisce bk1e) sarete in grado di scoprire con quell'output.

+0

Non sapevo -E. In questo caso l'output di g ++ -E è lo stesso di cpp. – ggambett

0

Mi sono appena imbattuto in questo problema anche durante la compilazione di un progetto C++ che normalmente creiamo su 10.5 e 10.6 (Xcode 3.0+) su una macchina PPC 10.4 con Xcode 2.5 installato. Sembra che il preprocessore tratti qualsiasi cosa aggiunta al percorso di inclusione di gcc con "-isystem" come se fosse "extern C". La modifica di "-isystem" in "-I" ha risolto il problema.

Problemi correlati