неопределенная ссылка на при связывании с общей библиотекой

Я пытаюсь написать небольшую программу, связывающуюся с общей библиотекой (* .so). Но когда я пытаюсь скомпилировать программу, я получаю сообщение об ошибке «неопределенная ссылка» на «функцию».

Содержание программного файла.

user@ubuntu:~/Perforce/user_ubuntu_3105/wp/eng/main/src/libfc/37D03B6/bin$ cat test.cpp 
#include <iostream>
#include <vector>
#include <memory>
#include "InfoModel.h"

int main() 
{
    libfc::InfoModel & model = libfc::InfoModel::instance();
    return 0;
}

Компилируя это, я получаю сообщение об ошибке "неопределенная ссылка на"

user@ubuntu:~/Perforce/user_ubuntu_3105/wp/eng/main/src/libfc/37D03B6/bin$ g++ -Wall -W -std=c++0x test.cpp -L. -lfc -o rst
test.cpp: In function ‘int main()’:
test.cpp:9:21: warning: unused variable ‘model’ [-Wunused-variable]
libfc::InfoModel & model = libfc::InfoModel::instance();
                 ^
/tmp/ccFtLDxc.o: In function `main':
test.cpp:(.text+0x9): undefined reference to `libfc::InfoModel::instance()'
collect2: error: ld returned 1 exit status

Но когда я смотрю на символы в файле .so, я вижу там символ.

user@ubuntu:~/Perforce/user_ubuntu_3105/wp/eng/main/src/libfc/37D03B6/bin$ nm --demangle libfc.so | grep InfoModel 
0000000000007e40 t _GLOBAL__sub_I_InfoModel.cpp
00000000002464a0 b guard variable for libfc::InfoModel::instance()::instance_
0000000000010260 t libfc::InfoModel::add_unknown(unsigned int, unsigned short, unsigned short)
0000000000010520 t libfc::InfoModel::registerIEType(libfc::IEType const*)
000000000000f550 t libfc::InfoModel::add(libfc::InfoElement const&)
0000000000012980 t libfc::InfoModel::add(std::string const&)
0000000000010a60 t libfc::InfoModel::instance()
00000000000106f0 t libfc::InfoModel::initTypes()
00000000000108f0 t libfc::InfoModel::InfoModel()
00000000000108f0 t libfc::InfoModel::InfoModel()
0000000000027ae0 t libfc::InfoModel::~InfoModel()
0000000000027ae0 t libfc::InfoModel::~InfoModel()
0000000000010b00 t libfc::InfoModel::parseIESpec(std::string const&) const
000000000000ee80 t libfc::InfoModel::lookupIEType(unsigned int) const
000000000000ed40 t libfc::InfoModel::lookupIEType(std::string const&) const
000000000000ef20 t libfc::InfoModel::dump(std::ostream&) const
000000000000f0c0 t libfc::InfoModel::lookupIE(unsigned int, unsigned short, unsigned short) const
000000000000f1b0 t libfc::InfoModel::lookupIE(libfc::InfoElement const&) const
0000000000012840 t libfc::InfoModel::lookupIE(std::string const&) const
000000000000f410 t libfc::InfoModel::lookupIE2(unsigned int, std::string const&, unsigned short, unsigned short) const
00000000002463a0 b libfc::InfoModel::instance()::instance_

Я тоже так делал.

user@ubuntu:~/Perforce/user_ubuntu_3105/wp/eng/main/src/libfc/37D03B6/bin$ readelf -s libfc.so | grep FILE 
34: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS EncodePlan.cpp
43: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS InfoElement.cpp
49: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS FileExportDestination.cpp
53: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS IETemplate.cpp
58: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS IEType.cpp
104: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS InfoModel.cpp
113: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS libfc.cpp
118: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS PlacementExporter2.cpp
124: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS PlacementTemplate.cpp
129: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS TemplateState.cpp
135: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS test.cpp
141: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS UdpSocketExportDestinatio
149: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
158: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS BasicOctetArray.cpp
159: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS Exception.cpp
160: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS ExportError.cpp
161: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS FormatError.cpp
162: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS IESpecError.cpp
163: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS error_code.cpp
187: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
190: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS

Обновление: файл make для создания этой разделяемой библиотеки

PLUGIN          = libfc
OUTPUT_DIR      = bin
OUTPUT          = $(OUTPUT_DIR)/$(PLUGIN).so
PLUG_SRC        = src
EXCEPTION_SRC   = src/exceptions
CPP             = g++
THIRD_PARTY_DIR = ../../../../../third-party
BOOST_DIR       = $(THIRD_PARTY_DIR)/boost/1.66.0
G3LOG_DIR       = $(THIRD_PARTY_DIR)/g3log/2017-07-18_g3log
FLAGS           = -c -std=c++0x -fvisibility-inlines-hidden -pthread \
              -fPIC -fvisibility=hidden -fno-omit-frame-pointer -fpermissive 
MACROS          = -D_libfc_HAVE_NIXIO -U_libfc_HAVE_LOG4CPLUS_ -U_libfc_HAVE_WANDIO_
INCLUDES        = -I$(PLUG_SRC) \
              -I$(EXCEPTION_SRC) \
              -I$(BOOST_DIR) \
              -I$(G3LOG_DIR)/src \
              -I$(G3LOG_DIR)/include
LFLAGS          = -shared -lpthread -L$(G3LOG_DIR)/build -lg3logger
CPPFLAGS     = $(FLAGS) $(MACROS) $(INCLUDES)  
LDFLAGS      = $(LFLAGS)
ifeq ($(BUILD),DEBUG)
CPPFLAGS += -ggdb3 -O0 
else
CPPFLAGS += -g -Wall -O2 -D NDEBUG
LDFLAGS += -flto 
endif

# compile static boost lib as
# ./bjam --toolset=gcc address-model=64 cxxflags=-fPIC cflags=-fPIC 
variant=release threading=multi link=static --with-system stage
BOOST_LIBS      = $(BOOST_DIR)/stage/lib/libboost_system.a
OBJ_DIR         = obj
PLUG_OBJS       = $(patsubst %.cpp,$(OBJ_DIR)/%.o,$(subst 
$(PLUG_SRC)/,,$(wildcard $(PLUG_SRC)/*.cpp)))
FRAME_OBJS      = $(patsubst %.cpp,$(OBJ_DIR)/%.o,$(subst 
$(EXCEPTION_SRC)/,,$(wildcard $(EXCEPTION_SRC)/*.cpp)))
VPATH           = $(PLUG_SRC) $(EXCEPTION_SRC)

all: $(PLUGIN)
$(PLUG_OBJS): $(OBJ_DIR)/%.o: %.cpp
   $(CPP) $(CPPFLAGS) -o $@ $<
$(FRAME_OBJS): $(OBJ_DIR)/%.o: %.cpp
   $(CPP) $(CPPFLAGS) -o $@ $<
$(PLUG_OBJS) $(FRAME_OBJS): | $(OBJ_DIR)
$(OBJ_DIR):
   mkdir $(OBJ_DIR)
$(OUTPUT): | $(OUTPUT_DIR)
$(OUTPUT_DIR):
   mkdir $(OUTPUT_DIR)
$(PLUGIN): $(PLUG_OBJS) $(FRAME_OBJS) $(OUTPUT)
   $(CPP) $(LDFLAGS) -o $(OUTPUT)  $(PLUG_OBJS) $(FRAME_OBJS) $(BOOST_LIBS)

.PHONY: clean
clean:
   rm -f $(PLUG_OBJS) $(FRAME_OBJS) $(OUTPUT)
   rm -rf $(OBJ_DIR)
   rm -rf $(OUTPUT_DIR)

И на выходе make

user@ubuntu:~/Perforce/sselvam_ubuntu_3105/wp/eng/main/src/libfc/37D03B6$ make all 
mkdir obj
g++ -c -std=c++0x -fvisibility-inlines-hidden -pthread -fPIC -fvisibility=hidden -fno-omit-frame-pointer -fpermissive  -D_libfc_HAVE_NIXIO -U_libfc_HAVE_LOG4CPLUS_ -U_libfc_HAVE_WANDIO_ -Isrc -Isrc/exceptions -I../../../../../third-party/boost/1.66.0 -I../../../../../third-party/g3log/2017-07-18_g3log/src -I../../../../../third-party/g3log/2017-07-18_g3log/include -g -Wall -O2 -D NDEBUG -o obj/BasicOctetArray.o src/BasicOctetArray.cpp
g++ -c -std=c++0x -fvisibility-inlines-hidden -pthread -fPIC -fvisibility=hidden -fno-omit-frame-pointer -fpermissive  -D_libfc_HAVE_NIXIO -U_libfc_HAVE_LOG4CPLUS_ -U_libfc_HAVE_WANDIO_ -Isrc -Isrc/exceptions -I../../../../../third-party/boost/1.66.0 -I../../../../../third-party/g3log/2017-07-18_g3log/src -I../../../../../third-party/g3log/2017-07-18_g3log/include -g -Wall -O2 -D NDEBUG -o obj/EncodePlan.o src/EncodePlan.cpp
src/EncodePlan.cpp: In constructor ‘libfc::EncodePlan2::EncodePlan2(const libfc::PlacementTemplate*)’:
src/EncodePlan.cpp:90:9: warning: unused variable ‘ie_present’ [-Wunused-variable]
bool ie_present
     ^
g++ -c -std=c++0x -fvisibility-inlines-hidden -pthread -fPIC -fvisibility=hidden -fno-omit-frame-pointer -fpermissive  -D_libfc_HAVE_NIXIO -U_libfc_HAVE_LOG4CPLUS_ -U_libfc_HAVE_WANDIO_ -Isrc -Isrc/exceptions -I../../../../../third-party/boost/1.66.0 -I../../../../../third-party/g3log/2017-07-18_g3log/src -I../../../../../third-party/g3log/2017-07-18_g3log/include -g -Wall -O2 -D NDEBUG -o obj/FileExportDestination.o src/FileExportDestination.cpp
g++ -c -std=c++0x -fvisibility-inlines-hidden -pthread -fPIC -fvisibility=hidden -fno-omit-frame-pointer -fpermissive  -D_libfc_HAVE_NIXIO -U_libfc_HAVE_LOG4CPLUS_ -U_libfc_HAVE_WANDIO_ -Isrc -Isrc/exceptions -I../../../../../third-party/boost/1.66.0 -I../../../../../third-party/g3log/2017-07-18_g3log/src -I../../../../../third-party/g3log/2017-07-18_g3log/include -g -Wall -O2 -D NDEBUG -o obj/IETemplate.o src/IETemplate.cpp
 g++ -c -std=c++0x -fvisibility-inlines-hidden -pthread -fPIC -fvisibility=hidden -fno-omit-frame-pointer -fpermissive  -D_libfc_HAVE_NIXIO -U_libfc_HAVE_LOG4CPLUS_ -U_libfc_HAVE_WANDIO_ -Isrc -Isrc/exceptions -I../../../../../third-party/boost/1.66.0 -I../../../../../third-party/g3log/2017-07-18_g3log/src -I../../../../../third-party/g3log/2017-07-18_g3log/include -g -Wall -O2 -D NDEBUG -o obj/IEType.o src/IEType.cpp
 g++ -c -std=c++0x -fvisibility-inlines-hidden -pthread -fPIC -fvisibility=hidden -fno-omit-frame-pointer -fpermissive  -D_libfc_HAVE_NIXIO -U_libfc_HAVE_LOG4CPLUS_ -U_libfc_HAVE_WANDIO_ -Isrc -Isrc/exceptions -I../../../../../third-party/boost/1.66.0 -I../../../../../third-party/g3log/2017-07-18_g3log/src -I../../../../../third-party/g3log/2017-07-18_g3log/include -g -Wall -O2 -D NDEBUG -o obj/InfoElement.o src/InfoElement.cpp
g++ -c -std=c++0x -fvisibility-inlines-hidden -pthread -fPIC -fvisibility=hidden -fno-omit-frame-pointer -fpermissive  -D_libfc_HAVE_NIXIO -U_libfc_HAVE_LOG4CPLUS_ -U_libfc_HAVE_WANDIO_ -Isrc -Isrc/exceptions -I../../../../../third-party/boost/1.66.0 -I../../../../../third-party/g3log/2017-07-18_g3log/src -I../../../../../third-party/g3log/2017-07-18_g3log/include -g -Wall -O2 -D NDEBUG -o obj/InfoModel.o src/InfoModel.cpp
g++ -c -std=c++0x -fvisibility-inlines-hidden -pthread -fPIC -fvisibility=hidden -fno-omit-frame-pointer -fpermissive  -D_libfc_HAVE_NIXIO -U_libfc_HAVE_LOG4CPLUS_ -U_libfc_HAVE_WANDIO_ -Isrc -Isrc/exceptions -I../../../../../third-party/boost/1.66.0 -I../../../../../third-party/g3log/2017-07-18_g3log/src -I../../../../../third-party/g3log/2017-07-18_g3log/include -g -Wall -O2 -D NDEBUG -o obj/libfc.o src/libfc.cpp
g++ -c -std=c++0x -fvisibility-inlines-hidden -pthread -fPIC -fvisibility=hidden -fno-omit-frame-pointer -fpermissive  -D_libfc_HAVE_NIXIO -U_libfc_HAVE_LOG4CPLUS_ -U_libfc_HAVE_WANDIO_ -Isrc -Isrc/exceptions -I../../../../../third-party/boost/1.66.0 -I../../../../../third-party/g3log/2017-07-18_g3log/src -I../../../../../third-party/g3log/2017-07-18_g3log/include -g -Wall -O2 -D NDEBUG -o obj/PlacementExporter2.o src/PlacementExporter2.cpp
g++ -c -std=c++0x -fvisibility-inlines-hidden -pthread -fPIC -fvisibility=hidden -fno-omit-frame-pointer -fpermissive  -D_libfc_HAVE_NIXIO -U_libfc_HAVE_LOG4CPLUS_ -U_libfc_HAVE_WANDIO_ -Isrc -Isrc/exceptions -I../../../../../third-party/boost/1.66.0 -I../../../../../third-party/g3log/2017-07-18_g3log/src -I../../../../../third-party/g3log/2017-07-18_g3log/include -g -Wall -O2 -D NDEBUG -o obj/PlacementTemplate.o src/PlacementTemplate.cpp
g++ -c -std=c++0x -fvisibility-inlines-hidden -pthread -fPIC -fvisibility=hidden -fno-omit-frame-pointer -fpermissive  -D_libfc_HAVE_NIXIO -U_libfc_HAVE_LOG4CPLUS_ -U_libfc_HAVE_WANDIO_ -Isrc -Isrc/exceptions -I../../../../../third-party/boost/1.66.0 -I../../../../../third-party/g3log/2017-07-18_g3log/src -I../../../../../third-party/g3log/2017-07-18_g3log/include -g -Wall -O2 -D NDEBUG -o obj/TemplateState.o src/TemplateState.cpp
g++ -c -std=c++0x -fvisibility-inlines-hidden -pthread -fPIC -fvisibility=hidden -fno-omit-frame-pointer -fpermissive  -D_libfc_HAVE_NIXIO -U_libfc_HAVE_LOG4CPLUS_ -U_libfc_HAVE_WANDIO_ -Isrc -Isrc/exceptions -I../../../../../third-party/boost/1.66.0 -I../../../../../third-party/g3log/2017-07-18_g3log/src -I../../../../../third-party/g3log/2017-07-18_g3log/include -g -Wall -O2 -D NDEBUG -o obj/UdpSocketExportDestination.o src/UdpSocketExportDestination.cpp
g++ -c -std=c++0x -fvisibility-inlines-hidden -pthread -fPIC -fvisibility=hidden -fno-omit-frame-pointer -fpermissive  -D_libfc_HAVE_NIXIO -U_libfc_HAVE_LOG4CPLUS_ -U_libfc_HAVE_WANDIO_ -Isrc -Isrc/exceptions -I../../../../../third-party/boost/1.66.0 -I../../../../../third-party/g3log/2017-07-18_g3log/src -I../../../../../third-party/g3log/2017-07-18_g3log/include -g -Wall -O2 -D NDEBUG -o obj/Exception.o src/exceptions/Exception.cpp
g++ -c -std=c++0x -fvisibility-inlines-hidden -pthread -fPIC -fvisibility=hidden -fno-omit-frame-pointer -fpermissive  -D_libfc_HAVE_NIXIO -U_libfc_HAVE_LOG4CPLUS_ -U_libfc_HAVE_WANDIO_ -Isrc -Isrc/exceptions -I../../../../../third-party/boost/1.66.0 -I../../../../../third-party/g3log/2017-07-18_g3log/src -I../../../../../third-party/g3log/2017-07-18_g3log/include -g -Wall -O2 -D NDEBUG -o obj/ExportError.o src/exceptions/ExportError.cpp
g++ -c -std=c++0x -fvisibility-inlines-hidden -pthread -fPIC -fvisibility=hidden -fno-omit-frame-pointer -fpermissive  -D_libfc_HAVE_NIXIO -U_libfc_HAVE_LOG4CPLUS_ -U_libfc_HAVE_WANDIO_ -Isrc -Isrc/exceptions -I../../../../../third-party/boost/1.66.0 -I../../../../../third-party/g3log/2017-07-18_g3log/src -I../../../../../third-party/g3log/2017-07-18_g3log/include -g -Wall -O2 -D NDEBUG -o obj/FormatError.o src/exceptions/FormatError.cpp
g++ -c -std=c++0x -fvisibility-inlines-hidden -pthread -fPIC -fvisibility=hidden -fno-omit-frame-pointer -fpermissive  -D_libfc_HAVE_NIXIO -U_libfc_HAVE_LOG4CPLUS_ -U_libfc_HAVE_WANDIO_ -Isrc -Isrc/exceptions -I../../../../../third-party/boost/1.66.0 -I../../../../../third-party/g3log/2017-07-18_g3log/src -I../../../../../third-party/g3log/2017-07-18_g3log/include -g -Wall -O2 -D NDEBUG -o obj/IESpecError.o src/exceptions/IESpecError.cpp
mkdir bin
g++ -shared -lpthread -L../../../../../third-party/g3log/2017-07-18_g3log/build -lg3logger -flto  -o bin/libfc.so  obj/BasicOctetArray.o obj/EncodePlan.o obj/FileExportDestination.o obj/IETemplate.o obj/IEType.o obj/InfoElement.o obj/InfoModel.o obj/libfc.o obj/PlacementExporter2.o obj/PlacementTemplate.o obj/TemplateState.o obj/UdpSocketExportDestination.o obj/Exception.o obj/ExportError.o obj/FormatError.o obj/IESpecError.o ../../../../../third-party/boost/1.66.0/stage/lib/libboost_system.a

Любая помощь будет действительно полезной.


person user1429322    schedule 06.09.2018    source источник
comment
@ πάνταῥεῖ Автор, кажется, понимает, что такое неопределенные ссылки, и, насколько я могу судить, не сделал ни одной из распространенных простых ошибок. Если какой-то ответ объясняет эту конкретную проблему, то какая? Голосование открыто на данный момент.   -  person aschepler    schedule 07.09.2018
comment
@aschepler Ответ в тупике. Порядок связанных двоичных файлов имеет значение.   -  person πάντα ῥεῖ    schedule 07.09.2018
comment
@ πάνταῥεῖ test.cpp появляется перед -lfc в командной строке. Не правда ли?   -  person aschepler    schedule 07.09.2018
comment
Это действительно выглядит подозрительно, что nm сообщает символы как t, а не T, а readelf говорит LOCAL. Строчный код nm обычно означает внутреннюю привязку. (Но я не уверен, как у вас вообще получится внутренняя связь для функций-членов класса.)   -  person aschepler    schedule 07.09.2018
comment
@aschepler Вы правы заказ правильный   -  person πάντα ῥεῖ    schedule 07.09.2018
comment
Так что было бы полезно посмотреть, как был собран libfc.so. (И, кстати, в системах Unix / ELF файл lib * .a является статической библиотекой, а файл lib * .so - общей библиотекой.)   -  person aschepler    schedule 07.09.2018
comment
@aschepler Обновлен с дополнительной информацией о том, как был собран libfc.so.   -  person user1429322    schedule 07.09.2018
comment
stackoverflow.com/questions/22244428/   -  person Matthew Fisher    schedule 07.09.2018
comment
stackoverflow.com/a/52216452/5769463   -  person ead    schedule 07.09.2018


Ответы (1)


libfc::InfoModel & model = libfc::InfoModel::instance();
                 ^
/tmp/ccFtLDxc.o: In function `main':
test.cpp:(.text+0x9): undefined reference to `libfc::InfoModel::instance()'
collect2: error: ld returned 1 exit status

В сочетании с -fvisibility=hidden (и друзьями):

$ nm -gCD ...

0000000000012980 t libfc::InfoModel::add(std::string const&)
0000000000010a60 t libfc::InfoModel::instance()
00000000000106f0 t libfc::InfoModel::initTypes()
...

Я считаю, что все это означает, что вы скрыли свой InfoModel класс, и он больше не отображается. Я предполагаю, что вы вручную добавили -fvisibility=hidden (и друзей), но не редактировали исходные файлы и не добавляли DLL_PUBLIC (согласно GCC Visibility wiki).

Я думаю, что самое простое решение для вас - создать статический архив без видимости. То есть, не используйте -fvisibility=hidden (и друзей). Затем, когда вы создаете свой общий объект / плагин, который использует статический архив, используйте -fvisibility=hidden (и друзей) и включите -Wl,--exclude-libs,ALL флаги компоновщика. Дополнительные флаги компоновщика гарантируют, что вы не будете повторно экспортировать символы из статических архивов.

В ваших исходных файлах для подключаемого модуля будет использоваться DLL_PUBLIC (согласно вики GCC Visibility). Рецепт make-файла будет использовать что-то вроде:

$(PLUGIN): $(PLUG_OBJS) $(FRAME_OBJS) $(OUTPUT)
   $(CXX) -shared -o $(OUTPUT) $(CXXFLAGS) $(PLUG_OBJS) $(FRAME_OBJS) $(BOOST_LIBS) $(LDFLAGS) -Wl,--exclude-libs,ALL

Затем вы можете проверить, что экспортируется из вашего общего объекта / плагина, примерно так:

nm -gCD libplugin.so | grep ' T '

К сожалению, нет способа избежать nm -gCD libplugin.so | grep ' T ' бородавки. Я просто был в списке рассылки Binutils в поисках лучшего способа отображения экспорта.

Отчет о проблеме GCC был недавно открыт для документации по адресу Проблема 87190, Отзыв о документация по видимости символа. Также см. Компоновщик, раскрывающий частные символы в списке рассылки Binutils.


Несколько дополнительных быстрых комментариев ...

CPP = g++

CPP - это препроцессор. Используйте CXX.

FLAGS = ...

Используйте CXXFLAGS для проектов C ++. Ваши рецепты на C ++ могут выглядеть так:

SRCS = $(sort $(wildcard *.cpp))
OBJS = $(SRCS:.cpp=.o)

%.o : %.cpp
    $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $<
person jww    schedule 08.09.2018