c++xcode4.6duplicate-symbol

Random duplicate symbols in xcode (C++)


I am trying to build a C++ project in Xcode 4.6.3.

In my project (the beginnings of a very simple OpenGL game) I have two files:

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");
}

Here util.h defines the util::loadTexture function.

There are two files that include textures.h. The first (main.cpp) calls the load() function as part of initialization and accesses the dirt variable to bind the Soil.png texture. The second (Chunk.cpp) includes textures.h, but doesn't actually access anything from it yet.

When I try to build the project, it gives me the following error:

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)

I understand that this means there is a duplicate somewhere, or a header is included multiple times. But all of my headers use #pragma once, and I have done search in workspace for "dirt" and such, and there are no other definitions. My other headers work fine, even the ones that are included multiple times. I have googled this problem many times with different keywords, and have taken a look at other similar questions, but all I found was this SO question.

I have encountered other "random" errors before in Xcode - for example, one project kept trying to use a dynamic library that I had deleted and replaced with a static one. The error stayed, even when I created a brand new project. It worked when compiled manually from Terminal.

What am I missing?


Solution

  • #pragma once does not stop a header file being included multiple times.

    It stops a header file being included multiple times when compiling a single file. You have (at least) three files so you are declaring the same variables 3 times.

    Don't put variable definitions in a header file. Do this instead

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

    You can have as many declarations of a variable as you want (provided they are all identical), so it's OK to put declarations in a header file, you must have exactly one variable definition, so you put that in a .cpp file.

    The key to remember is that every .cpp file is compiled completely independently of every other .cpp file, this is called separate compilation. So your idea that #pragma once would stop a header file from being included by one .cpp file just because it had been included in another .cpp file just doesn't work. You're not the first to misunderstand this.