2013-09-21 19 views
5

Próbuję zbudować projekt C++ w Xcode 4.6.3.Losowe duplikaty symboli w kodzie Xcode (C++)

W moim projekcie (początki to bardzo prosta gra OpenGL) Mam dwa pliki:

textures.h:

#pragma once 

#include <GLUT/GLUT.h> 

void load(); // load textures 

GLuint dirt, water; // variables to store texture handles 

textures.cpp:

#include "textures.h" 

#include "util.h" 

void textures::load() { 
    dirt = util::loadTexture("/Some/Path/Soil.png"); 
    water = util::loadTexture("/Some/Path/Water_fresh.png"); 
} 

Tutaj util.h definiuje funkcję util :: loadTexture.

Istnieją dwa pliki, które zawierają textures.h. Pierwsza (main.cpp) wywołuje funkcję load() jako część inicjalizacji i uzyskuje dostęp do zmiennej brudu, aby powiązać tekst Soil.png. Drugi (Chunk.cpp) zawiera textures.h, ale nie ma jeszcze dostępu do niczego z niego.

Kiedy próbuję zbudować projekt, to daje mi następujący błąd:

duplicate symbol _dirt in: 
    /Users/me/Library/Developer/Xcode/DerivedData/OpenGL_Testing-epporrdukapbwzawfhiwnlztzdns/Build/Intermediates/OpenGL Testing.build/Debug/OpenGL Testing.build/Objects-normal/x86_64/main.o 
    /Users/me/Library/Developer/Xcode/DerivedData/OpenGL_Testing-epporrdukapbwzawfhiwnlztzdns/Build/Intermediates/OpenGL Testing.build/Debug/OpenGL Testing.build/Objects-normal/x86_64/Chunk.o 
duplicate symbol _water in: 
    /Users/me/Library/Developer/Xcode/DerivedData/OpenGL_Testing-epporrdukapbwzawfhiwnlztzdns/Build/Intermediates/OpenGL Testing.build/Debug/OpenGL Testing.build/Objects-normal/x86_64/main.o 
    /Users/me/Library/Developer/Xcode/DerivedData/OpenGL_Testing-epporrdukapbwzawfhiwnlztzdns/Build/Intermediates/OpenGL Testing.build/Debug/OpenGL Testing.build/Objects-normal/x86_64/Chunk.o 
duplicate symbol _dirt in: 
    /Users/me/Library/Developer/Xcode/DerivedData/OpenGL_Testing-epporrdukapbwzawfhiwnlztzdns/Build/Intermediates/OpenGL Testing.build/Debug/OpenGL Testing.build/Objects-normal/x86_64/main.o 
    /Users/me/Library/Developer/Xcode/DerivedData/OpenGL_Testing-epporrdukapbwzawfhiwnlztzdns/Build/Intermediates/OpenGL Testing.build/Debug/OpenGL Testing.build/Objects-normal/x86_64/textures.o 
duplicate symbol _water in: 
    /Users/me/Library/Developer/Xcode/DerivedData/OpenGL_Testing-epporrdukapbwzawfhiwnlztzdns/Build/Intermediates/OpenGL Testing.build/Debug/OpenGL Testing.build/Objects-normal/x86_64/main.o 
    /Users/me/Library/Developer/Xcode/DerivedData/OpenGL_Testing-epporrdukapbwzawfhiwnlztzdns/Build/Intermediates/OpenGL Testing.build/Debug/OpenGL Testing.build/Objects-normal/x86_64/textures.o 
ld: 4 duplicate symbols for architecture x86_64 
clang: error: linker command failed with exit code 1 (use -v to see invocation) 

Rozumiem, że to oznacza, że ​​nie jest duplikatem gdzieś, czy nagłówek jest wliczone wiele razy. Ale wszystkie moje nagłówki używają #pragma once i zrobiłem wyszukiwanie w przestrzeni roboczej dla "brudu" i takie, i nie ma innych definicji. Moje inne nagłówki działają dobrze, nawet te, które są zawarte wiele razy. Często googlowałem ten problem wielokrotnie za pomocą różnych słów kluczowych i przyjrzałem się innym podobnym pytaniom, ale znalazłem tylko this SO question.

Napotkałem inne "losowe" błędy wcześniej w Xcode - na przykład jeden projekt próbował używać biblioteki dynamicznej, którą usunąłem i zastąpiłem statyczną. Błąd pozostał, nawet gdy stworzyłem zupełnie nowy projekt. To działało, gdy kompilowano ręcznie z Terminalu.

Czego mi brakuje?

Odpowiedz

5

#pragma once nie zatrzymuje pliku nagłówkowego dołączanego wiele razy.

Zatrzymuje plik nagłówkowy dołączany wiele razy podczas kompilowania pojedynczego pliku. Masz (przynajmniej) trzy pliki, więc deklarujesz te same zmienne 3 razy.

Nie umieszczaj definicji zmiennych w pliku nagłówkowym. Czy zamiast tego

// textures.h 
extern GLuint dirt, water; // variable declarations 


// textures.cpp 
GLuint dirt, water; // variable definitions 

Można mieć tyle deklaracji zmiennej, jak chcesz (pod warunkiem, że wszystkie są identyczne), więc jest OK, aby umieścić deklaracji w pliku nagłówka, trzeba mieć dokładnie jedną definicji zmiennej, więc umieszczasz to w pliku .cpp.

Kluczem do zapamiętania jest to, że każdy plik .cpp jest kompilowany całkowicie niezależnie od każdego innego pliku .cpp, nazywa się to osobną kompilacją. Tak więc twój pomysł, że #pragma once zatrzyma plik nagłówkowy od dołączenia przez jeden plik .cpp tylko dlatego, że był zawarty w innym pliku .cpp po prostu nie działa. Nie jesteś pierwszy, który źle to zrozumiał.

+0

Próbowałem już zastępować #pragma raz dla #ifndef #define #endif, który początkowo tworzy Xcode, i nadal nie działało ... – qxz

+0

Dobrze #ifndef ...działa dokładnie tak samo jak #pragma raz i nie robi tego, co Twoim zdaniem powinno się robić z tego samego powodu. To, co zamieściłem, nie jest wskazówką, jest to właściwy sposób na użycie zmiennych globalnych. – john

+0

Nie przestawaj używać #pragma raz lub #ifndef ... to tylko rozwiązuje inny problem niż myślisz. – john

Powiązane problemy