LINUX.ORG.RU

подключение статической библиотеки (lib.a)

 ,


0

1

Всем привет, возникла проблема с подключением статической библиотеки. Файлы с библиотеки (для теста):

libMy.c:

#include "libMy.h"
void func1()
{
    sys_err("Test work lib");
}
libMy.h:
extern void func1();
компилирую библиотеку так:
gcc libMy.c -c -o libMy.o
ar cr libMy.a libMy.o
Подключить данную библиотеку хочу к исходникам сервера игры. Саму библиотеку (libMy.a) закинул по пути ../../libMy/lib (по отношения исходника игры).

в makefile добавил новую библиотеку:

LIBDIR +=  -L../../libMy/lib
LIBS += -lMy
Т.е добавление в makefile, как я понял, должно уже подключить библиотеку. добавил инклуд libMy.h в stack.cpp:
#include "libMy.h"
Сам хейдер выглядит так: libMy.h:
void func1();
в файле исходника игры stack.cpp вызываю так:
func1();
Уже после компиляции сервера (когда линкуется\собирается сам основной файл) выдается ошибка:
linking ../game....

stack.cpp:1728: undefined reference to `func1()'
stack.cpp:1728: undefined reference to `func1()'
collect2: error: ld returned 1 exit status
gmake: *** [../game] Error 1
Как правильно подключить статическую библиотеку?



Последнее исправление: cetjs2 (всего исправлений: 3)

Приведи полную команду вызова gcc. Что там make нагененрировал?

Будешь вручную писать makefile и не таких проблем огребёшь. CMake же мейнстрим.

ox55ff ★★★★★
()
Ответ на: комментарий от ox55ff

https://pastebin.com/Q2JYFbRB сюда вывел весь makefile. Там уже были стандартные библиотеки от игры, я просто дописал свою туда.

компилирую исходник игры командой gmake -j8

p.s. Без подключения новой библиотеки все нормально компилируется без ошибок

Qweqwe
() автор топика

Попробуй вместо:

LIBDIR +=  -L../../libMy/lib
LIBS += -lMy

Просто:

LIBS += ../../libMy/libMy.a
EXL ★★★★★
()
Ответ на: комментарий от EXL

Потому что name mangling. Раз там libMy.c, то нужно заворачивать содержимое заголовка в:

#ifdef __cplusplus
extern "C" {
#endif

#ifdef __cplusplus
}
#endif
xaizek ★★★★★
()
Ответ на: комментарий от EXL
..................... 
*все без ошибок*
...........
Compile -> quest.cpp
Compile -> mini.c
linking ../game....
OBJDIR/stack.o: In function `CHARACTER::SendDamagePacket(CHARACTER*, int, unsigned char)':
/game/src/stack.cpp:1728: undefined reference to `func1()'
/game/src/stack.cpp:1728: undefined reference to `func1()'
collect2: error: ld returned 1 exit status
gmake: *** [../game] Error 1

Qweqwe
() автор топика
Ответ на: комментарий от xaizek

# nm libMy.a

libMy.o: 00000000 T func1 U sys_err

А если поменять libMy.c на libMy.cpp то как скомпилировать правильно? Вообще мне статическая библиотека нужна на с++

Qweqwe
() автор топика
Ответ на: комментарий от Qweqwe

А если поменять libMy.c на libMy.cpp то как скомпилировать правильно?

Наверное. Он мог по расширению гадать язык (и судя по выводу nm так и есть, если всё было сделано правильно).

Вообще мне статическая библиотека нужна на с++

Тогда стоит переименовать в любом случае.

xaizek ★★★★★
()
Ответ на: комментарий от xaizek

Хотя не похоже, что g++ так гадает. Может ar не был сделан? Можно ещё libMy.a для верности сначала снести.

xaizek ★★★★★
()
Ответ на: комментарий от xaizek

Да, ты прав, почему-то думал, что в глобальной области нет манглинга.

@Qweqwe, засунь сишные хедеры в extern "C" { }, например, в самом проекте или в хедере, как предложено выше.

Но если тебе нужна именно статическая библиотека на С++, без C-like интерфейса, то эта проблема просто отпадёт, переименовывай файл в *.cpp и компилируй его через g++-враппер, как в твоём примере выше:

$ cat libMy.cpp 
#include "libMy.h"

void func1()
{
    ;
}

$ cat libMy.h
extern void func1();

$ cat appMy.cpp 
#include "libMy.h"

int main() {
    func1();
}

$ g++ libMy.cpp -c -o libMy.o
$ ar cr libMy.a libMy.o
$ g++ appMy.cpp libMy.a
$ ./a.out
EXL ★★★★★
()
Последнее исправление: EXL (всего исправлений: 2)
Ответ на: комментарий от xaizek

хм, возник еще вопрос, я не могу в библиотеке функции void func1() использовать sys_err функцию (для вывода в лог сообщения), которая используется и создана на сервере игры?

например: в библиотеке

libMy.cpp:

#include "libMy.h"
void func1()
{
	sys_err("Test work lib");
}

но в библиотеке нигде не объявлена sys_err. должна же быть ошибка при компиляции самой библиотеки?

если компилирую в расширении .cpp то ошибка, командой:

 # g++7 libMy.cpp -c -o libMy.o
libMy.cpp: In function 'void func1()':
libMy.cpp:4:2: error: 'sys_err' was not declared in this scope
  sys_err("Test work lib");

а если в расширении libMy.c то всё компилируется без ошибок, командой:

gcc libMy.c -c -o libMy.o

Просто раньше не сталкивался с статическими библиотеками..

Qweqwe
() автор топика
Ответ на: комментарий от Qweqwe

или без добавлений в расширение .c

extern «C» { }

ошибка не вылетает, потому что компилируется пустой файл, т.к. компилятор не видит кода внутри функции? Или я вообще не пойму..

Qweqwe
() автор топика
Ответ на: комментарий от EXL

да так все нормально скомпилировалось, спасибо. Возник вопрос, возможно ли перенести функцию с основной программы в библиотеку? А в основной программе просто вызывать ее? Эта функция так же имеет переменные и обращения к классу внутри основной программы. Или есть другие способы скрыть функцию?

Qweqwe
() автор топика
Ответ на: комментарий от Qweqwe

Возник вопрос, возможно ли перенести функцию с основной программы в библиотеку?

Я таким никогда не занимался, но думаю что можно, используя хак через LD_PRELOAD или подобное: https://github.com/crutchwalkfactory/motocakerteam/blob/master/Projects/vibrate_menu/libezxvibrate.cpp#L30

я не могу в библиотеке функции void func1() использовать sys_err функцию (для вывода в лог сообщения), которая используется и создана на сервере игры?

Так подключи её. Исходники исполнительного файла game ведь открыты, верно?

EXL ★★★★★
()
Ответ на: комментарий от beeen007

1ссылка гугла

Которая никак не решает проблему ТС.

EXL ★★★★★
()
Ответ на: комментарий от Qweqwe

должна же быть ошибка при компиляции самой библиотеки?

В C это может проканать без ошибок, компилятор просто угадает сигнатуру. Это устаревшее поведение, но компилятор может промолчать без дополнительных опций компиляции.

хм, возник еще вопрос, я не могу в библиотеке функции void func1() использовать sys_err функцию (для вывода в лог сообщения), которая используется и создана на сервере игры?

Можно, но нужно сделать соответствующий #include.

xaizek ★★★★★
()
Ответ на: комментарий от xaizek

То есть, нужно компилировать библиотеку в папке основной программы, и в библиотеки прописывать инклуд файлов с основной программы?

Qweqwe
() автор топика
Ответ на: комментарий от EXL

Да, открыты. Через LD_PRELOAD подключается на сколько я помню только динамические (.so), у меня же статическая. То есть чтобы скомпилировать библиотеку с вызванной функцией из основной программы, нужно компилировать библиотеку в той же папке где исходник основной программы и прописать в библиотеку нужные инклуды с основной программы?

Qweqwe
() автор топика
Ответ на: комментарий от Qweqwe

Если исходники клиента/сервера открыты, зачем тебе все эти сложности? Бери и правь их. Выноси в либы нужную функциональность или меняй её прямо напрямую.

То есть, нужно компилировать библиотеку в папке основной программы, и в библиотеки прописывать инклуд файлов с основной программы?

Нет разницы где компилировать библиотеку, к ней нужно подцепить ту сущность, где определена sys_err().

EXL ★★★★★
()
Ответ на: комментарий от Qweqwe

Важно наличие #include, а не где находятся исходники.

xaizek ★★★★★
()
Ответ на: комментарий от EXL

Хм, что-то не получается правильно передать функцию, если я делаю инклуд хейдера с которого мне нужна функция (с основной программы). То при компиляции библиотеки вылетают ошибки: что не может найти все функции которые указаны в том хейдеры (а мне нужна только одна функция оттуда). Некоторые из ошибок:

int'
../../game/src/battle.h:45: error: expected primary-expression before 'const'
../../game/src/state.h: In member function 'void CStateTemplate<T>::ExecuteBeginState() [with T = CFSM]':
libMy.cpp:129:   instantiated from here
../../game/src/state.h:68: error: 'assert' was not declared in this scope
../../game/src/state.h: In member function 'void CStateTemplate<T>::ExecuteState() [with T = CFSM]':
libMy.cpp:129:   instantiated from here
../../game/src/state.h:75: error: 'assert' was not declared in this scope
../../game/src/state.h: In member function 'void CStateTemplate<T>::ExecuteEndState() [with T = CFSM]':
libMy.cpp:129:   instantiated from here

В libMy.cpp прописан инклуд только к battle.h (а в battle.h куча своих инклудов еще прописаны).

А мне нужно сделать:

1. удалить функцию

 bool IS_TASK(LPCHARACTER ch, LPCHARACTER victim, DWORD current_time) 
из файла battle.cpp (это можно сделать в ручную)

2. Создать функцию

 bool IS_TASK(LPCHARACTER ch, LPCHARACTER victim, DWORD current_time) 
в libMy.cpp (проблема в том, что эта функция использует различные переменные с основной программы).

3. И передать эту функцию с libMy.cpp в battle.cpp (вызвать её).

Qweqwe
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.