Hi,

I have 3 seperate make file where,
1st one generates a static library libCanOpen.a,
(using ""ar -r ")
2nd one creates a dynamically linkable library libPixyCANopen.so
(using "g++ -Wall -fPIC -shared")
and the 3rd one creates the executable by linking it to libPixyCANopen.so.

The 1st two makefiles build without a single warning (-Wall is used)
The last Makefile is generating linking error like the following:

../lib/libPixyCANopen.so: undefined reference to `coTimerPulse'
../lib/libPixyCANopen.so: undefined reference to `releaseTimer'

nm command shows that the corresponding object names are mangled (e.g. _Z12releaseTimerv), Using extern "C" in the header file did not remove it.

But, I am using g++ for every compilation, so I think the mangling should not matter.

Any suggestion is appreciated.

Thanks,
Anirban

> nm command shows that the corresponding object names are mangled (e.g. _Z12releaseTimerv),
Try adding the extern "C" to the implementation of those functions as well.

> Using extern "C" in the header file did not remove it.
But it did make it so that the users of that function did get the unmangled name.

Thanks .. that did help ..

There is only one linking error now, it's an extern variable .. the problem is same .. "undefined reference to <var_name>" ..

Need to share this variable .. that means I have to keep that extern stuff .. but, how?

Thanks .. that did help ..

There is only one linking error now, it's an extern variable .. the problem is same .. "undefined reference to <var_name>" ..

Need to share this variable .. that means I have to keep that extern stuff .. but, how?

The short answer to that one is that you should not have public access to the variable, access should be wrapped within get/set methods.

And you shouldn't have to worry about name-mangling, declaring functions as extern C isn't necessary. What do your makefiles look like?

It's shouldn't be necessary to use extern,
generally you have access to all the public variables and function in the symboltable, but only the externed are required to have the same signature, from version to version.
This is atleast how it should be.

http://people.redhat.com/drepper/dsohowto.pdf

try doing a ldd on your compiled files to see if anything is missing

This was my assumption too. As I am using g++ for all the cmpilation, extern "C" stuff does not seem logical. however, here are the outputs of 3 Makefiles in order:

Makefile #1

root:/tmp/trunk/CANopenStack/source# make CC=g++
g++ -Wall -I/tmp/trunk/PIXYapi/include -I/tmp/trunk/PIXYapi -I../include -I. -I/tmp/trunk/CANdriver/include   -c -o access_o.o access_o.c
g++ -Wall -I/tmp/trunk/PIXYapi/include -I/tmp/trunk/PIXYapi -I../include -I. -I/tmp/trunk/CANdriver/include   -c -o cmsmain.o cmsmain.c
g++ -Wall -I/tmp/trunk/PIXYapi/include -I/tmp/trunk/PIXYapi -I../include -I. -I/tmp/trunk/CANdriver/include   -c -o nmt.o nmt.c
g++ -Wall -I/tmp/trunk/PIXYapi/include -I/tmp/trunk/PIXYapi -I../include -I. -I/tmp/trunk/CANdriver/include   -c -o cmscodec.o cmscodec.c
g++ -Wall -I/tmp/trunk/PIXYapi/include -I/tmp/trunk/PIXYapi -I../include -I. -I/tmp/trunk/CANdriver/include   -c -o sdoserv.o sdoserv.c
g++ -Wall -I/tmp/trunk/PIXYapi/include -I/tmp/trunk/PIXYapi -I../include -I. -I/tmp/trunk/CANdriver/include   -c -o sdoclien.o sdoclien.c
g++ -Wall -I/tmp/trunk/PIXYapi/include -I/tmp/trunk/PIXYapi -I../include -I. -I/tmp/trunk/CANdriver/include   -c -o sdomain.o sdomain.c
g++ -Wall -I/tmp/trunk/PIXYapi/include -I/tmp/trunk/PIXYapi -I../include -I. -I/tmp/trunk/CANdriver/include   -c -o sdo.o sdo.c
g++ -Wall -I/tmp/trunk/PIXYapi/include -I/tmp/trunk/PIXYapi -I../include -I. -I/tmp/trunk/CANdriver/include   -c -o emerg.o emerg.c
g++ -Wall -I/tmp/trunk/PIXYapi/include -I/tmp/trunk/PIXYapi -I../include -I. -I/tmp/trunk/CANdriver/include   -c -o lme.o lme.c
g++ -Wall -I/tmp/trunk/PIXYapi/include -I/tmp/trunk/PIXYapi -I../include -I. -I/tmp/trunk/CANdriver/include   -c -o pdo.o pdo.c
g++ -Wall -I/tmp/trunk/PIXYapi/include -I/tmp/trunk/PIXYapi -I../include -I. -I/tmp/trunk/CANdriver/include   -c -o set_com.o set_com.c
g++ -Wall -I/tmp/trunk/PIXYapi/include -I/tmp/trunk/PIXYapi -I../include -I. -I/tmp/trunk/CANdriver/include   -c -o sync.o sync.c
g++ -Wall -I/tmp/trunk/PIXYapi/include -I/tmp/trunk/PIXYapi -I../include -I. -I/tmp/trunk/CANdriver/include   -c -o utility.o utility.c
g++ -Wall -I/tmp/trunk/PIXYapi/include -I/tmp/trunk/PIXYapi -I../include -I. -I/tmp/trunk/CANdriver/include   -c -o time.o time.c
g++ -Wall -I/tmp/trunk/PIXYapi/include -I/tmp/trunk/PIXYapi -I../include -I. -I/tmp/trunk/CANdriver/include   -c -o timer.o timer.c
g++ -Wall -I/tmp/trunk/PIXYapi/include -I/tmp/trunk/PIXYapi -I../include -I. -I/tmp/trunk/CANdriver/include   -c -o nmterr.o nmterr.c
g++ -Wall -I/tmp/trunk/PIXYapi/include -I/tmp/trunk/PIXYapi -I../include -I. -I/tmp/trunk/CANdriver/include   -c -o nmt_s.o nmt_s.c
g++ -Wall -I/tmp/trunk/PIXYapi/include -I/tmp/trunk/PIXYapi -I../include -I. -I/tmp/trunk/CANdriver/include   -c -o led.o led.c
g++ -Wall -I/tmp/trunk/PIXYapi/include -I/tmp/trunk/PIXYapi -I../include -I. -I/tmp/trunk/CANdriver/include   -c -o co_debug.o co_debug.c
g++ -Wall -I/tmp/trunk/PIXYapi/include -I/tmp/trunk/PIXYapi -I../include -I. -I/tmp/trunk/CANdriver/include   -c -o heartbt.o heartbt.c
g++ -Wall -I/tmp/trunk/PIXYapi/include -I/tmp/trunk/PIXYapi -I../include -I. -I/tmp/trunk/CANdriver/include   -c -o slave_ut.o slave_ut.c
ar -r ./lib/libCanOpen.a access_o.o cmsmain.o nmt.o cmscodec.o sdoserv.o sdoclien.o sdomain.o sdo.o emerg.o lme.o pdo.o set_com.o sync.o utility.o time.o timer.o nmterr.o nmt_s.o led.o co_debug.o heartbt.o slave_ut.o
ar: creating ./lib/libCanOpen.a

Makefile #2

root:/tmp/trunk/PIXYapi# make CC=g++
g++ -Wall -fPIC -shared -DNO_RT -I. -I./include -I../CANopenStack/include -I../CANdriver/include   -c -o ../CANdriver/src/can_p_l.o ../CANdriver/src/can_p_l.c
g++ -Wall -fPIC -shared -DNO_RT -I. -I./include -I../CANopenStack/include -I../CANdriver/include   -c -o ../CANdriver/src/cpu_generic.o ../CANdriver/src/cpu_generic.c
g++ -Wall -fPIC -shared -DNO_RT -I. -I./include -I../CANopenStack/include -I../CANdriver/include   -c -o ../CANdriver/src/cdriver.o ../CANdriver/src/cdriver.c
g++ -Wall -fPIC -shared -DNO_RT -I. -I./include -I../CANopenStack/include -I../CANdriver/include   -c -o ../CANdriver/src/cpu.o ../CANdriver/src/cpu.c
g++ -Wall -fPIC -shared -DNO_RT -I. -I./include -I../CANopenStack/include -I../CANdriver/include   -c -o co_init.o co_init.c
g++ -Wall -fPIC -shared -DNO_RT -I. -I./include -I../CANopenStack/include -I../CANdriver/include   -c -o nmtslave.o nmtslave.c
g++ -Wall -fPIC -shared -DNO_RT -I. -I./include -I../CANopenStack/include -I../CANdriver/include   -c -o objects.o objects.c
g++ -Wall -fPIC -shared -DNO_RT -I. -I./include -I../CANopenStack/include -I../CANdriver/include   -c -o usr_301.o usr_301.c
g++ -Wall -fPIC -shared -DNO_RT -I. -I./include -I../CANopenStack/include -I../CANdriver/include   -c -o PixyCANopen.o PixyCANopen.c
g++ -Wall -fPIC -shared -DNO_RT -I. -I./include -I../CANopenStack/include -I../CANdriver/include -shared -o lib/libPixyCANopen.so ../CANdriver/src/can_p_l.o ../CANdriver/src/cpu_generic.o ../CANdriver/src/cdriver.o ../CANdriver/src/cpu.o co_init.o nmtslave.o objects.o usr_301.o PixyCANopen.o -L../CANopenStack/source/lib/ -L./lib -lpcan -lCanOpen -lh8com

Makefile #3

root:/tmp/trunk/PIXYapi/test# make
g++ -g -Wall -DNO_RT -I../include/ -I../ -I../../CANopenStack/include/ -I../../CANdriver/include/ -I../CANopenStack/source   -c -o src/main.o src/main.cpp
g++ -g -Wall -DNO_RT -I../include/ -I../ -I../../CANopenStack/include/ -I../../CANdriver/include/ -I../CANopenStack/source -L../lib -lPixyCANopen -o ApiTest src/main.o 
../lib/libPixyCANopen.so: undefined reference to `coTimerPulse'

Existence of coTimerPulse in code is:

root:/tmp/trunk# grep -nR "coTimerPulse" *
CANdriver/src/.svn/text-base/cpu_generic.c.svn-base:164:VOLATILE UNSIGNED16 CO_CONST coTimerPulse = CONFIG_TIMER_INC; /**< length of 1 tick / unit 100us */
CANdriver/src/cpu_generic.c:169:UNSIGNED16 CO_CONST coTimerPulse = CONFIG_TIMER_INC; /**< length of 1 tick / unit 100us */
CANopenStack/include/co_drv.h:149:extern UNSIGNED16 coTimerPulse;
CANopenStack/include/co_drv.h:151:extern UNSIGNED16 CO_CONST coTimerPulse;
Binary file CANopenStack/source/timer.o matches
CANopenStack/source/lme.c:533:    GL_VAR(coTimerPulse) = CONFIG_TIMER_INC;
Binary file CANopenStack/source/lib/libCanOpen.a matches
CANopenStack/source/globvars.c:261://UNSIGNED16 coTimerPulse;
CANopenStack/source/timer.c:565:    if (timerVal > ((UNSIGNED32)GL_VAR(coTimerPulse) << 15))  {
CANopenStack/source/timer.c:573:    if ((timerVal + pTimer->restTime) <= GL_VAR(coTimerPulse))  {
CANopenStack/source/timer.c:580:        pTimer->endTime = tVal / GL_VAR(coTimerPulse);
CANopenStack/source/timer.c:582:        pTimer->endTime = (UNSIGNED16)(tVal / GL_VAR(coTimerPulse));
CANopenStack/source/timer.c:585:        pTimer->restTime = (UNSIGNED16)(tVal % GL_VAR(coTimerPulse));
CANopenStack/source/timer.c:744:        retVal = addTimerEvent(pTimer, pTimer->endTime * GL_VAR(coTimerPulse),
CANopenStack/source/timer.c:829:    ticks = timerVal / GL_VAR(coTimerPulse);
CANopenStack/source/timer.c:831:    if ((ticks * GL_VAR(coTimerPulse)) < timerVal)  {
GL_VAR(coTimerPulse) = CONFIG_TIMER_INC;
Binary file PIXYapi/test/lib/libPixyCANopen.so matches
Binary file PIXYapi/lib/libPixyCANopen.so matches

It's shouldn't be necessary to use extern,
generally you have access to all the public variables and function in the symboltable, but only the externed are required to have the same signature, from version to version.
This is atleast how it should be.

http://people.redhat.com/drepper/dsohowto.pdf

try doing a ldd on your compiled files to see if anything is missing

root:/tmp/trunk/PIXYapi/lib# ldd libPixyCANopen.so
libpcan.so.0 => /usr/lib/libpcan.so.0 (0x00138000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x0013b000)
libm.so.6 => /lib/libm.so.6 (0x0021c000)
libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x00241000)
libc.so.6 => /lib/libc.so.6 (0x0024c000)
/lib/ld-linux.so.2 (0xb7f07000)$

I removed the extern variable and now the linking problem is gone .. but still I will keep trying to remove the extern "C" completely from my code.

Could you try doing a
'ldd libPixyCANopen.so'

This article has been dead for over six months. Start a new discussion instead.