Forum: PC-Programmierung C/C++ Linux einbinden einer Lib über header funktioniert nicht


von René S. (thebit)


Lesenswert?

Hallo

ich habe ein Problem unter linux an dem ich verzweifle. Das Problem 
besteht sowohl in eclipse als auch beim compilieren auf der console
folgende files sind vorhanden:

main.c:
1
/*
2
*main.c
3
*
4
*/
5
6
#include <k8055.h>
7
8
#define false 0
9
#define true 1
10
 
11
int i,j;
12
 
13
int main (void){
14
   i=OpenDevice(0) //initialisiert Vellemann k8055 board-id 0
15
   j=0;
16
     while(true){
17
         WriteAllDigital(j);
18
         j++;
19
         if (j=3){
20
             j=0;
21
            }
22
     }
23
}

k8055.h (liegt unter /usr/local/include)
1
/* $Id: k8055.h,v 1.4 2008/05/21 20:25:51 mr_brain Exp $
2
This file is part of the libk8055 Library.
3
The libk8055 Library is free software; you can redistribute it and/or
4
modify it under the terms of the GNU Lesser General Public
5
License as published by the Free Software Foundation; either
6
version 2.1 of the License, or (at your option) any later version.
7
The libk8055 Library is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10
Lesser General Public License for more details.
11
You should have received a copy of the GNU General Public License
12
along with this program; if not, write to the
13
Free Software Foundation, Inc.,
14
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15
http://opensource.org/licenses/
16
*/
17
#ifdef __cplusplus
18
extern "C" {
19
#endif
20
/* prototypes */
21
int OpenDevice(long board_address);
22
int CloseDevice();
23
long ReadAnalogChannel(long Channelno);
24
int ReadAllAnalog(long* data1, long* data2);
25
int OutputAnalogChannel(long channel, long data);
26
int OutputAllAnalog(long data1,long data2);
27
int ClearAllAnalog();
28
int ClearAnalogChannel(long channel);
29
int SetAnalogChannel(long channel);
30
int SetAllAnalog();
31
int WriteAllDigital(long data);
32
int ClearDigitalChannel(long channel);
33
int ClearAllDigital();
34
int SetDigitalChannel(long channel);
35
int SetAllDigital();
36
int ReadDigitalChannel(long channel);
37
long ReadAllDigital();
38
int ResetCounter(long counternr);
39
long ReadCounter(long counterno);
40
int SetCounterDebounceTime(long counterno, long debouncetime);
41
int ReadAllValues (long int *data1, long int *data2, long int *data3, long int *data4, long int *data5);
42
int SetAllValues(int digitaldata, int addata1, int addata2);
43
long SetCurrentDevice(long deviceno);
44
long SearchDevices(void);
45
char *Version(void);
46
#ifdef __cplusplus
47
}
48
#endif

die dazugehörige libk8055.so liegt in /usr/local/lib
es gibt eine /etc/ld.so.conf.d/k8055.conf mit dem inhalt /usr/local/lib

laut dem Ersteller der lib (http://libk8055.sourceforge.net/)kann man 
diese einfach so nutzen:

gcc -Wall -lk8055 main.c

mache ich das, erhalte ich als Fehlermeldung:
Nicht definierter Verweis auf 'OpenDevice'
Nicht definierter Verweis auf 'WriteAllDigital'

die gleichen Fehler meldet auch Eclipse. Das Header File findet eclipse

Das der lib beigefügte Testprogramm funktioniert und bringt auch beim 
make keine Fehler. Ich habe zum Test auch mal alle includes des 
originalen Testprogramms in mein kleines Programm eingefügt, 
funktioniert auch nicht.
So langsam bin ich am Ende meiner Weisheit.

Normalerweise müsste der Code, an dem ja nicht viel dran ist, doch so 
funktionieren oder übersehe ich da etwas?


Gruß René

von nicht "Gast" (Gast)


Lesenswert?

Probier mal:
1
gcc -Wall main.c -lk80558
Die Reihenfolge ist wichtig.

von René S. (thebit)


Lesenswert?

Danke für die Info

hat zum Teil geholfen. Die "Nicht definierter Verweis" Fehler sind weg. 
Dafür meckert der gcc jetzt Funktionen an in der libk8055.so die wohl in 
der libusb drin sind. Erweitere ich die Zeile auf
1
gcc -Wall main.c -lk8055 -lusb

verschwinden die Fehler bis auf einen:

Nicht definierter Verweise in libk8055.so auf sqrtf

Irgendwie ist das suspekt. Warum meckert der Funktionen in einer 
gelinkten lib an? Vielleicht kann mir da noch jemand helfen solche 
Probleme hatte ich bisher noch nie. Obgleich ich zugeben muss ich habe 
lange nichts mehr programmiert und bisher immer nur die "Standard" libs 
benutzt.


Gruß René

von Narfie (Gast)


Lesenswert?

gcc -Wall main.c -lk8055 -lusb -lm

von g457 (Gast)


Lesenswert?

> icht definierter Verweise in libk8055.so auf sqrtf

Klingt nach -lm

> Warum meckert der Funktionen in einer gelinkten lib an?

Weil sie fehlt?

von René S. (thebit)


Lesenswert?

g457 schrieb:
> Weil sie fehlt?

ja aber gerade das wundert mich halt. Die libk8055 ist doch bereits 
erstellt und beim ursprünglichen compilieren der lib wurde doch die 
libusb etc. bereits mit verlinkt. Ich dachte eigentlich immer das alles 
was bereits in libs eingebaut ist muss dann nicht mehr angegeben werden. 
Irgendwie stehe ich da grade bisserl auf dem Schlauch.

gcc -Wall main.c -lk8055 -lusb -lm -o main führte dann übrigens zu einer 
funktionierenden ausführbaren Datei... nun muss ich das nur noch in 
Eclipse hinbekommen. Am Ende soll da mal etwas mit gui werden wobei es 
für die Vellemann k8055 auch eine qtk8055lib gibt, die habe ich jedoch 
noch nicht getestet.

Gruß René

von Bitflüsterer (Gast)


Lesenswert?

René S. schrieb:
> g457 schrieb:
>> Weil sie fehlt?
>
> ja aber gerade das wundert mich halt. Die libk8055 ist doch bereits
> erstellt und beim ursprünglichen compilieren der lib wurde doch die
> libusb etc. bereits mit verlinkt.
Nein.

> Ich dachte eigentlich immer das alles
> was bereits in libs eingebaut ist muss dann nicht mehr angegeben werden.

Das wurde sie nicht.
Versuche doch einmal selbst eine Library zu erzeugen.
Hier gibt es eine Anleitung: 
http://www.adp-gmbh.ch/cpp/gcc/create_lib.html
die ich mit dem Suchterm: "erstellen einer library" gefunden habe. (Ist 
allerdings ein Beispiel für'n PIC). Damit findet man sicher noch 
anderes, was Dir mehr Informationen gibt.

Es wäre auch kontraproduktiv, Funktionen aus anderen Libraries in die 
neu erzeugte Library zu übernehmen (im Sinne von kopieren). Nimm an, Du 
möchtest mehrere Libraries verwenden, die aller wiederum eine bestimmte 
Funktion aus einer dritten Library verwenden. Wenn jede davon eine Kopie 
der Funktion enthält, wäre das ineffektiv.
Gut. Man könnte da Gegenmaßnahmen überlegen, aber das einfachste ist, 
eben nur einen Verweis hinzuzufügen, der dann am Ende, vom Linker zu 
einer einzigen Kopie dieser Funktion führt. Das entspricht ohnehin der 
Vorgehensweise beim erzeugen von Objekt-Dateien (eine Library ist in 
gewisser Weise nur eine besondere Form von Objekt-Datei).

von René S. (thebit)


Lesenswert?

Bitflüsterer schrieb:
> Es wäre auch kontraproduktiv, Funktionen aus anderen Libraries in die
> neu erzeugte Library zu übernehmen (im Sinne von kopieren). Nimm an, Du
> möchtest mehrere Libraries verwenden, die aller wiederum eine bestimmte
> Funktion aus einer dritten Library verwenden. Wenn jede davon eine Kopie
> der Funktion enthält, wäre das ineffektiv.

Hmm dann habe ich das wohl etwas falsch ausgedrückt. Ich meinte wenn ich 
die libk8055 compiliere dann wird ja auf die Funktionen der libusb 
verwiesen. Diese ist wiederum im Quellcode der lib als include 
eingebunden. Ich meinte daher das der Compiler von der lib mitgeteilt 
bekommt welche er noch dazu linken muss. Das gleiche Problem ergibt sich 
ja wenn ich das File in Eclipse compilieren will. Auch eclipse weiß 
anscheinend nicht was und in welcher Reihenfolge er noch verlinken muss. 
Das irritiert mich halt ein wenig. Wenn ich z.B. iostream include wird 
in der ja auch weiter verlinkt ohne das ich die libs spezifisch angeben 
muss.

Den Link werde ich mir mal ansehen. Hier gings jedoch um eine Lib  die 
ich nicht selbst erstellt hab sondern auf dem System installiert ist.


Gruß René

von Bitflüsterer (Gast)


Lesenswert?

René S. schrieb:
> Hmm dann habe ich das wohl etwas falsch ausgedrückt. Ich meinte wenn ich
> die libk8055 compiliere dann wird ja auf die Funktionen der libusb
> verwiesen.
> Diese ist wiederum im Quellcode der lib als include
> eingebunden. Ich meinte daher das der Compiler von der lib mitgeteilt
> bekommt welche er noch dazu linken muss.

Wenn ich das versuche ganz neutral auszudrücken, dann verwendest Du die 
Begriffe "verweisen" und "einbinden" nicht so wie es den realen 
Vorgängen entspricht. Auch bekommt der Compiler nichts von einer Library 
"mitgeteilt". Das Du das nicht ohne Weiteres weisst, ist an sich nicht 
negativ, führt aber einfach zu falschen Schlussfolgerungen. Das ging uns 
allen mal so, das wir theoretisch mögliche Zusammenhänge die wir für 
bequem und sinnvoll hielten, irrigerweise für gegeben hielten, weil das 
dem "gesunden Menschenverstand" entsprach.

Tatsache ist aber folgendes:

1. Eine include-Anweisung fügt den Inhalt der genannten Header-Datei in 
den Programmtext ein. Nicht mehr nicht weniger. Ein "Verweis" ist damit 
in keiner Hinsicht erzeugt, beschrieben, genannt oder Ähnliches.
Da in einer Header-Datei im wesentlichen nichts weiter als Deklarationen 
stehen passt der Begriff "Verweis" auch nicht eigentlich.
Du wirst vielleicht schon wissen, das eine Deklaration erstmal nur 
festlegt welche Rückgabewert und welche Parameter eine Funktion hat bzw. 
welchen Typ eine Variable hat. Wenn Du darunter einen "Verweis" 
verstehst, dann fügst Du eine Bedeutung hinzu die so nicht enthalten 
ist.
Es kann irreführend sein, aber selbst wenn der Name der Header-Datei mit 
dem Namen der Library-Datei übereinstimmt, dann nutzt der Compiler diese 
Information nicht und gibt sie auch nicht an den Linker weiter.
Der Compiler nutzt die Deklarationen lediglich um vom Default-Typ 
abweichende Funktionen bzgl. der Verwendung des Rückgabewertes und der 
übergebenen Typen zu prüfen und passende Zuweisungs- bzw. 
Stackoperationen zu erzeugen. Mehr nicht.

2. Beim compilieren wird nur und ausschliesslich eine einzige 
Quelltext-Datei angeschaut. Der Compiler stellt keinen Zusammenhang 
zwischen einer Header-Datei und einer evtl. dazugehörigen Library-Datei 
her, wie er auch keinen Zusammenhang zu einer C-Datei herstellt, falls 
die Header-Datei sich darauf bezieht. Der Bezug wird ausschliesslich im 
Kopf des Programmierers hergestellt wenn er die Struktur seines 
Programmes plant und erstellt. Insbesondere ist eine Library kein 
aktives "Ding" das dem Compiler etwas mitteilt.
Der Compiler "sieht" ja letztlich auch, wie unter 1. erwähnt, auch 
garnicht das er evtl. gerade Text liest, der aus einer Header-Datei 
stammt. Er sieht nur Deklarationen. Nur C-Text.
Es wäre eine mehr philosophische Diskussion ob er das nicht doch tun 
sollte. Der Punkt ist, das das automatische (also programmatische, denn 
der Compiler ist ja auch ein Programm) Verhalten, wenn denn solche 
Zusammenhänge hergestellt werden sollen, wesentlich komplexer und 
fehleranfälliger wäre, weil neben dem Konzept das Du Dir auf dem Papier 
vorher gemacht hast, die Deutung des Programmtextes durch den Compiler 
dazu käme. Es ist auch wesentlich effizienter das Programm immer in 
kleinen Häppchen zu behandeln.

3. Weder beim kompilieren oder beim Linken wird der Quelltext einer 
verwendeten Library angeschaut. Andernfalls brächte man nämlich keine 
Library, wenn man jedesmal den gesamten Quelltext aller beteiligten 
Teile anschauen würde. Ausserdem eine Menge Speicher. Eine Library dient 
ja gerade dazu schon fertige ("schon perfekte") Teile zur weiteren 
Verwendung zusammenzufassen, ohne sie jedesmal neu "anschauen" zu 
müssen.


Die Zusammenhänge sind eigentlich nicht wirklich kompliziert. Das wirst 
Du schon begreifen, wenn Du mal ein wenig darüber liest und diskutierst. 
Passe nur sehr darauf auf, was Du nur "unterstellst" weil es DIR 
sinnvoll erscheinst und was dann tatsächlich ausdrücklich über das 
kompilieren und linken gesagt wird.
Der wesentliche Begriff ist der der "Modularisierung" und der damit 
angezielten Unabhängigkeit der Vorgänge der Kompiliation (in Bezug auf 
mehrere C-Dateien untereinander) und des Linkens voneinander. Was die 
Übersetzung und das Linken betrifft, sollen jedesmal in sich 
geschlossene Vorgänge stattfinden, die in Bezug auf den Code ein 
"sinnvolles" Teilergebnis ergeben.
Ein Objekt-File ist so ein Teil. Es enthält den ausführbaren Code der 
C-Datei mit "Verweisen" (hier kommt das Wort sinnvoll vor) auf 
Funktionen und Variablen die in anderen Objekt-Dateien "enthalten" sind 
(in dem Sinne das sie den Code dafür und Speicherplatzreservierungen 
enthalten).
Eine Library ist im wesentlichen auch so ein Objekt-File, wenn auch mit 
etwas komplexerer "Verweisstruktur".


> Das gleiche Problem ergibt sich
> ja wenn ich das File in Eclipse compilieren will. Auch eclipse weiß
> anscheinend nicht was und in welcher Reihenfolge er noch verlinken muss.

Eclipse ist lediglich eine IDE - eine Benutzeroberfläche mit 
komfortablem Editor. Über den Kompiliationsvorgang selbst weiß es 
absolut nichts. Und es braucht darüber auch nichts zu wissen. Wichtig 
ist, dass der Compiler und der Linker ihre notwendigen Informationen 
erhalten.
Es ist zugegeben nicht offensichtlich, dass, obwohl man in Eclipse z.B. 
die zum Projekt gehörenden Dateien angibt, nicht Eclipse compiliert und 
linkt sondern es diese Eingaben nur nutzt um den Compiler etc. 
aufzurufen.
Auch das Eclipse gewisse textuelle Zusammenhänge kennt, (etwa eine 
Funktionsdefinition auffinden kann, wenn man mal nachgucken will) 
bedeutet nicht, dass es den Programmtext in der selben Weise "versteht" 
wie der Compiler. (Das ist zugegeben etwas schwammig ausgedrückt). 
Eclipse nimmt den Text nur als Text, wie ein Mensch, der kein Spanisch 
kann, wohl in der Lage ist, einzelne Wörter zu isolieren und im 
Wörterbuch nachzuschlagen. Erst die Interpretation eines Satzes durch 
den Menschen ergibt die Bedeutung. Die Wortfolge und auch die Folge der 
Übersetzungen aus dem Wörterbuch enthält sie nicht.


> Das irritiert mich halt ein wenig. Wenn ich z.B. iostream include wird
> in der ja auch weiter verlinkt ohne das ich die libs spezifisch angeben
> muss.

iostream lässt sich nicht unmittelbar mit dem Fall einer selbst 
erstellten (oder von einem Dritten erstellten Library) vergleichen. Sie 
ist nämlich Teil des Sprachstandards und Compiler und Linker sind so 
geschrieben, dass sie gerade diese Library ohne Dein Eingreifen, d.h. 
ohne das Du sie ausdrücklicher im Linker-Befehl als Parameter angibst, 
dazulinken.

> Den Link werde ich mir mal ansehen. Hier gings jedoch um eine Lib  die
> ich nicht selbst erstellt hab sondern auf dem System installiert ist.

Ich habe Dir den Link genannt, damit Du Dir den Vorgang anschaust und 
evtl. die eine oder andere Schlussfolgerung ziehst. Libraries die Du 
nicht selbst erstellt hast, wurden jedenfalls so oder so ähnlich (wenn 
auch von jemand Anderem erstellt). Ihre allgemeinen Eigenschaften sind 
dieselben, egal wer die Library erstellt.

von Bitflüsterer (Gast)


Lesenswert?

Ich möchte Dir auch empfehlen unter den Stichworten "Compiler" und 
"Linker" einmal in Wikipedia nachzulesen und auch den verlinkten 
Begriffen nachzugehen. Wenn Du magst auch mal in der englischen 
Wikipedia (die ich bei solchen Themen meist bevorzuge - warum will ich 
hier mal nicht ausbreiten).

von René S. (thebit)


Lesenswert?

Danke für die ausführliche Erklärung. Muss mich wohl doch mal tiefer 
damit befassen. Obwohl ich das ganze vor gut 20 Jahren mal gelernt habe 
war mir das irgendwie nicht so bewusst. Kommt möglicherweise auch davon 
das ich bisher mehr php und selten c programmiert habe. Wenn in c habe 
ich bisher nur die Systembibliotheken genutzt.
Auf dem PC unter Windows in Delphi und Lazarus, aber auch nur wenig. Von 
Pascal bin ich halt gewöhnt, wenn ich mit uses xyz was einbinde dann 
holt der sich beim compilieren was er braucht.
Wollte das jetzt einfach mal unter C und Linux testen und merke das es 
doch ned so einfach mal schnell geht. Ich denke das auch hier meine 
Lesefaulheit Sonntag nachts die Ursache war. Ich hatte einfach den 
Befehl übernommen den der Autor der lib auf der Sourceforge Seite 
beschrieben hat... :)


Gruß René

von Rolf Magnus (Gast)


Lesenswert?

René S. schrieb:
> Wenn ich z.B. iostream include wird in der ja auch weiter verlinkt ohne
> das ich die libs spezifisch angeben muss.

Das liegt aber nur daran, dass der Compiler das schon implizit in die 
Linker-Kommandozeile mit aufnimmt, genauso wie die C-Standardlib und 
noch ein paar andere wie z.B. die libsupc++ oder libgcc. Wenn du ihm 
beim Linken den Kommandozeilenparameter -nostdlib mitgibst, tut er das 
nicht, und du bekommst auch für alle Standardfunktionen die Meldung 
"undefined reference", wenn du die Lib nicht explizit linkst.

von Bitflüsterer (Gast)


Lesenswert?

@ René

Bitte. Gern geschehen.

Unter Einbeziehung Deiner Vorerfahrungen, sind mir Deine "intuitiven" 
Annahmen nun etwas verständlicher. Ich hatte diesen Aspekt nicht sehr 
ausgebreitet und nur kurz unter dem Stichwort "Philosophie" angerissen.

Ich habe selbst mal mit Pascal bzw. dem alten TurboPascal unter CP/M 
angefangen. Ein anderer Fall ist z.B. Perl, dass ich recht oft verwende 
(PHP kenne ich nur vom Hörensagen :-) )

Es gibt da schon Unterschiede. Das alte TurboPascal z.B. hatte eine 
monolithischen Struktur: One For All.
Perl (ich denke in diesem Zusammenhang ist PHP nicht wirklich anders), 
kriegt ein "use" und dann war es das.

Theoretisch wäre so eine "Library-Intelligenz" (was einen Teil Deiner 
Frage betrifft) auch mit C möglich (und ich meine mich an einige 
C-Varianten z.B. für MSDOS oder CP/M zu erinnern, die das auch so 
machten. Allerdings ist das auch nicht ganz unproblematisch. Ich hatte 
das oben schon kurz angerissen, will das hier aber nicht weiter 
ausbreiten.

Klar: Wenn man eigentlich nur schnell mal was probieren wollte, dann ist 
das zunächst problematisch. Aber jedenfalls ist das alles nicht wirklich 
kompliziert. Und wenn Du mal die Wikipedia-Artikel gelesen hast und 
vielleicht noch einige Aspekte hier nachfragst, dann wirst Du das schon 
recht schnell verinnerlichen.

Viel Erfolg noch.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Bitflüsterer schrieb:
> Theoretisch wäre so eine "Library-Intelligenz" (was einen Teil Deiner
> Frage betrifft) auch mit C möglich

Nein, sogar praktisch. Es gibt C-Compiler, die über ein pragma einen 
Kommentar in Objektdateien unterbringen, der wiederum vom Linker 
ausgewertet wird und dafür sorgt, daß die so benannte Library quasi 
"automatisch" gelinkt wird.

Bei dieser Vorgehensweise genügt es also tatsächlich, eine Headerdatei 
einzubinden (sofern diese den pragma-Kommentar enthält) und der Rest 
passiert von alleine.

Aber das ist halt eine herstellerspezifische Vorgehensweise, und weil 
sie von Microsoft stammt, entweder verpönt oder möglicherweise 
patentrechtlich unterdrückt.
1
#pragma comment(lib, "libcmtd.lib")

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.