PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Shared Libs / Object in C++ unter Linux



ufosworld
12-04-2007, 15:05
Kurz nee fragende Anmerkung zum Thema Shared Objects in C++ unter Linux

Nachdem ich das schöne .so Beispiel "cosinus" in C zum laufen gebracht habe.

Hab ich mir ein Beispiel besorgt, das unter C++ kompiliert werden kann (in Kdevelop)

Nachdem ja in dem Cosinus Code die so-File direkt ohne ./ oder Verzeichniss angegeben wird,
dachte ich mir das geht auch ganz einfach mit ner selbst geschriebenen .so File.

Hier der Code vom Cosinus Beispiel:

#include <stdio.h>
#include <dlfcn.h>

int main(int argc, char **argv) {
void *handle;
double (*cosine)(double);
char *error;

handle = dlopen ("libm.so", RTLD_LAZY);
if (!handle) {
fprintf (stderr, "%s\n", dlerror());
exit(1);
}

cosine = dlsym(handle, "cos");
if ((error = dlerror()) != NULL) {
fprintf (stderr, "%s\n", error);
exit(1);
}

printf ("%f\n", (*cosine)(2.0));
dlclose(handle);
return 0;
}

Kompiliert wird das dann in der Console mit

gcc -rdynamic -o foo foo.c -ldl

Wie man sieht steht bei dlopen nur "libm.so" also weder "./libm.so" oder gar "/usr/lib/libm.so"

Das funktioniert ja, weil die libm.so in dem Library-Verzeichniss des Betriebssystem liegen

und das Programm dann während der ausführung automatisch in diesem Verzeichniss sucht.


Nun habe ich folgende File geladen

(siehe Anhang)

dann mit

tar zxvf examples.tar.tar

entpackt.

Wenn man sich den Quellcode main.cpp anschaut, sieht man folgende Zeile.

void* triangle = dlopen("./triangle.so", RTLD_LAZY);

d.h. die .so File muss sich also dann im lokalen Verzeichniss befinden in dem sich auch die Runfile befindet.

Nachdem ich alles kompiliert hatte (nicht mit dem mitgeliefertem Make, sondern als Projekt in KDevelop)
mit einem zusätzlichen Parameter -ldl (da er sonst mit dem dlopen usw total aussteigt)

(zu finden in KDevelop unter

Projekt-> Optionen -> Compiler Einstellungen->Linker Schalter->weiter Schalter und dort in dieses Feld -ldl eintragen

)
hatte er die Runfile erzeugt und eine File triangle.o

Diese .o File muss ich ja jetzt noch dynamic shared machen mit folgendem Befehl

g++ -rdynamic -shared -o triangle.so triangle.o

nun habe ich eine .so File....

nun will ich aber die .so File nicht im lokalen Verzeichniss haben, sondern wie die libm.so
(von oben) im /usr/lib Verzeichniss (Library Verzeichniss des Systems)

Da ich aber keine Root Rechte besitze in dieses Verzeichniss zu schreiben

erzeuge ich kurzerhand selbst ein Verzeichniss

/usr/usr/myaccount/mylibs/

und setze mit setenv den Library Path darauf

setenv LD_LIBRARY_PATH /usr/usr/myaccount/mylibs

eine Überprüfung mit env | grep LIB zeigt mir das der Pfad gesetzt wurde

wenn ich nun die .so File in das mylibs Verzeichniss verschiebe

und dann im Quellcode statt "./triangle.so" einfach "triangle.so" schreibe,
meldet er nachdem das Programm gestartet wurde, das er die Library nicht findet.


Was mach ich falsch?

bin hier echt am verzweifeln....
wieso funktioniert das mit der Standard Lib libm.so , aber mit der selbst geschriebenen im selbst gesetzten Lib-Verzeichniss nicht


danke schon mal für alle Infos

UFO



p.s. habe auch schon mal mittels

g++ -shared -Wl,-soname,triangle.so.1 -o triangle.so.1.0 triangle.cpp

mv triangle.so.1.0 /usr/myaccount/mylibs
mv triangle.so /usr/myaccount/mylibs

ln -sf /usr/myaccount/mylibs/triangle.so.1.0
ln -sf /usr/myaccount/mylibs/triangle.so
ln -sf /usr/myaccount/mylibs/triangle.so.1

Symbolisch links erzeugt...
d.h. im lokalen verzeichniss ist dann ein Link namens triangle.so der auf die /usr/myaccount/mylibs/triangle.so verlinkt

das mag er aber auch nicht... sondern nur wenn ich wieder "triangle.so" in "./trinangle.so" umändere dann funzt das Ding mit dem Link...


p.p.s. mein Ziel ist es... das die Libs einmal alle kompiliert werden und in ein Verzeichniss abgelegt werden, das als LD_LIBRARY_PATH gesetzt wird,
d.h. ich will keine Libs oder Verlinkungen drauf in meinem Programmverzeichniss liegen haben

anda_skoa
12-04-2007, 19:20
Hab main.cpp so geändert:


void* triangle = dlopen("triangle.so", RTLD_LAZY);

Dann triangle.so nach /tmp verschoben und LD_LIBRARY_PATH auf /tmp gesetzt.

Hat einwandfrei funktioniert

Ciao,
_

ufosworld
13-04-2007, 09:33
also bei mir klappt das net...

ich hab etz auch die .so file (keine verlinkung ... die reine .so file) nach /tmp verschoben

danach mit setenv LD_LIBRARY_PATH /tmp

den Lib Pfad gesetzt

(das alles in der console)

und dann das Programm geändert und kompiliert (in Kdevelop)
dann in der Console ausgeführt...

NULL ... nix geht... immer noch Fehlermeldung das er die Library nicht finden kann...

dann hab ich gemerkt das im Reiter KOnsole in Kdevelop wenn ich env |grep LIB eingeben der neue Pfad /tmp nicht angezeigt wird.. also auch hier nochmal den Pfad gesetzt....

hab auch nix gebracht... also weder starten von der Konsole als auch aus Kdevelop raus...

dann hab ich mal den Pfad statt /tmp in /tmp/ geändert...

wieder überall gesetzt... das brachte auch nix...

ich bin ehrlich mit meinem Latein am Ende...

noch irgendwelche Tips?

danke schon mal

ufo

anda_skoa
13-04-2007, 13:54
Welche Shell setzt du ein? Bzw, bist du sicher, daß die den setenv Syntax benutzt und nicht wie Bash "export"?

Ciao,
_

ufosworld
15-04-2007, 22:12
also wenn ich setenv mache und dann mit env |grep LIB überprüfe dann hat er das in der Cosole auch gemacht... also den Pfad hinzugefügt...

export gibt es nicht... da schlägt er exports vor...

export geht nur wenn ich

bash --login mache...

is ein Suse 8.1 Pc mit Kernel 2.4.19 -64GB -SMP /i686 an dem ich arbeite...

bei Kdevelop zeigt er 2.13 an

bei g++ zeigt er gcc 3.2 an

:confused: :mad:

anda_skoa
16-04-2007, 15:35
Hmm, eigenartig daß SUSE nicht auch eine Bash benutzt.

Aber wenn es nachweislich mit env | grep gefunden wird, hat das Setzen geklappt.

Wenn es in dieser Shell dann bei dir trotzdem nicht klappt, ist das schon eigenartig.
Als root arbeitest du eh nicht, oder?

Ciao,
_

ufosworld
17-04-2007, 09:41
nee hab keine root rechte...und auch keine change welche zu bekommen... deswegen ja das rumgefummel da mit dem zusätlichen lib verzeichniss und dem setzen... sonst hätte ich ja die Libs ins /usr/lib Verzeichniss gepackt, da sagt aber das System das ich keine Rechte habe...
echt zum kotzen...

wenn ich einen ln ... (verweiss) auf die Library setze und diesen verweiss dann in das Programmverzeichniss packe und im Code dann mit "./Library.so" arbeite dann funzt es... aber das funzt auch wenn ich den Pfad nicht setze...
somit nimmt der nur den Link her...

wenn ich dann abändere in "Library.so" dann sagt er das er die Lib nicht findet... egal ob jetzt Pfad gesetzt in Bash, normale Console oder im Konsolenfenster von KDevelop...

traurig traurig... da setzt man Werte bis zum umfallen und Linux beachtet diese gar nicht... :o :( :mad: :confused:

falls noch jemand nen Tip hat... bitte posten...

thx UFO

p.s. nen Neustart benötigt man aber net nicht oder... also nacht setzen der Library... (weil soweit ich weiss löscht der das wieder... also das gesetzte Verzeichniss.. also bei Neustart des Systems)

RHBaum
17-04-2007, 10:09
und setze mit setenv den Library Path darauf
setenv LD_LIBRARY_PATH /usr/usr/myaccount/mylibs


ldconfig hasst aber ausgefuehrt ?

IMHO holt sich das dlopen zur laufzeit ned die pfade aus der env variable, sondern bekommt irgendwo nen hash, damit findets auch schneller die libs. Den hash erzeugst mit ldconfig ....

also mal fix vor programmstart die env variable anpassen und voiala, ploetzlich laden die programme alle ne andere version der .so geht so nicht, was auch sinn macht, weils nen ziemliches sicherheitsrisiko waer (programme mit suicid flag nutzen ja auch .so 's und die env variablen kann jeder fuer seine shell ueberschreiben ..... )

Ciao ...

anda_skoa
17-04-2007, 12:59
nee hab keine root rechte...und auch keine change welche zu bekommen...


Das war zu Absicherung gefragt, als root geht LD_LIBRARY_PATH aus Sicherheitsgründen nämlich nicht.



p.s. nen Neustart benötigt man aber net nicht oder... also nacht setzen der Library... (weil soweit ich weiss löscht der das wieder... also das gesetzte Verzeichniss.. also bei Neustart des Systems)

Nein. Wie gesagt hat dein Beispiel Programm bei mir einwandfrei funktioniert, ich hab extra die Bibliothek in ein anderes Verzeichnis verschoben um sicher zu gehen.

Da scheint irgendwas faul zu sein, die Frage ist nur was.

Ciao,
_

anda_skoa
17-04-2007, 13:02
ldconfig hasst aber ausgefuehrt ?

IMHO holt sich das dlopen zur laufzeit ned die pfade aus der env variable, sondern bekommt irgendwo nen hash, damit findets auch schneller die libs. Den hash erzeugst mit ldconfig ....

LD_LIBRARY_PATH erweitert den Lookup zur Laufzeit, d.h. dort wird vor den Verzeichnissen gesucht, die der Loader sonst konfiguriert hat.
ldconfig muß man nur aussführen, wenn man die Konfigurationsdatei in /etc geändert hat.



also mal fix vor programmstart die env variable anpassen und voiala, ploetzlich laden die programme alle ne andere version der .so geht so nicht, was auch sinn macht, weils nen ziemliches sicherheitsrisiko waer (programme mit suicid flag nutzen ja auch .so 's und die env variablen kann jeder fuer seine shell ueberschreiben ..... )


Darum geht es auch für root nicht. Für normale User schon (von Spezialsetups mit SELinux oder so abgesehen).

Ciao,
_

ufosworld
17-04-2007, 16:12
Ok, glaub ich weiss wieso das nicht geht..

ich mach das setenv LD_LIBRARY_PATH in Console 1

dann starte ich das Programm aus KDevelop heraus... dieser macht ja wieder eine neue Console auf... d.h. in dieser ist der LD_LIBRARY PATH nicht gesetzt.

dasselbe gilt für das Konsolen Fenster in Kdevelop...

d.h. ich müsste direkt bevor er das Programm startet in der Console, in dem er es dann ausführt

setenv LD_LIBRARY_PATH /blabla

ablaufen lassen...

=> ich müsste das irgendwo in KDEVELOP bei Parametern für das Consolenfenster das er da mitgibt einfügen... nur WO????

wenn ich nämlich in der Console, in der ich setenv mach, gleich dannach das Programm starte... funktioniert es auch... d.h. mit "triangle.so" und ohne links im Programm-Verzeichniss....

zu ldconfig...

wenn ich ldconfig aufrufe dann kommt nur Befehl nicht gefunden...

man ldconfig zeigt aber das an was ihr mir erklärt habt...
leider liegt ldconfig im Verzeichniss /sbin und da hab ich als normaler DAU-User keinen Zugriff drauf... nicht mal lesend....


aber das ist ja hinfällig, sobald ihr mr sagen könnt wo ich das setenv zeugs in KDevelop einfügen kann...

ansonsten bleibt mir nur die wahl das Tool in Kdevelop zu entwickeln, aber dann in der Console zu testen...

grüsse UFO

anda_skoa
17-04-2007, 18:15
Ok, glaub ich weiss wieso das nicht geht..

ich mach das setenv LD_LIBRARY_PATH in Console 1

dann starte ich das Programm aus KDevelop heraus... dieser macht ja wieder eine neue Console auf... d.h. in dieser ist der LD_LIBRARY PATH nicht gesetzt.

dasselbe gilt für das Konsolen Fenster in Kdevelop...

Klar, es heißt ja auch Umgebungsvariable, d.h. das aktuelle Environment eines Prozesses wird geändert (in diesem Fall der Shell).
Kindprozesse erben das Environment, d.h. Prozesse die aus der Shell gestartet werden hab es auch gesetzt.
Ein Prozess kann nicht in das Environment eines anderen eingreifen, daher wirkt sich das nicht auch in ein andere aus.



aber das ist ja hinfällig, sobald ihr mr sagen könnt wo ich das setenv zeugs in KDevelop einfügen kann...

Keine Ahnung, vielleicht dort wo man auch die Aufrufparameter des Programms angeben kann, mit denen es bei "Run" ausgeführt wird.

Ansonsten kannst du die Variable setzen und dann KDevelop in diesem Environment starten, siehe oben.

Ciao,
_

ufosworld
17-04-2007, 21:55
Ansonsten kannst du die Variable setzen und dann KDevelop in diesem Environment starten, siehe oben.


ja das dachte ich mir dann auch... also nicht mehr über K und dann Kdevelop

sondern in der Console nachdem ich gesetzt habe Kdevelop starten...

alles klar... denke dann hat sich das erledigt...

danke für die Hilfe

ufo :-D

RHBaum
18-04-2007, 07:46
Darum geht es auch für root nicht. Für normale User schon (von Spezialsetups mit SELinux oder so abgesehen).
DU meinst fuer alle die euid auf 0 haben schaut dlopen nicht auf den LD_LIBRARY_PATH ? Das wuerde auch Sinn machen.
Meine Linux Kentnisse liegen scho etwas zurueck, warn mal mit Suse 7.3 aktuell, da kann ich mich nicht an sowas erinnern ....


ja das dachte ich mir dann auch... also nicht mehr über K und dann Kdevelop
Solche umgebungsvariablen sind doch dafuer da, um sein programmverhalten zu steuern. Wenn dein Binary mal wo laufen soll, brauchst du da doch auch den wert in der LD_LIBRARY_PATH, ohne das KDevelop gestartet ist.
Denke mal der passendere Ort waere deine private .profile dann dafuer. Damit haette es deine loginshell und damit alle programme die du zu starten vermagst.

Ciao ....

anda_skoa
18-04-2007, 15:15
Solche umgebungsvariablen sind doch dafuer da, um sein programmverhalten zu steuern. Wenn dein Binary mal wo laufen soll, brauchst du da doch auch den wert in der LD_LIBRARY_PATH, ohne das KDevelop gestartet ist.

Je nach Art der Installation könnten die Module ja in einem der ld Suchpfade installiert sein, dann würde das wegfallen. Oder das Programm wird immer über ein Wrapperscript gestartet, das die entsprechenden Sachen setzt.

Ciao,
_

RHBaum
19-04-2007, 08:51
naja, Startscripte find ich mega unelegant, kann aber daher ruehren dass ich eher (berufsbedingt) in der windows welt unterwegs bin.

unter linux gibts sicher fertige scripts, wo man solche pfade erweitern kann in der .profile oder /etc/profile
Will man ne userfreundliche installationsroutine bauen (make install) wird man um so tricks eh ned herumkommen. Weiss nich ob man sich unter linux da prinzipiell so die muehe macht, und eigentlich gibts auch noch die packetmanager dafuer.

Ciao ...

anda_skoa
19-04-2007, 14:07
naja, Startscripte find ich mega unelegant, kann aber daher ruehren dass ich eher (berufsbedingt) in der windows welt unterwegs bin.

Du kannst auch ein Startbinary machen, wenn dir das besser gefällt (wie das unter Windows zB die meisten Spiele machen)



unter linux gibts sicher fertige scripts, wo man solche pfade erweitern kann in der .profile oder /etc/profile

Schon, aber das wirkt sich nur auf neue Shells aus, bei der Entwicklung will man meistens nur das Environment einer Shell schnell ändern und keine fixe Änderung machen.



Will man ne userfreundliche installationsroutine bauen (make install) wird man um so tricks eh ned herumkommen.

Ein Standard make install installiert eh nach /usr/local und dessen Pfade sind üblicherweise in den Variablen auch standardmäßig enthalten.
Wenn jeman ein anderes Prefix "configure"ed, dann hat er auch das Know-How das Environment anzupassen.

Problematischer sind Third-Party Installer, da wird praktisch immer mit einem Wrapperscript gestartet (bei Windows mit einem Wrapper Exe)



Weiss nich ob man sich unter linux da prinzipiell so die muehe macht, und eigentlich gibts auch noch die packetmanager dafuer.

Klar, im Idealfall hat man ein passendes Paket.

Ciao,
_

Tuxist
09-05-2007, 20:31
schreib ein sh script zum ausführen

#!/bin/bash
cd //exec ordener
export export LD_LIBARY_PATH= // libary pfad angeben
exec program