Recent

Author Topic: using c libraries in embedded fpc project  (Read 4327 times)

diego bertotti

  • Full Member
  • ***
  • Posts: 101
using c libraries in embedded fpc project
« on: April 13, 2020, 01:33:07 am »
Hello
Someone use a c library in a embedded arm/avr fpc project?
I know it can be do it, using external cdecl.
I'll try, but i appreciate all the help you'll can bring me
thanks
diego
« Last Edit: April 13, 2020, 01:44:28 am by diego bertotti »

Ñuño_Martínez

  • Hero Member
  • *****
  • Posts: 1186
    • Burdjia
Re: using c libraries in embedded fpc project
« Reply #1 on: April 13, 2020, 12:34:04 pm »
What problem do you have?

Anyway, read $L or $LINK : Link object file$LINKLIB : Link to a library and External functions.

Also note that not always you should use CDECL, sometimes you should use STDCALL.  It depends the way the function was declared and compiled in C.
Are you interested in game programming? Join the Pascal Game Development community!
Also visit the Game Development Portal

JiaXing

  • Jr. Member
  • **
  • Posts: 75
Re: using c libraries in embedded fpc project
« Reply #2 on: April 13, 2020, 01:14:34 pm »
What problem do you have?

Anyway, read $L or $LINK : Link object file$LINKLIB : Link to a library and External functions.

Also note that not always you should use CDECL, sometimes you should use STDCALL.  It depends the way the function was declared and compiled in C.

I didn't see anyone use STDCALL outside of the Windows world. It's all CDECL.
I'm subscribed to the church of 440bx. Say no to OOP  :P

PascalDragon

  • Hero Member
  • *****
  • Posts: 5486
  • Compiler Developer
Re: using c libraries in embedded fpc project
« Reply #3 on: April 13, 2020, 02:10:06 pm »
Also note that not always you should use CDECL, sometimes you should use STDCALL.  It depends the way the function was declared and compiled in C.

On non-i386 targets that doesn't matter anyway as there is only one calling convention per target (in general; there are a few exceptions, but they are very rare).

I didn't see anyone use STDCALL outside of the Windows world. It's all CDECL.

It's very seldom, but GCC does support the other calling conventions for i386 after all.

diego bertotti

  • Full Member
  • ***
  • Posts: 101
Re: using c libraries in embedded fpc project
« Reply #4 on: April 15, 2020, 04:04:52 am »
hi.

i try to use this units from arduino example "HardTimerAsEncoder".

was complied using gcc c compiler (arduino ide)

Code: Pascal  [Select][+][-]
  1. program project_ext_c_lib;
  2.  
  3. //{$L HardwareTimer.o}
  4.  
  5. uses cortexm3;
  6.  
  7. {$O-}
  8.   Procedure HardwareTimer(ID: byte); cdecl; external;// name 'HardwareTimer';
  9.   {$L HardwareTimer.o}
  10.   Procedure pause; cdecl; external;// name 'pause';
  11.   {$L HardwareTimer.o}
  12.   Procedure attachInterrupt(pin: byte; handler: byte; mode: byte); cdecl;  external;
  13.   {$L ext_interrupts.o}
  14.  
  15. begin
  16.  
  17.  HardwareTimer(2);
  18.  
  19.   pause;
  20.  
  21.   attachInterrupt(0,0,0); //not real params values, just to test compiler/linker
  22.  end.  
  23.  

and the result was.....

Messages window
***************************
Compile Project, OS: embedded, CPU: arm, Target: project_ext_c_lib: Exit code 1, Errors: 1
C:\Users\user\Documents\lib\arm-embedded\project_ext_c_lib.o: In function `PASCALMAIN':
project_ext_c_lib.lpr:(.text.n_main+0x14): undefined reference to `HardwareTimer'
project_ext_c_lib.lpr:(.text.n_main+0x18): undefined reference to `pause'
project_ext_c_lib.lpr:(.text.n_main+0x28): undefined reference to `attachInterrupt'
project_ext_c_lib.lpr(25,0) Error: Error while linking
***************************

what i do wrong?

HardwareTimer.o and  ext_interrupts.o and its parents .h and .cpp files are in the same directory of project

lazarus 2.1.0 fpc 3.3.1 win 10

thanks
« Last Edit: April 15, 2020, 07:53:22 pm by diego bertotti »

MiR

  • Sr. Member
  • ****
  • Posts: 250
Re: using c libraries in embedded fpc project
« Reply #5 on: April 15, 2020, 08:18:51 pm »
Things will get easier when you start simple, set your first goal to blink a led when creating bindings to c-objects is something new for you.

to do so check how the functions that you are using are exported from the object file, are they exported as simple symbols or are they name mangled. Arduino uses c++ internally so chances are high that the symbols are name mangled.

arm-none-eabi-nm will help you to find this out.

look for the symbols marked with the big letter T, those are the symbols defined in the object file. Do the look like simple plain names or are there crazy letters arround the symbol name?

When there are crazy letters then I‘d propose to stop just there, the stuff is name mangled and c++code. Things will get complicated, please trust me.

play arround with something that is not written in C++ like libopencm3 to get your feet wet.

Michael

diego bertotti

  • Full Member
  • ***
  • Posts: 101
Re: using c libraries in embedded fpc project
« Reply #6 on: April 16, 2020, 12:25:16 am »
thanks for the info

now IT WORKS!!! or maybe i don't see error at compile time. dont know at runtime yet.

look the names of functions in the c source code
************************************
void HardwareTimer::pause(void) {
    timer_pause(this->dev);
}

void HardwareTimer::resume(void) {
    timer_resume(this->dev);
}
************************************

and now look the functions real names at the .o file

Code: Pascal  [Select][+][-]
  1. program project_ext_c_lib;
  2.  
  3. uses cortexm3;
  4.  
  5.   Procedure _ZN13HardwareTimer5pauseEv; cdecl; external;// name 'pause';
  6.   {$L HardwareTimer.o}
  7.   Procedure _ZN13HardwareTimer6resumeEv; cdecl; external;// name 'pause';
  8.   {$L HardwareTimer.o}
  9.  
  10. begin
  11.  _ZN13HardwareTimer5pauseEv;
  12.  _ZN13HardwareTimer6resumeEv;
  13.  end.  
  14.  

and result on Messages windows was:

******************************
Compile Project, OS: embedded, CPU: arm, Target: project_ext_c_lib: Success
******************************

a nightmare!
« Last Edit: April 16, 2020, 12:31:57 am by diego bertotti »

diego bertotti

  • Full Member
  • ***
  • Posts: 101
Re: using c libraries in embedded fpc project
« Reply #7 on: April 16, 2020, 12:47:45 am »
good news!

i found this way
Code: Pascal  [Select][+][-]
  1. program project_ext_c_lib;
  2.  
  3. uses cortexm3;
  4.  
  5.   Procedure pause; cdecl; external name '_ZN13HardwareTimer5pauseEv';
  6.   Procedure resume; cdecl; external name '_ZN13HardwareTimer6resumeEv';
  7.   Function getCount: word; cdecl; external name'_ZN13HardwareTimer8getCountEv';
  8.   Procedure setCount(count: word); cdecl; external name'_ZN13HardwareTimer8setCountEt';
  9.   {$L HardwareTimer.o}
  10.  
  11. begin
  12.  pause;
  13.  resume;
  14.  setCount(getCount);
  15.  end.
  16.  

and compiled without error!
« Last Edit: April 16, 2020, 12:51:54 am by diego bertotti »

Cyrax

  • Hero Member
  • *****
  • Posts: 836
Re: using c libraries in embedded fpc project
« Reply #8 on: April 16, 2020, 03:51:16 am »
...
look the names of functions in the c source code
************************************
void HardwareTimer::pause(void) {
    timer_pause(this->dev);
}

void HardwareTimer::resume(void) {
    timer_resume(this->dev);
}
************************************
...

That isn't C, it is C++. And your program will burn and crash if run due to need for a pointer for the C++ class (this, it will be need to passed as hidden parameter).

diego bertotti

  • Full Member
  • ***
  • Posts: 101
Re: using c libraries in embedded fpc project
« Reply #9 on: April 16, 2020, 06:27:05 pm »
thanks cyrax

the object file (HardwareTimer.o) have this assembler (using objdump.exe)
Code: Pascal  [Select][+][-]
  1.  
  2. 00000000 <_ZN13HardwareTimer5pauseEv>:
  3.    0:   6803            ldr     r3, [r0, #0]
  4.    2:   2200            movs    r2, #0
  5.    4:   681b            ldr     r3, [r3, #0]
  6.    6:   015b            lsls    r3, r3, #5
  7.    8:   f103 4384       add.w   r3, r3, #1107296256     ; 0x42000000
  8.    c:   601a            str     r2, [r3, #0]
  9.    e:   4770            bx      lr
  10.  
  11.  
  12. 00000000 <_ZN13HardwareTimer6resumeEv>:
  13.    0:   6803            ldr     r3, [r0, #0]
  14.    2:   2201            movs    r2, #1
  15.    4:   681b            ldr     r3, [r3, #0]
  16.    6:   015b            lsls    r3, r3, #5
  17.    8:   f103 4384       add.w   r3, r3, #1107296256     ; 0x42000000
  18.    c:   601a            str     r2, [r3, #0]
  19.    e:   4770            bx      lr
  20.  

look the project assembler (project_ext_c_lib.s)

Code: Pascal  [Select][+][-]
  1. # [project_ext_c_lib.lpr]
  2. # [11] begin
  3.         mov     r12,r13
  4.         push    {r11,r14}
  5.         sub     r11,r12,#4
  6.         sub     r13,r13,#44
  7.         bl      fpc_initializeunits
  8. # [13] pause;
  9.         bl      _ZN13HardwareTimer5pauseEv
  10. # [14] resume;
  11.         bl      _ZN13HardwareTimer6resumeEv
  12. # [15] setCount(getCount);
  13.         bl      _ZN13HardwareTimer8getCountEv
  14.         uxth    r0,r0
  15.         uxth    r0,r0
  16.         bl      _ZN13HardwareTimer8setCountEt
  17. # [16] end.
  18.         bl      fpc_do_exit
  19.         add     r13,#44
  20.         pop     {r11,r15}
  21. .Lc1:
  22.  

it seems will not crash, but will don't work because i don't call before the initializing function, then this pointer is actually null, then compiler put empty function

Leledumbo

  • Hero Member
  • *****
  • Posts: 8757
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: using c libraries in embedded fpc project
« Reply #10 on: April 16, 2020, 08:38:04 pm »
I would flatten that class' methods to C before linking with FPC. C++ name mangling isn't standardized that even changing compiler version is enough to break existing code. At least in C it's consistent.

PascalDragon

  • Hero Member
  • *****
  • Posts: 5486
  • Compiler Developer
Re: using c libraries in embedded fpc project
« Reply #11 on: April 17, 2020, 05:45:52 pm »
I would flatten that class' methods to C before linking with FPC. C++ name mangling isn't standardized that even changing compiler version is enough to break existing code. At least in C it's consistent.

If you're just linking against specific libraries that doesn't really matter. And GCC's name mangling is rather stable (there was only a really big change in version 2, namely when they switched to the Sys V ABI).

Also how about something crazy? :-X

Code: Pascal  [Select][+][-]
  1. program tcppcls;
  2.  
  3. type
  4.   THardwareTimer = cppclass external name 'HardwareTimer'
  5.   public
  6.     procedure pause;
  7.     procedure resume;
  8.     function getCount: Word;
  9.     procedure setCount(count: Word);
  10.   end;
  11.   // enable this; I don't have a HardwareTimer.o
  12.   {.$L HardwareTimer.o}
  13.  
  14. var
  15.   // the mangled name of the hardwareTimer variable
  16.   // using "cvar; external;" instead it would look for "_hwtimer"
  17.   hwtimer: THardwareTimer; external name 'hardwareTimer';
  18. begin
  19.   hwtimer.resume;
  20.   hwtimer.pause;
  21.   hwtimer.setCount(42);
  22. end.

At least judging by the linker errors the correct functions are looked for ;)

Code: [Select]
PS E:\fpc\git> fpc -FEtestoutput .\fpctests\tcppcls.pp -al
Free Pascal Compiler version 3.0.4 [2019/10/27] for i386
Copyright (c) 1993-2017 by Florian Klaempfl and others
Note: Switching assembler to default source writing assembler
Target OS: Win32 for i386
Compiling .\fpctests\tcppcls.pp
Assembling tcppcls
Linking testoutput\tcppcls.exe
Error: Undefined symbol: hardwareTimer
Error: Undefined symbol: __ZN13HardwareTimer6resumeEv
Error: Undefined symbol: __ZN13HardwareTimer5pauseEv
Error: Undefined symbol: __ZN13HardwareTimer8setCountEt
Fatal: There were 4 errors compiling module, stopping
Fatal: Compilation aborted
Error: E:\lazarus\2.0.6\fpc\3.0.4\bin\i386-win32\ppc386.exe returned an error exitcode

MiR

  • Sr. Member
  • ****
  • Posts: 250
Re: using c libraries in embedded fpc project
« Reply #12 on: April 17, 2020, 06:11:51 pm »
Thank you for that cppclass syntax gem, PascalDragon, especially because when I researched it on the forum I found an article that pointed to this (imho big) gem:

http://www.fmxexpress.com/create-wrapper-interfaces-for-c-and-c-libraries-using-swig-with-delphi-support/

I have searched for something like this for a long time, and now I realize that it was hiding in plain sight for quite a long time!

Thank you again,

Michael


diego bertotti

  • Full Member
  • ***
  • Posts: 101
Re: using c libraries in embedded fpc project
« Reply #13 on: April 17, 2020, 10:03:43 pm »
hi

thanks for the info!!

i found this web to demangle names

http://demangler.com

Pascaldragon you can get the files from the attachment

now with this code
Code: Pascal  [Select][+][-]
  1. program project_ext_c_lib;
  2.  
  3. uses cortexm3;
  4.  
  5. type
  6.   THardwareTimer = cppclass external name 'HardwareTimer'
  7.   public
  8.     procedure pause;
  9.     procedure resume;
  10.     function getCount: Word;
  11.     procedure setCount(count: Word);
  12.   end;
  13.   // enable this; I don't have a HardwareTimer.o
  14.   {$L HardwareTimer.o}
  15.  
  16.  
  17.   var
  18.   // the mangled name of the hardwareTimer variable
  19.   // using "cvar; external;" instead it would look for "_hwtimer"
  20.   hwtimer: THardwareTimer; external name 'HardwareTimer';
  21.  
  22. begin
  23.  
  24.   hwtimer.HardwareTimer(2);
  25.   hwtimer.resume;
  26.   hwtimer.pause;
  27.   hwtimer.setCount(42);
  28.  end.  
  29.  

i have a this problem:

Compile Project, OS: embedded, CPU: arm, Target: project_ext_c_lib: Exit code 1, Errors: 1
project_ext_c_lib.lpr(24,11) Error: Identifier idents no member "HardwareTimer"

but it exist!

using objdump

Code: Pascal  [Select][+][-]
  1. Disassembly of section .text._ZN13HardwareTimerC2Eh:
  2.  
  3. 00000000 <_ZN13HardwareTimerC1Eh>:
  4.    0:   2300            movs    r3, #0
  5.    2:   b510            push    {r4, lr}
  6.    4:   4604            mov     r4, r0
  7.    6:   6003            str     r3, [r0, #0]
  8.    8:   b672            cpsid   i
  9.    a:   4b05            ldr     r3, [pc, #20]   ; (20 <_ZN13HardwareTimerC1Eh+0x20>)
  10.    c:   3119            adds    r1, #25
  11.    e:   7019            strb    r1, [r3, #0]
  12.   10:   4b04            ldr     r3, [pc, #16]   ; (24 <_ZN13HardwareTimerC1Eh+0x24>)
  13.   12:   6018            str     r0, [r3, #0]
  14.   14:   4804            ldr     r0, [pc, #16]   ; (28 <_ZN13HardwareTimerC1Eh+0x28>)
  15.   16:   f7ff fffe       bl      0 <timer_foreach>
  16.   1a:   b662            cpsie   i
  17.   1c:   4620            mov     r0, r4
  18.   1e:   bd10            pop     {r4, pc}
  19.         ...
  20.  








PascalDragon

  • Hero Member
  • *****
  • Posts: 5486
  • Compiler Developer
Re: using c libraries in embedded fpc project
« Reply #14 on: April 18, 2020, 11:46:59 am »
Thank you for that cppclass syntax gem, PascalDragon, especially because when I researched it on the forum I found an article that pointed to this (imho big) gem:

http://www.fmxexpress.com/create-wrapper-interfaces-for-c-and-c-libraries-using-swig-with-delphi-support/

I've we could finally get Delphi/FPC/Object Pascal support in upstream SWIG that would be a good bonus. As it is the version mentioned on fmxexpress is already no longer compatible with the development version of SWIG... (there was a recent thread somewhere here on the forum)

I have searched for something like this for a long time, and now I realize that it was hiding in plain sight for quite a long time!

Please note that currently cppclass is rather limited. Dynamic allocation does not work, virtual methods do not work and I don't know whether fields are handled correctly if inheritance is involved. However for the rather restricted use case of the Embedded frameworks (ARM, AVR, etc.) it might be just enought.

now with this code
Code: Pascal  [Select][+][-]
  1. program project_ext_c_lib;
  2.  
  3. uses cortexm3;
  4.  
  5. type
  6.   THardwareTimer = cppclass external name 'HardwareTimer'
  7.   public
  8.     procedure pause;
  9.     procedure resume;
  10.     function getCount: Word;
  11.     procedure setCount(count: Word);
  12.   end;
  13.   // enable this; I don't have a HardwareTimer.o
  14.   {$L HardwareTimer.o}
  15.  
  16.  
  17.   var
  18.   // the mangled name of the hardwareTimer variable
  19.   // using "cvar; external;" instead it would look for "_hwtimer"
  20.   hwtimer: THardwareTimer; external name 'HardwareTimer';
  21.  
  22. begin
  23.  
  24.   hwtimer.HardwareTimer(2);
  25.   hwtimer.resume;
  26.   hwtimer.pause;
  27.   hwtimer.setCount(42);
  28.  end.  
  29.  

i have a this problem:

Compile Project, OS: embedded, CPU: arm, Target: project_ext_c_lib: Exit code 1, Errors: 1
project_ext_c_lib.lpr(24,11) Error: Identifier idents no member "HardwareTimer"

but it exist!

No, it does not. At least not from the FPC side. Every method you want to use needs to be declared as such:

Code: Pascal  [Select][+][-]
  1. type
  2.   THardwareTimer = cppclass external name 'HardwareTimer'
  3.     // will have the mangled name _ZN13HardwareTimerC1Eh
  4.     // the Pascal name is only relevant for Pascal code
  5.     constructor Create(arg: Byte);
  6.   end;
  7.   {$L HardwareTimer.o}
  8.  
  9. var
  10.   // if you construct the class yourself then you don't need to use an external
  11.   hwtimer: THardwareTimer;
  12. begin
  13.   hwtimer.Create(2); // this will generate a call to _ZN13HardwareTimerC1Eh
  14.   // ...
  15. end.

 

TinyPortal © 2005-2018