• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
tanzanite7

(VC++) How to prevent linker throwing away globals it fails to see being used?

10 posts in this topic

Distilled example case:
 

template<class T> class Test {
    static __declspec(allocate(".xyz")) int snafu;
};

template<class T> int Test<T>::snafu = 42;

Everything in ".xyz" section is actually used - indirectly. Is there any way to prevent the linker from removing "snafu"? Did i miss something?

Note 1: I auto generate bullshit access functions for them and prevent linkers eagerness that way - so, no standing problem. My question is towards: is there something i have missed and i can just tell it (VS toolchain via source code) to not mess with certain globals? Not expecting there to be, but it does not hurt to ask.

Note 2: The whole point of doing what the example code is related to is to see where i can get with it - so, sidestepping the problem as shown is completely nonsensical. Please do not.

 

edit update:

Blaming linker was premature - this case has more todo with funky template behavior. Short: if you instantiate a template then its static variables are only instantiated when you have reachable references to it. Instantiation won't happen even when the constructor of the variable has visible side effects elsewhere.

Edited by tanzanite7
0

Share this post


Link to post
Share on other sites

I think you'd have to use /INCLUDE:<mangled name of your variable>. Or just use the variable. You can use a descriptively named macro (FORCE_LINKER_INCLUDE or something), or a function registered with atexit to use the variables.

 

If you want to force all unused references (not just select variables) to be included, you'd use /OPT:NOREF

Edited by richardurich
0

Share this post


Link to post
Share on other sites
Interesting. I can imagine a few possible reasons for it to be removed.

A template is not necessarily generated or expanded. It is like a cookie cutter with a specific shape, and it is used to shape cookies on demand. If there is no demand for a specific cookie shape the compiler might not generate anything.

Second, even if it does generate the right cookie, the optimizer and linker might decide the cookie isn't used and throw it away.

There might be a few more, but those are the two biggest that spring to mind with that code.


Your declaration of snafu is incomplete; it is cookie cutter and not a shaped cookie. You need to actually define and specialize an object by filling in the type: template<> int Test<YourTypeHere>::snafu = 42; I'm pretty sure (but not 100% certain on the case of a static data member) that would generate the symbol inside a source file.

For the second case, you can prevent the linker from removing a symbol (assuming it exists) by forcing a symbol reference so it doesn't get optimized away at that level. In the ide for the project options look up Linker / Input / Force Symbol References for that.
0

Share this post


Link to post
Share on other sites

You can use a descriptively named macro (FORCE_LINKER_INCLUDE or something)

That is pretty much exactly what i do currently.
 

A template is not necessarily generated or expanded.

Yeah, template is the worst case (i have to use FORCE_LINKER_INCLUDE kind of thing per specialization). Even when a static variable does have construction side effects etc - it won't be instantiated when not referenced.

Speaking of which, my OP is a bit misleading as with the example case i am pretty sure the linker never gets to even see it (did not realize that at the time).

Yeah, specialization of the member variable would almost surely help, but is essentially no different from the specializing FORCE_LINKER_INCLUDE macro. Except that the macro is guaranteed to work, whereas the specialization way could still be eaten by the linker.

... hm. Legally speaking: if i reference something in template that has side effects then the compiler should not be allowed to dump it afterwards even if the code that was the initial cause of reference will be completely optimized out.

... have to test that after dinner. Would rid me of specialized macros - not sure if the compiler is allowed to act differently.

edit: Do-nothing reference to static member variable that has side effects (*) does work. The variable will not be optimized out (Release build) nor dropped by linker. If the variable does not have side effects then it does get removed even with the do-nothing reference.

(*) side effect being: Touching/using the variable i actually care about, "snafu" in this case. Hence preventing it from disappearing.

... still, it is slightly better than using specializing macros. Annoyance being: i have to drop the do-nothing-reference into some used function of the template. Can not think of any way around that - yet. Edited by tanzanite7
0

Share this post


Link to post
Share on other sites

I think what frob means is that unless you instatiate the template with a concrete type, it won't actually exist anywhere. Test<T>::snafu doesn't actually exist as an entity. If you create a Test<int> then Test<int>::snafu then exists but the template itself creates nothing, including static members.

1

Share this post


Link to post
Share on other sites

I think what frob means is that unless you instatiate the template with a concrete type, it won't actually exist anywhere. Test<T>::snafu doesn't actually exist as an entity. If you create a Test<int> then Test<int>::snafu then exists but the template itself creates nothing, including static members.

That is it exactly.

A template allows the compiler to do something if it needs to. It does not by itself do anything. A template is not an instance, but instead is a pattern that can be used to make instances.

You essentially have a declaration, a statement that a template instance following that pattern can potentially have that value exist somewhere. Such a declaration still needs a definition, an actually defined thing that is code and data.
0

Share this post


Link to post
Share on other sites

OT: does anyone know a workaround for the forum software bug where the formatting toolbar wont show up. Currently it went poof again - can not do any formatting.

 

I think what frob means is that unless you instatiate the template with a concrete type, it won't actually exist anywhere. Test<T>::snafu doesn't actually exist as an entity. If you create a Test<int> then Test<int>::snafu then exists but the template itself creates nothing, including static members.

 

Erm, that much is obvious. I of course do instantiate the Test class with various stuff - the problem is that if the "snafu" is not used in any code path then it wont be created with the rest of the instantiation.

 

Ie.

template<class T> class Test {
    static __declspec(allocate(".xyz")) int snafu1;
    static __declspec(allocate(".xyz")) int snafu2;
public:
    static void doSomething() { ... something with side effects ... _also accessing "snafu2"_ ... }
};

template<class T> int Test<T>::snafu1 = 42;
template<class T> int Test<T>::snafu2 = 42;
 
int main() {
    Test<int>::doSomething();
}

=> "Test<int>::snafu1" does not exist, whereas "Test<int>::snafu2" does exist!

Also worth noting: whether the constructor of "snafu" has visible side effects (ex: writing stuff to logging file) or not will not change anything - which is quite bizarre.

 

I would have expected that both would exist, but that is not the case.

 

(What does the standard say? Looks bonkers. There are no substitution problems - why is it allowed to be ignored?)

Edited by tanzanite7
0

Share this post


Link to post
Share on other sites

A more complete example of what i am talking about:

// not sure what headers it needs. OutputDebugStringW seems to need Windows.h
 
#pragma section(".xyz$a")
#pragma section(".xyz$b")
#pragma section(".xyz$c")

int answer = 42;

template<class T> class Test {
    static __declspec(allocate(".xyz$b")) int snafu1;
    static __declspec(allocate(".xyz$b")) int snafu2;
public:
    static void doSomething() { OutputDebugStringW(L"\ndoing something\n"); snafu1 = (answer + snafu1) / 2; }
};

template<class T> int Test<T>::snafu1 = 40;
template<class T> int Test<T>::snafu2 = 43;

__declspec(allocate(".xyz$a")) int section_a;
__declspec(allocate(".xyz$c")) int section_c;
 
int main() {
    Test<int>::doSomething();
    int *at = &section_a;
    if(answer) OutputDebugStringW(L"\n");
    do {
        if(*at == 41) OutputDebugStringW(L"\ngot 41 => snafu1 is present\n");
        if(*at == 43) OutputDebugStringW(L"\ngot 43 => snafu2 is present\n");
        at++;
    } while(at != &section_c);
    return 0;
}

This will result:

"doing something"

"got 41 => snafu1 is present"

 

"snafu2" is not present.

 

edit:

If one changes "snafu1" and "snafu2" to type "Int" a'la:

struct Int {
    int val;
    Int(int _val) : val(_val) { OutputDebugStringW(L"\nImportant stuff happening!\n"); }
    int operator=(int _val) { return val = _val; }
    operator int&() { return val; }
};

then the output will be:

"Important stuff happening!"

"doing something"

"got 41 => snafu1 is present"

 

Just bonkers.

Edited by tanzanite7
0

Share this post


Link to post
Share on other sites

I know the problem you're dealing with, this is tedious to solve (more so when static libraries are involved across multiple platforms smile.png ).
The issue you are seeing is not caused by the linker, but rather by the compiler. You can easily verify that by using dumpbin.exe /SYMBOLS on the object file - snafu2 won't be in there, whereas snafu1 will be. So the linker never even has a chance of seeing the symbol.
 
The problem is that snafu2 is not used directly anywhere in the code you posted. It is never accessed, nor is its address taken. The compiler (unfortunately) doesn't care about the __declspec(allocate()) statements and the fact that you are merging sections, in order to iterate through them later. It will simply never emit the symbol "static int Test<int>::snafu2" into the object file.
 
There is one workaround, however. Tell the compiler you use this symbol by handing it to something he can't see, e.g. a function with external linkage defined in another translation unit, something akin to the following:
 

anyTranslationUnit.cpp:
 
void DummyRegister(int)
{
  // doesn't need to do anything
}

 
and in your code:

template<class T> class Test {
    static __declspec(allocate(".xyz$b")) int snafu1;
    static __declspec(allocate(".xyz$b")) int snafu2;
public:
    static void doSomething() { OutputDebugStringW(L"\ndoing something\n"); snafu1 = (answer + snafu1) / 2; }
    static void Register()
    {
      extern void DummyRegister();
      DummyRegister(snafu1);
      DummyRegister(snafu2); 
    }
};
 

I guess the code you posted is the result of some macro invocations, or other means of automatic code generation. I hope you're able to change the process to also include the dummy-registration process. I fear there's no other way around your issue other than letting the compiler believe you are somehow using those symbols (at least not in MSVC).

 

HTH,

-tiv

0

Share this post


Link to post
Share on other sites

There is one workaround, however. Tell the compiler you use this symbol /.../

 

Yeah, that is what i do. Hoped there to be something to avoid per specialization macros - but there are none. Digged up the relevant part in the specs - for the benefit to whoever comes by in future, here goes:

 

"1. /.../ The implicit instantiation of a class template specialization causes the implicit instantiation of the declarations, but not of the definitions or default arguments, of the class member functions, member classes, static data members and member templates; /.../"

 

"4 A class template specialization is implicitly instantiated if the class type is used in a context that requires a completely-defined object type /.../"

 

"7 The implicit instantiation of a class template does not cause any static data members of that class to be implicitly instantiated."

 

And that is that.

 

So, here ends the research. A bit torn whether it is of any use to me given the problems with templates (no problems anywhere else) - will see.

 

At least now i know where the problems lie.

 

What's the meta-problem behind the problem? There may be a more standard way to achieve your goals without tricking the tools and skirting around the fringes of the spec.

 

See note 2 in OP.
 

edit: made the spec excerpts more concise/relevant.

Edited by tanzanite7
0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0