Intermediate Tutorial 21 Bonus part cannot build for x86 platform

The Partridge Family were neither partridges nor a family. Discuss.
Post Reply
WilsonHuang
Posts: 44
Joined: February 13th, 2019, 3:23 am

Intermediate Tutorial 21 Bonus part cannot build for x86 platform

Post by WilsonHuang » January 20th, 2020, 3:52 am

I found that chili's Sprite solution cannot build for x86 platform, but x64 is OK.
The error appears at Graphics.h extern template part. It has link error

Code: Select all

Error	LNK2001	
unresolved external symbol 
"public: void __thiscall Graphics::DrawSprite<class SpriteEffect::Copy>(int,int,class Rect_<int>,class Rect_<int> const &,class Surface const &,class SpriteEffect::Copy,float)" (??$DrawSprite@VCopy@SpriteEffect@@@Graphics@@QAEXHHV?$Rect_@H@@ABV1@ABVSurface@@VCopy@SpriteEffect@@M@Z)
Why it has link error for x86 platform? How to solve it?

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Intermediate Tutorial 21 Bonus part cannot build for x86 platform

Post by albinopapa » January 20th, 2020, 9:41 am

If this is after the optimizations he made for std::vector and Debug, it's probably because you or he did not have "All Platforms" chosen in the project properties. I'm also not sure if all optimizations are available for x86, but it's been awhile since he went through and since I've seen it so I don't remember what changes were made to the project properties nor the GraphicsD.cpp and SurfaceD.cpp files.

That being said, Unresolved External usually means that the compiler "can't see/find" a definition of a function or static variable. Not entirely sure why it would work in x64 and not x86 other than what I mentioned above without taking a look at the code. Is this something you followed along with, or is this just a fresh copy without any changes from Github?
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

WilsonHuang
Posts: 44
Joined: February 13th, 2019, 3:23 am

Re: Intermediate Tutorial 21 Bonus part cannot build for x86 platform

Post by WilsonHuang » January 20th, 2020, 1:06 pm

Thanks for reply, the code is I downloaded from GitHub.
I didn't change anything. I just change the build platform from x64 to x86.

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Intermediate Tutorial 21 Bonus part cannot build for x86 platform

Post by albinopapa » January 21st, 2020, 1:15 am

Well, you're right, it does not compile in x86 for some reason. I tried checking the properties and they are relatively the same. The issue seems to be with the order in which files are compiled. What I mean is the GOD_GRAPHICS macro is defined in GraphicsD.cpp. If you have made it this far in the series, then you might remember how headers are compiled in with the source files.

GraphicsD.cpp defines the GOD_GRAPHICS macro then includes Graphics.h

Graphics.h includes some stuff at the top, then the Graphics class declaration and at the bottom, SpriteEffect.h is included then there's a #ifndef GOD_GRAPHICS directive. This says, "if GOD_GRAPHICS is not defined" do the stuff below until the #endif.

Now, what's weird about this is this should create a circular dependency where SpriteEffect.h includes Graphics.h and Graphics.h includes SpriteEffect.h. I'm not sure why this doesn't affect the x64 version, but is affecting the x86 version.

To explain the macro thing a little further, basically this means that the only time that the code:

Code: Select all

extern template
void Graphics::DrawSprite<SpriteEffect::Copy>( int x,int y,RectI srcRect,const RectI& clip,const Surface& s,SpriteEffect::Copy effect );
extern template
void Graphics::DrawSprite<SpriteEffect::Chroma>( int x,int y,RectI srcRect,const RectI& clip,const Surface& s,SpriteEffect::Chroma effect );
extern template
void Graphics::DrawSprite<SpriteEffect::Substitution>( int x,int y,RectI srcRect,const RectI& clip,const Surface& s,SpriteEffect::Substitution effect );
is recognized by the compiler is during the compilation of GraphicsD.cpp. All other files don't have the GOD_GRAPHICS macro defined before including Graphics.h so all other .cpp files won't even see those template extern forward declarations.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

WilsonHuang
Posts: 44
Joined: February 13th, 2019, 3:23 am

Re: Intermediate Tutorial 21 Bonus part cannot build for x86 platform

Post by WilsonHuang » January 21st, 2020, 1:09 pm

albinopapa wrote:
January 21st, 2020, 1:15 am
Well, you're right, it does not compile in x86 for some reason. I tried checking the properties and they are relatively the same. The issue seems to be with the order in which files are compiled. What I mean is the GOD_GRAPHICS macro is defined in GraphicsD.cpp. If you have made it this far in the series, then you might remember how headers are compiled in with the source files.

GraphicsD.cpp defines the GOD_GRAPHICS macro then includes Graphics.h

Graphics.h includes some stuff at the top, then the Graphics class declaration and at the bottom, SpriteEffect.h is included then there's a #ifndef GOD_GRAPHICS directive. This says, "if GOD_GRAPHICS is not defined" do the stuff below until the #endif.

Now, what's weird about this is this should create a circular dependency where SpriteEffect.h includes Graphics.h and Graphics.h includes SpriteEffect.h. I'm not sure why this doesn't affect the x64 version, but is affecting the x86 version.

To explain the macro thing a little further, basically this means that the only time that the code:

Code: Select all

extern template
void Graphics::DrawSprite<SpriteEffect::Copy>( int x,int y,RectI srcRect,const RectI& clip,const Surface& s,SpriteEffect::Copy effect );
extern template
void Graphics::DrawSprite<SpriteEffect::Chroma>( int x,int y,RectI srcRect,const RectI& clip,const Surface& s,SpriteEffect::Chroma effect );
extern template
void Graphics::DrawSprite<SpriteEffect::Substitution>( int x,int y,RectI srcRect,const RectI& clip,const Surface& s,SpriteEffect::Substitution effect );
is recognized by the compiler is during the compilation of GraphicsD.cpp. All other files don't have the GOD_GRAPHICS macro defined before including Graphics.h so all other .cpp files won't even see those template extern forward declarations.
Hi, I don't understand how the "#define" keyword work here. Why other files doesn't have the macro will cause the error.
Does #define have behavior same as #include, just copy and paste the code?

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Intermediate Tutorial 21 Bonus part cannot build for x86 platform

Post by albinopapa » January 21st, 2020, 5:13 pm

If you have something like:
#define NPOO 100

Then yes, but in this case it's just a flag that if defined before Graphics.h allow the template extern lines be shown, otherwise hide the lines of code. Developers use this technique to control compilation for different operating systems for example. #Ifdef _WIN32 or #ifdef __linux__ or something like that, to only compile Windows or Linux libraries. You can also use it to specify portions of code that might be C++ instead of strictly C,

#ifdef __cplusplus
// do C++ things
#else
// do C things
#endif
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

WilsonHuang
Posts: 44
Joined: February 13th, 2019, 3:23 am

Re: Intermediate Tutorial 21 Bonus part cannot build for x86 platform

Post by WilsonHuang » January 22nd, 2020, 1:51 am

albinopapa wrote:
January 21st, 2020, 5:13 pm
If you have something like:
#define NPOO 100

Then yes, but in this case it's just a flag that if defined before Graphics.h allow the template extern lines be shown, otherwise hide the lines of code. Developers use this technique to control compilation for different operating systems for example. #Ifdef _WIN32 or #ifdef __linux__ or something like that, to only compile Windows or Linux libraries. You can also use it to specify portions of code that might be C++ instead of strictly C,

#ifdef __cplusplus
// do C++ things
#else
// do C things
#endif
Thanks, now I know how #define works. So in this case only not define GOD_GRAPHICS macro will execute the extern template part (Game.cpp, Font.cpp ...), and what "extern template" means that we initiate DrawSprite in other place, you don't need to initiate once more, use the existed one. Is that right?
If my understanding is correct, the DrawSprite function is in the Graphics.h why the compiler cannot find it?

Code: Select all

//Graphics.h
class Graphics
{
...
template<typename E>
	void DrawSprite( int x,int y,const Surface& s,E effect )
	{
		DrawSprite( x,y,s.GetRect(),s,effect );
	}
	template<typename E>
	void DrawSprite( int x,int y,const RectI& srcRect,const Surface& s,E effect )
	{
		DrawSprite( x,y,srcRect,GetScreenRect(),s,effect );
	}
...

#include "SpriteEffect.h"

#ifndef GOD_GRAPHICS
extern template
void Graphics::DrawSprite<SpriteEffect::Copy>( int x,int y,RectI srcRect,const RectI& clip,const Surface& s,SpriteEffect::Copy effect );
extern template
void Graphics::DrawSprite<SpriteEffect::Chroma>( int x,int y,RectI srcRect,const RectI& clip,const Surface& s,SpriteEffect::Chroma effect );
extern template
void Graphics::DrawSprite<SpriteEffect::Substitution>( int x,int y,RectI srcRect,const RectI& clip,const Surface& s,SpriteEffect::Substitution effect );
#endif
}

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Intermediate Tutorial 21 Bonus part cannot build for x86 platform

Post by albinopapa » January 22nd, 2020, 4:08 am

and what "extern template" means that we initiate DrawSprite in other place, you don't need to initiate once more, use the existed one. Is that right?
Yep, it tells the compiler that the specialized template definition is somewhere else and to use it instead of instantiating a new version.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

User avatar
chili
Site Admin
Posts: 3948
Joined: December 31st, 2011, 4:53 pm
Location: Japan
Contact:

Re: Intermediate Tutorial 21 Bonus part cannot build for x86 platform

Post by chili » January 22nd, 2020, 8:55 am

Damnit did I fuck something up >:[
Chili

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Intermediate Tutorial 21 Bonus part cannot build for x86 platform

Post by albinopapa » January 22nd, 2020, 6:09 pm

chili wrote:
January 22nd, 2020, 8:55 am
Damnit did I fuck something up >:[
I can't tell. It could be Visual Studio.

I find it weird that SpriteEffect.h includes Graphics.h and Graphics.h includes SpriteEffect.h, and VS doesn't have a problem with this. I'm guessing because the inclusion of SpriteEffect.h doesn't interfere with the Graphics class declaration since it's after it, but circular references though. I tried moving things around and couldn't get it to compile or run correctly so extern template is a mystery to me, or it could be the need for the GOD_GRAPHICS macro that has stumped me...or both.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

Post Reply