views:

349

answers:

3

I have a CPP source file that uses #if / #endif to compile out completely in certain builds. However, this generates the following warning.

warning LNK4221: no public symbols found; archive member will be inaccessible

I was thinking about creating a macro to generate a dummy variable or function that wouldn't actually be used so this error would go away but I want to make sure that it doesn't cause problems such as using the macro in multiple files causing the linker to bomb on multiply defined symbols.

What is the best way to get rid of this warning (without simply suppressing the warning on the linker command line) ?

FWIW, I would be interested in knowing how to do it by suppressing the warning on the linker command line as well but all my attempts there appear to be simply ignored by the linker and still generate the error.

One other requirement: The fix must be able to stand up to individual file builds or unity build (combine CPP file builds) since one of our build configurations is a bulk build (like a unity build but groups of bulk files rather than a single master unity file).

+3  A: 

Use an anonymous namespace:

namespace { char dummy; };

Symbols within such namespace have external linkage, so there will be something in the export table. On the other hand, the namespace name itself will be distinct (you can think of it as "randomly generated") for every translation unit, so no clashes.

Pavel Minaev
I'm going to test that out. I need it to work with unity builds so I might have to make it a macro with "char dummy##__LINE__;" or something like that so I don't have replicated symbols within a single translation unit.
Adisak
Well I don't think you'd need more than one per unit.
GMan
The fix here bombs on our unity build as expected, but it should work with the minor mod I described.
Adisak
@GMan: Our translation units vary whether or not we do a bulk build (similar to unity build). You need to put this in each unit that could be empty. However, the bulk builds will dynamically bind units at compilation time.
Adisak
@Adisak, I'm still curious as to why it "bombs out", and why adding `__LINE__` changes that. Can you explain in some more detail?
Pavel Minaev
I think that his "unity build" cats all the cpp files together and compiles them as a single translation unit. Hence `(anonymous)::dummy` is the same symbol in each and the compiler would complain about multiple definitions. His fix is to instead distinguish the `dummy` objects with `__LINE__`.
Steve Jessop
Ah, understood now. Okay; unfortunately, `extern char` won't help, since it's not really a definition, but effectively a forward declaration for a variable (which may, and indeed usually is, in another translation unit). It won't result in an entry in the exported symbols table.
Pavel Minaev
@Steve: That's exactly right...except instead of cat, it generates a temp CPP file and #includes the other CPP files into it. But the result is fundamentally the same... so +1.
Adisak
@Pavel: yep, I realised that too. I must have replaced my comment as you were typing.
Steve Jessop
+1  A: 

OK, the fix I am going to use is Pavel's suggestion with a minor tweak. The reason I’m using this fix is it’s an easy macro to drop in and it will work in bulk-builds / unity-builds as well as normal builds:

Shared Header:

// The following macro "NoEmptyFile()" can be put into a file
// in order suppress the MS Visual C++ Linker warning 4221
//
// warning LNK4221: no public symbols found; archive member will be inaccessible
//
// This warning occurs on PC and XBOX when a file compiles out completely
// has no externally visible symbols which may be dependant on configuration
// #defines and options.

#define NoEmptyFile()   namespace { char NoEmptyFileDummy##__LINE__; }

File that may compile out completely:

NoEmptyFile()
#if DEBUG_OPTION
      // code
#endif // DEBUG_OPTION
Adisak
A: 

Here is one way:

#pragma warning (disable : 4221)

=)

Inverse
As noted in the comments in my question, this does not work. Mainly because this suppresses warning 4221 for the compiler but the warning occurs during the linker phase so this has no effect on eliminating the warning :-(
Adisak