Static libraries and shared libraries are two types of libraries commonly in C and C++ programming languages. They represent two different ways to package and distribute code.
In this blog post, we will discuss the differences between static libraries and shared libraries using an example approach.
Example
We will use an example to illustrate the difference between static libraries and shared libraries. All the source code is available on GitHub.
Implementation
In our example, we have two libraries, shape and rectangle, and one executable, main. The rectangle library depends on the shape library. The main executable depends on the rectangle library.
# Create a shared library add_library(shape_shared SHARED shape.cpp) # Create a static library add_library(shape_static STATIC shape.cpp)
We will build the rectangle library as a shared library that depends on the shape static library or the shape shared library, a static library that depends on the shape shared library or the shape static library.
# Create a shared library that links to another shared library. add_library(rectangle_shared_to_shape_shared SHARED rectangle.cpp) target_include_directories(rectangle_shared_to_shape_shared PUBLIC ${CMAKE_SOURCE_DIR}/src/shape) target_link_libraries(rectangle_shared_to_shape_shared PUBLIC shape_shared)
# Create a shared library that links to a static library. # This does not work. # add_library(rectangle_shared_to_shape_static SHARED rectangle.cpp) # target_include_directories(rectangle_shared_to_shape_static PUBLIC ${CMAKE_SOURCE_DIR}/src/shape) # target_link_libraries(rectangle_shared_to_shape_static PUBLIC shape_static)
# Create a static library that links to another shared library. add_library(rectangle_static_to_shape_shared STATIC rectangle.cpp) target_include_directories(rectangle_static_to_shape_shared PUBLIC ${CMAKE_SOURCE_DIR}/src/shape) target_link_libraries(rectangle_static_to_shape_shared PUBLIC shape_shared)
# Create a static library that links to a static library. add_library(rectangle_static_to_shape_static STATIC rectangle.cpp) target_include_directories(rectangle_static_to_shape_static PUBLIC ${CMAKE_SOURCE_DIR}/src/shape) target_link_libraries(rectangle_static_to_shape_static PUBLIC shape_static)
Shared libraries can only be linked to shared libraries, and static libraries can be linked to both shared libraries and static libraries.
Static library dependencies are resolved at compile time, and static library dependencies will become part of consumer executable or consumer static library.
The shared library dependencies are resolved at runtime, and shared library dependencies will not become part of consumer executable or consumer static library.
In our example, we have three rectangle libraries, rectangle_shared_to_shape_shared, rectangle_static_to_shape_shared, and rectangle_static_to_shape_static.
We will build the main executable in three different ways by linking to the three rectangle libraries.
# Create an executable that links to a shared library that links to another shared library. add_executable(app_to_rectangle_shared_to_shape_shared main.cpp) target_include_directories(app_to_rectangle_shared_to_shape_shared PRIVATE ${CMAKE_SOURCE_DIR}/src/rectangle) target_link_libraries(app_to_rectangle_shared_to_shape_shared PRIVATE rectangle_shared_to_shape_shared)
# Create an executable that links to a static library that links to another shared library. add_executable(app_to_rectangle_static_to_shape_shared main.cpp) target_include_directories(app_to_rectangle_static_to_shape_shared PRIVATE ${CMAKE_SOURCE_DIR}/src/rectangle) target_link_libraries(app_to_rectangle_static_to_shape_shared PRIVATE rectangle_static_to_shape_shared)
# Create an executable that links to a static library that links to a static library. add_executable(app_to_rectangle_static_to_shape_static main.cpp) target_include_directories(app_to_rectangle_static_to_shape_static PRIVATE ${CMAKE_SOURCE_DIR}/src/rectangle) target_link_libraries(app_to_rectangle_static_to_shape_static PRIVATE rectangle_static_to_shape_static)
The resulting main executables are app_to_rectangle_shared_to_shape_shared, app_to_rectangle_static_to_shape_shared, and app_to_rectangle_static_to_shape_static.
Run Example
After building the example, we can run the three main executables successfully.
1 2 3 4 5 6
$ ./build/src/app/app_to_rectangle_shared_to_shape_shared Area of Rectangle is 6 $ ./build/src/app/app_to_rectangle_static_to_shape_shared Area of Rectangle is 6 $ ./build/src/app/app_to_rectangle_static_to_shape_static Area of Rectangle is 6
Inspect Example
We could inspect the dependencies of the three main executables using the ldd command. Because static libraries will become part of the consumer executable or consumer static library, only shared library dependencies will be shown.
The app_to_rectangle_shared_to_shape_shared executable depends on both the rectangle_shared_to_shape_shared shared library and the shape_shared shared library.
The app_to_rectangle_static_to_shape_shared executable depends on the shape_shared shared library.
The app_to_rectangle_static_to_shape_static executable depends neither of the rectangle libraries nor the shape libraries.
We could verify the dependencies by removing the shape shared library and the rectangle shared library.
1 2 3 4 5 6 7 8 9 10 11 12
$ rm -rf build/src/rectangle/ $ ./build/src/app/app_to_rectangle_shared_to_shape_shared ./build/src/app/app_to_rectangle_shared_to_shape_shared: error while loading shared libraries: librectangle_shared_to_shape_shared.so: cannot open shared object file: No such file or directory $ ./build/src/app/app_to_rectangle_static_to_shape_shared Area of Rectangle is 6 $ ./build/src/app/app_to_rectangle_static_to_shape_static Area of Rectangle is 6 $ rm -rf build/src/shape/ $ ./build/src/app/app_to_rectangle_static_to_shape_shared ./build/src/app/app_to_rectangle_static_to_shape_shared: error while loading shared libraries: libshape_shared.so: cannot open shared object file: No such file or directory $ ./build/src/app/app_to_rectangle_static_to_shape_static Area of Rectangle is 6
Static Library VS Shared Library
From the example, we can see the pros and cons of static libraries and shared libraries.
Shared Library
Shared libraries make the consumer executable or consumer shared library more flexible and easier to update. Because shared libraries are not part of the consumer executable or consumer shared library, it’s possible to update the shared library without recompiling the consumer executable or consumer shared library. In addition, because shared libraries can be shared among multiple consumer executables or consumer shared libraries, using shared libraries can save disk space and memory.
Static Library
Static libraries makes the consumer executable or consumer static library more portable and easier to distribute. However, static libraries will increase the size of the consumer executable or consumer static library. In some scenarios, even if many consumer executables or consumer static libraries depend on the same static library, the static library will be duplicated in each consumer executable or consumer static library, which will waste disk space and memory.