与静态库链接时未定义的引用,但与 src 编译时链接成功

Avi*_*vet 4 c++ makefile linker-errors

我正在尝试使用 Boost::Test 为该库创建一个 C 库和一个 C++ 测试程序。我在这个问题中发布的代码是我的代码的简化,它显示了完全相同的问题。请帮忙!

这是目录结构。 childlib是我正在尝试创建的库,并且test是测试程序。

> tree
.
`-- src
    |-- main
    |   |-- c
    |   |   `-- childlib.c
    |   |-- childlib.h
    |   `-- makefile
    `-- test
        |-- cpp
        |   `-- test.cpp
        `-- makefile

5 directories, 5 files
Run Code Online (Sandbox Code Playgroud)

我可以childlib成功地制作成一个静态库:

> cd src/main    
> make
gcc -c -fPIC -o c/childlib.o c/childlib.c
ar rcs libchildlib.a c/childlib.o
ranlib libchildlib.a
Run Code Online (Sandbox Code Playgroud)

但是我无法通过链接来制作我的测试程序:

> cd ../test/
> make
g++ -I. -I../main -Imy_boost_install_dir/include -c -std=c++11 -o cpp/test.o cpp/test.cpp
g++ -L../main -Lmy_boost_install_dir/lib -lchildlib -lboost_unit_test_framework -Wl,-rpath=my_boost_install_dir/lib -o test_childlib cpp/test.o 
cpp/test.o: In function `test_func1::test_method()':
test.cpp:(.text+0x15e7e): undefined reference to `childlib_func1()'
collect2: error: ld returned 1 exit status
make: *** [test_childlib] Error 1
Run Code Online (Sandbox Code Playgroud)

另一方面,如果我通过删除对静态库的引用并添加 childlib.c 作为源文件来手动运行编译,我可以成功地制作测试程序:

> g++  -Lmy_boost_install_dir/lib -lboost_unit_test_framework -Wl,-rpath=my_boost_install_dir/lib -o test_childlib cpp/test.o ../main/c/childlib.c 
> ./test_childlib 
Running 1 test case...

*** No errors detected
Run Code Online (Sandbox Code Playgroud)

这是各种源文件。测试.cpp:

#include <cstdlib>
#include <stdint.h>

#define BOOST_TEST_MODULE childlib test
#include <boost/test/unit_test.hpp>
#include <boost/test/included/unit_test.hpp>

#include "childlib.h"

BOOST_AUTO_TEST_CASE( test_func1 ) {
  childlib_func1();

  BOOST_CHECK(true);
}
Run Code Online (Sandbox Code Playgroud)

childlib.h:

#ifndef CHILDLIB_H_
#define CHILDLIB_H_

void childlib_func1();

#endif /* CHILDLIB_H_ */
Run Code Online (Sandbox Code Playgroud)

最后是 childlib.c:

#include <stdint.h>

void childlib_func1() {
  return;
}
Run Code Online (Sandbox Code Playgroud)

下面是两个makefile。

childlibmakefile:最终我还想创建一个动态库,但现在它被注释掉了make all

# childlib

CC = gcc

SRCS             = $(wildcard c/*.c)
OBJS             = $(SRCS:.c=.o)
HDRS             = $(wildcard *.h)
MODULE_BASE_NAME = childlib
MODULE_LIB_A     = lib$(MODULE_BASE_NAME).a
MODULE_LIB_SO    = lib$(MODULE_BASE_NAME).so
INCLUDE_DIRS     = .
INCLUDE          = $(addprefix -I,$(INCLUDE_DIRS))
CFLAGS           = -c -fPIC


all: $(MODULE_LIB_A) # $(MODULE_LIB_SO)

$(MODULE_LIB_A): $(OBJS)
    ar rcs $@ $^
    ranlib $@

$(MODULE_LIB_SO): $(OBJS)
    $(CC) -shared -o $@ $^  

.c.o:
    $(CC) $(CFLAGS) -o $@ $^

clean:
    -rm -f $(MODULE_LIB_A) $(MODULE_LIB_SO) $(OBJS)
    -find . -name '*~' -delete
Run Code Online (Sandbox Code Playgroud)

这是测试工具makefile:

# test

CC        = g++

SRCS             = $(wildcard cpp/*.cpp)
OBJS             = $(SRCS:.cpp=.o)
MODULE_EXE       = test_childlib

MAIN_DIR         = ../main

BOOST_DIR        = my_boost_install_dir
BOOST_INC_DIR    = $(BOOST_DIR)/include
BOOST_LIB_DIR    = $(BOOST_DIR)/lib
BOOST_LIBS       = boost_unit_test_framework
INCLUDE          = $(addprefix -I,. $(MAIN_DIR) $(BOOST_INC_DIR))
LIB_DIRS         = $(addprefix -L,$(MAIN_DIR) $(BOOST_LIB_DIR))
LIBS             = $(addprefix -l,childlib $(BOOST_LIBS))
LINKER_OPTS      = -Wl,-rpath=$(BOOST_LIB_DIR)

CFLAGS           = -c -std=c++11


all: test

test: $(MODULE_EXE)
    ./$(MODULE_EXE)


$(MODULE_EXE): $(OBJS)
    $(CC) $(LIB_DIRS) $(LIBS) $(LINKER_OPTS) -o $@ $^ 

.cpp.o:
    $(CC) $(INCLUDE) $(CFLAGS) -o $@ $^

clean:
    -rm -f $(MODULE_EXE) $(OBJS)
    -find . -name '*~' -delete
Run Code Online (Sandbox Code Playgroud)

我正在使用 gcc & g++ 4.8.1。我也在使用用 gcc 4.7.2 编译的 boost 1.54.0。

似乎我只需要在我的测试 makefile 中为 g++ 提供正确的选项,但我不知道它们是什么。有人可以帮我将childlib库与我的测试程序链接吗?

Iva*_*iev 6

我还没有看到你的所有代码,但问题很可能是由静态链接的工作方式引起的(http://eli.thegreenplace.net/2013/07/09/library-order-in-static-linking/)。

尝试改变库的顺序,特别是,尝试改变这个:

$(MODULE_EXE): $(OBJS)
  $(CC) $(LIB_DIRS) $(LIBS) $(LINKER_OPTS) -o $@ $^ 
Run Code Online (Sandbox Code Playgroud)

进入这个:

$(MODULE_EXE): $(OBJS)
  $(CC) $(LIB_DIRS) $(LINKER_OPTS) -o $@ $^ $(LIBS)
Run Code Online (Sandbox Code Playgroud)