10

When I compile my iPhone app, xCode gives "duplicate symbol" error for my variables in MyConstants.h

I thought if I used:

#import "MyConstants.h"

it would avoid that?

But I still have the problem.

Added info:

  • The error occurs during "linking". (I'm just using xCode's "Build and Go" button.)

  • I also tried the (unnecessary with #import) #ifndef/def method, too.

    Maybe I should just ask this:

    If you needed to access a constant in EVERY part of ALL your source code files... what would you put in your .h file? What would you use to include that constant in other parts of your code.

    I thought (but I guess it's not) it was simple as:

  • MyConstants.h> int thisIsGlobal = 123;

    (No where am I re-defining thisIsGlobal anywhere in any code.)

    And then just "#import MyConstants.h" at the top of each of my other source files.

  • Susanna
    • 771
    • 3
    • 10
    • 17
    • how that constant is defined? – Vladimir May 02 '10 at 17:20
    • Does the error occur at compile or at link time? Might there be different definitions (in different headers) naming the same symbol. Say, an `extern int foo;` in header A and a `NSString* foo();` in header B? – Dirk May 02 '10 at 17:35

    5 Answers5

    20

    What you can do is put in your header (MyConstants.h):

    extern const int MyConstant;
    extern NSString * const MyStringConstant;
    

    And in a source file, include the header above but define the constants (MyConstants.m):

    const int MyConstant = 123;
    NSString * const MyStringConstant = @"SomeString";
    

    Then, you simply need to include the header in any other source file that uses either of these constants. The header is simply declaring that these constants exist somewhere, so the compiler won't complain, because it's the linker's job to resolve these constant names. The source file that contains your constant definitions gets compiled, and the linker sees that this is where the constants are, and resolves all of the references found in the other source files.

    The problem with declaring and defining a constant in a header (that is not declared as static) is that the compiler treats it as an independent global for each file that includes that header. When the linker tries to link all of your compiled sources together it encounters the global name as many times as you have included MyConstants.h.

    dreamlax
    • 93,976
    • 29
    • 161
    • 209
    • I used your example but the linker gives this error: Undefined symbols: "_abc", referenced from: _abc$non_lazy_ptr in FirstView.o ld: symbol(s) not found collect2: ld returned 1 exit status – Susanna May 11 '10 at 02:23
    • @Kimberly: Are you sure that the file containing the definitions of your constants (i.e. `MyConstants.m`) is being compiled and linked? – dreamlax May 11 '10 at 02:50
    • I have absolutely NO idea if the file is being compiled and linked. How would I tell? I just hit BUILD AND GO in xcode. Always compiles fine... but never when I try my MyConstants.h include. – Susanna May 12 '10 at 00:24
    • @Kimberly: Look at the build results (i.e. go to the Build menu and click Build Results, and make sure it is set to display All Messages (instead of Issues Only, the default). To make sure `MyConstants.m` is being built, right click on it (or Ctrl+Click for one-button mouse), and click "Get Info". Then, at the top, click on "Targets", and then make sure that the target you're working on is checked. – dreamlax May 12 '10 at 00:50
    • Thanks! But remember that since applying this fix only touches the .h file, this doesn't automatically recompile the respective class. I ended up deleting the derived data in order for this to work. Cleaning should be enough though. – user3099609 Jun 22 '15 at 15:46
    8

    Two options:

    static const int thisIsGlobal = 123;
    

    or

    #define thisIsGlobal 123
    
    Stephen Canon
    • 103,815
    • 19
    • 183
    • 269
    5

    I use like this, and works: (in a .h outside @interface)

    static NSString * const mkLocaleIdentifierUS = @"en_US";
    static NSString * const mkLocaleUserSystemSettings = nil;
    
    Everton Cunha
    • 1,017
    • 8
    • 10
    3

    This is because the symbol name in question (thisIsGlobal) is being emitted into every object file created, where the header containing the declaration for thisIsGlobal is included and visible.

    The examples provided by another poster: 'extern const int MyConstant;' is the best way, unless you need the value to be visible, in which case you can use an enum:

    int thisIsGlobal = 123; // bad

    enum { thisIsGlobal = 123 }; // ok

    using static will emit a lot of hidden symbols in a large program -- don't use it. Using a define is scary as well (considering there are safer alternatives available, why not use them?).

    Community
    • 1
    • 1
    justin
    • 104,054
    • 14
    • 179
    • 226
    • > 'extern const int MyConstant;' is the best way, unless you need the value to be visible Why would anyone *NOT* want a global var to ever be visible? – Susanna May 12 '10 at 00:28
    • @Fran There are many reasons to define it such that it is not visible to clients or translations. Private implementation and compilation times are the most common reasons. One int won't grossly impact compilation times, but it would affect compilation times for more complex types (i.e. larger C++ objects), or if the (visible) definition is early in a large interface/package -- then changing the value would require all clients to recompile all dependencies including the declaration - critical for large projects. As well, there are many good reasons to define privately. – justin May 14 '10 at 06:18
    2

    I usually put my application constants file in the Xcode project's MyApplication_Prefix.pch file, usually located within the Other Sources group. Any header file included in this pch file will be included from all files in your project.

    After adding this include statement, you would then no longer need to include your MyConstants.h file from every file in your project — it will be included automatically.

    Alex Reynolds
    • 95,983
    • 54
    • 240
    • 345