Single binary game or collection of libraries

Started by
10 comments, last by Dawoodoz 4 years, 10 months ago

Hi All, I am stuck with the question of whether to make my game a standalone binary or a collection of modules(libraries) and a startup binary.
To that I don't know exactly why I should pick one over other but one thing keeps bugging me is about bug fixes and addition of new features. 
So If I have single binary do I have to just replace the binary and call it "patch 0.5"?
Or If I have modules then If my patch is about adding new attack animation to an enemy then I just update "Enemy.so/Enemy.dll"?

How do I make such decisions? I wonder how Braid/Rocket League does the update? If they are made in Unreal/Unity I suppose these engine provide

solutions for updating game with patches. How did Braid do? I know it was not made with available game engines.

Advertisement

You can do both, this is how I/we do it. We have our engine/ game code set up in modules that each on it's own cover exactly one aspect of the engine/ game. For example we have a Common Module, a Math Module and so on.

Our modules are build as static libraries and then linked together into the final binary. This has a couple of advantages:

  • Faster Code; The OS dosen't has to initialize the function bindings and dosen't manage pointers to dynamically linked functions
  • Smaller Code; Only code that is actually used is linked into the binary while dynamic libraries carry all code in their binaries, even those code you didn't used
  • Easier Management; You can structure your project in a cleaner way because it dosen't effect the final binary how many static libraries you link into it. On a dynamic library based project you are getting wasted if you have too many .so's/.dll's

Updating your game isn't done by just replacing the binarys of your game. Normally you create a hash value SHA256 of your binary to determine the version. If the hash dosen't match any of your path hashes, something is broken and you have to download the full binary again, otherwise you apply patches iterative. You determine the version currently installed and then have deltas from that version to the next patch version. Those deltas contain all code changes made but not the full new binary and replace the sections in the binary so that the hash matches the hash of the new patched version

2 hours ago, Shaarigan said:

Our modules are build as static libraries and then linked together into the final binary

With this you are bound to compile binary again and also your binary size is bigger than if you had used dynamically loaded libraries. Is not it good to use dynamically loaded libraries with dlopen, dlsym and dlclose()? You will have smaller binary and individual dll libraries can be updated easily?

The binary itself is smaller, but as I wrote above, your code is little slower and the installation size of your game is bigger because you have more files and linker can't optimize unused code away.

And as I wrote above, Updates aren't made by replacing a file, you instead calculate the delta between your curent version and the patch and instead copy the delta to the files on disk

If you're unsure, I'd go with single binary. It'll be easier to work with, and truthfully, if you don't have a need for dynamic libraries then it's probably not a good idea to use them. I'm not much of an OS programmer, but as far as I know the main need for dynamic libraries is to have code shared between different programs without duplicating it. A specific use case I can remember, IIRC, is that Half-Life and Half-Life 2 loaded .dlls for mods, but that's far from the only way to implement mods. Especially with today's abundance of scripting languages.

The only usecase I see today for dynamic libraries is either loading them on demand like when using C# p/invoke or hiding your source code if your name is FMOD

2 hours ago, Shaarigan said:

The only usecase I see today for dynamic libraries is either loading them on demand like when using C# p/invoke or hiding your source code if your name is FMOD

You are not entirely correct.

There are major reasons why you would want to use dynamic libraries - example being support for various formats (i.e. plugin based architecture).

Example

2D images with plugin architecture - you create a common function call to load the image and return you width, height and rgb data. Now implement TGA.dll, BMP.dll, PNG.dll, etc. etc. etc. Place them all into plugin/texture folder.

Now your main application does dlopen for each dll in that directory, uses dlsym to get pointer to load function - and based on format it calls appropriate of these functions.

At this point adding a new format support is possible (and even 3rd parties can add it).

...

The advantage of dynamic libraries (in plugin-like architecture F.e.) is that all you need is to add another dynamic library. No need to link whole project again. Similar advantages are when you have multiple projects using same functionality (game, editors, viewer, etc.). Using a common dynamic library actually reduces space - as for versioning, for both scenarios (static libs linked into binaries, or dll modules with binaries) if you are responsible, you will have it correct.

For the original question - it also depends on the scale and purpose of the project. For small projects and games (you probably won't re-use modules) it most likely doesn't pay off having multiple dynamic libraries, single binary is easier to maintain, setup, etc.

My current blog on programming, linux and stuff - http://gameprogrammerdiary.blogspot.com

As we just are in a games related context, your example is something odd. I don't know any modern game that supports adding pre-build dlls as plugin rather than using a scripting language as @PageFile mentioned because those big studios don't want to expose their games/engines due to starting from Cheating up to DRM attack reasons. This means no header files, no lib files you would need to link against for a plugin and so no external dlls at all.

And even in development process you are using a compiler define to op-in non-production code because dlls have the disadvantage that they pre-build, are very difficult to debug from certain level.

So rather than using a dll, the engine will have several image formats built-in to support during development and anyways read and compress assets for production ready code.

So I stay at my statement and from someone I know working at AAA studio, they even be carefull to not expose too much from the engine for public use like scripting. They also would like to have the FMOD dll as static library because static code runs faster

The example from the OP of updating game functionality via new DLLs isn't much of a consideration in a game context in my experience, it is more likely to be used to fix bugs etc in runtime libraries (e.g. mscvrt etc). Usually by far the biggest component in games is the resources rather than the program itself, so updating the program isn't a big deal. Besides that, I am sure there are clever patching tools out there if need be for patches taking only a few KB.

The plugin example is still a reasonable example imo, agreed I have used this myself more for apps than games, but some engines may use such an approach to limit the modules that need to be loaded / distributed (consider you may not want to use e.g. the physics module). I have a feeling NetImmerse and Ogre perhaps used this in the past?

Another use case I've found myself is during development of large projects, in order to reduce build / debug / iteration time. Consider a large project (e.g. the entire Godot engine source tree) may take considerable time (maybe a minute or longer) to link even with a small change to the code. If you are only working on a small part of a project at a time, you can speed this up considerably by utilizing dynamic libraries as you only have to link your current module, the rest can be loaded dynamically. I have organised projects in the past where you switch a define in a cmake file and it either builds modules using dynamic libraries, or the whole thing statically for a final release.

The plugin example is occasionally used, but relatively rare.  We used the model in The Sims 3 for objects developed and sold on the online store. Effectively the objects included a plugin DLL and an asset pack.

But even then, the engine was designed that updates to the core game could override the presence of the DLLs. DLLs had lower priority. If/when the main executable contained the game object functionality the DLL plugin was not used, so game patches could replace downloaded objects.

The typical pattern is to completely replace the binaries for an update.  Using libraries is more about what makes your own organization of the code easier.  There was an era where it was done for memory purposes, but that's not been the case for over two decades now.

This topic is closed to new replies.

Advertisement