链接器找不到对作为gcc参数传递的.a库的引用

时间:2016-03-04 15:00:03

标签: c gcc linker makefile

我正在按照“学习艰难的方式”电子书(?),并达到exercise 32

它使用以前开发的项目结构,其中测试链接到构建的库。但是,当我运行make test时,我得到“未定义的引用X”,其中X是我的库头中定义的每个函数。

twoll_tests.c是我的测试文件,libds是库。请参阅此问题底部的项目树。

测试的编译行是这样的:

cc -g -O2 -Wall -Wextra -Isrc -rdynamic -DNDEBUG -std=c11 build/libds.a tests/twoll_tests.c -o tests/twoll_tests

Makefile内容:

CFLAGS=-g -O2 -Wall -Wextra -Isrc -rdynamic -DNDEBUG -std=c11 $(OPTFLAGS)
LIBS=-ldl $(OPTLIBS)
PREFIX?=/usr/local

SOURCES=$(wildcard src/**/*.c src/*.c)
OBJECTS=$(patsubst %.c,%.o,$(SOURCES))

TEST_SRC=$(wildcard tests/*_tests.c)
TESTS=$(patsubst %.c,%,$(TEST_SRC))

TARGET=build/libds.a
SO_TARGET=$(patsubst %.a,%.so,$(TARGET))

# The Target Build
all: $(TARGET) $(SO_TARGET)

dev: CFLAGS=-g -Wall -Isrc -Wall -Wextra $(OPTFLAGS)
dev: all

$(TARGET): CFLAGS += -fPIC
$(TARGET): build $(OBJECTS)
    ar rcs $@ $(OBJECTS)
    ranlib $@

$(SO_TARGET): $(TARGET) $(OBJECTS)
    $(CC) -shared -o $@ $(OBJECTS)

build:
    @mkdir -p build
    @mkdir -p bin

# The Unit Tests
.PHONY: test
test: CFLAGS += $(TARGET)
test: $(TESTS)
    sh ./tests/runtests.sh

valgrind:
    VALGRIND="valgrind --log-file=/tmp/valgrind-%p.log" $(MAKE)

# The Cleaner
clean:
    rm -rf build $(OBJECTS) $(TESTS)
    rm -f tests/tests.log
    find . -name "*.gc*" -exec rm {} \;
    rm -rf `find . -name "*.dSYM" -print`

# The Install
install: all
    install -d $(DESTDIR)/$(PREFIX)/lib/
    install $(TARGET) $(DESTDIR)/$(PREFIX)/lib/

# The Checker
BADFUNCS='[^_.>a-zA-Z0-9](str(n?cpy|n?cat|xfrm|n?dup|str|pbrk|tok|_)|stpn?cpy|a?sn?printf|byte_)'
check:
    @echo Files with potentially dangerous functions.
    @egrep $(BADFUNCS) $(SOURCES) || true

最后,项目树:

.
├── bin
├── build
│   ├── libds.a
│   └── libds.so
├── LICENSE
├── Makefile
├── README.md
├── src
│   └── libds
│       ├── twoll.c
│       ├── twoll.h
│       └── twoll.o
└── tests
    ├── runtests.sh
    ├── tester.h
    ├── tests.log
    └── twoll_tests.c

编辑:以下是make test的完整输出:

kroltan@kroltan ~/Projects/learncthehardway/ex32 $ make all
cc -g -O2 -Wall -Wextra -Isrc -rdynamic -std=c11  -fPIC   -c -o src/libds/twoll.o src/libds/twoll.c
ar rcs build/libds.a src/libds/twoll.o
ranlib build/libds.a
cc -shared -o build/libds.so src/libds/twoll.o
kroltan@kroltan ~/Projects/learncthehardway/ex32 $ make test
cc -g -O2 -Wall -Wextra -Isrc -rdynamic -DNDEBUG -std=c11  build/libds.a    tests/twoll_tests.c   -o tests/twoll_tests
/tmp/ccnOW9OX.o: In function `twoll_new_test':
/home/kroltan/Projects/learncthehardway/ex32/tests/twoll_tests.c:8: undefined reference to `twoll_new'
/tmp/ccnOW9OX.o: In function `twoll_del_test':
/home/kroltan/Projects/learncthehardway/ex32/tests/twoll_tests.c:13: undefined reference to `twoll_new'
/home/kroltan/Projects/learncthehardway/ex32/tests/twoll_tests.c:13: undefined reference to `twoll_del'
/tmp/ccnOW9OX.o: In function `twoll_push_pop_test':
/home/kroltan/Projects/learncthehardway/ex32/tests/twoll_tests.c:18: undefined reference to `twoll_new'
/home/kroltan/Projects/learncthehardway/ex32/tests/twoll_tests.c:18: undefined reference to `twoll_push'
/home/kroltan/Projects/learncthehardway/ex32/tests/twoll_tests.c:18: undefined reference to `twoll_push'
/home/kroltan/Projects/learncthehardway/ex32/tests/twoll_tests.c:18: undefined reference to `twoll_push'
/home/kroltan/Projects/learncthehardway/ex32/tests/twoll_tests.c:18: undefined reference to `twoll_pop'
/home/kroltan/Projects/learncthehardway/ex32/tests/twoll_tests.c:18: undefined reference to `twoll_pop'
/home/kroltan/Projects/learncthehardway/ex32/tests/twoll_tests.c:18: undefined reference to `twoll_pop'
collect2: error: ld returned 1 exit status
make: *** [tests/twoll_tests] Error 1

2 个答案:

答案 0 :(得分:3)

这部分编译器调用:

build/libds.a    tests/twoll_tests.c

很糟糕;你总是希望之后源文件库。可以这样想:

  1. 源文件创建对符号的引用
  2. 图书馆解决对符号的引用
  3. 在创建之前无法解析的内容,因此库应该是最后的。

答案 1 :(得分:0)

@unwind@Umamahesh P的帮助下,发现在调用编译器时必须在目标之后添加库。在互联网上进行一些额外的搜索之后,我发现库中正确的Make变量实际上是LDLIBS,而不是LIBS。我已更改变量用法,并将以下分配添加到我的test目标:

test: LDLIBS += $(TARGET)

只需这样,链接就成功了。