# C++ Makefile, Static Library

All of our previous examples have used only shared libraries. While shared libraries are very useful, static libraries also have their use. Link-time optimization can be done much more aggressively. Any functions that are not called can be pruned by the compiler, whereas they cannot be pruned from a shared library. Here, we will improve the makefile to compile either shared or static libraries.

First, let’s add variables to indicate whether we should build a static or a shared library.

BUILD_SHARED = 1
BUILD_STATIC = 0


If BUILD_SHARED is non-zero, we will build a shared library. If BUILD_STATIC is non-zero, we will build a static library. If both are non-zero, we will make both libraries. We will link the executables against whichever library’s value is greater.

Now, we define each library that we want to make.

ifneq ($(BUILD_SHARED),0) SHARED_LIBRARY_OUTPUT =$(patsubst %,lib/%.so,$(LIBRARY_FOLDERS)) endif ifneq ($(BUILD_STATIC),0)
STATIC_LIBRARY_OUTPUT = $(patsubst %,lib/%.a,$(LIBRARY_FOLDERS))
endif


Next, we want to define a different rule for building the object files. When compiling a shared library, we want the -fPIC flag, whereas we don’t want it when compiling a static library. The object files to go into a static library will end in .o, and object files to go into a shared library will end in .os.

build/$(BUILD)/build/%.os: %.cc mkdir -p$(@D)
$(CXX) -c -fPIC$(CPPFLAGS) $(CXXFLAGS)$< -o $@ build/$(BUILD)/build/%.o: %.cc
mkdir -p $(@D)$(CXX) -c $(CPPFLAGS)$(CXXFLAGS) $< -o$@


Now, we add a rule for each of the libraries. We will add a variable AR to allow the user to select which archiver to use. In addition, we define library_os_files in terms of library_o_files.

AR = ar
library_os_files  = $(addsuffix s,$(call library_o_files,$(1))) build/$(BUILD)/lib/lib%.a: $$(call library_o_files,%) mkdir -p (@D) (AR) rcs @ ^ build/(BUILD)/lib/lib%.so:$$(call library_os_files,%)
mkdir -p $(@D)$(CXX) $(LDFLAGS)$^ -shared $(SHARED_LDLIBS) -o$@


Finally, we want to have a rule to compile the executables. We will make two versions of the rule, depending on whether we are linking against the shared or the static libraries.

ifeq ($(shell test$(BUILD_SHARED) -gt $(BUILD_STATIC); echo$$?),0) build/$(BUILD)/bin/%: build/$(BUILD)/build/%.o$(O_FILES) | $(SHARED_LIBRARY_OUTPUT) mkdir -p$(@D)
$(CXX)$(ALL_LDFLAGS) $^$(ALL_LDLIBS) -o $@ else build/$(BUILD)/bin/%: build/$(BUILD)/build/%.o$(O_FILES) $(STATIC_LIBRARY_OUTPUT) mkdir -p$(@D)
$(CXX)$(ALL_LDFLAGS) $^$(ALL_LDLIBS) -o \$@
endif


Now, we can compile the code to either a shared or a static library, depending on what is needed for a particular project. The full makefile can be found on github.