c++ g++ Linux динамическая библиотека с классами. Как создать?

Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain

Ответить
smallkins
Сообщения: 5
Зарегистрирован: 06 июн 2016, 07:28

Поиск даёт результат того, что нужно использовать Си или extern C для функций библиотеки *.so. Я хочу использовать классы C++. Сейчас у меня не получается соединить динамическую библиотеку с программой.
ywk_printf.h:

Код: Выделить всё

#define YWK_PRINTF_H

class ywk_printf {
 public:
ywk_printf ();
~ywk_printf ();
 protected:
const int _len (const char theBlock []);
void _rn (void);
void _print (const char & theLiteral);
void _print_ln (const char & theLiteral);
void _print (const char theBlock []);
void _print_ln (const char theBlock []);
void _printw (const char theBlock []);
void _printd (const int & theValue);
void _printd_ln (const int & theValue);
void _showc (const char theName [], const char & theLiteral);
void _shows (const char theName [], const char theBlock []);
void _showsw (const char theName [], const char theBlock []);
void _showd (const char theName [], const int & theValue);
void _debug (const char thePath [], const int & theLine);
void _debug (const char thePath [], const int & theLine, const char theData []);
 private:
void _self (void);
 public:
int app (int argc, char * argv []);

};

#endif 
ywk_printf.cpp:

Код: Выделить всё

#include <cstdio>
#include <cstring>
#include "ywk_printf.h"

 ywk_printf::ywk_printf () {
 
 };
 ywk_printf::~ywk_printf () {
  
 };
 
 // Вывести количество символов в массиве.
 const int ywk_printf::_len (const char theBlock []) {
  return theBlock ? strlen (theBlock) : 0;
 }
 
 void ywk_printf::_rn (void) {
  printf ("%s", "\r\n");
 }
 
 void ywk_printf::_print (const char & theLiteral) {
  printf ("%c", theLiteral);
 }
 
 void ywk_printf::_print_ln (const char & theLiteral) {
  printf ("%c", theLiteral);
  _rn ();
 }
 
 void ywk_printf::_print (const char theBlock []) {
  printf ("%s", theBlock);
 }
 
 void ywk_printf::_print_ln (const char theBlock []) {
  printf ("%s", theBlock);
  _rn ();
 }
 
 void ywk_printf::_printw (const char theBlock []) {
  for (
  int x = 0;
  x < _len (theBlock);
  x++
  ) {
   printf ("'%c' ", theBlock [x]);
  };
  _rn ();
 }
 
 void ywk_printf::_printd (const int & theValue) {
  printf ("%d", theValue);
 }
 
 void ywk_printf::_printd_ln (const int & theValue) {
  _printd (theValue);
  _rn ();
 }
  
 void ywk_printf::_showc (const char theName [], const char & theLiteral) {
  _print (theName);
  _print (" == ");
  _print ('\'');
  _print (theLiteral);
  _print ('\'');
  _rn ();
 }
 
 void ywk_printf::_shows (const char theName [], const char theBlock []) {
  _print (theName);
  _print (" == ");
  _print ('\"');
  _print (theBlock);
  _print ('\"');
  _rn ();
 }
 
 void ywk_printf::_showsw (const char theName [], const char theBlock []) {
  _print (theName);
  _print (" == ");
  _printw (theBlock);
 }
 
 void ywk_printf::_showd (const char theName [], const int & theValue) {
  _print (theName);
  _print (" == ");
  _printd_ln (theValue);
 }
 
 
 void ywk_printf::_debug (const char thePath [], const int & theLine) {
  _print ("DEBUG : File : ");
  _print (thePath);
  _print (" ; Line : ");
  _printd (theLine);
  _print ('.');
  _rn ();
 }
 
 
 void ywk_printf::_debug (const char thePath [], const int & theLine, const char theData []) {
  _print ("DEBUG : File : ");
  _print (thePath);
  _print (" ; Line : ");
  _printd (theLine);
  _print (" : ");
  _print (theData);
  _print ('.');
  _rn ();
 }
 
 
 void ywk_printf::_self (void) {
  _debug (__FILE__,__LINE__);
  _print_ln ("Azbuka");
  _printw ("Azbuka");
  _showc ("Literal", 'a');
  _shows ("Data", "String");
  _showsw ("Data", "String");
  _showd ("Value", 17);
  _debug (__FILE__,__LINE__,"DEBUG");
 }
 
 int ywk_printf::app (int argc, char * argv []) {
  if (argc > 2) {
   for (int x = 1; x < argc; x++ ) {
    _print_ln (argv [x]);
   };
  } else {
   _self ();
  };
  
  return 0;
 }
Main.cpp:

Код: Выделить всё

#include "ywk_printf.h"


int main ( int argc, char * argv [] ) {
 ywk_printf c0;

 return c0.app (argc, argv);
}
Вывод такой:

Код: Выделить всё

g++ -o LMain.o -c Main.cpp -std=c++0x
g++ -fPIC -c ywk_printf.cpp -I. -o Lywk_printf.o -std=c++0x
g++ -shared Lywk_printf.o -o libywk_printf.so.0.0.0.ALPHA -Wl,-soname,libywk_printf.so.0.0.0.ALPHA
g++ -L. -lywk_printf.so.0.0.0.ALPHA LMain.o -o Lywk_print.bin
/usr/bin/ld: cannot find -lywk_printf.so.0.0.0.ALPHA
collect2: выполнение ld завершилось с кодом возврата 1
Почему ld не может найти библиотеку в текущем каталоге?
Что я делаю не так?
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Линкеру нужно указывать подключаемую библиотеку не только без префикса lib (как это у тебя сделано), но ещё и без расширения so. При этом расширение so подразумевается по умолчанию, и если библиотека будет без этого расширения, то залинковать вообще не получится.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
smallkins
Сообщения: 5
Зарегистрирован: 06 июн 2016, 07:28

Спасибо. Действительно, после удаления "лишних" суффиксов скомпилировалось.

Код: Выделить всё

#!/bin/bash

g++ -o LMain.o -c Main.cpp -std=c++0x

g++ -fPIC -c ywk_printf.cpp -I. -o Lywk_printf.o -std=c++0x

#g++ -shared Lywk_printf.o -o libywk_printf.so.0.0.0.ALPHA -Wl,-soname,libywk_printf.so.0.0.0.ALPHA
#g++ -shared Lywk_printf.o -o libywk_printf.so.0.0.0.ALPHA -Wl,-soname,libywk_printf.so.0
#g++ -shared Lywk_printf.o -o libywk_printf.so.0.0.0.ALPHA -Wl,-soname,libywk_printf.so
#g++ -shared Lywk_printf.o -o libywk_printf.so.0.0.0.ALPHA -Wl,-soname,libywk_printf
g++ -shared Lywk_printf.o -I. -o libywk_printf.so -Wl,-soname,libywk_printf.so

#g++ -L. -lywk_printf.so.0.0.0.ALPHA LMain.o -o Lywk_print.bin
g++ -L. -lywk_printf LMain.o -o Lywk_print.bin
Однако в процессе выполнения программа не может найти библиотеку.

Код: Выделить всё

./Lywk_print.bin libywk_printf.so
./Lywk_print.bin: error while loading shared libraries: libywk_printf.so: cannot open shared object file: No such file or directory
Я проверил, что имя требуемой библиотеки совпадает с именем существующей.

Код: Выделить всё

objdump -p Lywk_print.bin | grep NEEDED
  NEEDED               libywk_printf.so
  NEEDED               libstdc++.so.6
  NEEDED               libm.so.6
  NEEDED               libgcc_s.so.1
  NEEDED               libc.so.6
В чём тут заключается ошибка?
=====
Отредактировано позднее.
Я нашёл ошибку.

Код: Выделить всё

#!/bin/bash

g++ -o LMain.o -c Main.cpp -std=c++0x

g++ -fPIC -c ywk_printf.cpp -I. -o Lywk_printf.o -std=c++0x

g++ -shared Lywk_printf.o -I. -o libywk_printf.so -Wl,-soname,libywk_printf.so

g++ -L. -lywk_printf LMain.o -o Lywk_print.bin -Wl,-rpath,.
При сборке нужно явно указывать в -Wl путь к библиотеке.
А можете подсказать, как всё таки реализовать этот пример с контроллем версий. Чтоб после расширения (суффикса) .so можно было добавлять номера версий программы, и, если возможно, последний суффикс с указанием альфа-бета-версии или релиза?
============================
Добавлено позже.
Я разместил всё по подкаталогам и подготовил Мэйкфайл (Makefile).

Код: Выделить всё

# Makefile

# The directories.
BD:=bin/
OBD:=obj/
SOD:=src/
HD:=src/
LD:=lib/
BASE:=$(HOME)/Developer/YuriK_Librares/src/Printf/

# The suffixes.
# for Linux and UNIX
BS:=.bin
# for Windows and DOS may by .exe
OBS:=.o
# may by .obj
SOS:=.cpp
HS:=.h
# The library suffix:
LS:=.so
# The library prefix:
LP:=lib
# The version:
V0:=0
V1:=0
V2:=0
V3:=ALPHA
VER:=$(V0).$(V1).$(V2).$(V3)

FILE1:=ywk_printf

# The names of source files.
SOURCE:=$(SOD)Main$(SOS)
SOURCE+=$(SOD)$(FILE1)$(SOS)

# The names of headers files.
HEADER:=$(HD)$(FILE1)$(HS)

# The names of objects files.
OBJECT:=$(OBD)Main$(OBS)
OBJECT+=$(OBD)$(FILE1)$(OBS)

ProjectName:=ywk_print
# The name of project an executable files with local path.
Target:=$(BD)$(ProjectName)$(BS)

# The compiller options.
COPTION:=-std=c++0x

# The linker options.
LOPTION:=

# The compiller name.
CC:=gcc
C++:=g++
CPP:=g++

.PHONY: all

all: $(Target)

# To Linker.
$(Target): $(OBJECT) $(SOURCE) $(HEADER)
	$(C++) $(OBJECT) -o $(Target)

# To Compiler.
$(OBD)Main$(OBS): $(SOURCE) $(HEADER)
	$(C++) -o $(OBD)Main$(OBS) -c $(SOD)Main$(SOS) $(COPTION)
$(OBD)$(FILE1)$(OBS): $(SOD)$(FILE1)$(SOS) $(HEADER)
	$(C++) -o $(OBD)$(FILE1)$(OBS) -c $(SOD)$(FILE1)$(SOS) $(COPTION)

.PHONY: clean
clean:
	rm -f $(OBD)* $(Target)

.PHONY: install
install: $(Target)
	mkdir -p $(BASE)$(BD); cp -a $(Target) $(BASE)/$(Target)

.PHONY: uninstall
uninstall: $(BASE)/$(Target)
	rm -f $(BASE)/$(Target)

.PHONY: update
update: $(Target) $(BASE)/$(Target)
	cp -a $(Target) $(BASE)/$(Target)


##

LTARGET:=$(BD)L$(ProjectName)$(BS)

.PHONY: l
l: $(LTARGET)
$(LTARGET): $(OBD)LMain$(OBS) $(LD)$(LP)$(FILE1)$(LS).$(VER)
	$(C++) -L$(LD) -l$(FILE1) $(OBD)LMain$(OBS) -o $(BD)L$(ProjectName)$(BS) -Wl,-rpath,$(LD)

$(LD)$(LP)$(FILE1)$(LS).$(VER): $(OBD)L$(FILE1)$(OBS)
	$(C++) -shared $(OBD)L$(FILE1)$(OBS) -I$(SOD) -o $(LD)$(LP)$(FILE1)$(LS).$(VER) -Wl,-soname,$(LP)$(FILE1)$(LS) ; \
cd $(LD) ; \
ln -s $(LP)$(FILE1)$(LS).$(VER) $(LP)$(FILE1)$(LS) ; \
ln -s $(LP)$(FILE1)$(LS).$(VER) $(LP)$(FILE1)$(LS).$(V0).$(V1).$(V2) ; \
ln -s $(LP)$(FILE1)$(LS).$(VER) $(LP)$(FILE1)$(LS).$(V0).$(V1) ; \
ln -s $(LP)$(FILE1)$(LS).$(VER) $(LP)$(FILE1)$(LS).$(V0) ; \
cd - ;

$(OBD)L$(FILE1)$(OBS): $(SOD)$(FILE1)$(SOS) $(HD)$(FILE1)$(HS)
	$(C++) -fPIC -c $(SOD)$(FILE1)$(SOS) -I$(SOD) -o $(OBD)L$(FILE1)$(OBS) $(COPTION)

$(OBD)LMain$(OBS): $(SOD)Main$(SOS) $(SOD)$(FILE1)$(SOS) $(HD)$(FILE1)$(HS)
	$(C++) -o $(OBD)LMain$(OBS) -c $(SOD)Main$(SOS) $(COPTION)

lr:
	rm -Rf $(LTARGET) $(OBD)LMain$(OBS) $(OBD)L$(FILE1)$(OBS) $(LD)$(LP)$(FILE1)$(LS).$(VER)
Символьные ссылки упрощают задачу поиска программой библиотек.
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Да, я бы тоже решал проблему версионности (раз уж она стала) через символьные ссылки.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
smallkins
Сообщения: 5
Зарегистрирован: 06 июн 2016, 07:28

Скажите. Если, к примеру библиотека .so использует 2 другие созданные мной библиотеки .so, то куда передавать ссылки на них при кроссировании? В строку со сборокой so или в итоговую программу?
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Здесь что-то не так с терминологией. Мне незнакомо слово кроссирование. Более того, его не знает и гугл.

Зависимые библиотеки необходимы линкеру для разрешения символов. Таким образом, если ты используешь комплятор с опцией -o (то есть говоришь ему самому вызвать линковщик), то передаёшь эти библиотеки комплятору. Если же комплятор и линкер вызываешь раздельно, то скармливаешь непосредственно в ld.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
smallkins
Сообщения: 5
Зарегистрирован: 06 июн 2016, 07:28

Термин кроссирование -- не моё личное изобретение. Я подчерпнул его из литературы по Qt4. Это имелось ввиду, компиляци и сборка с послдующим выполнением программы.
Makefile

Код: Выделить всё

# Makefile

# The directories.
BD:=bin/
OBD:=obj/
SOD:=src/
HD:=src/
LD:=lib/
ID:=include/
BASE:=$(HOME)/Developer/YuriK_Librares/src/Compare/

# The suffixes.
# for Linux and UNIX
BS:=.bin
# for Windows and DOS may by .exe
OBS:=.o
# may by .obj
SOS:=.cpp
HS:=.h
# The library suffix:
LS:=.so
# The library prefix:
LP:=lib
# The version:
V0:=0
V1:=0
V2:=0
V3:=ALPHA
VER:=$(V0).$(V1).$(V2).$(V3)

FILE1:=ywk_compare

# The names of source files.
SOURCE:=$(SOD)Main$(SOS)
SOURCE+=$(SOD)$(FILE1)$(SOS)

# The names of headers files.
HEADER:=$(HD)$(FILE1)$(HS)

# The names of objects files.
OBJECT:=$(OBD)Main$(OBS)
OBJECT+=$(OBD)$(FILE1)$(OBS)

ProjectName:=$(FILE1)
# The name of project an executable files with local path.
Target:=$(BD)$(ProjectName)$(BS)

# The compiller options.
COPTION:=-std=c++0x

# The linker options.
LOPTION:=

# The compiller name.
CC:=gcc
C++:=g++
CPP:=g++

.PHONY: all

all: $(Target)

# To Linker.
$(Target): $(OBJECT) $(SOURCE) $(HEADER)
	$(C++) $(OBJECT) -o $(Target) -L../Base/lib/ -lywk_base -L../Printf/lib/ \
-lywk_printf -Wl,-rpath,../Base/lib/ -Wl,-rpath,../Printf/lib/

# To Compiler.
$(OBD)Main$(OBS): $(SOURCE) $(HEADER)
	$(C++) -o $(OBD)Main$(OBS) -c $(SOD)Main$(SOS) $(COPTION)
$(OBD)$(FILE1)$(OBS): $(SOD)$(FILE1)$(SOS) $(HEADER)
	$(C++) -o $(OBD)$(FILE1)$(OBS) -c $(SOD)$(FILE1)$(SOS) $(COPTION) -I../Base/src/ \
-I../Printf/src/ -Wl,-soname,libywk_base.so,libywk_printf.so

.PHONY: clean
clean:
	rm -f $(OBD)* $(Target)

.PHONY: install
install: $(Target)
	mkdir -p $(BASE)$(BD); cp -a $(Target) $(BASE)/$(Target)

.PHONY: uninstall
uninstall: $(BASE)/$(Target)
	rm -f $(BASE)/$(Target)

.PHONY: update
update: $(Target) $(BASE)/$(Target)
	cp -a $(Target) $(BASE)/$(Target)


##

LTARGET:=$(BD)L$(ProjectName)$(BS)

.PHONY: l
l: $(LTARGET)
$(LTARGET): $(OBD)LMain$(OBS) $(LD)$(LP)$(FILE1)$(LS).$(VER)
	$(C++) -L$(LD) -l$(FILE1) $(OBD)LMain$(OBS) \
-Wl,-rpath,$(LD) \
-L../Base/lib -Wl,-rpath,../Base/lib/ -lywk_base \
-L../Printf/lib/ -Wl,-rpath,../Printf/lib/ -lywk_printf \
-o $(BD)L$(ProjectName)$(BS)

$(LD)$(LP)$(FILE1)$(LS).$(VER): $(OBD)L$(FILE1)$(OBS)
	$(C++) -shared $(OBD)L$(FILE1)$(OBS) -I$(SOD)  \
-o $(LD)$(LP)$(FILE1)$(LS).$(VER) \
-Wl,-soname,$(LP)$(FILE1)$(LS)   \
-L../Base/lib -Wl,-rpath,../Base/lib/ -lywk_base \
-L../Printf/lib/ -Wl,-rpath,../Printf/lib/ -lywk_printf ; \
cd $(LD) ; \
ln -s $(LP)$(FILE1)$(LS).$(VER) $(LP)$(FILE1)$(LS) ; \
ln -s $(LP)$(FILE1)$(LS).$(VER) $(LP)$(FILE1)$(LS).$(V0).$(V1).$(V2) ; \
ln -s $(LP)$(FILE1)$(LS).$(VER) $(LP)$(FILE1)$(LS).$(V0).$(V1) ; \
ln -s $(LP)$(FILE1)$(LS).$(VER) $(LP)$(FILE1)$(LS).$(V0) ; \
cd - ;

$(OBD)L$(FILE1)$(OBS): $(SOD)$(FILE1)$(SOS) $(HD)$(FILE1)$(HS)
	$(C++) -fPIC -c $(SOD)$(FILE1)$(SOS) -I$(SOD) -o $(OBD)L$(FILE1)$(OBS) $(COPTION) \
-I../Base/src/ -I../Printf/src/ -Wl,-soname,libywk_base.so,libywk_printf.so

$(OBD)LMain$(OBS): $(SOD)Main$(SOS) $(SOD)$(FILE1)$(SOS) $(HD)$(FILE1)$(HS)
	$(C++) -o $(OBD)LMain$(OBS) -c $(SOD)Main$(SOS) $(COPTION)

lr:
	rm -Rf $(LTARGET) $(OBD)LMain$(OBS) $(OBD)L$(FILE1)$(OBS) $(LD)$(LP)$(FILE1)$(LS).$(VER) \
$(LD)$(LP)$(FILE1)$(LS) $(LD)$(LP)$(FILE1)$(LS).$(V0).$(V1).$(V2) \
$(LD)$(LP)$(FILE1)$(LS).$(V0).$(V1) $(LD)$(LP)$(FILE1)$(LS).$(V0)

##

.PHONY: ex0
ex0:
	cp -a $(Target) ../../$(Target) ; \
cp -a $(LD)$(LP)$(FILE1)$(LS).$(VER) ../../$(LD)$(LP)$(FILE1)$(LS).$(VER) ; \
cp -a $(LD)$(LP)$(FILE1)$(LS) ../../$(LD)$(LP)$(FILE1)$(LS) ; \
cp -a $(LD)$(LP)$(FILE1)$(LS).$(V0).$(V1).$(V2) ../../$(LD)$(LP)$(FILE1)$(LS).$(V0).$(V1).$(V2) ; \
cp -a $(LD)$(LP)$(FILE1)$(LS).$(V0).$(V1) ../../$(LD)$(LP)$(FILE1)$(LS).$(V0).$(V1) ; \
cp -a $(LD)$(LP)$(FILE1)$(LS).$(V0) ../../$(LD)$(LP)$(FILE1)$(LS).$(V0) ; \
cp -a $(HEADER) ../../$(ID) ; \
cp -a $(LTARGET) ../../$(LTARGET) 
Использую Make l
Ура! Наконец-то получилось )) Спасибо за пояснения.
В моём Makefile нет ничего лишнего? Как вы считаете?
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Если честно, мне лень разбирать в нём. Была бы там проблема и что-то не получилось, я бы помог. А если всё работает, но вопрос только в том, нет ли там ничего лишнего, я пожалую пас ковыряться в нём :)
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Ответить