为什么要将这个练习分开
我之前的笔记都是聚合在一篇文章的,但是因为后面几个问题比较难,而且会遇见各种各样的环境问题,所以这里将练习笔记分开,同时记录一下按照教程存在的一些问题。
简介
双向链表是一种比较重要的数据结构,在大部分学习C语言的教程中都有介绍,由于我是直接跳到32问的,所以无法直接按照教程内的步骤操作。这里我将介绍我完成这个工作的步骤。
构建框架
在《笨办法学C》中,作者搭建了一个简易的工程框架,将文件分布在了./bin、./build、./src、./tests等文件夹,并使用了在之前的part创建的minunit项目,对链表进行了简单的测试。
创建文件夹
在当前的工程目录下创建文件夹
mkdir bin/ build/ src/ tests/
cd src
mkdir lcthw
分别创建下述文件
cd lcthw
touch dbg.h list.c list.h
cd ../../tests/
touch dbg.h list_tesst.c minunit.h runtests.sh
cd ..
touch LICENSE Makefile
编写代码
我这里主要是对makefile做出了调整。由于在使用git时,为了方便gitignore文件识别编译得到的库文件和可执行文件,所以我们给可执行文件加上.out后缀。
在某些环境下,库文件必须写在.c文件的后面,cc在.c文件中读取到了函数后,会将这些函数名记下来,然后在后面的库文件中寻找函数定义。如果库文件在前,cc在读取到库文件后,会认为没有c文件使用这些函数,就不会记下这些函数,但是后面又在处理c文件时找不到。如下
cc -g -O2 -Wall -Wextra -Isrc -rdynamic -DNDEBUG build/libYOUR_LIBRARY.a tests/list_tests.c -ldl -o tests/list_tests.out
/usr/bin/ld: /tmp/cchVG058.o: in function `test_create':
/home/fengqi/Documents/GitRepos/ysyx/pre-study_phase/2024_12_18/Q32/tests/list_tests.c:12: undefined reference to `List_create'
/usr/bin/ld: /tmp/cchVG058.o: in function `test_destroy':
/home/fengqi/Documents/GitRepos/ysyx/pre-study_phase/2024_12_18/Q32/tests/list_tests.c:20: undefined reference to `List_clear_destroy'
/usr/bin/ld: /tmp/cchVG058.o: in function `test_push_pop':
/home/fengqi/Documents/GitRepos/ysyx/pre-study_phase/2024_12_18/Q32/tests/list_tests.c:27: undefined reference to `List_push'
/usr/bin/ld: /home/fengqi/Documents/GitRepos/ysyx/pre-study_phase/2024_12_18/Q32/tests/list_tests.c:30: undefined reference to `List_push'
/usr/bin/ld: /home/fengqi/Documents/GitRepos/ysyx/pre-study_phase/2024_12_18/Q32/tests/list_tests.c:33: undefined reference to `List_push'
/usr/bin/ld: /home/fengqi/Documents/GitRepos/ysyx/pre-study_phase/2024_12_18/Q32/tests/list_tests.c:37: undefined reference to `List_pop'
/usr/bin/ld: /home/fengqi/Documents/GitRepos/ysyx/pre-study_phase/2024_12_18/Q32/tests/list_tests.c:40: undefined reference to `List_pop'
/usr/bin/ld: /home/fengqi/Documents/GitRepos/ysyx/pre-study_phase/2024_12_18/Q32/tests/list_tests.c:43: undefined reference to `List_pop'
/usr/bin/ld: /tmp/cchVG058.o: in function `test_unshift':
/home/fengqi/Documents/GitRepos/ysyx/pre-study_phase/2024_12_18/Q32/tests/list_tests.c:52: undefined reference to `List_unshift'
/usr/bin/ld: /home/fengqi/Documents/GitRepos/ysyx/pre-study_phase/2024_12_18/Q32/tests/list_tests.c:55: undefined reference to `List_unshift'
/usr/bin/ld: /home/fengqi/Documents/GitRepos/ysyx/pre-study_phase/2024_12_18/Q32/tests/list_tests.c:58: undefined reference to `List_unshift'
/usr/bin/ld: /tmp/cchVG058.o: in function `test_remove':
/home/fengqi/Documents/GitRepos/ysyx/pre-study_phase/2024_12_18/Q32/tests/list_tests.c:70: undefined reference to `List_remove'
/usr/bin/ld: /tmp/cchVG058.o: in function `test_shift':
/home/fengqi/Documents/GitRepos/ysyx/pre-study_phase/2024_12_18/Q32/tests/list_tests.c:83: undefined reference to `List_shift'
/usr/bin/ld: /home/fengqi/Documents/GitRepos/ysyx/pre-study_phase/2024_12_18/Q32/tests/list_tests.c:86: undefined reference to `List_shift'
/usr/bin/ld: /tmp/cchVG058.o: in function `test_destroy':
/home/fengqi/Documents/GitRepos/ysyx/pre-study_phase/2024_12_18/Q32/tests/list_tests.c:20: undefined reference to `List_clear_destroy'
collect2: error: ld returned 1 exit status
所以我们调整原有的makefile文件,增添对tests的单独处理,如下
.PHONY: tests
$(TESTS): %: %.c $(TARGET)
$(CC) $(CFLAGS) $< -o $@.out $(TARGET) $(LIBS)
tests: $(TESTS)
sh ./tests/runtests.sh
同时我们也要编写自己的测试脚本runtests.sh
#!/bin/sh
SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
cd "$SCRIPT_DIR"
./list_tests.out
测试
运行make,得到如下的输出
make clean
rm -rf build src/lcthw/list.o tests/list_tests
rm -f tests/tests.log
find . -name "*.gc*" -exec rm {} \;
find . -name "*.out*" -exec rm {} \;
rm -rf `find . -name "*.dSYM" -print`
make
cc -g -O2 -Wall -Wextra -Isrc -rdynamic -DNDEBUG -fPIC -c -o src/lcthw/list.o src/lcthw/list.c
ar rcs build/libYOUR_LIBRARY.a src/lcthw/list.o
ranlib build/libYOUR_LIBRARY.a
cc -shared -o build/libYOUR_LIBRARY.so src/lcthw/list.o
cc -g -O2 -Wall -Wextra -Isrc -rdynamic -DNDEBUG tests/list_tests.c -o tests/list_tests.out build/libYOUR_LIBRARY.a -ldl
sh ./tests/runtests.sh
DEBUG tests/list_tests.c:107:----- RUNNING: ./list_tests.out
----
RUNNING: ./list_tests.out
DEBUG tests/list_tests.c:97:
----- test_create
DEBUG tests/list_tests.c:98:
----- test_push_pop
DEBUG tests/list_tests.c:99:
----- test_unshift
DEBUG tests/list_tests.c:100:
----- test_remove
DEBUG tests/list_tests.c:101:
----- test_shift
DEBUG tests/list_tests.c:102:
----- test_destroy
ALL TESTS PASSED
Tests run: 6
工程文件
最后附上本文的工程文件
Comments 1 条评论
刚好今天也遇到了这个问题,在链接命令中给出所依赖的库时,需要注意库之间的依赖顺序,依赖其他库的库一定要放到被依赖库的前面,这样才能真正避免undefined reference的错误,完成编译链接。
备注:在MAC上可以正常编译通过。