Devs.site

Static, shared and dynamic libraries in C++

The main goal of creating and using libraries is reusability. As soon as you find yourself duplicating the same set of functionalities for one or more applications, you'd better use a static or dynamic library. They can be developed and maintained independently of the projects, integrated into the final product's binary or delivered alongside it in a separate file (without revealing the source code if you want).

This guide describes with exemplified steps how to declare and define exportable code, how to build it into libraries, how to link against them and import variables, functions and classes. For compiling and linking we will use MSVC in Windows, GCC in Linux and Clang in Mac OS, in order to cover all main environments.


Static libraries
Extensions
Characteristics
Definitions

mystaticlib.cpp

// declarations header
#include "mystaticlib.h"

namespace MyNamespace
{
    int myvar = 10;

    // function
    int myFunc(int param)
    {
        return myvar + param;
    }

    // class public variable
    int MyClass::mystaticvar = 10;

    // constructor
    MyClass::MyClass(int param)
    {
        mystaticvar = param;
    }

    // class public function
    int MyClass::myfunc()
    {
        return mystaticvar + _myvar;
    }
}
Declarations

mystaticlib.h

#ifndef MYSTATICLIB_H
#define MYSTATICLIB_H

namespace MyNamespace
{
    // variable with external linkage
    extern int myvar;

    // function
    int myFunc(int);

    // class
    class MyClass
    {
        public:
            // public static variable
            static int mystaticvar;

            // constructor
            MyClass(int);

            // public function
            int myfunc();

        private:
            // private variable
            int _myvar = 10;
    };
}
#endif
Compiling and building
g++ -static -c -o mystaticlib.o mystaticlib.cpp
ar rcs libmystaticlib.a mystaticlib.o

First we compile and build the static object by specifying the -static option. Then we archive it into a library with ar rcs. In Linux, libraries must start with the lib prefix.

cl /c /EHsc mystaticlib.cpp
lib -out:mystaticlib.lib E:\mystaticlib.obj

This will create the object file. We create the static library with the help of the lib command Make sure that you have the path to cl and lib added to the Path environment variable in Windows. An IDE like Microsoft Visual Studio takes care of all this.

clang++ -c -std=c++11 -o mystaticlib.o mystaticlib.cpp
ar -r libmystaticlib.a mystaticlib.o

or

clang++ -c -std=c++11 -o mystaticlib.o mystaticlib.cpp
libtool -static mystaticlib.o -o libmystaticlib.a

The same procedure as on Linux. Compile, build the object and create the archive. We specify -std=c++11 for the compiler if we use the latest features of the C++ language.

Importing

myapp.cpp

#include <iostream>
// you just have to include the header with the declarations
#include "mystaticlib.h"

// use the library's namespace
using namespace MyNamespace;

int main()
{
    // using variable from the library
    std::cout << myvar << std::endl;
    // using function from the library
    std::cout << myFunc(2) << std::endl;
    // using class from the library
    MyClass newinstance(3);
    std::cout << newinstance.myfunc() << std::endl;
}
Linking
g++ -o myapp myapp.cpp -lmystaticlib -L .

We specify the output executable's name and the source file. At the end we link the library (without the lib prefix an the extension) and include the current directory in the libraries paths list so the linker can find it.

cl /c /EHsc myapp.cpp /link mystaticlib.lib

Again, you need to make sure that the paths for standard included headers and imported libraries are added to the INCLUDE and LIB environment variables, if not using an IDE that does this for you

clang++ -std=c++11 myapp.cpp -o myapp -lmystaticlib -L .
Dynamic libraries
Extensions
Characteristics
Definitions

In Linux, you use the same code as in mystaticlib.cpp and mystaticlib.h. In Windows you need some Microsoft specific keywords for the generation of the .lib import library.

mydynamiclib.cpp

// declarations header
#include "mydynamiclib.h"

namespace MyNamespace
{

#ifdef _WIN32
#   ifdef __cplusplus
        extern "C" {
#   endif
#endif
    int myvar = 10;

    // function
    int myFunc(int param)
    {
        return myvar + param;
    }

    // class public variable
    int MyClass::mystaticvar = 10;

    // constructor
    MyClass::MyClass(int param)
    {
        mystaticvar = param;
    }

    // class public function
    int MyClass::myfunc()
    {
        return mystaticvar + _myvar;
    }
#ifdef _WIN32
#   ifdef __cplusplus
    }
#   endif
#endif
}
Declarations

mydynamiclib.h

#ifndef MYSTATICLIB_H
#define MYSTATICLIB_H

#ifdef _WIN32
#   ifdef MYDLL
#       define EXPORT __declspec(dllexport)
#   else 
#       define EXPORT __declspec(dllimport)
#   endif
#else
#   define EXPORT
#endif

namespace MyNamespace
{
#ifdef _WIN32
#   ifdef __cplusplus
    extern "C" {
#   endif
#endif
        // variable
        EXPORT extern int myvar;

        // function
        EXPORT int myFunc(int);

        // class
        class EXPORT MyClass
        {
        public:
            // public static variable
            static int mystaticvar;

            // constructor
            MyClass(int);

            // public function
            int myfunc();

        private:
            // private variable
            int _myvar = 10;
        };
#ifdef _WIN32
#ifdef __cplusplus
    }
#endif
#endif
}

#endif
Compiling and building

The code above can be compiled in both Windows and Linux. The pre-processor conditionals will make sure that Windows related code is ignored in Linux.

g++ -shared -fPIC -o libmysharedlib.so mysharedlib.cpp

We specify that this is a shared library with the -shared command. The -fPIC stands for Position Independent Code, which will allow the library to be relocated in memory.

cl /DMYDLL /D_WIN32 /LD mydynamiclib.cpp /link /DLL /OUT:mydynamiclib.dll /IMPLIB:mydynamiclib.lib

One single command will compile and link everything into a final DLL. By defining _WIN32 we make the Windows specific directives available for the compiler. By defining MYDLL we enable the export directive. By using IMPLIB we also request a LIB with the exported functions.

clang++ -c -std=c++11 -o mydynamiclib.o mydynamiclib.cpp
libtool -dynamic mydynamiclib.o -o libmydynamiclib.dylib
Importing

You import and use functionalities from the dynamic libraries in the same way. Just include the header in the source file of your application's project.

Linking
g++ -o myapp myapp.cpp -lmysharedlib -L .

Linking a shared library in Linux is done just like with the static one. But in order to have the library available at runtime you need to add it to the LD_LIBRARY_PATH environment variable:

export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH

In our example we generate the library in the current path, so that is what we add.

E:\>cl /MT /D_WIN32 myapp.cpp /link /SUBSYSTEM:CONSOLE "mydynamiclib.lib"

This should generate an EXE file that you can test. Yu can also use the #pragma comment(lib, "mydynamiclib.lib") directive directly in the code, instead of using /link in the command line.

clang++ -std=c++11 myapp.cpp -o myapp -lmydynamiclib -L .
Notes

Libraries can also be loaded dynamically, at whichever point in the program you choose. This will be addressed in a future article. With the examples above now you are at least familiar with the commands for creating static, shared or dynamic libraries and linking other generated object files against them (mainly executables but other libraries as well).

0 comments

Specify your e-mail if you want to receive notifications about new comments and replies