Klasa w Dll/So bez funkcji constructClass()

0

Witajcie,

Jak zrobic biblioteke dynamiczną żeby używać tak jak tej statycznej, jak np. w Qt. Wiem ze to przez to że Run Time nie jest znany adres do operator new w klasie, co w przypadku łączenia statycznego się nie dzieje. Może można jakoś pobrać wskaźnik do konstruktora i operatora new z dll, tylko wtedy do czego go przypisać? Po prostu, jak to zrobić?

0

Moim zdaniem da rady (nie warto się w to bawić), chociażby ze względu na name mangling. Musisz w DLLce (tam gdzie masz klasę) wystawić interfejs w postaci funkcji C, a po stronie programu utworzyć odpowiedni adapter.

0

Czyli ze np.

 
/* Class.hpp */

class Class
{
public:
    int sum(int a, int b);
/* Albo w C++11 */
    auto& sum = sumWrapper;
    std::function<int(int, int)>sum2 = sumWrapper;
/* Albo w starszym C++ */
    int (&sum)(int, int) = sumWrapper;
}
/* ClassWrapper.cpp */
#include <Class.hpp>

extern "C" int sumWrapper(Class* this, int a, int b)
{
    return a + b;
}
/* Class.cpp */
#include <Class.hpp>
#include <ClassWrapper.hpp>

Class::sum(int a, int b)
{
    sumWrapper(this, a, b);
}
0

Zawsze istnieje możliwość napisania całości obiektu w pliku *.dll a na zewnątrz można eksportować tylko funkcję która tworzy nowy obiekt i zwraca go do pliku *.exe.

2

jeżeli program i dll-ka używają tej samej biblioteki standardowej (linkowanej po obu stronach dynamicznie) i kompilowane są tym samym kompilatorem (ten sam name mangling itp.) to ja nie widzę problemu.

0

No to jak ma być to moduł opcjonalny, to musisz szukać w internecie pod hasłem plugin. I takie rozwiązanie jak podałem jest najbardziej odpowiednie. Nie ma co kombinować. Takie coś jest bardziej eleganckie niż kod który pokazałeś kilka postów wcześniej.

0

Poczytałem trochę o bibliotekach (wcześniej było tu "dynamicznych", ale poprawiłem) i wiem już ze faktycznie są ich 3 rodzaje.

  • statyczne, to wiadomo.
  • dynamiczne, które muszą być dostępne w czasie kompilacji (żeby chyba odczytać referencje do funkcji/metod) i jest w czasie uruchamiania programu ładowana jako zależność.
  • dynamiczna, linkowana w czasie działania programu, nie musi być obecna w czasie kompilacji programu. Takiej używa sie do pluginów.

Tylko moje pytanie teraz, jak zrobić tą drugą na Linuxie i Windowsie? Da sie na Win w ogóle tak? Tam jest wszystko zacofane, więc można spodziewać się wszystkiego. Z tego co widzę w Linuxie większość jest tego typu z 2 myślnika. Nie potrzeba do nich ładować żadnych bibliotek statycznych, które je ładują run-time.

PS. Chodzi mi bardziej o sposób w CMake bo CLion obsługuje tylko projekty CMake...

0

Trochę namieszałeś. Nie ma czegoś takiego jak statyczny dll tak naprawdę. Sama nazwa wskazuje na to Dynamic-Link Library - biblioteka łączona dynamicznie.

bajos napisał(a):

statyczne, to wiadomo.
Tu wiadomo nie ma pliku *.dll. Linker po prostu łączy plik lib w którym znajduje się skompilowany kod.

bajos napisał(a):
  • dynamiczne, które muszą być dostępne w czasie kompilacji (żeby chyba odczytać referencje do funkcji/metod) i jest w czasie uruchamiania programu ładowana jako zależność.
    Trochę namieszałeś. Plik dll nigdy nie musi być dostępny w czasie kompilacji. W czasie kompilacji musisz mieć plik *.lib który zawiera definicje funkcji/metod/zmiennych czy cokolwiek eksportujesz z pliku *.dll. Jeśli za pomocą pliku *.lib dodajesz do projektu bibliotekę, to ona musi być podczas uruchamiania programu dostępy plik dll. Jeśli program nie znajdzie to się nie uruchomi. Tu dll'ka jest ładowana na starcie programu.
bajos napisał(a):
  • dynamiczna, linkowana w czasie działania programu, nie musi być obecna w czasie kompilacji programu. Takiej używa sie do pluginów.
    I znowu pomieszanie, linkowanie odbywa się tylko raz podczas kompilacji programu i produkowania pliku *.exe. Biblioteka wtedy jest ładowana podczas działania programu w wybranym przez programistę momencie czasu.
bajos napisał(a):

Tylko moje pytanie teraz, jak zrobić tą drugą na Linuxie i Windowsie? Da sie na Win w ogóle tak? Tam jest wszystko zacofane, więc można spodziewać się wszystkiego. Z tego co widzę w Linuxie większość jest tego typu z 2 myślnika. Nie potrzeba do nich ładować żadnych bibliotek statycznych, które je ładują run-time.
Zapewniam Cię że każdy z tych sposobów działa pod systemem Windows. Ja osobiście w pracy piszę wszystko w plikach dll które łączę statycznie (2-ga metoda). Ale mam 2 dll'ki które wczytuję dynamicznie.

0

Dynamically linked shared object libraries (.so): There is only one form of this library but it can be used in two ways. 1. Dynamically linked at run time but statically aware. The libraries must be available during compile/link phase. The shared objects are not included into the executable component but are tied to the execution. 2. Dynamically loaded/unloaded and linked during execution (i.e. browser plug-in) using the dynamic linking loader system functions.
Tu jest problem z nazewnictwem. Słówko linked nie oznacza linkowania jakie wykonuje linker. Ale raczej wiązanie. Ale i tak nie rozumiem dlaczego napisali, że The libraries must be available during compile/link phase. Przecież podczas kompilacji nie potrzeba mieć dostępu do pliku dll. Od tego jest plik *lib.

Jak chciałem skompilować shared.cpp i shared.h przez komende g++ -fPIC -shared shared.cpp -o libshared.so przeszło ok. Ale jak chciałem skompilować main.cpp w którym użyłem nagłowka shared.h i kompilowałem przez g++ -L. -lshared main.cpp -o main to był błąd undefined reference to [...].
Akurat nie kompilowałem z palca pod Linuxem, więc nie powiem Ci za dużo. Ale wygląda mi na to, że kompilator nie widzi pliku z definicjami eksportowanych rzeczy z biblioteki.

0

Mam pliki (w tym samym folderze):

 /*  shared.hpp */
#ifndef SHARED_HPP__
#define SHARED_HPP__
 
void f();
 
class X 
{
public:
  X();
  void mX();
};
#endif

 /* shared.cpp */
#include "shared.hpp"
#include <iostream>

void f() { std::cout << "f()\n"; }
X::X() { std::cout << "X::X()\n"; }
void X::mX() { std::cout << "X::mX()\n"; }

 /* main.cpp */
#include "shared.hpp"
#include <iostream>
 
int main() 
{
	std::cout << "Hello!" << std::endl;

	f();
	X x;
	x.mX();
	return 0;
}

Biblioteke kompiluje z pozytywny skutkiem przez:
g++ -fPIC -shared shared.cpp -o libshared.so
Polecenie:
nm libshared.so --demangled
Zawiera w wyniku:

...
0000000000000900 T f()
...
0000000000000940 T X::mX()
000000000000091c T X::X()
000000000000091c T X::X()
 ...

Main.cpp kompiluje poleceniem:
g++ -L. -lshared main.cpp -o main
ze skutkiem:

/tmp/ccZRM8El.o: In function `main':
main.cpp:(.text+0x34): undefined reference to `f()'
main.cpp:(.text+0x40): undefined reference to `X::X()'
main.cpp:(.text+0x4c): undefined reference to `X::mX()'
collect2: error: ld returned 1 exit status

ŁŁŁaaajjj?

1

Rozwiązałem samemu ten problem.
Ja wcześniej kompilowałem przez:
g++ -fPIC -shared shared.cpp -o libshared.so
Powinno być:
g++ -fPIC -shared -Wl,-soname-libshared.so shared.cpp -o libshared.so
-Wl to przekazanie parametrów oddzielonych przecinkiem do linkera.
-soname=libshared.so to parametr linkera. Ustawia on "wewnętrzną" nazwę biblioteki tak żeby kompilator albo system mógł znaleźć odpowiednią niezależnie od nazwy jej pliku. Chętni mogą sobie sami doczytać więcej. :p

0

Cóż, trochę dziwne. Ale na przyszłość pisz pod jakimś porządnym IDE które takie rzeczy ustawi za Ciebie :P

1 użytkowników online, w tym zalogowanych: 0, gości: 1