Fault
Fault

Reputation: 420

Makefile linker error

I seem to be going from one problem to the next ever since I decided to organize my code into subdirectories. The problems are naturally arising from the Makefile. So here's what I've currently got:

UNAME := $(shell uname)

# Directories
SOURCEDIR = src/
BUILDDIR = build/

# Compiler options
CC = clang++
DEBUG = -g
CFLAGS = -std=c++11 -Wall -c $(DEBUG)
LFLAGS = -Wall $(DEBUG)

# Files
SRC = $(wildcard $(SOURCEDIR)*.cpp) $(wildcard $(SOURCEDIR)**/*.cpp)
OBJS = $(SRC:$(SOURCEDIR)%.cpp=$(BUILDDIR)%.o)

ifeq ($(UNAME), Darwin)
    LIBS = -lglfw3 -framework OpenGL -lglew -framework IOKit -framework CoreFoundation -framework ApplicationServices -framework Foundation -framework AppKit 
    BUILDDIR = ./build/osx/
endif
ifeq ($(UNAME), Linux)
    LIBS = -lglfw -lGL -lGLEW
    BUILDDIR = ./build/linux/
endif

# Build target
TARGET = test

all: $(TARGET)

$(TARGET): $(OBJS)
    $(CC) $(LFLAGS) $? -o $(TARGET) $(LIBS)

$(OBJS): $(BUILDDIR)%.o : $(SOURCEDIR)%.cpp
    @mkdir -p $(dir $@)
    $(CC) $(CFLAGS) $< -o $@

clean:
    rm -rf $(BUILDDIR)*.o $(BUILDDIR)**/*.o $(TARGET)

I was really glad when it actually compiled everything! Except when I made a change to a file, and tried to make it again, it spat this at me:

Undefined symbols for architecture x86_64:
  "_main", referenced from:
     implicit entry/start for main executable
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [test] Error 1

Thing is, when I make it once more, it works just fine. The problem seems to be with resolving dependencies? And for that, I need to specify a VPATH? Well, that's the closest I've gotten, except trying to specify a VPATH hasn't made a difference. I'm probably specifying it incorrectly, or then I'm taking the wrong approach to this.

I'm pretty inexperienced when it comes to Makefiles, so I'd really appreciate some guidance!

Upvotes: 0

Views: 1545

Answers (1)

Fault
Fault

Reputation: 420

Thanks to Etan Reisner for the solution. The problem was with the difference between $? and $^. Here's the fixed version:

UNAME := $(shell uname)

# Directories
SOURCEDIR = src/
BUILDDIR = build/

# Compiler options
CC = clang++
DEBUG = -g
CFLAGS = -std=c++11 -Wall -c $(DEBUG)
LFLAGS = -Wall $(DEBUG)

# Files
SRC = $(wildcard $(SOURCEDIR)*.cpp) $(wildcard $(SOURCEDIR)*/*.cpp)
OBJS = $(SRC:$(SOURCEDIR)%.cpp=$(BUILDDIR)%.o)

ifeq ($(UNAME), Darwin)
    LIBS = -lglfw3 -framework OpenGL -lglew -framework IOKit -framework CoreFoundation -framework ApplicationServices -framework Foundation -framework AppKit 
    BUILDDIR = ./build/osx/
endif
ifeq ($(UNAME), Linux)
    LIBS = -lglfw -lGL -lGLEW
    BUILDDIR = ./build/linux/
endif

# Build target
TARGET = test

all: $(TARGET)

$(TARGET): $(OBJS)
    $(CC) $(LFLAGS) $^ -o $(TARGET) $(LIBS)

$(OBJS): $(BUILDDIR)%.o : $(SOURCEDIR)%.cpp
    @mkdir -p $(dir $@)
    $(CC) $(CFLAGS) $< -o $@

clean:
    rm -rf $(BUILDDIR)*.o $(BUILDDIR)*/*.o $(TARGET)

Upvotes: 1

Related Questions