我正在按照“学习艰难的方式”电子书(?),并达到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
答案 0 :(得分:3)
这部分编译器调用:
build/libds.a tests/twoll_tests.c
很糟糕;你总是希望之后源文件库。可以这样想:
在创建之前无法解析的内容,因此库应该是最后的。
答案 1 :(得分:0)
在@unwind和@Umamahesh P的帮助下,发现在调用编译器时必须在目标之后添加库。在互联网上进行一些额外的搜索之后,我发现库中正确的Make变量实际上是LDLIBS
,而不是LIBS
。我已更改变量用法,并将以下分配添加到我的test
目标:
test: LDLIBS += $(TARGET)
只需这样,链接就成功了。