Building and Linking Static and Shared Libraries with Makefiles

Library Creation and Linking Basics

Consider a C++ project with the following structure:

add.h

int compute_sum(int x, int y);

add.cpp

#include "add.h"

int compute_sum(int x, int y)
{
    return x + y;
}

main.cpp

#include <iostream>
#include "add.h"

int main()
{
    std::cout << compute_sum(1, 2) << std::endl;
    return 0;
}

Static Library Creation and Linking

Makefile for static library generation:

compiler_flags := -g -O3 -std=c++11 -I ./
linker_flags := -l mathlib -L ./

add.o : add.cpp
	@g++ -c $^ -o $@ $(compiler_flags)

libmathlib.a : add.o
	@ar -rcs $@ $^

static_target : libmathlib.a

main.o : main.cpp
	@g++ -c $^ -o $@ $(compiler_flags)

app_static : main.o
	@g++ $^ -o $@ $(linker_flags)

all_static : static_target app_static

clean :
	@rm -rf *.o *.a *.so app_static

Execute make all_static to generate libmathlib.a and app_static. Verify dependencies with ldd app_static:

linux-vdso.so.1 (0x00007ffe567f1000)
libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f8d3a8c0000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8d3a6ce000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f8d3a57f000)
/lib64/ld-linux-x86-64.so.2 (0x00007f8d3aadc000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f8d3a564000)

Shared Library Creation and Linking

Makefile for shared library generation:

compiler_flags := -g -O3 -w -fPIC -I ./
linker_flags := -l mathlib -L ./ -Wl,-rpath=./

add.o : add.cpp
	@g++ -c $^ -o $@ $(compiler_flags)

libmathlib.so : add.o
	@g++ -shared $^ -o $@

dynamic_target : libmathlib.so

main.o : main.cpp
	@g++ -c $^ -o $@ $(compiler_flags)

app_dynamic : main.o
	@g++ $^ -o $@ $(linker_flags)

all_dynamic : dynamic_target app_dynamic

clean :
	@rm -rf *.o *.a *.so app_dynamic

Execute make all_dynamic to generate libmathlib.so and app_dynamic. Check dependencies with ldd app_dynamic:

linux-vdso.so.1 (0x00007ffc25df8000)
libmathlib.so => ./libmathlib.so (0x00007f4b2a42e000)
libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f4b2a219000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f4b2a027000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f4b29ed8000)
/lib64/ld-linux-x86-64.so.2 (0x00007f4b2a432000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f4b29ebd000)

Multi-Directory Project Structure

Extended project structure with subdirectories:

subtract.h

int compute_difference(int x, int y);

subtract.cpp

#include "subtract.h"

int compute_difference(int x, int y)
{
    return x - y;
}

main.cpp

#include <iostream>
#include "add.h"
#include "subtract.h"

int main()
{
    std::cout << compute_sum(1, 2) << std::endl;
    std::cout << compute_difference(1, 2) << std::endl;
    return 0;
}

Static Library with Subdirectories

Makefile using object files directly:

lib_sources := $(shell find ./src -name "*.cpp")
lib_objects := $(lib_sources:.cpp=.o)

compiler_flags := -g -O3 -std=c++11 -I ./include
linker_flags := -l corelib -L ./

src/%.o : src/%.cpp
	g++ -c $^ -o $@ $(compiler_flags)

libcorelib.a : $(lib_objects)
	ar -rcs $@ $^

static_lib : libcorelib.a

main.o : main.cpp
	g++ -c $^ -o $@ $(compiler_flags)

app_main : main.o $(lib_objects)
	g++ $^ -o $@

all_static : static_lib app_main

clean :
	rm -rf *.o src/*.o *.a *.so app_main

Alternative Makefile linking against static library:

lib_sources := $(shell find ./src -name "*.cpp")
lib_objects := $(lib_sources:.cpp=.o)

compiler_flags := -g -O3 -std=c++11 -I ./include
linker_flags := -l corelib -L ./

src/%.o : src/%.cpp
	g++ -c $^ -o $@ $(compiler_flags)

libcorelib.a : $(lib_objects)
	ar -rcs $@ $^

static_lib : libcorelib.a

main.o : main.cpp
	g++ -c $^ -o $@ $(compiler_flags)

app_main : main.o
	g++ $^ -o $@ $(linker_flags)

all_static : static_lib app_main

clean :
	rm -rf *.o src/*.o *.a *.so app_main

Shared Library with Subdirectories

Makefile using object files directly:

lib_sources := $(shell find ./src -name "*.cpp")
lib_objects := $(lib_sources:.cpp=.o)

compiler_flags := -g -O3 -w -fPIC -I ./include
linker_flags := -l corelib -L ./ -Wl,-rpath=./

src/%.o : src/%.cpp
	g++ -c $^ -o $@ $(compiler_flags)

libcorelib.so : $(lib_objects)
	g++ -shared $^ -o $@

dynamic_lib : libcorelib.so

main.o : main.cpp
	g++ -c $^ -o $@ $(compiler_flags)

app_main : main.o $(lib_objects)
	g++ $^ -o $@

all_dynamic : dynamic_lib app_main

clean :
	rm -rf *.o src/*.o *.a *.so app_main

Alternative Makefile linking against shared library:

lib_sources := $(shell find ./src -name "*.cpp")
lib_objects := $(lib_sources:.cpp=.o)

compiler_flags := -g -O3 -w -fPIC -I ./include
linker_flags := -l corelib -L ./ -Wl,-rpath=./

src/%.o : src/%.cpp
	g++ -c $^ -o $@ $(compiler_flags)

libcorelib.so : $(lib_objects)
	g++ -shared $^ -o $@

dynamic_lib : libcorelib.so

main.o : main.cpp
	g++ -c $^ -o $@ $(compiler_flags)

app_main : main.o
	g++ $^ -o $@ $(linker_flags)

all_dynamic : dynamic_lib app_main

clean :
	rm -rf *.o src/*.o *.a *.so app_main

Advanced Library Combinations

Building Static Library and Linking External Static Library

lib_sources := $(shell find ./src -name "*.cpp")
lib_objects := $(lib_sources:.cpp=.o)

compiler_flags := -g -O3 -std=c++11 -I ./include
linker_flags := -l corelib -L ./ -l mathlib -L ./lib

src/%.o : src/%.cpp
	g++ -c $^ -o $@ $(compiler_flags)

libcorelib.a : $(lib_objects)
	ar -rcs $@ $^

static_lib : libcorelib.a

main.o : main.cpp
	g++ -c $^ -o $@ $(compiler_flags)

app_main : main.o
	g++ $^ -o $@ $(linker_flags)

all_static : static_lib app_main

clean :
	rm -rf *.o src/*.o *.a *.so app_main

Building Shared Library and Linking External Static Library

lib_sources := $(shell find ./src -name "*.cpp")
lib_objects := $(lib_sources:.cpp=.o)

compiler_flags := -g -O3 -w -fPIC -I ./include
linker_flags := -l mathlib -L lib -l corelib -L ./ -Wl,-rpath=./

src/%.o : src/%.cpp
	g++ -c $^ -o $@ $(compiler_flags)

libcorelib.so : $(lib_objects)
	g++ -shared $^ -o $@

dynamic_lib : libcorelib.so

main.o : main.cpp
	g++ -c $^ -o $@ $(compiler_flags)

app_main : main.o
	g++ $^ -o $@ $(linker_flags)

all_dynamic : dynamic_lib app_main

clean :
	rm -rf *.o src/*.o *.a *.so app_main

Building Shared Library and Linking External Shared Library

lib_sources := $(shell find ./src -name "*.cpp")
lib_objects := $(lib_sources:.cpp=.o)

compiler_flags := -g -O3 -std=c++11 -I ./include
linker_flags := -l corelib -L ./ -l mathlib -L ./lib

src/%.o : src/%.cpp
	g++ -c $^ -o $@ $(compiler_flags)

libcorelib.so : $(lib_objects)
	g++ -shared $^ -o $@

dynamic_lib : libcorelib.so

main.o : main.cpp
	g++ -c $^ -o $@ $(compiler_flags)

app_main : main.o
	g++ $^ -o $@ $(linker_flags)

all_dynamic : dynamic_lib app_main

clean :
	rm -rf *.o src/*.o *.a *.so app_main

Dependency check with ldd app_main shows:

linux-vdso.so.1 (0x00007ffd8a3f2000)
libcorelib.so => ./libcorelib.so (0x00007f1b4c839000)
libmathlib.so => ./libmathlib.so (0x00007f1b4c834000)
libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f1b4c61f000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f1b4c42d000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f1b4c2de000)
/lib64/ld-linux-x86-64.so.2 (0x00007f1b4c845000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f1b4c2c3000)

Merging Static Libraries

Extract objects from existing static library and combine:

lib_sources := $(shell find ./src -name "*.cpp")
lib_objects := $(lib_sources:.cpp=.o)

compiler_flags := -g -O3 -std=c++11 -I ./include

src/%.o : src/%.cpp
	g++ -c $^ -o $@ $(compiler_flags)
	ar -x lib/libmathlib.a

libcorelib.a : $(lib_objects) add.o
	ar -rcs $@ $^

static_lib : libcorelib.a

main.o : main.cpp
	g++ -c $^ -o $@ $(compiler_flags)

app_main : main.o libcorelib.a
	g++ $^ -o $@

all_static : static_lib app_main

clean :
	rm -rf *.o src/*.o *.a *.so app_main

Creating Shared Library from Static Library Components

lib_sources := $(shell find ./src -name "*.cpp")
lib_objects := $(lib_sources:.cpp=.o)

compiler_flags := -g -O3 -w -fPIC -I ./include
linker_flags := -l corelib -L ./ -Wl,-rpath=./

src/%.o : src/%.cpp
	g++ -c $^ -o $@ $(compiler_flags)
	ar -x lib/libmathlib.a

libcorelib.so : $(lib_objects) add.o
	g++ -shared $^ -o $@

dynamic_lib : libcorelib.so

main.o : main.cpp
	g++ -c $^ -o $@ $(compiler_flags)

app_main : main.o
	g++ $^ -o $@ $(linker_flags)

all_dynamic : dynamic_lib app_main

clean :
	rm -rf *.o src/*.o *.a *.so app_main

Note: Linux systems do not support embedding shared libraries within other shared or static libraries.

Tags: Makefile static-library shared-library C++ build-systems

Posted on Sat, 12 Sep 2026 16:40:00 +0000 by MattMan