Recent

Author Topic: C-library problem with interfacing  (Read 818 times)

ThomasK

  • Jr. Member
  • **
  • Posts: 50
C-library problem with interfacing
« on: January 25, 2025, 05:39:12 pm »
Hello,

I am trying to build a wrapper for a C-library provided by a hardware supplier.

I have problems defining the forward declaration, the compiler generates Errors:
Code: Text  [Select][+][-]
  1. Projekt kompilieren, Ziel: H:\GitHub\IOT-Neu\bin\x86_64-win64\spitest.exe: Exit code 1, Fehler: 2, Hinweise: 4
  2. call_monarco.pas(95,31) Hint: Parameter "cxt" not used
  3. call_monarco.pas(95,51) Hint: Parameter "spi_device" not used
  4. call_monarco.pas(95,75) Hint: Parameter "spi_clkfreq" not used
  5. call_monarco.pas(95,98) Hint: Parameter "platform" not used
  6. call_monarco.pas(106,12) Error: Calling convention doesn't match forward
  7. call_monarco.pas(97,12) Error: Found declaration: monarco_init(var monarco_cxt_t;AnsiString;LongWord;pPlatfrm):LongInt; CDecl;
  8.  
Lazarus 2.2.0
FPC 3.2.2
W10-64 bit
When I remove the CDecl after the declaration and also the reference to the external library and complete the function with a dummy it does not create the error.
Code: Pascal  [Select][+][-]
  1. //
  2. .
  3. .
  4.  {$mode ObjFPC}
  5. .
  6. .
  7. int monarco_init(monarco_cxt_t *cxt, const char *spi_device, uint32_t spi_clkfreq, void *platform);
  8. //function monarco_init(var cxt: monarco_cxt_t; const spi_device: PChar; spi_clkfreq: Cardinal; platform: Pointer): Integer;
  9.  
  10.   function monarco_init_1(var cxt: monarco_cxt_t; spi_device: Ansistring; spi_clkfreq: LongWord; platform: pPlatfrm): LongInt;
  11. //
  12.   function monarco_init(var cxt: monarco_cxt_t; spi_device: Ansistring; spi_clkfreq: LongWord; platform: pPlatfrm): LongInt; CDecl;
  13. //
  14.  
  15. implementation
  16.   function monarco_init_1(var cxt: monarco_cxt_t; spi_device: AnsiString; spi_clkfreq: LongWord; platform: pPlatfrm): LongInt;
  17.   begin
  18.     result:=0;
  19.   end;
  20. //
  21.   function monarco_init(var cxt: monarco_cxt_t; spi_device: AnsiString; spi_clkfreq: LongWord; platform: pPlatfrm): LongInt; external monarcolib; // name 'monarco_init';
  22. //
  23. end.
  24.  

Has anybody an idea whats I am doing wring? I added the original header as an attachment.

« Last Edit: January 25, 2025, 05:57:18 pm by ThomasK »
Started Pascal on a Siemens 4004/151 in 1977. TurboPascal 1.0 in 1984 on PC-Dos.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12028
  • FPC developer.
Re: C-library problem with interfacing
« Reply #1 on: January 25, 2025, 05:52:19 pm »
Add cdecl to all declarations, not just one.

TRon

  • Hero Member
  • *****
  • Posts: 3930
Re: C-library problem with interfacing
« Reply #2 on: January 25, 2025, 06:30:52 pm »
I see you have the library function declared twice in your example while only one is allowed. You also seem to want to make use of a wrapper function that will call the actual library function.

You would have to decide which function is named what (you can use another name for the library function but in that case you would have to define the name that should be imported form the library).

In short, your example is not compile-able as it stands thus nearly impossible to advise as we do not able to grasp the intention of the actual code.
I do not have to remember anything anymore thanks to total-recall.

Thaddy

  • Hero Member
  • *****
  • Posts: 16520
  • Kallstadt seems a good place to evict Trump to.
Re: C-library problem with interfacing
« Reply #3 on: January 25, 2025, 06:44:44 pm »
Add cdecl to all declarations, not just one.
Well that is not strictly necessary:
Code: Pascal  [Select][+][-]
  1. {$calling cdecl}
or the automatic one:
Code: Pascal  [Select][+][-]
  1. {$calling winapi}
In the latter case the compiler will choose the correct calling convention, not only on Windows, but also on other platforms.
Since you are using a 64 bit version of the compiler, cdecl has no effect anyway.
Your best bet is the second option I gave you. winapi

* there are very rare cases that cdecl is necessary even if you should have been using a 64 bit ABI. You can only check that with a) documentation or b) the debugger or c) the header file.
« Last Edit: January 25, 2025, 06:57:29 pm by Thaddy »
But I am sure they don't want the Trumps back...

TRon

  • Hero Member
  • *****
  • Posts: 3930
Re: C-library problem with interfacing
« Reply #4 on: January 25, 2025, 07:55:45 pm »
I do not have to remember anything anymore thanks to total-recall.

Thaddy

  • Hero Member
  • *****
  • Posts: 16520
  • Kallstadt seems a good place to evict Trump to.
Re: C-library problem with interfacing
« Reply #5 on: January 26, 2025, 09:16:01 am »
Thanks for that link.
Looks like the 64 version of the code uses the standard linux64 ABI, not cdecl.
FPC will also choose the linux64 ABI, so cdecl is not necessary for 64bit.
(That's what I expected:for spi it is a kernel module anyway, so needs to conform, as I already expected).

It may be that you run into some alignment problems,  but it is not ABI calling convention related.:

OTOH in that repository I see no code for Win64 at all...
So what are you actually compiling for? win32 on win64? Then everything is probably cdecl (or stdcall) after all.
If you try to cross-compile for the raspberry pi, which cross compiler are you using? for 32bit Raspberry Pi OS or for AARCH64? The former is with cdecl the latter is w/o
« Last Edit: January 26, 2025, 09:54:15 am by Thaddy »
But I am sure they don't want the Trumps back...

ThomasK

  • Jr. Member
  • **
  • Posts: 50
Re: C-library problem with interfacing
« Reply #6 on: January 26, 2025, 10:56:34 am »
Thanks for all feedbacks.

@marcov - I have two functions with different names declared, one as external, the other standard.
The second has an dummy code in implementation and can be compiled.

@TRon - two functions with different names: function monarco_init_1 and function monarco_init.

@Thaddy - the two different calling declarations are just in case. It has to run on Raspberry Pi. I do the most of coding and syntax tests on a win system.

In the mean time I found the problem.

Code: Pascal  [Select][+][-]
  1. unit call_monarco;
  2. // *****************************************************************************
  3. // * @file monarco.h
  4. // * @brief libmonarco - Main API
  5. // *****************************************************************************
  6. // * @section License
  7. // * Copyright REX Controls s.r.o. http://www.rexcontrols.com
  8. // * Author: Vlastimil Setka
  9. // * This file is covered by the BSD 3-Clause License
  10. // *   see LICENSE.txt in the root directory of this project
  11. // *****************************************************************************
  12. //
  13. //
  14. //
  15. {$H+}
  16. {$BITPACKING ON}
  17. {$IFDEF FPC}
  18.    {$MODE DELPHI}
  19. {$ENDIF}
  20.  
  21. interface
  22.  
  23. uses
  24.   Classes, SysUtils, monarco_structure;
  25. //{$I stdinth.inc}
  26. Const
  27.   MONARCO_SDC_ITEMS_SIZE = 256;
  28.  
  29. type
  30.   Platfrm  = Pchar;
  31.   pPlatfrm = ^platfrm;
  32. Const
  33. // Library name
  34.   {$IFDEF MSWINDOWS}
  35.   monarcolib = 'monarco.dll';
  36.   {$ELSE}
  37.   monarcolib = 'monarco.so';  // valid for all Unix platforms
  38.   {$ENDIF}
  39.   {
  40.    * Monarco Initialization
  41.    *   Connect to `*spi_device` with `spi_clkfreq` clock frequency (Hz)
  42.    *   and provide some `*platform` data - for generic linux platform it is a debug print prefix.
  43.  
  44.    int monarco_init(monarco_cxt_t *cxt, const char *spi_device, uint32_t spi_clkfreq, void *platform);
  45.    }
  46.  
  47.   function monarco_init(var cxt: monarco_cxt_t; spi_device: Pchar; spi_clkfreq: Dword; platform: pPlatfrm): Integer;
  48.   {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF}
  49.  
  50.   {
  51.   * Monarco Main
  52.   *   Performs one SPI transaction with Monarco HAT - exchange of complete input and output process data
  53.   *   and single new service data reqeust and response to previous request.
  54.   *   Have to be called periodically, at least faster than process data watchod timeout (default 100 ms)!
  55.  
  56.   int monarco_main(monarco_cxt_t *cxt);
  57.   }
  58.  
  59.   function monarco_main(var cxt: monarco_cxt_t): Integer;
  60.   {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF}
  61.  
  62.   {
  63.   * Monarco Cleanup
  64.   *   Free all resources allocated by `monarco_init()`.
  65.  
  66.   int monarco_exit(monarco_cxt_t *cxt);
  67.   }
  68.  
  69.   function monarco_exit(var cxt: monarco_cxt_t): Integer;
  70.   {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF}
  71.  
  72.  
  73. implementation
  74.  
  75.   function monarco_init;                external monarcolib name 'monarco_init';
  76.   function monarco_main;                external monarcolib name 'monarco_main';
  77.   function monarco_exit;                external monarcolib name 'monarco_exit';
  78.  
  79. end.
  80.  
  81.  

It was the compiler switch, the code can be compiled without error.

When I added a new unit with File - new Unit, the switch {$mode ObjFPC} is automatically set, compile fails.
If I omit it it fails too.
Error Message:

call_monarco.pas(129,24) Fatal: Syntax error, ":" expected but ";" found

This was the reason for me to duplicate the function definition.

If i use  {$MODE DELPHI}  it passes.

I heavily use another library on Windows systems and Raspberries, snap7 and have copied the definitions from there but overlooked the compiler switch.

When I place all function declaration information before implementation and omit it after implementation it works too with {$mode ObjFPC}
Started Pascal on a Siemens 4004/151 in 1977. TurboPascal 1.0 in 1984 on PC-Dos.

PascalDragon

  • Hero Member
  • *****
  • Posts: 5855
  • Compiler Developer
Re: C-library problem with interfacing
« Reply #7 on: January 26, 2025, 03:27:53 pm »
Add cdecl to all declarations, not just one.
Well that is not strictly necessary:
Code: Pascal  [Select][+][-]
  1. {$calling cdecl}
or the automatic one:
Code: Pascal  [Select][+][-]
  1. {$calling winapi}
In the latter case the compiler will choose the correct calling convention, not only on Windows, but also on other platforms.

$Calling does not support WinApi. You'd know this if you had actually tested this:

Code: Pascal  [Select][+][-]
  1. program tcallconv;
  2.  
  3. {$calling winapi}
  4.  
  5. begin
  6.  
  7. end.

Code: [Select]
PS C:\fpc\git> fpc -FEtestoutput .\fpctests\tcallconv.pp
Free Pascal Compiler version 3.2.2 [2022/01/02] for x86_64
Copyright (c) 1993-2021 by Florian Klaempfl and others
Target OS: Win64 for x64
Compiling .\fpctests\tcallconv.pp
tcallconv.pp(5,6) Warning: Unknown procedure directive had to be ignored: "WINAPI"
Linking testoutput\tcallconv.exe
7 lines compiled, 0.1 sec, 32240 bytes code, 1508 bytes data
1 warning(s) issued

(Same with main by the way)

 

TinyPortal © 2005-2018