0

I have a simple structure as below for a small library I'm building.

  • I want make build to build the library (libproj.a) from sources under ./source
  • I want make build_test to build every source file under ./test prefixed with test_ into it's own binary

I can build the library libproj.a just fine, but can't figure out how to build the tests. I'm currently getting the following linker error when attempting to build /cygdrive/d/Source/proj/build/obj/test_proj.o:test_proj.c:(.text+0x15): undefined reference to 'test'.

Directory structure

+---build
|   +---lib
|   +---obj
|   \---test
+---include
|   \---proj
+---source
\---test

Makefile

PROJECT             = proj
LIBNAME             = lib$(PROJECT).a

CFLAGS              = -Wall -Wextra -O0

DIR_ROOT            = $(abspath .)
DIR_SRC_LIB         = $(DIR_ROOT)/source
DIR_SRC_TEST        = $(DIR_ROOT)/test

DIR_BLD_OBJ         = $(DIR_ROOT)/build/obj
DIR_BLD_LIB         = $(DIR_ROOT)/build/lib
DIR_BLD_TEST        = $(DIR_ROOT)/build/test

LST_OBJ_LIB         = $(patsubst $(DIR_SRC_LIB)/%.c, $(DIR_BLD_OBJ)/%.o, $(wildcard $(DIR_SRC_LIB)/*.c))
LST_OBJ_TEST        = $(patsubst $(DIR_SRC_TEST)/%.c, $(DIR_BLD_OBJ)/%.o, $(wildcard $(DIR_SRC_TEST)/*.c))
LST_BIN_TEST        = $(patsubst $(DIR_SRC_TEST)/%.c, $(DIR_BLD_TEST)/%, $(wildcard $(DIR_SRC_TEST)/test_*.c))

INCLUDES            = -I $(DIR_ROOT)/include

clean:
    $(RM) $(LST_OBJ_LIB)
    $(RM) $(LST_OBJ_TEST)

build:
    $(info build)

build-test: $(LST_BIN_TEST)
    $(info build-test)

run-test:
    $(info run-test)

install:
    $(info install)

$(LIBNAME): $(LST_OBJ_LIB)
    $(AR) rvs $(DIR_BLD_LIB)/$@ $^

$(DIR_BLD_OBJ)/%.o: $(DIR_SRC_LIB)/%.c
    $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@

$(DIR_BLD_TEST)/%: $(DIR_BLD_OBJ)/%.o $(LIBNAME)
    $(CC) $(LDFLAGS) -L $(DIR_BLD_LIB) -l $(PROJECT) $< -o $@

$(DIR_BLD_OBJ)/%.o: $(DIR_SRC_TEST)/%.c
    $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@

1 Answers1

0

My guess is that this line:

$(CC) $(LDFLAGS) -L $(DIR_BLD_LIB) -l $(PROJECT) $< -o $@

is wrong. You're passing to the compiler (I'm assuming gcc) the libraries before the object files. If your compiler acts as gcc does, the code in the libraries is getting discarded because it hasn't been referenced yet when it parses them see -l option documentation.

It should be

$(CC) $(LDFLAGS) -L $(DIR_BLD_LIB) $< -l $(PROJECT) -o $@

(Note the changed position of $<)

Furthermore, remeber that the order of libraries is important: see this excellent explanation.

Community
  • 1
  • 1
miravalls
  • 365
  • 1
  • 7