分享

Static Library Example: EAE 6320

 兰亭文艺 2022-08-03 发布于加拿大

Static Library Example

Download the solution here Download here .

In addition to executable files we will also deal with 'libraries' in this class. There are both 'dynamic' and 'static' libraries. Dynamic libraries can be loaded at run-time, which means:

  • They can be changed without changing the executable file
  • As long as they fulfill an interface that the executable expects they can be used as 'plug-ins' so that anyone can create code that an existing program will use

In our class our experience with dynamic libraries will be limited to Maya plug-ins (Maya will load libraries that we create and execute our code). All other libraries that we create will be static.

Static Libraries

Static libraries are separate files whose executable code gets embedded into the executable at build time. Functionally there is no real reason to use them in the way we will in this class as opposed to just putting the source files in a single project. The reason that we will use static libraries so extensively in this class is for organization: It allows us to create separate projects to handle separate responsibilities. This means:

  • We will learn to make good design and architectural decisions by decoupling functionality where possible (as well as being forced to think about proper dependencies between different functionality)
  • We will only have to recompile functionality that we have changed
  • When we get error messages they will relate to the specific library functionality we have changed (or a dependent library functionality that we have broken by making a change)

All of the above arguments could also be made in favor of using dynamic libraries instead and many games do exactly that.

Creation

  • Right-click the solution in Solution Explorer and choose Add->New Project...
  • Choose Windows Desktop Wizard
    • (This is on the newest update of Visual Studio 2017. If you don't see that option choose 'Win32 Console Application')
  • In the window that appears change the Application type: to Static library (.lib)
  • (In our class also uncheck 'Precompiled Header' in the 'Additional Options' section.)

Now when you build this project it will create a LIB file instead of an EXE file. The rest of the required set-up is the same as the other projects in our class.

Using

Look at EntryPoint.cpp in the Executable project. This consists of a standard main() function like you are used to, and the only thing that this main() does is call two trivial example functions. The first function comes from the Static Library project (declared in StaticLibrary.h and defined in StaticLibrary.cpp), and the second comes from Windows. Notice that the C/C++ code doesn't care that these functions are from external libraries! It is exactly the same as if StaticLibrary.h and StaticLibrary.cpp (or the Windows message box code) were part of the Executable project.

A consequence of this is that if you don't set up a static library correctly you will not get compile errors (the solution will compile successfully) but instead you will get linker errors: Compiling just guarantees that the calls to the static library have correct syntax (as determined by the header file), and it is the 'linker' that actually tries to associate ('link') the calls to the static library with real compiled machine code. When this happens you will see 'unresolved external symbol' errors (LNK2019 (Links to an external site.)). When you see an 'unresolved external symbol' error DON'T PANIC! Remember what it means: Your code is calling some externally-defined function correctly, but the linker can't find that externally-defined function and you need to help locate it.

This is how you get Visual Studio to successfully use a static library that your project needs to call a function from:

  • Expand your project (the one that needs to link to a static library) in Visual Studio's Solution Explorer
  • Right-click References and select Add Reference...
  • In the tree view to the left make sure that 'Projects' is expanded (not 'Shared Projects')
  • You should see a list of projects in your solution. Check the box next to the static library project that your project uses.

When you do this the following should happen:

  • The linked-to project should show up as a child of 'References' in Solution Explorer
    • Expand the Executable project's references to see the StaticLibrary project
  • The linked-to project is now automatically set as a build dependency:
    • Right-click the Executable project and choose Build Dependencies->Project Dependencies...
    • Note that the StaticLibrary is checked as a dependency
      • (Try to uncheck it and see what happens!)
    • Change the tab in the Project Dependencies window to 'Build Order'. You should see that, as expected, the StaticLibrary project will build before the Executable project. This is necessary! The Executable project can compile by itself, but it can't link until the StaticLibrary has been built. (Or, in other words, if the Executable project tries to link before the StaticLibrary project has finished building then you will get an LNK2019 'unresolved external' error.)
      • (Remove the reference to the StaticLibrary project and then build the solution and see what happens!)

Static Library Chains

This example program is simple and only has a single executable and a single static library. In many cases, however, you will encounter a situation where you have a chain of static libraries: Executable A calls a function from Static Library B, and Static Library B calls a function from Static Library C. In this hypothetical situation, even though Executable A never calls a function from Static Library C directly it still needs to link to it! This is because static libraries don't link to other static libraries: All of the executable code only gets embedded in the executable.

Technically, then, no static library depends on any other static library. Instead, an executable depends on all of the static libraries that have functions called by any static library that it uses directly. Even though this is technically true, it is not how we want to think of things as humans because it is confusing and error prone.

Using Visual Studio's reference mechanism allows us to worry about the conceptual dependencies of each static library in isolation. If Static Library B in your solution calls a function from Static Library C you should add Static Library C to the list of Static Library B's references. By doing this Visual Studio will automatically set up the dependencies and link all of the necessary projects to the final executable, and you do not need to set Library C as a reference of Executable A. (Each reference has a properties page that controls this behavior, but it is ok to leave the default values.)

In summary: If a project X calls any functions from project Y then project Y should be added as a reference to project X. This is true regardless of whether project X is an executable or a static library.

External Libraries

All of the techniques discussed above assume that the referenced libraries are projects in your code solution. While this covers the majority of the cases in our class there are some functions that you will need to call from external libraries (e.g. Windows, Direct3D, OpenGL, Maya).

The way that Visual Studio handles this for executables is nice and straightforward, but I haven't found a good way to handle things automatically for chains of static libraries. The following method is what I think is the least offensive alternative, and in our class we will use it for everything (static libraries and executables) to keep things consistent:

  • Create a platform-specific Windows file whose sole responsibility is to handle external libraries
    • In this example program the file is ExternalLibraries.win.h in the Executable project
  • In that file use the Visual Studio-specific #pragma directive for each external library that the project calls a function from:
    • #pragma comment( lib, 'someLibrary.lib' )
  • Right-click the project and choose 'Properties'
  • In the tree view to the left select Configuration Properties->C/C++->Advanced
  • Find the Forced Include File field, click the empty field, click the down arrow that appears, and select <Edit...>
  • Add the platform-specific file in the text area, prefixed by $(ProjectDir):
    • $(ProjectDir)Windows/ExternalLibraries.win.h
  • (Make sure that 'Inherit from parent or project defaults' is checked, and that the 'Evaluated value' section shows '%(ForcedIncludeFiles)')

Doing the steps above will result in the same behavior that adding a reference to a local project does. Note that the external libraries we use in this class are actually dynamic libraries and not static libraries (there isn't any code from Windows that is directly embedded in your game executable, for example; it is loaded dynamically and shared with all other processes that are running).

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多