Shared-library details decide whether your binaries run after installation and whether your ABI stays stable.
Shared libraries add concerns static ones don't have.
Symbol visibility. On Linux every function is exported by default; on Windows nothing is unless marked __declspec(dllexport). Make both behave the same by hiding symbols by default and exporting your API explicitly:
set_target_properties(geo PROPERTIES CXX_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN ON)include(GenerateExportHeader)andgenerate_export_header(geo)creategeo_export.hwith aGEO_EXPORTmacro to put on public classes and functions.
Smaller export tables load faster, avoid symbol clashes and make ABI breakage visible.
Versioning. VERSION 1.4.2 and SOVERSION 1 properties produce libgeo.so.1.4.2 with the SONAME libgeo.so.1 and symlinks. Bump SOVERSION only when you break the ABI.
Finding libraries at run time. An executable records an RPATH listing directories to search. CMake gives build-tree binaries an RPATH pointing at the build tree, and by default strips it at install time, so installed programs may fail with "cannot open shared object file". Set CMAKE_INSTALL_RPATH to a relative path, $ORIGIN/../lib on Linux or @loader_path/../lib on macOS, to make the installed tree relocatable. Windows has no RPATH: DLLs must sit next to the executable or on PATH, which $<TARGET_RUNTIME_DLLS:app> (3.21+) helps copy.
Example
cmake_minimum_required(VERSION 3.25)
project(geo VERSION 1.4.2 LANGUAGES CXX)
include(GNUInstallDirs)
include(GenerateExportHeader)
add_library(geo SHARED src/geo.cpp)
generate_export_header(geo) # writes geo_export.h with GEO_EXPORT
target_include_directories(geo PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include;${CMAKE_CURRENT_BINARY_DIR}>")
set_target_properties(geo PROPERTIES
CXX_VISIBILITY_PRESET hidden
VISIBILITY_INLINES_HIDDEN ON
VERSION ${PROJECT_VERSION} # libgeo.so.1.4.2
SOVERSION ${PROJECT_VERSION_MAJOR}) # SONAME libgeo.so.1
add_executable(app src/main.cpp)
target_link_libraries(app PRIVATE geo)
set_target_properties(app PROPERTIES INSTALL_RPATH "$ORIGIN/../${CMAKE_INSTALL_LIBDIR}")
install(TARGETS geo app)
# include/geo.h: #include "geo_export.h"
# GEO_EXPORT double area(double r); // exported; helpers stay hidden
# $ readelf -d build/libgeo.so | grep SONAME -> [libgeo.so.1]Remember
- Hide symbols by default and export the API with generate_export_header
- VERSION and SOVERSION set file names and the SONAME
- Set INSTALL_RPATH to $ORIGIN/../lib so installed binaries find their libraries
Watch out for
- Installing a program linked to your shared library without an install RPATH, so it only runs from the build tree.