Search code examples
makefilecompilationlinkerg++sfml

Failing to link to SFML libraries using Makefile even though it works as a one liner


Here is my directory structure :

.
├── a.out
├── assets
│   └── ...
├── build
│   ├── apps
│   └── objects
├── include
│   └── engine
│       └── Class.h
├── Makefile
└── src
    ├── engine
    │   └── Class.cpp
    └── program.cpp

I can compile program.cpp into a.out using the following command :

g++ src/engine/*.cpp src/program.cpp -Iinclude/ -L/usr/lib -lstdc++ -lm -lsfml-graphics -lsfml-window -lsfml-system -Wall

While this works, this project is likely to grow and obviously making a serious Makefile would be preferable to direct compiling with a one liner. So I've used a Makefile format that I've used many times before, and that works perfectly fine but I've never linked it to outside libraries in the past. Here is the Makefile I'm using :

CXX      := -g++
CXXFLAGS := -std=gnu++0x -g -Wall
LDFLAGS  := -L/usr/lib -lstdc++ -lm -lsfml-graphics -lsfml-window -lsfml-system
BUILD    := ./build
OBJ_DIR  := $(BUILD)/objects
APP_DIR  := $(BUILD)/apps
TARGET   := program
INCLUDE  := -Iinclude/
SRC      := $(wildcard src/engine/*.cpp) $(wildcard src/*.cpp)
OBJECTS  := $(SRC:%.cpp=$(OBJ_DIR)/%.o)

all: build $(APP_DIR)/$(TARGET)

$(OBJ_DIR)/%.o: %.cpp
    @mkdir -p $(@D)
    $(CXX) $(CXXFLAGS) $(INCLUDE) -o $@ -c $<

$(APP_DIR)/$(TARGET): $(OBJECTS)
    @mkdir -p $(@D)
    $(CXX) $(CXXFLAGS) $(INCLUDE) $(LDFLAGS) -o $(APP_DIR)/$(TARGET) $(OBJECTS)

.PHONY: all build clean debug release

build:
    @mkdir -p $(APP_DIR)
    @mkdir -p $(OBJ_DIR)

debug: CXXFLAGS += -DDEBUG -g
debug: all

release: CXXFLAGS += -O2
release: all

clean:
    -@rm -rvf $(OBJ_DIR)/*
    -@rm -rvf $(APP_DIR)/*

However, this leads to compilation errors, in the form of undefined references to SFML methods :

./build/objects/src/engine/Class.o: In function `Class::draw()':
/dir/Class.cpp:60: undefined reference to `sf::RenderTarget::getView() const'

I'm confused as to why this happens given that the one liner above compiles fine. The Makefile also works just fine if I remove all references to SFML from my code. Were the added LDFLAGS not enough even though they're all that's needed to make my one liner link to SFML ? If so, what else is needed ?


Solution

  • From gcc link options

    -llibrary

    It makes a difference where in the command you write this option; the linker searches and processes libraries and object files in the order they are specified. Thus, foo.o -lz bar.o searches library z after file foo.o but before bar.o. If bar.o refers to functions in z, those functions may not be loaded.

    So put the libraries (-l<lib_1> ... -l<lib_x>) last on the line, after your object files.