DLL or Static Library

Started by
15 comments, last by SeanMiddleditch 8 years, 8 months ago


Do you also have link-time optimization disabled? Just a hunch, but I bet that would make linking noticeably longer.

Can't check right now, but it's quite likely that I do have it disabled.

That does raise the question, however, of whether you actually need it enabled during development. Is the performance impact high enough that you need link-time optimisation in debug builds?

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

Advertisement


Nobody wants 2 minute link times just for simple one-line changes.

Jesus. What sort of volume of source code and libraries are you linking?

I have game, engine, and all ~15 dependent libraries statically linked, and link times are still imperceptible. But then again, I'm only dealing with low-thousands of source files, all told.

This is not so uncommon at all places I worked so far this is the general case, with my previous job taking the crown with link times of 5-10 minutes. In both cases the solutions exist of more than 20 projects which in turn can drag in a few more libraries from other places.

This is why my code-compile-test loop includes a "read the internet" step between compile and test nowadays ;).

Worked on titles: CMR:DiRT2, DiRT 3, DiRT: Showdown, GRID 2, theHunter, theHunter: Primal, Mad Max, Watch Dogs: Legion

But is that with or without link time code generation?

My dev build configurations always leave it off (partly because at least in the bit of experimentation I did, if I wanted to disable optimisations in any source file for easier debugging in an IDE, it seemed to be incompatible, and putting the debugger into fully optimised code is a pain that normally results in me using the disassembly view to get anywhere), and linking is a lot faster than my release builds.


I don't think that's a good reason to use dll's. It would probably be better to use other methods for these kinds of resources, the simplest being to just load the files directly from a subdir of the game directory.

Sorry I think I misrepresented what I was trying to say. My point being that loading the resources in a moderate size game project can be a reason for slow iteration times. One way I've got my iteration times down was to separate the light weight gameplay code into a separate DLL and only recompile and reload that part. I leave the resource manager running the whole time so it doesn't have to reload resources. This a quick way and pretty straight forward way of getting a "hot reload" working... I don't know how you would get hot-reload using static libs.


The biggest advantage for DLLs during development is iteration time. DLLs let you compile and link smaller chunks of the game and then get back into the game quicker, meaning you can test and iterate on your game faster. Which means you can make a better game with less time and money.

Even without a hot reload, iteration is quicker with dlls.


Nobody wants 2 minute link times just for simple one-line changes.

I have the same problems with link times in static link mode, so I rarely build those... but I like to keep them working so that I can use it as an optimised release build (with all the bells an whistles, LTCG e.t.c) I automate this using a TeamCity server, which is free and simple to setup in-case you are interested.

Jesus. What sort of volume of source code and libraries are you linking?

I have game, engine, and all ~15 dependent libraries statically linked, and link times are still imperceptible. But then again, I'm only dealing with low-thousands of source files, all told.


A few million lines of very template-heavy code plus some very heavy middleware. Linking from spinning disks can take up to ~5 minutes. Linking with Linux's default linker (BFD) can take upwards of 7. Linking with Microsoft's linker on an SSD is only around 30-60 seconds. Switching to DLLs dropped that to 10.

Most of that time is in debug symbol generation. Eliminate those (don't do that), the rest is just disk I/O time on the code itself. The symbols for Linux by themselves are 1GB; the Windows PDBs around 600MB. We've never been able to enable LTCG without crushing a build machine.

This is hardly atypical for larger commercial game engines.

(Number of source files is pretty unimportant to the linker in any case. The linker scales by symbol count and code size, not by translation unit count, generally speaking. The worse case you can get into is having headers or the like that bloat symbol count per TU and then have a lot of TUs, giving a multiplicative effect, but... well, don't do that.)

Sean Middleditch – Game Systems Engineer – Join my team!


(Number of source files is pretty unimportant to the linker in any case. The linker scales by symbol count and code size, not by translation unit count, generally speaking. The worse case you can get into is having headers or the like that bloat symbol count per TU and then have a lot of TUs, giving a multiplicative effect, but... well, don't do that.)

This is a good point... and probably more important to keeping compile times low than using a dynamic or static lib config. I see pro-coders do this and it bugs me. I think people coming over from C# or Java tend to be the culprits.

...As a general rule, if a class is referenced in a header as a pointer or reference type then you don't need to include the header file with the declaration for the type. A simple forward declare is enough.

i.e. the following example would be found in header files...


//header includes

class CForwardDeclared;

//class declarations + codes

or you can do it in the code. (i personally like to do it this way)


class CSomeClass
{
public:
     CSomeClass(const class CSomeConstDataOrSomething& InData);
     const class CSomeConstDataOrSomething& Data;

    void SomeFunction(class CSomeOtherClass* ptr);
};

Same goes for template instantiation parameters


TWeakPtr<class CSomeClass> SomeClassPointer;

This also means that changes to the header files wont dirty any unecussary TU's which will just result in less compiling generally.

... but this will not help with linker times, so still better to use DLL's as well anyway.

Keep in mind that DLLs still reduce link time even if you do trim down your codebase's symbol and .obj sizes.

Consider a typical game engine suite. This will consist of the game client, a game server, a number of editors, exporters, and tools, etc. If your process of building the game for a gameplay developer (who often have to work on bits of content as well as the game itself) consists of building the game client, building your automated tests, building your asset pipeline tool, and building your level/object editor, then using static libraries means you're multiplying your base link time by ~4x, and since you're linking a huge conglomerate of code you may well have trouble linking those in parallel without a very beefy machine (e.g. in one project, 16GB of RAM wasn't enough to link more than two executables at once).

DLLs mean that you need only link many of your changes once (since the DLL is then consumed by all the executables). Even if your build system ends up wanting to relink the executables (because the DLL changed so the build system thinks the exes are out of date), that executable linking step will be much simpler and faster and parallelizable since it has far fewer symbols to consider.

So yeah, doing the work to make sure your codebase is small and friendly to the C/C++ compilation model's quirks is an important thing, but DLLs are still a big win in development.

Sean Middleditch – Game Systems Engineer – Join my team!

This topic is closed to new replies.

Advertisement