Неопределенная ссылка на ошибки членов класса библиотеки из программы-звонящего

Дополнительные вопросы, добавленные ниже, 4/11/2011

Я разрабатываю кросс-платформенный набор разделяемых библиотек DLL/Sos и тестер программ на С++, хотя я должен иметь возможность поддерживать C. Библиотеки будут поставляться только как объектный код, но программа (и) тестировщика отправит с источником, поэтому наши клиенты могут иметь пример кода. По этой причине я разрабатываю библиотеки для загрузки во время выполнения, то есть динамическое связывание с использованием dlopen()/LoadLibraryA().

Я использую g++ 4.4.3-4 для Umbutu 10.04 и VС++ 2008 для Vista/64 (в 32-разрядном режиме).

Все, кажется, отлично работает в Windows (прямо сейчас). Однако, когда я компилирую на Linux, я получаю некоторые ошибки, которые я не могу понять.

Тестер и библиотека имеют несколько классов, закодированных в нескольких .cpp и .h's. Классы и большинство всего в библиотеке, кроме основных точек входа, находятся в пространстве имен DISCOVER_NS.

Вот краткий очерк проекта:

Во-первых, прием, я сократил кучу имен, чтобы код был более читабельным.

discover.cpp

  • Создает объект класса с указателем на него, называемым MainObject типа DiscoverObject.

  • Имеет внешнюю функцию "C" , которая возвращает объект MainObject программе-вызывателю как void *.

  • DiscoverObject имеет несколько методов и создает экземпляры других классов, найденных в отдельных cpp и .h. Один конкретный метод называется Hello(), который делает то, что вы ожидаете, он печатает тестовое сообщение "привет".


tester.cpp

  • Получает дескриптор библиотеки

  • получает указатель на функцию, возвращающую объект MainObject.

  • Выполняет функцию (указатель) и возвращает возвращенный адрес из void * в DISCOVER_NS:: DiscoverObject * aDiscoverObject.

  • Запустите aDiscoverObject- > Hello().


Я компилирую с помощью:

CC = @g++

gflags = -g3

cflags = -fPIC -Wall -pedantic

lib_linkflags: = -shared -fPIC -lstdС++ -lrt -lpthread -rdynamic

tester_linkflags: = -ldl -lpthread

определяет = -D_linux_ -D_DEBUG -D_IPC_ARCH_INTEL = 1 -D_THREAD_SAFE


Теперь, когда я компилирую, я получаю следующие ошибки: * Tester.cpp: 142: undefined ссылка на `Discover_NS:: DiscoverObject:: hello() '*

Я также получаю кучу других справочных ошибок undefined от find.so, например, например: * discover.so: undefined ссылка на `Discover_NS:: DeviceList:: ~ DeviceList() *


Я попытался сделать практически все в SO extern "C" . Нет разницы.

Я попытался поставить утверждения в файл open.cpp, который выглядит так:      extern void Discover_NS:: OtherClass:: method (args); но это дает мне ошибки об ошибках "Объявление за пределами класса не является дефинированием".


Я знаю, что это поможет увидеть код, но мне нужно время, чтобы выпустить что-то маленькое для публикации.

Кто-нибудь может предложить идеи для решения этой проблемы?

Спасибо,

Уэс

Решение Дмитрия было не совсем полным исправлением, но было необходимым элементом в решении. После изучения моего файла makefile я обнаружил пару непреднамеренно дублированных строк, которые я удалил, и два "опечатки", где у меня был неправильный путь для -o, закодированного в этапах компиляции. Сломанные шаги скомпилировали logger.cpp и RemException.cpp:

./common/logger.o : ./common/logger.cpp
    $(CC) $(gflags)  $(cflags) -c  $(defines)  -I ./common  
        -I ./EdgeIO  -I ./Discover   
        -o ./common/Debug/logger.o   <+++++++++ path to .o was wrong
        ./common/logger.cpp   2>&1  | tee ./RemKonTester/logger.ERR

Тогда я нашел реальную ошибку. Я полностью упустил тот факт, что я не собирал весь свой .cpp в каталоге Discover!. Потребовался хороший час, чтобы удалить все nit-pics, но теперь она легко компилируется из make файла.

НОВАЯ ВЕРСИЯ ОРИГИНАЛЬНОГО ВОПРОСА: NOw, что я знаю, что он будет работать через makefile, как я могу говорить Eclipse о том, что делает makefile?

Спасибо, Дмитрий.

Уэс

Ну, моя проблема все еще здесь.

У меня есть компиляция кода с предложениями Дмитрия (@Dmitry). Только они, по-видимому, вызывают отдельную проблему. Я хочу, чтобы мои библиотеки связывались с основной программой тестирования динамически во время выполнения. Добавление -l Discover -l EdgeIO в ссылку получает все, чтобы скомпилировать, но это дает мне статическую привязку.

FYI, неиспользуемые "pi" - это так, что SO имеет в нем число с плавающей запятой и, таким образом, скомпилируется с поддержкой с плавающей запятой. Требуется, если вызывающий абонент когда-либо хочет использовать числа с плавающей запятой. Кто-нибудь получил лучший способ заставить g++ скомпилировать с включенной плавающей запятой?

После исправления многих ошибок Дмитрий помог мне найти, теперь я получаю этот вывод:

make
./Discover/dllmain.cpp: In function ‘void InitalizeLibraryServices()’:
./Discover/dllmain.cpp:175: warning: unused variable ‘pi’


./EdgeIO/dllMain.cpp: In function ‘void InitalizeLibraryServices()’:
./EdgeIO/dllMain.cpp:158: warning: unused variable ‘pi’


linking RemKonTester
    gflags = -g3
    tstlinkflags = -ldl  -lpthread 
    defines =  -D__linux__   -D_DEBUG   -D_IPC_ARCH_INTEL=1   -D_THREAD_SAFE

./RemKonTester/Debug/RemKonTester.o: In function `main':
/home/wmiller/Projects/Eclipse/./RemKonTester/RemKonTester.cpp:81: undefined 
    reference to `RemKon_EdgeIO::EdgeIoObject::hello()'
/home/wmiller/Projects/Eclipse/./RemKonTester/RemKonTester.cpp:111: undefined 
    reference to `RemKon_Discover::DiscoverObject::hello()'
/home/wmiller/Projects/Eclipse/./RemKonTester/RemKonTester.cpp:116: undefined 
    reference to `RemKon_Discover::DiscoverObject::SetLogLevel(unsigned int)'
/home/wmiller/Projects/Eclipse/./RemKonTester/RemKonTester.cpp:117: undefined 
    reference to `RemKon_Discover::DiscoverObject::hello()'
/home/wmiller/Projects/Eclipse/./RemKonTester/RemKonTester.cpp:118: undefined 
    reference to `RemKon_Discover::DiscoverObject::LocalIpAddress(int)'
/home/wmiller/Projects/Eclipse/./RemKonTester/RemKonTester.cpp:122: undefined 
    reference to `RemKon_Discover::DiscoverObject::RegisterCallback(bool(*)
    (void*), void*)'
/home/wmiller/Projects/Eclipse/./RemKonTester/RemKonTester.cpp:123: undefined 
    reference to `RemKon_Discover::DiscoverObject::Search()'

collect2: ld returned 1 exit status

Я получаю тот же набор сообщений об ошибках из Eclipse.

RemKonTester.cpp содержит все .h, где объявляются эти элементы. Я пробовал их с объявлениями extern "C" , а не.

Надеясь на помощь,

Уэс

Ответ 1

Ваша проблема кажется позицией -l<library>:

$(CC)  $(gflags)  $(tstlinkflags) $(defines)      -L ./Debug    -ldiscover   
        -ledgeio -o ./Debug/RemKonTester  ./RemKonTester/Debug/RemKonTester.o  
        ./RemKonTester/Debug/logger.o  ./RemKonTester/Debug/libraryClass.o   
        2>&1  | tee ./RemKonTester/make.ERR

Они должны быть после объектных файлов, потому что компоновщик загружает их, когда они встречаются в командной строке и ищут символы undefined.

Подробнее см. man ld (в частности, -l):

-l namespec

...

Линкеров будет искать архив только один раз, в том месте, где он указан в командной строке. Если архив определяет            символ, который был undefined в некотором объекте, который появился перед архивом в командной строке, компоновщик будет включать            файл из архива. Однако символ undefined в объекте, появляющемся позже в командной строке, не будет вызывать            компоновщик, чтобы снова искать архив.

Это должно сработать для вас:

$(CC) $(gflags) $(tstlinkflags) $(определяет) -L./Debug -o./Debug/RemKonTester./RemKonTester/Debug/RemKonTester.o./RemKonTester/Debug/logger.o./RemKonTester/Debug/libraryClass.o -ldiscover -ledgeio 2 > & 1 | tee./RemKonTester/make.ERR

P.S. Обратите внимание, что есть опция для редактирования вашего вопроса в StackOverflow, размещение дополнительной информации в качестве ответа не является хорошей практикой.

Ответ 2

EDITED: Наконец выяснил "редактор". Сделал это красивее. wjm

Извините за задержку. Вчера вечером мне пришлось вытащить упавшее дерево из моего переднего двора.

Примечание. Я изменяю несколько имен в оригинальной ноте, чтобы сделать их короче. В этом ответе есть все, что указано.


g++ output...

$ make
./EdgeIO/dllMain.cpp: In function ‘void InitalizeLibraryServices()’:
./EdgeIO/dllMain.cpp:158: warning: unused variable ‘pi’
./Discover/dllmain.cpp: In function ‘void InitalizeLibraryServices()’:
./Discover/dllmain.cpp:174: warning: unused variable ‘pi’
./RemKonTester/RemKonTester.cpp: In function ‘int main(int, char**)’:
./RemKonTester/RemKonTester.cpp:130: warning: ISO C++ forbids casting between     
pointer-to-function and pointer-to-object
./RemKonTester/RemKonTester.cpp:152: warning: unused variable ‘searchResp’
./RemKonTester/libraryClass.cpp: In member function ‘int 
library::AttachLibrary()’:
./RemKonTester/libraryClass.cpp:132: warning: ISO C++ forbids casting between 
pointer-to-function and pointer-to-object
./RemKonTester/libraryClass.cpp:154: warning: ISO C++ forbids casting between 
pointer-to-function and pointer-to-object
./RemKonTester/Debug/RemKonTester.o: In function `main': 
/home/wmiller/Projects/Eclipse/
./RemKonTester/RemKonTester.cpp:142: undefined reference to 
`RemKon_Discover::DiscoverObject::hello()'
collect2: ld returned 1 exit status
gflags = -g3
tstlinkflags = -ldl  -lpthread
defines =  -D__linux__   -D_DEBUG   -D_IPC_ARCH_INTEL=1   -D_THREAD_SAFE
./Debug/libdiscover.so: undefined reference to     
`RemKon_Discover::RemKonDeviceList::~RemKonDeviceList()'
./Debug/libdiscover.so: undefined reference to 
`RemKon_Discover::RemSocket::ClientPort(unsigned short)'
./Debug/libdiscover.so: undefined reference to 
`RemKon_Discover::RemSocket::PayloadSize(unsigned int)'
./Debug/libdiscover.so: undefined reference to 
`RemKon_Discover::RemSocket::Socket() const'
./Debug/libdiscover.so: undefined reference to 
`RemKon_Discover::RemKonDeviceList::Count() const'
./Debug/libdiscover.so: undefined reference to 
`RemKon_Discover::RemException::~RemException()'
./Debug/libdiscover.so: undefined reference to 
`RemKon_Discover::RemSocket::UDPbinder()'
./Debug/libdiscover.so: undefined reference to 
`RemKon_Discover::RemSocket::ListenTimeOut(int)'
./Debug/libdiscover.so: undefined reference to 
`RemKon_Discover::RemSocket::ServerPort(unsigned short)'
./Debug/libdiscover.so: undefined reference to 
`RemKon_Discover::RemKonDeviceList::Next()'
./Debug/libdiscover.so: undefined reference to `RemKon_Discover::Log(char 
const*, ...)'
./Debug/libdiscover.so: undefined reference to 
`RemKon_Discover::RemSocket::UDPlisten(unsigned char*, int*, sockaddr_in*, int*)'
./Debug/libdiscover.so: undefined reference to 
`RemKon_Discover::RemException::RemException()'
./Debug/libdiscover.so: undefined reference to `RemKon_Discover::VerboseLogging()'
./Debug/libdiscover.so: undefined reference to 
`RemKon_Discover::RemSocket::RegisterCallbackFunction(void (*)(void*, unsigned 
char*, int), void*)'
./Debug/libdiscover.so: undefined reference to 
`RemKon_Discover::RemKonDeviceList::First()'
./Debug/libdiscover.so: undefined reference to 
`RemKon_Discover::RemSocket::TestData(unsigned int, unsigned int, unsigned char*, 
unsigned int)'
./Debug/libdiscover.so: undefined reference to `RemKon_Discover::Logging()'
./Debug/libdiscover.so: undefined reference to 
`RemKon_Discover::RemSocket::MessageLength(int)'
./Debug/libdiscover.so: undefined reference to 
`RemKon_Discover::RemSocket::LocalIpAddress(int)'
./Debug/libdiscover.so: undefined reference to 
`RemKon_Discover::RemSocket::UDPsend()'
./Debug/libdiscover.so: undefined reference to 
`RemKon_Discover::DiscoverObject::LocalIpAddress() const'
./Debug/libdiscover.so: undefined reference to 
`RemKon_Discover::RemSocket::SetBroadcastMode()'
./Debug/libdiscover.so: undefined reference to 
`RemKon_Discover::MakeMacAddressString(unsigned char*, char*)'
./Debug/libdiscover.so: undefined reference to 
`RemKon_Discover::RemKonDeviceList::RemKonDeviceList()'
./Debug/libdiscover.so: undefined reference to 
`RemKon_Discover::RemKonDeviceList::New()'
./Debug/libdiscover.so: undefined reference to 
`RemKon_Discover::ActivateLogging(unsigned int)'
./Debug/libdiscover.so: undefined reference to 
`RemKon_Discover::RemSocket::RemSocket()'
./Debug/libdiscover.so: undefined reference to 
`RemKon_Discover::RemSocket::Payload(unsigned int)'
collect2: ld returned 1 exit status

И это makefile. Извините, я не говорю так хорошо, поэтому makefile работает, а не красиво.

CC = @g++
gflags = -g3
cflags = -fPIC -Wall -pedantic
liblinkflags := -shared -fPIC -lstdc++ -lrt -lpthread -rdynamic
tstlinkflags := -ldl  -lpthread
defines = -D__linux__   -D_DEBUG   -D_IPC_ARCH_INTEL=1   -D_THREAD_SAFE


all : clean edgeio discover tester


############################################

edgeio : ./EdgeIO/dllMain.o ./EdgeIO/EdgeIO.o
$(CC) $(gflags)  $(liblinkflags) $(defines)    -Wl,-soname,./Debug
    /libedgeio.so.1  -o ./Debug/libedgeio.so.1.0 ./EdgeIO/Debug/edgeio.o  
    ./EdgeIO/Debug/dllmain.o    2>&1  | tee ./EdgeIO/make.ERR
            @cd ./Debug; ln -sf libedgeio.so.1.0    libedgeio.so
        @cd ./Debug; ln -sf libedgeio.so.1.0    libedgeio.so.1

./EdgeIO/dllMain.o : ./EdgeIO/dllMain.cpp
        $(CC) $(gflags)  $(cflags) -c $(defines)   -I ./common  -I ./EdgeIO  
    -I ./Discover   -o./EdgeIO/Debug/dllmain.o  ./EdgeIO/dllMain.cpp   2>&1  
    | tee ./EdgeIO/dllmain.ERR

./EdgeIO/EdgeIO.o : ./EdgeIO/EdgeIO.cpp
    $(CC) $(gflags)  $(cflags) -c $(defines)   -I ./common  -I ./EdgeIO  
    -I ./Discover   -o./EdgeIO/Debug/edgeio.o  ./EdgeIO/EdgeIO.cpp     2>&1  | 
    tee ./EdgeIO/EdgeIO.ERR

############################################

discover : ./Discover/Discover.o ./Discover/dllmain.o
    $(CC) $(gflags)  $(liblinkflags) $(defines)    -Wl,-soname,./Debug
        /libdiscover.so.1  -o ./Debug/libdiscover.so.1.0          ./Discover/Debug
        /Discover.o  ./Discover/Debug/dllmain.o    2>&1  | tee ./Discover/make.ERR
    @cd ./Debug; ln -sf libdiscover.so.1.0  libdiscover.so
    @cd ./Debug; ln -sf libdiscover.so.1.0  libdiscover.so.1

./Discover/Discover.o : ./Discover/Discover.cpp
    $(CC) $(gflags)  $(cflags) -c $(defines)   -I ./common  -I ./EdgeIO  
    -I ./Discover   -o./Discover/Debug/Discover.o  ./Discover/Discover.cpp  
     2>&1  | tee ./Discover/Discover.ERR

./Discover/dllmain.o : ./Discover/dllmain.cpp
        $(CC) $(gflags)  $(cflags) -c  $(defines)  -I ./common  -I ./EdgeIO  
        -I ./Discover   -o./Discover/Debug/dllmain.o  ./Discover/dllmain.cpp   
        2>&1  | tee ./Discover/dllmain.ERR

############################################

tester : ./RemKonTester/RemKonTester.o ./common/logger.o  ./RemKonTester
        /libraryClass.o    ./common/RemException.o
    $(CC)  $(gflags)  $(tstlinkflags) $(defines)       
        -L ./Debug -o ./Debug/RemKonTester  ./RemKonTester/Debug
        /RemKonTester.o  ./RemKonTester/Debug/logger.o  ./RemKonTester/Debug
        /libraryClass.o   2>&1  | tee ./RemKonTester/make.ERR

    @echo "gflags = $(gflags)"   2>&1  | tee ./RemKonTester/make.ERR
    @echo "tstlinkflags = $(tstlinkflags)"   2>&1  | tee ./RemKonTester/make.ERR
    @echo "defines =  $(defines)"   2>&1  | tee ./RemKonTester/make.ERR

    $(CC)  $(gflags)  $(tstlinkflags) $(defines)      -L ./Debug    -ldiscover   
        -ledgeio -o ./Debug/RemKonTester  ./RemKonTester/Debug/RemKonTester.o  
        ./RemKonTester/Debug/logger.o  ./RemKonTester/Debug/libraryClass.o   
        2>&1  | tee ./RemKonTester/make.ERR

./RemKonTester/RemKonTester.o : ./RemKonTester/RemKonTester.cpp
    $(CC) $(gflags)  $(cflags) -c $(defines)   -I ./common  -I ./EdgeIO  
        -I ./Discover   -o ./RemKonTester/Debug/RemKonTester.o   ./RemKonTester
        /RemKonTester.cpp   2>&1  | tee ./RemKonTester/RemKonTester.ERR

./common/logger.o : ./common/logger.cpp
    $(CC) $(gflags)  $(cflags) -c  $(defines)  -I ./common  -I ./EdgeIO  
        -I ./Discover    -o ./RemKonTester/Debug/logger.o  ./common/logger.cpp
        2>&1  | tee ./RemKonTester/logger.ERR

./RemKonTester/libraryClass.o : ./RemKonTester/libraryClass.cpp
    $(CC) $(gflags)  $(cflags) -c  $(defines)  -I ./common  -I ./EdgeIO  
        -I ./Discover    -o ./RemKonTester/Debug/libraryClass.o 
        ./RemKonTester/libraryClass.cpp   2>&1  | tee ./RemKonTester
        /libraryClass.ERR

./common/RemException.o : ./common/RemException.cpp
    $(CC) $(gflags)  $(cflags) -c  $(defines)  -I ./common  -I ./EdgeIO  
        -I ./Discover    -o ./RemKonTester/Debug/RemException.o ./common
        /RemException.cpp   2>&1  | tee ./RemKonTester/RemException.ERR


############################################

clean :
    @rm -f *.ERR
    @rm -f ./common/*.ERR
    @rm -f ./EdgeIO/*.ERR
    @rm -f ./Discover/*.ERR
    @rm -f ./RemKonTester/*.ERR

    @rm -f QEMACRO*
    @rm -f ./common/EdgeIO/QEMACRO*
    @rm -f ./EdgeIO/QEMACRO*
    @rm -f ./Discover/QEMACRO*
    @rm -f ./RemKonTester/QEMACRO*

    @rm -f ./Debug/*.o
    @rm -f ./common/Debug/*.o
    @rm -f ./EdgeIO/Debug/*.o
    @rm -f ./Discover/Debug/*.o
    @rm -f ./RemKonTester/Debug/*.o

    @rm -f ./Debug/*.log
    @rm -f ./common/Debug/*.log
    @rm -f ./EdgeIO/Debug/*.log
    @rm -f ./Discover/Debug/*.log
    @rm -f ./RemKonTester/Debug/*.log

    @rm -f ./Debug/*.so*

############################################

Спасибо,

Уэс