PushSize_ in handmade.h can cause duplicate symbol

If the implementation of PushSize_() is going to stay in handmade.h, it should be defined as inline to avoid duplicate symbol linker errors when two translation units include handmade.h.

Also, the InitializeArena() function right above it should probably also be defined as inline instead of internal if we're keeping the implementation in the .h file. "internal" technically works okay in this case, but static function implementations in a .h file create a separate definition of the function in every file they're included in. That might be what you want in very specific conditions, but probably not what you want here.
Every h file has this in it:

#if not hfilename

(Filecontent)

#define hfilename

#endif

Edited by Roderic Bos on
Yes, but this isn't helping if the .h file is included in two different .cpp files which are compiled separately and linked together.

The right thing would be to either mark them as inline, or probably better to define them in a .cpp file and only declare the interface in the header file.

Actually, is "inline" enough in C++ or should it be "static inline" as is required by C99?
Casey mentioned he only wants 1 (well 2 now with the platform separatly) compile unit, so for him it will never happen I think.
Casey is using a technique called a "unity build." The basic idea is that, from the compiler's perspective, there is only one translation unit (or two in this case - one for the platform and one for the game). This is why what Casey has done is fine as long as the code is only used in the context of a unity build.

Unity builds have some nice properties - they are the fastest way to do a full rebuild and they may make it easier for the compiler to optimize since it sees all the code at once and it knows what will be external and not. They also have some downsides - you are force to always do a full build (granted this means you will never get odd bugs that are caused by build problems) and, the one I struggle with, you lose the ability to encapsulate unless you jump through extra hoops - static still means file scope but there is only one file so it is basically global.

Edited by Patrick Lahey on
Most of the time, Handmade Hero will not be buildable as separate source files. It's only an accident that that has been working thus far. We will often not be typing in (redundant) forward declarations for functions so if you're trying to compile as multiple files, that will fail, also.

- Casey
cmuratori
Most of the time, Handmade Hero will not be buildable as separate source files. It's only an accident that that has been working thus far. We will often not be typing in (redundant) forward declarations for functions so if you're trying to compile as multiple files, that will fail, also.


Aren't you worried that using this approach compile times will get much too long later on?
Just a clarification: I'm not trying to compile the "game code" as separate units, only my platform layer code. I broke up my OS X platform layer code into separate files to isolate the Cocoa code from the OS platform code in order to more easily share the source between the traditional Xcode port and the minimal one.

I'd like to only need to include handmade_platform.h (and not handmade.h) in the OS X platform layer code, but that's not quite possible at the moment. I thought the original intent of handmade_platform.h was to define the structures and function interfaces that the game code and the platform layer needed to communicate with each other. If that's the intent, then a few more things need moved into handmade_platform.h. If that's not the intent, then well, I misunderstood.

Either way, I can fix this issue in my platform layer.

-Jeff
Even on larger projects, a lot of the time is spent on disk access, preprocessing and parsing the same files over and over again. So even larger projects can benefit from using unity builds.

Edited by Johan Gustafsson on
itfrombit
I'd like to only need to include handmade_platform.h (and not handmade.h) in the OS X platform layer code, but that's not quite possible at the moment.

Hmm - why is that not possible at the moment? The code to which you were referring is not in handmade_platform.h, it's in handmade.h, which is not included by the platform layer. Is there some reason your platform layer has to include handmade.h as well, or am I misunderstanding the problem?

- Casey
Hmm - why is that not possible at the moment? The code to which you were referring is not in handmade_platform.h, it's in handmade.h, which is not included by the platform layer. Is there some reason your platform layer has to include handmade.h as well, or am I misunderstanding the problem?

I include handmade.h in the platform layer in order to get the definitions for:
- internal, local_persist, global_variable
- Pi32
- Kilobytes, Megabytes, Gigabytes, Terabytes
- ArrayCount()
- Assert()
- GetController()

Yes, I could live without most of them in the platform layer or redefine them myself, but I was trying to keep consistent with your code style and not worry about some of my redefinitions getting out of sync with something (like Assert()) that you might change in the future (I'm not so worried about the definition of Gigabytes changing). And they seem like reasonable things to put in handmade_platform.h

I tested moving the above definitions from handmade.h to handmade_platform.h. Then I removed all includes of handmade.h from my platform layer source files so that the only .h file I include is handmade_platform.h and everything compiled and ran fine. It feels much cleaner, and now you can treat handmade.h as inside the private black box of the platform-independent game code. I also tested the changes under win32 and it still compiles clean and runs fine there.

Except for GetController(), I put all of the above definitions in handmade_platform.h right after the numeric typedef section near the top. GetController() needed to be placed after the game_input structure was defined near the bottom of the file. I can send you my versions of the files if you want to see the diffs.

-Jeff
OK, that makes sense - you just want to be able to use the utility functions. I think we can solve that reasonably cleanly so that you won't have to #include handmade.h anymore, which I really want to avoid in any separate-compilation situation.

I'll make a note of it.

- Casey
Thanks!

-Jeff
Yeah (I'm still only at video #27), but I've been wondering about "utility" functions.
I.e. logic that can be used by both the platform layer and the game logic, like string length, string concatenation, etc.
If we want to make sure we're keeping a clean separation between the game code and the platform layer code, then win32_handmade.cpp should also only include handmade_platform.h and not handmade.h. That way, the different platform layers will all be eating the same dog food.

I tried this under win32 and it worked okay once I also moved SafeTruncateUInt64() to handmade_platform.h (in addition to the changes I mentioned above).

-Jeff