[C++] undefined ref met g++, niet met gcc

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • Bob
  • Registratie: Mei 2005
  • Laatst online: 20-09 11:26
Volgende code geraakt wel gelinkt als C code, niet als C++ code:

C, commando en output:
code:
1
2
3
4
5
6
=== Compiling main.o
arm-angstrom-linux-gnueabi-gcc -Wall   -I /home/bob/khepera3toolbox/Modules/khepera3 -I /home/bob/khepera3toolbox/Modules/i2cal -c  main.c -o main.o
main.c: In function ‘main’:
main.c:5: warning: control reaches end of non-void function
=== Building ctest
arm-angstrom-linux-gnueabi-gcc -o ctest main.o   /home/bob/khepera3toolbox/Modules/khepera3/khepera3.a /home/bob/khepera3toolbox/Modules/i2cal/i2cal.a -lm    -I /home/bob/khepera3toolbox/Modules/khepera3 -I /home/bob/khepera3toolbox/Modules/i2cal


C:
1
2
3
4
5
#include "khepera3.h"

int main(int bl, char** bla){
khepera3_init();
}


C++ commando en output:
code:
1
2
3
4
5
6
7
8
=== Compiling main.o
arm-angstrom-linux-gnueabi-g++ -Wall   -I /home/bob/khepera3toolbox/Modules/khepera3 -I /home/bob/khepera3toolbox/Modules/i2cal -c  main.cpp -o main.o
=== Building ctest
arm-angstrom-linux-gnueabi-g++ -o ctest main.o   /home/bob/khepera3toolbox/Modules/khepera3/khepera3.a /home/bob/khepera3toolbox/Modules/i2cal/i2cal.a -lm    -I /home/bob/khepera3toolbox/Modules/khepera3 -I /home/bob/khepera3toolbox/Modules/i2cal
main.o: In function `main':
main.cpp:(.text+0xc): undefined reference to `khepera3_init()'
collect2: ld returned 1 exit status
make: *** [ctest] Error 1


C++:
1
2
3
4
5
#include "khepera3.h"

int main(){
khepera3_init();
}


De cross compiler werkt, ik heb al enkele zaken zonder problemen gedraaid op het arm platform. De functie die hij niet vindt zit in khepera3.a. Ik heb al wat geprutst met extern maar dat hielp tot nu toe niet. Wat gaat er mis?

Acties:
  • 0 Henk 'm!

  • Matis
  • Registratie: Januari 2007
  • Laatst online: 22-09 14:14

Matis

Rubber Rocket

Moest je outputfile niet als laatste?

arm-angstrom-linux-gnueabi-g++ -o ctest main.o /home/bob/khepera3toolbox/Modules/khepera3/khepera3.a /home/bob/khepera3toolbox/Modules/i2cal/i2cal.a -lm -I /home/bob/khepera3toolbox/Modules/khepera3 -I /home/bob/khepera3toolbox/Modules/i2cal

Misschien kun je even je makefile posten!

Ik heb hier een makefile voorbeeld:

Bash:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
CC := g++
OUTPUTDIR := $(CURDIR)/MakeFolder
CFLAGS := -g

Thread: Thread.cpp
    $(CC) $(CFLAGS) -c Thread.cpp -o $(OUTPUTDIR)/Thread.o

Framedeinterlacer: Framedeinterlacer.cpp
    $(CC) $(CFLAGS) -c Framedeinterlacer.cpp -o $(OUTPUTDIR)/Framedeinterlacer.o

DeinterlacerProject: Deinterlacer.cpp $(OUTPUTDIR)/Thread.o $(OUTPUTDIR)/Framedeinterlacer.o
    $(CC) $(CFLAGS) -lpthread Deinterlacer.cpp $(OUTPUTDIR)/Thread.o $(OUTPUTDIR)/Framedeinterlacer.o -o $(OUTPUTDIR)/DeinterlacerProject

clean:
    -rm -f $(OUTPUTDIR)/*.*
    -rm -f $(OUTPUTDIR)/DeinterlacerProject

all: clean Thread Framedeinterlacer DeinterlacerProject

[ Voor 56% gewijzigd door Matis op 20-03-2009 12:19 . Reden: Extra tekst, Typo's ]

If money talks then I'm a mime
If time is money then I'm out of time


Acties:
  • 0 Henk 'm!

  • Bob
  • Registratie: Mei 2005
  • Laatst online: 20-09 11:26
Het ligt blijkbaar niet aan de linker, als de object file produceer met gcc zijn er geen problemen, dan lukt de link stap steeds. Het is met een door g++ geproduceerde object file dat het linken niet lukt.

Relevante delen van de Makefile (is nogal groot):
code:
1
2
3
4
5
6
7
$(TARGET): $(OBJS) $(MODS)
    @echo "=== Building $@"
    $(CXX) -o $@ $(OBJS) $(MODS) $(LIBS) $(INCS) $(CFLAGS)

%.o: %.cpp
    @echo "=== Compiling $@"
    $(CXX) -Wall $(INCS) -c $(CFLAGS) $< -o $@

Acties:
  • 0 Henk 'm!

  • Bob
  • Registratie: Mei 2005
  • Laatst online: 20-09 11:26
Gefikst.

C++:
1
2
3
4
5
6
7
extern "C" {
  void khepera3_init();
}

int main(){
khepera3_init();
}


De include mag er blijkbaar niet staan.

Acties:
  • 0 Henk 'm!

  • Matis
  • Registratie: Januari 2007
  • Laatst online: 22-09 14:14

Matis

Rubber Rocket

Bob schreef op vrijdag 20 maart 2009 @ 12:52:
Gefikst.

C++:
1
2
3
4
5
6
7
extern "C" {
  void khepera3_init();
}

int main(){
khepera3_init();
}


De include mag er blijkbaar niet staan.
Ik vind dit een beetje een fatsige workaround, maar het werkt wel. Dat is iig mooi om vanuit te gaan. Anders moet je ff een headerfile maken e.d.

Edit: heb je dit wel eens gelezen: http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html

Althans, dat zou je kunnen doen.

[ Voor 10% gewijzigd door Matis op 20-03-2009 13:22 . Reden: Extra tekst, Typo's ]

If money talks then I'm a mime
If time is money then I'm out of time


Acties:
  • 0 Henk 'm!

  • Bob
  • Registratie: Mei 2005
  • Laatst online: 20-09 11:26
toaomatis schreef op vrijdag 20 maart 2009 @ 13:21:
[...]


Ik vind dit een beetje een fatsige workaround, maar het werkt wel. Dat is iig mooi om vanuit te gaan. Anders moet je ff een headerfile maken e.d.

Edit: heb je dit wel eens gelezen: http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html

Althans, dat zou je kunnen doen.
Thx, ziet er nuttig uit.

Dus dit is 'proper'?

C++:
1
2
3
extern "C" {
#include "khepera3.h"
}

[ Voor 9% gewijzigd door Bob op 20-03-2009 14:45 ]


Acties:
  • 0 Henk 'm!

  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

Het heeft te maken met name mangling waarschijnlijk.
Op linux durf ik niet met 100% zekerheid te zeggen, maar een dynamic library (.so) heeft een lijst met geexporteerde functies, en khepera3_init() is er daar 1 van. In C was dat vrij simpel, de naam van de functie werd gebruikt als het "symbool" in de dynamic library.

In C++ komt er veel meer om de hoek kijken (calling conventions, function overloading) zodat een functie niet meer uniek geidentificeerd kan worden met de functie naam. Daarvoor gebruikt men "name mangling" die onder andere ook de typen van argumenten en calling conventions meenemen bij het genereren van het "symbool" voor die functie.

Omdat jij nu een library gebruikt die in C is geschreven, moet je aangeven dat bij het opzoeken van de functie khepera3_init de "C naam" gezocht moet worden. Dat doe je dus met extern "C". Soms word dit al in de header gedaan met een constructie als:
C:
1
2
3
4
5
6
7
#ifdef __cplusplus
extern "C" {
#endif
//de header file voor de rest
#ifdef __cplusplus
}
#endif


Maar helaas doet niet iedereen dit, en moet je het soms dus zelf doen. De netste manier is om gewoon de header file te gebruiken, in de extern "C" tags, zoals je nu zelf post. Je hebt dan het voordeel dat als je een vernieuwde header file hebt, je nog steeds kan compilen zonder problemen. Als je de hack doet zoals je een paar posts terug doet, en de ontwikkelaar van de library besluit om het type van een argument van een functie te veranderen, dan compiled en linkt jouw code nog wel, maar gaat mogelijk allerlei vage fouten geven als je het draait :)

-niks-


Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 23:05
Om een lang verhaal kort te maken:
Bob schreef op vrijdag 20 maart 2009 @ 13:54:
Dus dit is 'proper'?
C++:
1
2
3
extern "C" {
#include "khepera3.h"
}
Dit is een prima oplossing.

Acties:
  • 0 Henk 'm!

  • Bob
  • Registratie: Mei 2005
  • Laatst online: 20-09 11:26
Bedankt, de combinatie van het antwoord van Soultaker en MLM was het perfecte antwoord :)

Acties:
  • 0 Henk 'm!

  • Bob
  • Registratie: Mei 2005
  • Laatst online: 20-09 11:26
We zijn een week verder, ik heb geen problemen meer gehad tot vandaag. Wat werkte tot nu toe:
Ik had m'n eigen C++ libs gemaakt die verderbouwen op de C libs waarmee ik probeerde te linken. Werkte prima, ook had ik enkele C++ progs die ik dan weer linkte met deze C en eigen C++ libs. No problemo.
Vandaag typ ik 'make' en ... undefined reference van hier tot ginder. Ik gok dat ik ergens iets veranderd heb maar ik vind echt niet wat. Misschien weet nog een van jullie waar ik best zoek want ik vind het niet.

Dus: ik heb de C libs al opnieuw gecompileerd, mijn C++ libs ook, zonder errors.
Het linken van mijn C++ app loopt echter weer mis, als vroeger.

Nochtans include ik mijn C++ header van mijn C++ lib, en in die header (kheptools.h) staat dan weer:

C++:
1
2
3
extern "C" {
#include "khepera3.h"
}


Ik ga er morgen alleszins met een frisse kop eens opnieuw naar kijken, maar misschien weet er iemand of ik nog iets mis om te kunnen linken met een C lib?

de errors:
code:
1
2
3
4
5
6
7
8
9
/home/bob/khepera3toolbox/Modules/kheptools/kheptools.a(kheptools.o): In function `Khepera::setRightSpeed(float)':
kheptools.cpp:(.text+0x188): undefined reference to `khepera3_motor_set_speed'
kheptools.cpp:(.text+0x1a0): undefined reference to `khepera3'
/home/bob/khepera3toolbox/Modules/kheptools/kheptools.a(kheptools.o): In function `Khepera::setLeftSpeed(float)':
kheptools.cpp:(.text+0x240): undefined reference to `khepera3_motor_set_speed'
kheptools.cpp:(.text+0x258): undefined reference to `khepera3'
/home/bob/khepera3toolbox/Modules/kheptools/kheptools.a(kheptools.o): In function `Khepera::updateAmbientIR()':
kheptools.cpp:(.text+0x374): undefined reference to `khepera3_infrared_ambient_p'
 *enzovoort ...*

Acties:
  • 0 Henk 'm!

  • Bob
  • Registratie: Mei 2005
  • Laatst online: 20-09 11:26
Solved. Het is blijkbaar nogal belangrijk in welke volgorde de libs worden doorgegeven in de link fase. Het c++ lib eerst zetten was de oplossing. Kan dit niet vermeden worden? Het lijkt me nogal stom om altijd handmatig de juiste volgorde te moeten invoeren in de Makefile.

Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 23:05
Sommige linkers maakt 't niets uit, maar GNU binutils werken nog op de klassieke manier. Daarbij worden argumenten één voor één afgehandeld; alle definities uit object files worden in het geheel meegenomen, maar van libraries worden alleen die definities meegenomen waarop een eerdere object file een dependency heeft. Dat betekent dus dat je jouw code meestal voorop zet, en alle libraries waar je gebruik van maakt erachter (als libraries onderling depedencies hebben moet je ze ook weer goed ordenen, en bij cyclische dependencies moet je sommige libraries meer dan eens opgeven).

Het voordeel van die aanpak was/is dat je niet alles in het geheugen hoeft te houden en dat je argumenten (object files, libraries...) ook niet meer dan eens hoeft te openen. Ik zou zeggen dat linking tegenwoordig dermate snel is dat het niet echt een issue is om dat te optimaliseren, maar het is in de praktijk ook niet echt een probleem om libraries in die juiste volgorde op te geven, als je ongeveer begrijpt hoe de linker te werk gaat. ;)

Acties:
  • 0 Henk 'm!

  • TheWickedD
  • Registratie: Juli 2002
  • Laatst online: 02-04-2024
Hmm, mooie tips in dit topic, ik dacht het ook even uit te proberen met VS2008, lukt dus niet:

Als ik onderstaande eerste in onderstaande tweede verander krijg ik build (niet linker!) errors

C++:
1
2
3
4
5
6
7
8
9
#   include "..\flybox\lv3.h"

extern "C" int  open_lv(bglv *, char *, int );
extern "C" int  init_lv(bglv *);
extern "C" void close_lv(bglv *bgp);
extern "C" int  w_lv(int sp_fd, char *mode);
extern "C" int  r_lv(bglv *);
extern "C" int  check_rev(bglv *);
extern "C" int  check_setup(bglv *);

C++:
1
2
3
4
extern "C" { 
    //http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html
#   include "..\flybox\lv3.h"
}

code:
1
2
3
4
5
6
1>.\Flybox.cpp(64) : error C3861: 'w_lv': identifier not found
1>.\Flybox.cpp(95) : error C3861: 'open_lv': identifier not found
1>.\Flybox.cpp(105) : error C3861: 'init_lv': identifier not found
1>.\Flybox.cpp(117) : error C3861: 'close_lv': identifier not found
1>.\Flybox.cpp(124) : error C3861: 'r_lv': identifier not found
1>.\Flybox.cpp(131) : error C3861: 'w_lv': identifier not found


Maak ik hier een stomme fout?

Acties:
  • 0 Henk 'm!

  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

Je haalt je include file uit de extern "C" context, dat lijkt me niet de bedoeling

Tevens is technisch gezien extern "C" X niet hetzelfde als extern "C" { X } omdat in het eerste geval extern ook als storage type voor X word meegenomen. Ik zie niet hoe dat uit gaat maken...

-niks-


Acties:
  • 0 Henk 'm!

  • TheWickedD
  • Registratie: Juli 2002
  • Laatst online: 02-04-2024
Goed, dit was een heel stomme fout van mij. Die functies worden helemaal niet gedeclareerd in die header (tis een oude driver, best een zootje), logisch dat het dan bij het builden al fout gaat, zo kan hij heel die functies niet vinden natuurlijk.

Sorry, maar bedankt voor deze thread, weer wat geleerd ervan!

Toch benieuwd, MLM, wat bedoel je met ik haal mijn include uit de extern "C" context? Hij zit toch tussen de {}'s?

[ Voor 15% gewijzigd door TheWickedD op 30-03-2009 09:00 ]

Pagina: 1