我无法尝试从某个编程书中编译双链表项目。该项目附有一些有助于测试的图书馆。
以下是测试
#include "minunit.h"
#include <lcthw/list.h>
#include <assert.h>
static List *list = NULL;
char *test1 = "test1 data";
char *test2 = "test2 data";
char *test3 = "test3 data";
char *test_create()
{
list = List_create();
mu_assert(list != NULL, "Failed to create list.");
return NULL;
}
char *test_destroy()
{
List_clear_destroy(list);
return NULL;
}
char *test_push_pop()
{
List_push(list, test1);
mu_assert(List_last(list) == test1, "Wrong last value.");
List_push(list, test2);
mu_assert(list_last(list) == test2, "Wrong last value");
List_push(list, test3);
mu_assert(List_last(list) == test3, "Wrong last value.");
mu_assert(List_count(list) == 3, "Wrong count on push.");
char *val = List_pop(list);
mu_assert(val == test3, "Wrong value on pop.");
val = List_pop(list);
mu_assert(val == test2, "Wrong value on pop.");
val = List_pop(list);
mu_assert(val == test1, "Wrong value on pop.");
mu_assert(List_count(list) == 0, "Wrong count after pop.");
return NULL;
}
char *test_unshift()
{
List_unshift(list, test1);
mu_assert(List_first(list) == test1, "Wrong first value.");
List_unshift(list, test2);
mu_assert(List_first(list) == test2, "Wrong first value.");
List_unshift(list, test3);
mu_assert(List_first(list) == test3, "Wrong last value.");
mu_assert(List_count(list) == 3, "Wrong count on unshift.");
return NULL;
}
char *test_remove()
{
// we only need to test the middle remove case since push/shift
// already tests the other cases
char *val = List_remove(list, list->first->next);
mu_assert(val == test2, "Wrong removed element.");
mu_assert(List_count(list) == 2, "Wrong count after remove.");
mu_assert(List_first(list) == test3, "Wrong first after remove");
mu_assert(List_last(list) == test1, "Wrong last after remove.");
return NULL;
}
char *test_shift()
{
mu_assert(List_count(list) != 0, "Wrong count before shift.");
char *val = List_shift(list);
mu_assert(val == test3, "Wrong value on shift.");
val = List_shift(list);
mu_assert(val == test1, "Wrong value on shift.");
mu_assert(List_count(list) == 0, "Wrong count after shift.");
return NULL;
}
char *all_tests()
{
mu_suite_start();
mu_run_test(test_create);
mu_run_test(test_push_pop);
mu_run_test(test_unshift);
mu_run_test(test_remove);
mu_run_test(test_shift);
mu_run_test(test_destroy);
return NULL;
}
RUN_TESTS(all_tests);
这也是我用来编译整个项目的Makefile:
CFLAGS=-g -O2 -Wall -Wextra -Isrc -rdynamic -DNDEBUG $(OPTFLAGS)
#LDLIBS=-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/liblcthw.a
SO_TARGET=$(patsubst %.a,%.so,$(TARGET))
# The Target Build
all: $(TARGET) $(SO_TARGET) tests
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: tests
tests: CFLAGS += $(TARGET)
tests: $(TESTS)
sh ./tests/runtests.sh
# 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
check:
@echo Files with potentially dangerous function.
@egrep '[^_.>a-zA-Z0-9](str(n?cpy|n?cat|xfrm|n?dup|str|pbrk|tok|_)\
|stpn?cpy|a?sn?printf|byte_)' $(SOURCES) || true
当我跑步时,我得到了这个:
cc -g -O2 -Wall -Wextra -Isrc -rdynamic -DNDEBUG -fPIC -c -o src/lcthw/list.o src/lcthw/list.c
ar rcs build/liblcthw.a src/lcthw/list.o
ranlib build/liblcthw.a
cc -shared -o build/liblcthw.so src/lcthw/list.o
cc -g -O2 -Wall -Wextra -Isrc -rdynamic -DNDEBUG build/liblcthw.a tests/list_tests.c -o tests/list_tests
In file included from tests/list_tests.c:1:0:
tests/list_tests.c: In function ‘main’:
tests/minunit.h:16:38: warning: parameter ‘argc’ set but not used [-Wunused-but-set-parameter]
#define RUN_TESTS(name) int main(int argc, char *argv[]) {\
^
tests/list_tests.c:107:1: note: in expansion of macro ‘RUN_TESTS’
RUN_TESTS(all_tests);
^
/tmp/ccFfwxRB.o: In function `test_create':
/home/pxcel/liblcthw/tests/list_tests.c:12: undefined reference to `List_create'
/tmp/ccFfwxRB.o: In function `test_destroy':
/home/pxcel/liblcthw/tests/list_tests.c:20: undefined reference to `List_clear_destroy'
/tmp/ccFfwxRB.o: In function `test_push_pop':
/home/pxcel/liblcthw/tests/list_tests.c:27: undefined reference to `List_push'
/home/pxcel/liblcthw/tests/list_tests.c:30: undefined reference to `List_push'
/home/pxcel/liblcthw/tests/list_tests.c:33: undefined reference to `List_push'
/home/pxcel/liblcthw/tests/list_tests.c:37: undefined reference to `List_pop'
/home/pxcel/liblcthw/tests/list_tests.c:40: undefined reference to `List_pop'
/home/pxcel/liblcthw/tests/list_tests.c:43: undefined reference to `List_pop'
/tmp/ccFfwxRB.o: In function `test_unshift':
/home/pxcel/liblcthw/tests/list_tests.c:52: undefined reference to `List_unshift'
/home/pxcel/liblcthw/tests/list_tests.c:55: undefined reference to `List_unshift'
/home/pxcel/liblcthw/tests/list_tests.c:58: undefined reference to `List_unshift'
/tmp/ccFfwxRB.o: In function `test_remove':
/home/pxcel/liblcthw/tests/list_tests.c:70: undefined reference to `List_remove'
/tmp/ccFfwxRB.o: In function `test_shift':
/home/pxcel/liblcthw/tests/list_tests.c:83: undefined reference to `List_shift'
/home/pxcel/liblcthw/tests/list_tests.c:86: undefined reference to `List_shift'
/tmp/ccFfwxRB.o: In function `test_destroy':
/home/pxcel/liblcthw/tests/list_tests.c:20: undefined reference to `List_clear_destroy'
collect2: error: ld returned 1 exit status
<builtin>: recipe for target 'tests/list_tests' failed
make: *** [tests/list_tests] Error 1
我用谷歌搜索了我得到的错误,到目前为止我得到的答案是建议检查我是否有拼写错误或者我是否没有正确链接文件。可能是后者吗?
答案 0 :(得分:3)
你有:
cc … build/liblcthw.a tests/list_tests.c -o tests/list_tests
您必须在(源或)目标文件之后列出库 - 尤其是带有.a
后缀的静态库:
cc … tests/list_tests.c build/liblcthw.a -o tests/list_tests
是的,库和文件选项的顺序真的很重要! (在某些系统上,您有时会在目标文件之前列出共享库。在所有系统上,在目标文件之后列出库始终。做什么有效!)一些选项更具移动性;例如,-o tests/list_tests
选项可以在命令行中更早出现而没有问题。但是库(-l…
选项,以及对库的简单引用,如本例所示)应该出现在目标文件之后的命令行上(如果你不将源代码编译成对象,则应该出现在源文件中)链接前的文件)。