Recent

Author Topic: [SOLVED] Can't access .so library function from Ubuntu  (Read 5504 times)

Mujie

  • Jr. Member
  • **
  • Posts: 64
[SOLVED] Can't access .so library function from Ubuntu
« on: July 30, 2017, 01:35:45 pm »
Hi,

In MS Windows I was successfully call the function from my own dll library. Then I tried to crosscompile the sources  to Linux (Elementary OS which is Ubuntu based). But no luck when result has become standalone application on Ubuntu/Elementary OS.

Here is my OS
Quote
Linux G230 4.10.0-27-generic #30~16.04.2-Ubuntu SMP Thu Jun 29 16:07:46 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

My Lazarus IDE
Quote
Lazarus 1.6.4 rUnversioned directory FPC 3.0.2 x86_64-linux-gtk 2

My application sources

Code: Pascal  [Select][+][-]
  1. //appcool.lpr
  2. program appcool;
  3.  
  4. {$mode objfpc}{$H+}
  5. //for threads
  6. {$define UseCThreads}
  7.  
  8. uses
  9.   {$IFDEF UNIX}{$IFDEF UseCThreads}
  10.   cthreads,
  11.   {$ENDIF}{$ENDIF}
  12.   Interfaces, // this includes the LCL widgetset
  13.   Forms, login_f, login_u
  14.   { you can add units after this };
  15.  
  16. {$R *.res}
  17.  
  18. begin
  19.   Application.Title:='Cool Application';
  20.   RequireDerivedFormResource:=True;
  21.   Application.Initialize;
  22.   Application.CreateForm(TformLogin, formLogin);
  23.   Application.Run;
  24. end.
  25.  

Code: Pascal  [Select][+][-]
  1. //login_u.pas for unit
  2. unit login_u;
  3.  
  4. {$mode objfpc}{$H+}
  5.  
  6. interface
  7.  
  8. uses
  9.   Classes, SysUtils,
  10.   //additional
  11.   LCLIntf, Dynlibs, Dialogs, Buttons;
  12.  
  13. type
  14.  
  15. //API Testing
  16.   ThreadAPITesting = class(TThread)
  17.   protected
  18.     procedure LoadingLib;
  19.     procedure Execute; override;
  20.   end;
  21.  
  22. procedure ShowApiTesting;
  23.  
  24. implementation
  25.  
  26. //uses
  27.  
  28. type
  29.  
  30. //API TESTING
  31. //=========== API TESTING =============
  32.   TApiTesting = function (client_key, client_secret: string): string; cdecl; //API TESTING
  33.  
  34. procedure ThreadApiTesting.LoadingLib;
  35. var
  36.   MyHandle: TLibHandle;
  37.   ApiTestingFunc: TApiTesting;
  38.   DataResult: string;
  39.   client_key, client_secret: string;
  40. begin
  41.   MyHandle := LoadLibrary('libs/libdbq.so');
  42.   if MyHandle<>0 then
  43.     begin
  44.       ApiTestingFunc := TApiTesting(GetProcedureAddress(MyHandle,'ApiTesting'));
  45.       if Assigned(@ApiTestingFunc) then
  46.         begin
  47.           DataResult := ApiTestingFunc('what', 'ever');
  48.         end;
  49.     FreeLibrary(MyHandle);
  50.     end
  51.   else
  52.     begin
  53.       FreeLibrary(MyHandle);
  54.       ShowMessage('Library failed.');
  55.     end;
  56.   Exit;
  57. end;
  58.  
  59. procedure ThreadApiTesting.Execute;
  60. begin
  61.   if not Terminated then
  62.     begin
  63.       Synchronize(@LoadingLib);
  64.       Exit;
  65.     end;
  66. end;
  67.  
  68. procedure ShowApiTesting;
  69. var
  70.  ExecApiTesting: ThreadApiTesting;
  71. begin
  72.  ExecApiTesting := ThreadApiTesting.Create(False);
  73.  ExecApiTesting.FreeOnTerminate := True;
  74.  Exit;
  75. end;
  76.  
  77. end.

Code: Pascal  [Select][+][-]
  1. //login_f for form
  2. unit login_f;
  3.  
  4. {$mode objfpc}{$H+}
  5.  
  6. interface
  7.  
  8. uses
  9.   Classes, SysUtils, FileUtil, BCButton, Forms, Controls, Graphics,
  10.   Dialogs, ExtCtrls, StdCtrls;
  11.  
  12. type
  13.  
  14.   { TformLogin }
  15.  
  16.   TformLogin = class(TForm)
  17.     btLogin: TBCButton;
  18.     procedure btLoginClick(Sender: TObject);
  19.     procedure FormCreate(Sender: TObject);
  20.   private
  21.     { private declarations }
  22.   public
  23.     { public declarations }
  24.   end;
  25.  
  26. var
  27.   formLogin: TformLogin;
  28.  
  29. implementation
  30.  
  31. {$R *.lfm}
  32.  
  33. uses
  34.   //Unit
  35.   login_u;
  36.  
  37. { TformLogin }
  38.  
  39. procedure TformLogin.btLoginClick(Sender: TObject);
  40. begin
  41.   ShowApiTesting();
  42. end;
  43.  
  44. //anti flicker
  45. procedure TformLogin.FormCreate(Sender: TObject);
  46. begin
  47.   Self.DoubleBuffered:=True;
  48. end;
  49.  
  50. end.
  51.  

And the .so (dll) library

Code: Pascal  [Select][+][-]
  1. unit login;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils,
  9.   //additional
  10.   LCLIntf, cmem;
  11.  
  12. implementation
  13.  
  14. function ApiTesting(client_key, client_secret: string): string; cdecl;
  15. begin
  16.   MessageBox(0,PChar('Success!'),PChar('Info'));
  17. end;
  18.  
  19. exports ApiTesting;
  20.  

Is there something I missed?

Thank you before.
« Last Edit: August 06, 2017, 11:50:29 am by Mujie »

Thaddy

  • Hero Member
  • *****
  • Posts: 14214
  • Probably until I exterminate Putin.
Re: Can't access .so library function from Ubuntu
« Reply #1 on: July 30, 2017, 01:39:33 pm »
A dll is a library, not a program. Where's your main LIBRARY code?....... >:D
If it compiles to a dll it will compile to an .so on nixes. But your code is no good anyway, so why bother?
« Last Edit: July 30, 2017, 01:41:29 pm by Thaddy »
Specialize a type, not a var.

Mujie

  • Jr. Member
  • **
  • Posts: 64
Re: Can't access .so library function from Ubuntu
« Reply #2 on: July 30, 2017, 01:46:11 pm »
A dll is a library, not a program. Where's your main LIBRARY code?....... >:D
If it compiles to a dll it will compile to an .so on nixes. But your code is no good anyway, so why bother?

Hi,

Thanks for your reply. There is my main library codes, not good enough  :-[

Code: Pascal  [Select][+][-]
  1. unit login;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils,
  9.   //additional
  10.   LCLIntf, cmem;
  11.  
  12. implementation
  13.  
  14. function ApiTesting(client_key, client_secret: string): string; cdecl;
  15. begin
  16.   MessageBox(0,PChar('Success!'),PChar('Info'));
  17. end;
  18.  
  19. exports ApiTesting;

molly

  • Hero Member
  • *****
  • Posts: 2330
Re: Can't access .so library function from Ubuntu
« Reply #3 on: July 30, 2017, 04:19:02 pm »
Thanks for your reply. There is my main library codes, not good enough  :-[
You are not creating a (shared) library there but, you are exporting functions. There is an important difference there.

Programming shared libraries
« Last Edit: July 30, 2017, 05:02:15 pm by molly »

Mujie

  • Jr. Member
  • **
  • Posts: 64
Re: Can't access .so library function from Ubuntu
« Reply #4 on: July 30, 2017, 06:27:55 pm »
You are not creating a (shared) library there but, you are exporting functions. There is an important difference there.

Programming shared libraries

Hi,

Thanks for your reply.

I got this messages from GetLoadErrorStr

Code: Pascal  [Select][+][-]
  1. libs/libdbq.so: undefined symbol: ApiTesting

molly

  • Hero Member
  • *****
  • Posts: 2330
Re: Can't access .so library function from Ubuntu
« Reply #5 on: July 30, 2017, 06:56:32 pm »
Code: Pascal  [Select][+][-]
  1. libs/libdbq.so: undefined symbol: ApiTesting
You have not showed us a library unit named (lib)dbq so how would you expect it to load/link a function named ApiTesting ?

Thaddy

  • Hero Member
  • *****
  • Posts: 14214
  • Probably until I exterminate Putin.
Re: Can't access .so library function from Ubuntu
« Reply #6 on: July 30, 2017, 08:21:31 pm »
A library looks like this:
Code: Pascal  [Select][+][-]
  1. library somelibrary;
  2. interface  // not required
  3. exports...
  4. implementation // not required
  5. end.
It is not a program..... As you wrote, it's your own library.... (some people lack their glasses)
« Last Edit: July 31, 2017, 09:00:07 am by Thaddy »
Specialize a type, not a var.

Leledumbo

  • Hero Member
  • *****
  • Posts: 8747
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Can't access .so library function from Ubuntu
« Reply #7 on: July 31, 2017, 06:44:37 am »
You should try a simple program-library first. If you can make this work on Linux, then you should have no problem doing it for more complex program:
Code: Pascal  [Select][+][-]
  1. library mylib;
  2.  
  3. uses
  4.   strings;
  5.  
  6. // NEVER declare string as parameter in library function, string is a managed type and each program and library has their own copy of the memory manager
  7. function f(p: pchar): integer; cdecl;
  8. begin
  9.   f := strlen(p);
  10. end;
  11.  
  12. exports
  13.   f;
  14.  
  15. end.
  16.  
Code: Pascal  [Select][+][-]
  1. program mylibtest;
  2.  
  3. uses
  4.   dynlibs;
  5.  
  6. type
  7.  Tf = function (p: pchar): integer;
  8.  
  9. var
  10.   OK: Boolean;
  11.   h: TLibHandle;
  12.   f: Tf;
  13. begin
  14.   OK := false;
  15.   h :=  LoadLibrary('./libmylib.' + SharedSuffix);
  16.   if h <> NilHandle then begin
  17.     f := Tf(GetProcedureAddress(h,'f'));
  18.     if Assigned(f) then begin
  19.       WriteLn(f('test'));
  20.       OK := true;
  21.     end;
  22.   end;
  23.  
  24.   if not OK then
  25.     WriteLn(StdErr,GetLoadErrorStr);
  26. end.
  27.  

Thaddy

  • Hero Member
  • *****
  • Posts: 14214
  • Probably until I exterminate Putin.
Re: Can't access .so library function from Ubuntu
« Reply #8 on: July 31, 2017, 09:02:08 am »
"// NEVER declare string as parameter in library function, string is a managed type and each program and library has their own copy of the memory manager"

Well. As long it is pure pascal for pure pascal, one could use {$H-}. Shortstrings are not a managed string type!!
Specialize a type, not a var.

Mujie

  • Jr. Member
  • **
  • Posts: 64
Re: Can't access .so library function from Ubuntu
« Reply #9 on: July 31, 2017, 04:35:42 pm »
Hi LeleDumbo,

Thanks for your reply. Its look like I struggle with 'LCLIntf' on my .so library source codes. I try to replace 'Windows' uses with 'LCLIntf'. My codes is fine on MS Windows, maybe I should take a look another distro.


You should try a simple program-library first. If you can make this work on Linux, then you should have no problem doing it for more complex program:
Code: Pascal  [Select][+][-]
  1. library mylib;
  2.  
  3. uses
  4.   strings;
  5.  
  6. // NEVER declare string as parameter in library function, string is a managed type and each program and library has their own copy of the memory manager
  7. function f(p: pchar): integer; cdecl;
  8. begin
  9.   f := strlen(p);
  10. end;
  11.  
  12. exports
  13.   f;
  14.  
  15. end.
  16.  
Code: Pascal  [Select][+][-]
  1. program mylibtest;
  2.  
  3. uses
  4.   dynlibs;
  5.  
  6. type
  7.  Tf = function (p: pchar): integer;
  8.  
  9. var
  10.   OK: Boolean;
  11.   h: TLibHandle;
  12.   f: Tf;
  13. begin
  14.   OK := false;
  15.   h :=  LoadLibrary('./libmylib.' + SharedSuffix);
  16.   if h <> NilHandle then begin
  17.     f := Tf(GetProcedureAddress(h,'f'));
  18.     if Assigned(f) then begin
  19.       WriteLn(f('test'));
  20.       OK := true;
  21.     end;
  22.   end;
  23.  
  24.   if not OK then
  25.     WriteLn(StdErr,GetLoadErrorStr);
  26. end.
  27.  

Mujie

  • Jr. Member
  • **
  • Posts: 64
Re: Can't access .so library function from Ubuntu
« Reply #10 on: July 31, 2017, 04:38:19 pm »
Hi,

'library' syntax has been declare on .lpr
You're right about the glasses  :D

A library looks like this:
Code: Pascal  [Select][+][-]
  1. library somelibrary;
  2. interface  // not required
  3. exports...
  4. implementation // not required
  5. end.
It is not a program..... As you wrote, it's your own library.... (some people lack their glasses)

Mujie

  • Jr. Member
  • **
  • Posts: 64
Re: Can't access .so library function from Ubuntu
« Reply #11 on: August 06, 2017, 07:40:27 am »
Hi,

It's me again, I solved this by adding the code into one instead of the unit outside the library code.

Example

Work library codes
Code: Pascal  [Select][+][-]
  1. //myapilibrary.lpr
  2.  
  3. library myapilibrary;
  4.  
  5. {$mode objfpc}{$H+}
  6.  
  7. uses
  8.   Classes
  9.   { you can add units after this };
  10.  
  11. function ApiTesting(p: PChar): integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
  12. begin
  13.   ApiTesting:= strlen(p);
  14. end;
  15.  
  16. exports ApiTesting;
  17.  
  18. begin
  19. end.  


Not work on Ubuntu 16 and Centos 7, error message appears 'undefined symbol ApiTesting'. But work on MS Windows 7 and MS Windows 10. I put a function on unit and linked with lpr.
Code: Pascal  [Select][+][-]
  1. //myapilibrary.lpr
  2.  
  3. library myapilibrary;
  4.  
  5. {$mode objfpc}{$H+}
  6.  
  7. uses
  8.   Classes, myanotherunit
  9.   { you can add units after this };
  10.  
  11. begin
  12. end.  


Code: Pascal  [Select][+][-]
  1. //myanotherunit.pas
  2.  
  3. unit myanotherunit;
  4.  
  5. {$mode objfpc}{$H+}
  6.  
  7. interface
  8.  
  9. uses
  10.   Classes, SysUtils;
  11.  
  12. implementation
  13.  
  14. function ApiTesting(p: PChar): integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
  15. begin
  16.   ApiTesting:= strlen(p);
  17. end;
  18.  
  19. exports ApiTesting;
  20.  
  21. end.
  22.  

 

TinyPortal © 2005-2018