gpt4 book ai didi

c - 使用 unitests 构建我自己的库提示 undefined reference

转载 作者:太空宇宙 更新时间:2023-11-04 08:12:15 25 4
gpt4 key购买 nike

我正在构建一个带有一些 unitest 设施的简单图书馆。但是,make 提示在构建 unitest 时存在 undefined reference 。我已经发布了所有代码和 makefile。这是什么原因?

文件层次结构:

/bin
/build
Makefile
/src
dbg.h
ex30.c
libex30.c
/tests
dbg.h
libex30_tests.c
minuint.h
runtests.sh

生成文件:

CFLAGS=-g -O2 -Wall -Wextra -Isrc -rdynamic -DNDEBUG $(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/libYOUR_LIBRARY.a
#SO_TARGET=$(patsubst %.a,%.so,$(TARGET))

# The Target Build
#all: $(TARGET) $(SO_TARGET) tests
all: $(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

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

在/src 目录下,我有两个文件 ex30.c、libex30.c 和 dbg.h

ex30.c:

#include <stdio.h>
#include "dbg.h"
#include <dlfcn.h>

typedef int (*lib_function)(const char *data);


int main(int argc, char *argv[])
{
int rc = 0;
check(argc == 4, "USAGE: ex30 libex30.so function data");

char *lib_file = argv[1];
char *func_to_run = argv[2];
char *data = argv[3];

void *lib = dlopen(lib_file, RTLD_NOW);
check(lib != NULL, "Failed to open the library %s: %s", lib_file, dlerror());

lib_function func = dlsym(lib, func_to_run);
check(func != NULL, "Did not find %s function in the library %s: %s", func_to_run, lib_file, dlerror());

rc = func(data);
check(rc == 0, "Function %s return %d for data: %s", func_to_run, rc, data);

rc = dlclose(lib);
check(rc == 0, "Failed to close %s", lib_file);

return 0;

error:
return 1;
}

libex30.c:

#include <stdio.h>
#include <ctype.h>
#include "dbg.h"


int print_a_message(const char *msg)
{
printf("A STRING: %s\n", msg);
return 0;
}

int uppercase(const char *msg)
{
int i = 0;
// BUG: \0 termination problems
for(i = 0; msg[i] != '\0'; i++) {
printf("%c", toupper(msg[i]));
}

printf("\n");
return 0;
}

int lowercase(const char *msg)
{
int i = 0;

// BUG: \0 termination problems
for(i = 0; msg[i] != '\0'; i++) {
printf("%c", tolower(msg[i]));
}

printf("\n");
return 0;
}

int fail_on_purpose(const char *msg)
{
return 1;
}

dbg.h:

#ifndef __dbg_h__
#define __dbg_h__

#include <stdio.h>
#include <errno.h>
#include <string.h>

#ifdef NDEBUG
#define debug(M, ...)
#else
#define debug(M, ...) fprintf(stderr, "DEBUG %s:%d:%s: " M "\n", __FILE__, __LINE__, __func__, ##__VA_ARGS__)
#endif

#define clean_errno() (errno == 0 ? "None" : strerror(errno))

#define log_err(M, ...) fprintf(stderr, "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__)

#define log_warn(M, ...) fprintf(stderr, "[WARN] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__)

#define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%d) " M "\n", __FILE__, __LINE__, ##__VA_ARGS__)

#define check(A, M, ...) if(!(A)) {log_err(M, ##__VA_ARGS__); errno=0; goto error;}

#define sentinel(M, ...) {log_err(M, ##__VA_ARGS__); errno=0; goto error;}

#define check_mem(A) check((A), "Out of memory.")

#define check_debug(A, M, ...) if(!(A)){debug(M, ##__VA_ARGS__); errno=0; goto error;}

#endif

在/tests 中,我有 libex30_tests.c、minunit.h 和 dbg.h:

libex30_tests.c:

#include "minunit.h"

char *test_dlopen()
{

return NULL;
}

char *test_functions()
{

return NULL;
}

char *test_failures()
{

return NULL;
}

char *test_dlclose()
{

return NULL;
}

char *all_tests() {
mu_suite_start();

mu_run_test(test_dlopen);
mu_run_test(test_functions);
mu_run_test(test_failures);
mu_run_test(test_dlclose);

return NULL;
}

RUN_TESTS(all_tests);

最小单位.h

#undef NDEBUG
#ifndef _minunit_h
#define _minunit_h

#include <stdio.h>
#include "dbg.h"
#include <stdlib.h>

#define mu_suite_start() char *message = NULL

#define mu_assert(test, message) if (!(test)) { log_err(message); return message; }
#define mu_run_test(test) debug("\n-----%s", " " #test); \
message = test(); tests_run++; if (message) return message;

#define RUN_TESTS(name) int main(int argc, char *argv[]) {\
argc = 1; \
debug("----- RUNNING: %s", argv[0]);\
printf("----\nRUNNING: %s\n", argv[0]);\
char *result = name();\
if (result != 0) {\
printf("FAILED: %s\n", result);\
}\
else {\
printf("ALL TESTS PASSED\n");\
}\
printf("Tests run: %d\n", tests_run);\
exit(result != 0);\
}


int tests_run;

#endif

运行测试.sh:

echo "Running unit tests:"

for i in tests/*_tests
do
if test -f $i
then
if $VALGRIND ./$i 2>> tests/tests.log
then
echo $i PASS
else
echo "ERROR in test $i: here's tests/tests.log"
echo "------"
tail tests/tests.log
exit 1
fi
fi
done

echo ""

这是我在 make 之后得到的:

cc -g -O2 -Wall -Wextra -Isrc -rdynamic -DNDEBUG  build/libYOUR_LIBRARY.a    tests/libex30_tests.c   -o tests/libex30_tests
In file included from tests/libex30_tests.c:1:0:
tests/libex30_tests.c: In function ‘main’:
tests/minunit.h:15:38: warning: parameter ‘argc’ set but not used [-Wunused-but-set-parameter]
#define RUN_TESTS(name) int main(int argc, char *argv[]) {\
^
tests/libex30_tests.c:38:1: note: in expansion of macro ‘RUN_TESTS’
RUN_TESTS(all_tests);
^
/tmp/ccqde9jD.o: In function `main':
/home/rex/rex/projects/programming/c/learn_hard_way/ex30/tests/libex30_tests.c:38: multiple definition of `main'
build/libYOUR_LIBRARY.a(ex30.o):/home/rex/rex/projects/programming/c/learn_hard_way/ex30/src/ex30.c:9: first defined here
build/libYOUR_LIBRARY.a(ex30.o): In function `main':
ex30.c:(.text.startup+0x85): undefined reference to `dlopen'
ex30.c:(.text.startup+0x9c): undefined reference to `dlsym'
ex30.c:(.text.startup+0x120): undefined reference to `dlclose'
ex30.c:(.text.startup+0x188): undefined reference to `dlerror'
ex30.c:(.text.startup+0x1f0): undefined reference to `dlerror'
collect2: error: ld returned 1 exit status
make: *** [tests/libex30_tests] Error 1

最佳答案

这些符号由 libdl.so 导出。与 -ldl 链接。

关于c - 使用 unitests 构建我自己的库提示 undefined reference ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38442205/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com