Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / containers / virtual-machine

Microsoft Visual C++ Static and Dynamic Libraries

4.93/5 (76 votes)
26 Jul 2010CPOL17 min read 404.7K   7.4K  
A simple introduction to static and dynamic libraries with Microsoft Visual C++.

Stages

Introduction

This article is intended to be a basic introduction to the Microsoft Visual C++ Static and Dynamic Libraries. This article assumes that you have a basic understanding of the C language, and are familiar with the Microsoft Visual C++ IDE. I will show you how to compile and reference dynamic and static libraries so that you can share and distribute your own libraries. You will need to have a version of Microsoft Visual C++. If you do not own a copy, you can download the Express edition here.

This tutorial will cover step-by-step how to compile and reference your libraries with plenty of visuals. This article is intended to be repetitive to help beginners grasp and develop their own libraries with Microsoft Visual C++. I strongly recommend you read my previous article about compiling libraries with MinGW. The article provides a comparison between static and dynamic libraries. In general, I find the GCC compiler easier to comprehend and easier to develop libraries. This will assist beginners in developing their own libraries.

The Static Library

The code for a static library is identical to that in my previous post on compiling libraries for MinGW, found here. This is an over simplistic library to emphasize the process of creation, not the concept of a library. The library is pretty standard, in that the function is declared in the header and defined within the 'c/cpp' file. The files are listed below:

add.h:
C++
#ifndef ADD_H
#define ADD_H
int add(int a, int b);
#endif  // ADD_H
add.c:
C++
#include "add.h"
int add(int a, int b) {
    return a + b;
}

The Wizard (Recommended Use: A Planned Static Library)

The wizard sets up all the necessary configurations for a static library automatically. This method is appropriate for when you initially plan to develop a library.

When you start up Microsoft Visual C++, ensure that you select a Win32 Console project and not a C/C++ CLI project. The Win32 console project is a native application that produces machine code as opposed to intermediate language code. A C/C++ CLI (Common Language Infrastructure) code is managed code compiled down to a form of byte-code which is interpreted by a virtual machine. The actual definition of a "Managed Language" and "CLI" is out of the scope of the project; read up on it if you are interested. A Win32 project is native language that will only run on a Windows Operating System with .NET Framework installed.

NewProject.PNG

Once you start up Microsoft Visual C++, select File->New Project->Win32 Console Application. Select Next and select Static Library. This will produce an empty project. Add the files provided, or right-click on the Solution Explorer and add a new header *.h and a new *.cpp file. Copy the solution source code into your newly created header and CPP file.

StaticWizard.PNG

The Project Properties (Recommend Use: A Design Change)

The project properties method allows you to change your library type later in the development phase.

StaticConfig.png

The alternative to using the wizard is to use the project properties. The second option allows a user to implement a static library after following the Wizard. A "use case" for this might be where you intended to implement an application, but after that is decided, it would be best suited as a static library. To implement this change, go to Project->Add Properties->General and select Static Libraries from the configuration field (refer to figure above). To compile the solution, right click on the solution and hit Build.

Referencing the Static Library

The implementation of the library is pretty standard. You must have access to the header file and reference it. If you do not have the header file, or do not wish to reference it, you must indicate the function definition with the extern tag. The main.c file is pretty standard, and demonstrates how to run a static library. You'll notice in the next figure that a new project was added to the library solution file. To add a new project to a solution, right-click on the solution file and hit Add New Project.

AddProjects.png

Then add a new file to your new project by right-clicking on the new project's Source Files and selecting Add New Item, specifically "C++" file. Add the following code to your project:

main.c:
C++
#include "../Add/add.h"
#include <stdio.h>
//extern int add(int a, int b);
int main() {
    int a = 2;
    int b = 1;
    printf("a=%d, b=%d\n", a,b);

    printf("add: %d\n", add(a,b));
    getchar();
    return 0;
}

The Reference Method (Recommended Use: Access to the Original Project File)

The reference method allows you to easily add a dependency on another MSVC (Microsoft Visual C++) Project File in your possession. For example, this method is most suitable for the library we are creating now because we have access to the original project.

To implement this method, include the project you want into the current solution. (In the case of this example, you should have already added a new project to the library solution). If not, you will need to right-click on the Solution File->Add->Existing Project. Now right-click on the project that will depend upon your static library: select Common Properties->Framework and Reference->Add New Reference and select the project that has the required dependencies. If you have completed this successfully, you should see something similar to the image below.

ProjectReference.PNG

The Drag and Drop Method (Recommended Use: Third Party Libraries)

The Drag and Drop method is appropriate when you don't have access to the original project files. A developer might not want to share his source code with you, and in this case, you will only have a header *.h and a library file *.lib.

In order to reference your newly compiled library (or a third party library), you can navigate to your "Debug" or "Release" directory to select your newly compiled library file. Grab the file labeled Add.lib or *.lib for any other library, and drag it over to your project resources. The drag and drop method is much simpler than the following method of using the configuration. You must also identify your library file so that the linker is able to properly identify the compiled function. To this, you must include your library header, or add an extern reference defining the functions you wish to call.

ReferenceD_D.PNG

The Configuration Method (Recommend Use: Third Party Libraries with Special Configurations)

The reasons for this library are similar to that mentioned in the drag and drop method. However, this method gives you more control. This is best suited for a third party library.

The configuration serves the exact same purposes as the drag and drop method, but is more difficult. Navigate to Project->Properties-> Input->Additional Dependencies and add the directory path to the source of your library. Additional dependencies are references using your solution file as the base directory, so that '.' indicates the current solution directory followed by the path to the direct library file. You can also explicitly write in the whole directory path, i.e., C:\Users\.... Should you require further assistance, refer to the MSDN article which is very specific but not very graphical or explanatory.

ReferenceConfig.PNG

The Dynamic Library

The tutorial for the dynamic library is intended to be as similar as possible to the static library. You'll notice that the only addition is __declspec(dllexport), which is a Microsoft specific identifier, which identifies that the function will be used as a DLL (Dynamically Linked Library) export. The C file is exactly the same as the previous examples.

add.h:
C++
#ifndef ADD_H
#define ADD_H
int __declspec(dllexport) add(int a, int b);
#endif  // ADD_H
add.c:
C++
#include "add.h"
int add(int a, int b) {
    return a + b;
}

The Wizard (Recommended Use: A Planned Dynamic Library)

The wizard sets up all the necessary configurations for a dynamic library automatically. This method is appropriate for when you initially plan to develop a library.

The Wizard method to creating a dynamic library is very similar to the static library as mentioned above. I selected DLL from Application Type and selected Empty Project. If you do not select Empty Project, you will have to delete the files provided by the IDE. Although the project files provided by the Wizard have a specific purpose, they will over complicate this tutorial.

DynamicWizard.PNG

The Project Properties (Recommend Use: A Design Change)

The project properties method allows you to change your library type later in the development phase.

The Project Properties page is identical to the static library method. To implement this change, go to Project->Add Properties->General and select Dynamic Library from the configuration field:

DynamicConfig.png

Referencing the Dynamic Library

The first thing you should notice is that the header file has been modified to import the library with __declspec(dllimport) as opposed to __declspec(dllexport). This tells the compiler that this is referencing a dynamic library. This process seems redundant to explicitly declare your import or export statements as you would either be compiling a library or exporting a library, and most likely, neither doing both in the same project. This is why I prefer the GCC compiler to produce dynamic libraries. In addition, the Microsoft Visual C++ IDE requires that you link the *.lib file when producing your shared/dynamic libraries (although, it is possible that you can link your dynamic libraries explicitly using the Windows API; this will be covered in the next article). In addition, keep in mind that you still require the header file or require the function definition.

add.h
C++
#ifndef ADD_H
#define ADD_H
int __declspec(dllimport) add(int a, int b);
#endif  // ADD_H
main.c
C++
#include <stdio.h>
#include "add.h"

//extern int __declspec(dllimport) add(int a, int b);
int main() {
    int a = 2;
    int b = 1;
    printf("a=%d, b=%d\n", a,b);
    printf("add: %d\n", add(a,b));
    getchar();
    return 0;
}

The Reference Method (Recommended Use: Access to the Original Project File)

The reference method allows you to easily add a dependency on another MSVC Project File in your possession. For example, this method is most suitable for the library we are creating now because we have access to the original project.

To implement this method, include the project you want into the current solution. (In the case of this example, you should have already added a new project to the library solution.) If not, you will need to right-click on Solution File->Add->Existing Project. Now right-click on the project that will depend upon your static library: select Common Properties->Framework and Reference->Add New Reference, and select the project that has the required dependencies. In the case of our library, you should only see one project to reference.

DynamicReference.PNG

The Drag and Drop Method (Recommended Use: Third Party Libraries)

This is the fastest and simplest way to reference a third party library with only the *.lib and *.h file.

The drag and drop method is identical to the static library method, and requires that you include the *.lib file. Including the lib file is called implicit linking, as the machine code is known at compile time but not actually included into the actual application. (Static libraries include the machine code directly into the application, where as dynamic code load it in at run time.)

DynamicReferenceD_D.PNG

The Configuration Method (Recommended Use: Third Party Libraries with Special Configurations)

This configuration method is best suited for third party libraries that may have special configurations, allowing you more control. You still require the *.h and *.lib files.

The configuration method is identical to the static library. Navigate to Project->Properties-> Input->Additional Dependencies and add the directory path to the source of your library.

DynamicReferenceConfig.PNG

A Reusable Header

addGuard.h:
C++
#ifndef ADD_H
#define ADD_H
#ifdef BUILD_DLL
#define PORT_DLL __declspec(dllexport)
#else
#define PORT_DLL __declspec(dllimport)
#endif
int PORT_DLL add(int a, int b);
#endif  // ADD_H

The reusable header is probably the most common dynamic library header file type for Windows. It allows you re-use your header for both the library compilation or the actual application that links the library. PORT_DLL will define an export if declared at compile time. If it's not defined during compilation, then it is intended to be used by the application. This is an extremely common way of reusing a header as the creator of the library file will define the export, while users will only need to include the header.

The Command Line Options

CommandLineOptions.PNG

To define your exports, you must go to Project->Properties->C/C++->Command Line and add the flag /D. This stands for define. In this specific case, you are defining BUILD_DLL, which means you intend to implement this library as an export. Users of the library would not be defining the variable if they intended to use the library. For more details on dynamic implicit linking, refer to MSDN.

C Run-Time Libraries (CRT)

The C Run-Time Library will cause a lot of frustration down the road, especially when you are trying to link with third party libraries. It could also potentially cause a lot of frustration with your customers when they can't reference your libraries. You must understand how the CRT will impact your library to successfully integrate your work with others.

CRT Libraries

The CRT in a nutshell is all the library functions you rely on to develop your code. It includes the Standard C++ Library as well as the Microsoft functions and declarations. This is a summary list of the libraries you can integrate with. For the full list, see MSDN.

  • LIBCPMT.LIB - Multithreaded (Standard C++ Library) /MT
  • LIBCMT.LIB - Multithreaded (C Runtime Library) /MT
  • MSVCPRT.LIB - Multithreaded Dynamically Linked Library w/ MSVCP90.dll (Standard C++ Library) /MD
  • MSVCRT.LIB - Multithreaded Dynamically Linked (C Runtime Library) w/ MSVCR90.dll /MD

There are more libraries; however, the flags MT (multithreaded) and MD (multithreaded DLL) are the most common, and as of VS2008, the only flags available (not including the debug flags). I am unable to use the single threaded libraries as of VS2008. The various libraries allow you to link your project to the CRT of your current version of Visual Studio. To set your version of the CRT, go to 'Project Properties->Code Generation->Runtime Library' and select either /MT, /MTd, /MD, or /MDd, (Multithreaded[debug] or Multithreaded DLL[debug]).

CodeGeneration.PNG

Unfortunately, every new addition of VS has a new CRT. The main problem with linking libraries is that the older libraries rely on the CRT of their release and can cause conflicts with newer versions of VS. This specifically has to do with the allocation of memory. MSDN goes into specifics, but here is an excerpt:

"If you design your DLL so that it passes CRT objects across the boundary or allocates memory and expects it to be freed outside the DLL, you restrict the DLL users to use the same copy of the CRT library as the DLL. The DLL and its users use the same copy of the CRT library only if both are linked with the same version of the CRT DLL." - MSDN

Third Party Libraries

If you have a thirrd party library including a DLL, lib, and header file, you should be set to compile and link your project to the library. However, if you run into CRT issues, you will need to determine the version of CRT that the third party vendor compiled their library with. To do this, you need to go into the MSVS Command Line tool and type:

dumpbin /imports <dllname.dll>

This will list all the imports that were used to compile the library. In the case of our library "Add.lib", we only have "kernel32.dll" as a resource because we did not use any of the CRT functions. However, in most cases, you would see something like "msvcr80.dll" or "libcmt.lib". The exact libraries will need to be refered to from MSDN to translate the DLL name to the specific library and the necessary compiler flags (refer MSDN: C-Runtime Libraries and MS Support: C-Runtime Libraries). If you refer to the various CRT libraries on MSDN, you will notice "msvcr80.dll" was compiled with the /MD switch. You will have to configure your library as shown in the previous section. If this is not successful, then you most likely need the version of 8.0 (which was VS2005) and compile it with /MD.

Custom CRT

Forcing your customers to rely on out of date libraries, or worse, forcing your customers to upgrade to the new expensive version of Visual Studio could really annoy your customers. Luckily, MS provides a way to compile the CRT libraries so that you can package them with your library. To compile your own version of CRT, go to the VS Command Line Tool. (Ensure that you have Administrator rights by right clicking on the VS Command Line Tool and selecting 'Run as Administrator'.) Type 'set vctools=C:\Program files\Microsoft Visual Studio x.x\VC' (where x.x is your version of VS). Then type 'crt\src\bldnt.cmd'. This will build the CRT libraries. This will run for a minute or so, compiling all the necessary libraries for your system. Once completed, I received 'libcmt.lib', 'libcpmt.lib', '_sample_.dll', and '_sample_.lib'. The sample files are actually copies of msvcrXX.dll (where XX is your VS version). They are renamed so that they do not conflict with the actual MS libraries. For the full naming conventions, refer to MSDN: Building the Run-Time Libraries.

BuildCustomCrt.PNG

Once you have built your custom libraries, you need to link them into your project. To link them into your project, you have to get back into the Project Properties and add them as previously taught. Since you are linking the custom CRT libraries, you need to move the default libraries by going to 'Project Properties->Linker->Input->Ignore All Default Libraries->Yes'. This will override the default MT or MD flags which will automatically include the standard CRT for your VS versions. However, be warned that once you do this, you will be required to import all the additional dependencies by hand. 'Additional Dependencies=.\_sample_lib', or whatever happened to be your dependencies libraries. The other alternative is just to ignore the default CRT libraries by going to 'Ignore Specific Library=msvcr9.0.lib' and place 'Additional Dependencies '_sample_.lib' so that your library relies on your compiled library and not the system defaults. This allows for greater flexibility when sharing your libraries with customers, as your dependencies get shipped along with your libraries.

ForceCustomCrt.PNG

Comparison

As stated in my previous article, a dynamic library is loaded at runtime, which means that your *.dll file must be made available to your application. A dynamic library allows the application to reduce its overall file size. DLL files are best for large projects that require the exact same function calls. Notice in the figure below that if you delete/remove the library, the executable will not run. A static library includes the machine code directly into your application so that it does not require an external library. A static library is good for sharing a project without giving direct access to your source.

DLL Requirements

DynamicFail.PNG

Static Library Properties

  • Small/medium projects that have specific code not normally shared
  • Application executables relatively larger
  • No dynamic linking overhead (compiled into application)
  • Shares project without giving up source code
  • No linking at runtime

Dynamic Library Properties

  • Best for large projects that share redundant code across applications
  • Application executables relatively smaller
  • Overhead of dynamic linking
  • Shares project without giving up source code
  • Requires library at runtime

Conclusion

This article was intended to demonstrate how to build your own static and dynamic implicitly linked library. There are two methods to create a library, either initially using the wizard, or through the project properties at a later stage. The library may be utilized using a project reference method, the drag and drop method, and finally, the configuration method. The project reference method is best suited for libraries that you have access to the source. The drag and drop method and the configuration method are better suited to third party libraries where you only have access to the library files and definition headers. A static library is intended for small/medium projects that you wish to share your work without providing source. A dynamic library provides the opportunity to share your work without your source and allows you to reduce your overall application size. Although, dynamic libraries require more overhead to run, both a static and a dynamic library have a place within your projects.

Special Thanks

This article would not have included the reference method if it were not for the following people:

  • Aescleal - Reference method (justification and instructions).
  • Randor - Reference method (additional justification).
  • Rolf Kristensen - CRT critique.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)