用unitests构建我自己的库抱怨未定义的引用 [英] Building my own library with unitests complains about undefined reference

查看:82
本文介绍了用unitests构建我自己的库抱怨未定义的引用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在建立一个具有一些统一设施的简单图书馆.但是,make抱怨在建立unitest时存在未定义的引用.我已经发布了所有代码和makefile.这是什么原因呢?

I am building a simple library with some unitest facilities. However, the make complains that there is undefined reference while building the unitest. I have posted all the code and makefile. What is the reason for this?

文件层次结构:

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

Makefile:

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

In /src dirctory, I have two files ex30.c, libex30.c, and 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:

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:

In /tests, I have libex30_tests.c, minunit.h, and dbg.h:

libex30_tests.c:

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);

minunit.h

minunit.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

runtests.sh:

runtests.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 ""

这是我化妆后得到的:

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链接.

Those symbols are exported by libdl.so. Link with -ldl.

这篇关于用unitests构建我自己的库抱怨未定义的引用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆