Skip to content

Latest commit

 

History

History
181 lines (129 loc) · 4.84 KB

File metadata and controls

181 lines (129 loc) · 4.84 KB

Understanding Makefiles and Dynamic Link Libraries (DLLs)

This document explains how Makefiles work, their workflow, and the role of dynamic link libraries (DLLs) in a C++ project. It includes examples and clarifies their build-time and runtime usage.


1. Makefile Overview and Workflow

A Makefile automates the build process by specifying rules and dependencies for building a project. When you run make, it:

  1. Reads the first target (default).
  2. Resolves dependencies for that target.
  3. Executes rules (commands) to build required files.

Example Makefile:

# Compiler
CXX = g++

# Flags
CXXFLAGS = -Wall -Wextra -std=c++11

# Directories
SRC_DIR = src
BUILD_DIR = build
INCLUDE_DIR = include
LIB_DIR = lib

# Source files
SRC_FILES = $(wildcard $(SRC_DIR)/*.cpp)

# Object files
OBJ_FILES = $(patsubst $(SRC_DIR)/%.cpp, $(BUILD_DIR)/%.o, $(SRC_FILES))

# Targets
all: $(LIB_DIR)/trig.lib $(LIB_DIR)/compound_interest.dll calculator

calculator: $(OBJ_FILES)
	$(CXX) $(CXXFLAGS) -o $@ $^ -L$(LIB_DIR)

$(BUILD_DIR)/%.o: $(SRC_DIR)/%.cpp
	$(CXX) $(CXXFLAGS) -I$(INCLUDE_DIR) -c -o $@ $<

# Rule to create the compound interest DLL
$(LIB_DIR)/compound_interest.dll: $(BUILD_DIR)/compound_interest.o
	$(CXX) -shared -o $@ $^

# Rule to create the trigonometric static library
$(LIB_DIR)/trig.lib: $(BUILD_DIR)/trig_operations.o
	lib /OUT:$@ $^

clean:
	rm -rf $(BUILD_DIR)/*.o calculator $(LIB_DIR)/compound_interest.dll $(LIB_DIR)/trig.lib

.PHONY: all clean

Workflow with Example Makefile

  1. Default Target: The first target all is invoked by default:

    all: $(LIB_DIR)/trig.lib $(LIB_DIR)/compound_interest.dll calculator
    • Dependencies like trig.lib, compound_interest.dll, and calculator are built.
  2. Building Dependencies:

    • If trig.lib doesn’t exist or is outdated, its rule is invoked:
      $(LIB_DIR)/trig.lib: $(BUILD_DIR)/trig_operations.o
          lib /OUT:$@ $^
  3. Building Executable:

    • The calculator target links all .o files and libraries:
      calculator: $(OBJ_FILES)
          $(CXX) $(CXXFLAGS) -o $@ $^ -L$(LIB_DIR)
  4. Output:

    • make produces:
      • lib/trig.lib (static library)
      • lib/compound_interest.dll (shared library)
      • calculator (executable).

2. Indentation in Makefiles

Makefiles require tabs for indentation. To ensure proper formatting in VS Code:

  1. Set Tabs in VS Code:

    • Go to the bottom-right corner and select "Convert Indentation to Tabs".
  2. Force Tabs for Makefiles:

    • Add this to your VS Code settings (settings.json):
      "[makefile]": {
          "editor.insertSpaces": false,
          "editor.tabSize": 4
      }
  3. Check Indentation:

    • Enable "Render Whitespace" in VS Code to see if tabs () are used.

3. DLLs and Their Role

Static vs. Dynamic Libraries

  • Static Libraries (trig.lib):

    • Bundled into the executable at compile time.
    • Increases executable size but makes it self-contained.
  • Dynamic Libraries (compound_interest.dll):

    • Referenced at runtime, not bundled into the executable.
    • Reduces size and promotes modularity.

Why Include DLLs in Makefiles?

DLLs must still be built during the build process, even though they are used at runtime.

  1. Building the DLL:

    $(LIB_DIR)/compound_interest.dll: $(BUILD_DIR)/compound_interest.o
        $(CXX) -shared -o $@ $^
    • Compiles compound_interest.o into compound_interest.dll using the -shared flag.
  2. Runtime Usage:

    • The executable (calculator) references the DLL.
    • At runtime, the OS loads the DLL.

4. DLLs: Build-Time vs. Runtime

  • Build-Time:

    • DLLs are compiled and generated.
    • The Makefile ensures they are created and placed in the correct location.
  • Runtime:

    • DLLs are loaded by the OS when the executable runs.
    • They must be in the same directory as the executable or a directory in the system's PATH.

5. Dependency Chain Summary

  1. Source files: src/*.cppbuild/*.ocalculator.
  2. Static library: src/trig_operations.cppbuild/trig_operations.olib/trig.lib.
  3. Shared library: src/compound_interest.cppbuild/compound_interest.olib/compound_interest.dll.

6. Cleaning Builds

The clean target removes generated files:

clean:
    rm -rf $(BUILD_DIR)/*.o calculator $(LIB_DIR)/compound_interest.dll $(LIB_DIR)/trig.lib

Run it with:

make clean

Conclusion

This Makefile demonstrates:

  • Automated builds using static and dynamic libraries.
  • Understanding the difference between DLL usage at runtime vs. build-time.
  • Proper formatting and debugging of Makefiles in tools like VS Code.

By mastering this workflow, you can handle complex C++ projects efficiently!