* * *

Author Topic: When I use C++ code in Object Pascal, I get error  (Read 943 times)

İbrahim

  • New member
  • *
  • Posts: 11
When I use C++ code in Object Pascal, I get error
« on: January 10, 2018, 06:16:16 pm »
Hi. I wrote a code like this (Note: I' using this doc: ftp://ftp.freepascal.org/fpc/docs-pdf/CinFreePascal.pdf):
CppExample.h:
Code: Diff  [Select]
  1. #ifndef CPPEXAMPLE_H
  2. #define CPPEXAMPLE_H
  3. #include <iostream>
  4. #include <string>
  5.  
  6. class CppExample
  7. {
  8. private:
  9.   int _number;
  10.   std::string _text;
  11. public:
  12.   CppExample();
  13.   CppExample(int number, const std::string& text);
  14.   int get_number() const;
  15.   const std::string& get_text() const;
  16. };
  17.  
  18. #endif // CPPEXAMPLE_H
  19.  
CppExample.cpp
Code: Diff  [Select]
  1. #include "CppExample.h"
  2.  
  3. CppExample::CppExample() : _number(0), _text("")
  4. {
  5. }
  6.  
  7. CppExample::CppExample(int number, const std::string& text)
  8.   : _number(number), _text(text)
  9. {
  10. }
  11.  
  12. int CppExample::get_number() const
  13. {
  14.   return _number;
  15. }
  16.  
  17. const std::string& CppExample::get_text() const
  18. {
  19.   return _text;
  20. }
  21.  
Then I wrote a C wrapper to use C++ code in Free Pascal:
CWrapper.h:
Code: Diff  [Select]
  1. #ifndef CWRAPPER_H
  2. #define CWRAPPER_H
  3.  
  4. #ifdef __cplusplus
  5. #include "CppExample.h"
  6. #define EXPORTCALL __attribute__((stdcall))
  7. typedef CppExample* CppExampleHandle;
  8. #else
  9. #define EXPORTCALL
  10. typedef struct CppExample* CppExampleHandle;
  11. #endif
  12.  
  13. #ifdef __cplusplus
  14. extern "C"
  15. {
  16. #endif
  17. extern CppExampleHandle EXPORTCALL init_Example();
  18. extern CppExampleHandle EXPORTCALL init_Example_Args_IC(int number, const char* text);
  19. extern void EXPORTCALL destroy_Example(CppExampleHandle instance);
  20. extern int EXPORTCALL get_number_Example(CppExampleHandle instance);
  21. extern const char* get_text_Example(CppExampleHandle instance);
  22. //
  23. extern CppExampleHandle EXPORTCALL c_init_Example();
  24. extern CppExampleHandle EXPORTCALL c_init_Example_Args_IC(int number, const char* text);
  25. extern void EXPORTCALL c_destroy_Example(CppExampleHandle instance);
  26. extern int EXPORTCALL c_get_number_Example(CppExampleHandle instance);
  27. extern const char* c_get_text_Example(CppExampleHandle instance);
  28. #ifdef __cplusplus
  29. }
  30. #endif
  31.  
  32. #endif
  33.  
CWrapper.c:
Code: Diff  [Select]
  1. #include "CWrapper.h"
  2.  
  3. CppExampleHandle c_init_Example()
  4. {
  5.   return init_Example();
  6. }
  7.  
  8. CppExampleHandle c_init_Example_Args_IC(int number, const char* text)
  9. {
  10.   return init_Example_Args_IC(number, text);
  11. }
  12.  
  13. void c_destroy_Example(CppExampleHandle instance)
  14. {
  15.   destroy_Example(instance);
  16. }
  17.  
  18. int c_get_number_Example(CppExampleHandle instance)
  19. {
  20.   return get_number_Example(instance);
  21. }
  22.  
  23. const char* c_get_text_Example(CppExampleHandle instance)
  24. {
  25.   return get_text_Example(instance);
  26. }
  27.  
CWrapper.cpp:
Code: Diff  [Select]
  1. #include "CWrapper.h"
  2.  
  3. extern "C"
  4. {
  5.  
  6. CppExampleHandle EXPORTCALL init_Example()
  7. {
  8.   return new CppExample();
  9. }
  10.  
  11. CppExampleHandle EXPORTCALL init_Example_Args_IC(int number, const char* text)
  12. {
  13.   return new CppExample(number, std::string(text));
  14. }
  15.  
  16. void EXPORTCALL destroy_Example(CppExampleHandle instance)
  17. {
  18.   delete instance;
  19. }
  20.  
  21. int EXPORTCALL get_number_Example(CppExampleHandle instance)
  22. {
  23.   return instance->get_number();
  24. }
  25.  
  26. const char* get_text_Example(CppExampleHandle instance)
  27. {
  28.   return instance->get_text().c_str();
  29. }
  30.  
  31. }
  32.  
I compiled these codes these commands:
Code: Diff  [Select]
  1. gcc -c CWrapper.c -o clib.o
  2. g++ -std=c++17 -c CWrapper.cpp -o cpplib.o
  3.  
I wrote a Pascal file (PasExample.pas):
Code: Pascal  [Select]
  1. unit PasExample;
  2.  
  3. {$IFDEF FPC}
  4.   {$MODE DELPHI}
  5. {$ENDIF}
  6.  
  7. {$LINK clib.o}
  8. {$LINKLIB c}
  9. {$LINKLIB stdc++}
  10.  
  11. interface
  12.  
  13. type
  14.   CppExampleHandle = type Pointer;
  15.  
  16. function init_Example: CppExampleHandle; cdecl;
  17. function init_Example_Args_IC(number: Integer; const text: PAnsiChar): CppExampleHandle; cdecl;
  18. procedure destroy_Example(instance: CppExampleHandle); cdecl;
  19. function get_number_Example(instance: CppExampleHandle): Integer; cdecl;
  20. function get_text_Example(instance: CppExampleHandle): PAnsiChar; cdecl;
  21.  
  22. implementation
  23.  
  24. function init_Example: CppExampleHandle; cdecl; external;
  25. function init_Example_Args_IC(number: Integer; const text: PAnsiChar): CppExampleHandle; cdecl; external;
  26. procedure destroy_Example(instance: CppExampleHandle); cdecl; external;
  27. function get_number_Example(instance: CppExampleHandle): Integer; cdecl; external;
  28. function get_text_Example(instance: CppExampleHandle): PAnsiChar; cdecl; external;
  29.  
  30. end.
  31.  
I'm using this file like this (aTest.pas):
Code: Pascal  [Select]
  1. program aTest;
  2.  
  3. {$IFDEF FPC}
  4.   {$MODE DELPHI}
  5. {$ENDIF}
  6.  
  7. uses PasExample;
  8.  
  9. var
  10.   example : CppExampleHandle;
  11. begin
  12.   example := init_Example_Args_IC(7, 'Hello');
  13.   WriteLn(get_number_Example(example));
  14.   WriteLn(get_text_Example(example));
  15. end.
  16.  
When I compile this file like this: fpc aTest.pas, I get this error message:
Code: Diff  [Select]
  1. Free Pascal Compiler version 3.0.4 [2017/12/13] for x86_64
  2. Copyright (c) 1993-2017 by Florian Klaempfl and others
  3. Target OS: Linux for x86-64
  4. Compiling aTest.pas
  5. Linking aTest
  6. /usr/bin/ld: warning: link.res contains output sections; did you forget -T?
  7. PasExample.o: In function `PASEXAMPLE_$$_INIT_EXAMPLE$$CPPEXAMPLEHANDLE':
  8. PasExample.pas:(.text.n_pasexample_$$_init_example$$cppexamplehandle+0x1): undefined reference to `init_Example'
  9. PasExample.o: In function `PASEXAMPLE_$$_INIT_EXAMPLE_ARGS_IC$LONGINT$PCHAR$$CPPEXAMPLEHANDLE':
  10. PasExample.pas:(.text.n_pasexample_$$_init_example_args_ic$longint$pchar$$cppexamplehandle+0x1): undefined reference to `init_Example_Args_IC'
  11. PasExample.o: In function `PASEXAMPLE_$$_DESTROY_EXAMPLE$CPPEXAMPLEHANDLE':
  12. PasExample.pas:(.text.n_pasexample_$$_destroy_example$cppexamplehandle+0x1): undefined reference to `destroy_Example'
  13. PasExample.o: In function `PASEXAMPLE_$$_GET_NUMBER_EXAMPLE$CPPEXAMPLEHANDLE$$LONGINT':
  14. PasExample.pas:(.text.n_pasexample_$$_get_number_example$cppexamplehandle$$longint+0x1): undefined reference to `get_number_Example'
  15. PasExample.o: In function `PASEXAMPLE_$$_GET_TEXT_EXAMPLE$CPPEXAMPLEHANDLE$$PCHAR':
  16. PasExample.pas:(.text.n_pasexample_$$_get_text_example$cppexamplehandle$$pchar+0x1): undefined reference to `get_text_Example'
  17. aTest.pas(15,1) Error: Error while linking
  18. aTest.pas(15,1) Fatal: There were 1 errors compiling module, stopping
  19. Fatal: Compilation aborted
  20. Error: /usr/bin/ppcx64 returned an error exitcode
  21.  
What is the problem? Thanks.

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1900
Re: When I use C++ code in Object Pascal, I get error
« Reply #1 on: January 10, 2018, 06:21:57 pm »
you're missing
Code: Pascal  [Select]
  1. {$linklib cpplib}
  2.  
in your pascal code

The linker explicitly tells you so by "undefined reference to `init_Example'".
It doesn't know where to search for the function.
That's why you need to add $linklib into your code.

İbrahim

  • New member
  • *
  • Posts: 11
Re: When I use C++ code in Object Pascal, I get error
« Reply #2 on: January 11, 2018, 02:15:05 pm »
I added this preprocessors:
Code: Diff  [Select]
  1. {$LINK clib.o}
  2. {$LINKLIB cpplib}
  3. {$LINKLIB c}
  4. {$LINKLIB stdc++}
  5.  
Then I tried this command: fpc -Fo/path/of/object/file/  aTest.pas
But I get this error:
Code: Diff  [Select]
  1. Free Pascal Compiler version 3.0.4 [2017/12/13] for x86_64
  2. Copyright (c) 1993-2017 by Florian Klaempfl and others
  3. Target OS: Linux for x86-64
  4. Compiling aTest.pas
  5. Linking aTest
  6. /usr/bin/ld: warning: link.res contains output sections; did you forget -T?
  7. /usr/bin/ld: cannot find -lcpplib
  8. aTest.pas(15,1) Error: Error while linking
  9. aTest.pas(15,1) Fatal: There were 1 errors compiling module, stopping
  10. Fatal: Compilation aborted
  11. Error: /usr/bin/ppcx64 returned an error exitcode
  12.  

Leledumbo

  • Hero Member
  • *****
  • Posts: 7845
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: When I use C++ code in Object Pascal, I get error
« Reply #3 on: January 11, 2018, 06:42:30 pm »
you're missing
Code: Pascal  [Select]
  1. {$linklib cpplib}
  2.  
in your pascal code

The linker explicitly tells you so by "undefined reference to `init_Example'".
It doesn't know where to search for the function.
That's why you need to add $linklib into your code.
He didn't create library, only object files, hence linklib is incorrect to use.
I added this preprocessors:
Code: Diff  [Select]
  1. {$LINK clib.o}
  2. {$LINKLIB cpplib}
  3. {$LINKLIB c}
  4. {$LINKLIB stdc++}
  5.  
Let's go back to your compilation command:
Code: [Select]
gcc -c CWrapper.c -o clib.o
g++ -std=c++17 -c CWrapper.cpp -o cpplib.o
Those two create clib.o and cpplib.o, so you have to {$LINK clib.o} and {$LINK cpplib.o}, along with {$LINKLIB} for C & C++ runtime library (at least you have iostream and string used there, but I'm not sure whether stdc++ alone is enough), instead of {$LINK clib.o} and {$LINKLIB cpplib}, because you don't create libcpplib.a or libcpplib.so.

 

Recent

Get Lazarus at SourceForge.net. Fast, secure and Free Open Source software downloads Open Hub project report for Lazarus