Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2019-01

trying to use C code in .pas on WIN32

20 messages · 6 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

conlin664

I've done research, but am just missing something. my .pas code links just fine, but doesn't RUN.
( first writeln never appears )
If I remove the external call to C code, then the writeln works as normal.

Problem:

I have c code, which I'm compiling on a WIN32 machine ( yes the horror ) using GCC 4.5.2 target mingw32

It generates .o files which i grouped together with ar into common.a I then renamed common.a to be libcommon.a

Then I have a

Common.pas file:

unit Common;
interface
uses
sysutils, dos, CTypes;
{$linklib libcommon.a }
procedure CutilInit;  cdecl; external 'CutilInit';
implementation
end.

the a CommonTest.pp file:

Program commonTest;
uses
 Common;
begin
  writeln('got here');
  CutilInit();
end.

fpc.exe -TWin32 -Mdelphi -vw -Sg -Ci -O1 -Cp386 -XS -gl -p- -b-

is the relevant way I'm invoking fpc

It links, but then does nothing on execution.

If I change the C line to be:

 procedure CutilInit;  cdecl; external;

I think get a link error
Undefined Symbol: _CutilInit

Any ideas ?

Does the linklib define need to be below where I declare the C routines ? Is it something to do with WINDOWS.. ( aka the _ in the name )

Maybe I need different options on the C compile..

Marc Santhoff
to conlin664
conlin664 wrote 31 lines
I've done research, but am just missing something. my .pas code links just fine, but doesn't RUN. ( first writeln never appears ) If I remove the external call to C code, then the writeln works as normal. Problem: I have c code, which I'm compiling on a WIN32 machine ( yes the horror ) using GCC 4.5.2 target mingw32 It generates .o files which i grouped together with ar into common.a I then renamed common.a to be libcommon.a Then I have a Common.pas file: unit Common; interface uses sysutils, dos, CTypes; {$linklib libcommon.a } procedure CutilInit; cdecl; external 'CutilInit'; implementation end.

Try stdcall on Win32:

  procedure CutilInit;  stdcall; external 'common' name 'CutilInit';

If the full external declaration is necessary you'll have to try. I had to when using a dynamic library (.dll in win32 terms).

Marc Santhoff
Sven Barth
to Marc Santhoff

Am Fr., 25. Jan. 2019, 01:01 hat Marc Santhoff
geschrieben:

Show quoted text 41 lines
On Wed, 2019-01-23 at 14:30 -0700, conlin664 via fpc-pascal wrote: > I've done research, but am just missing something. > my .pas code links just fine, but doesn't RUN. > ( first writeln never appears ) > If I remove the external call to C code, then the writeln works as normal. > > Problem: > > I have c code, which I'm compiling on a WIN32 machine ( yes the horror ) > using GCC 4.5.2 target mingw32 > > It generates .o files which i grouped together with ar into common.a > I then renamed common.a to be libcommon.a > > Then I have a > > Common.pas file: > > unit Common; > interface > > uses > sysutils, dos, CTypes; > > {$linklib libcommon.a } > > procedure CutilInit; cdecl; external 'CutilInit'; > > implementation > > end. > Try stdcall on Win32: procedure CutilInit; stdcall; external 'common' name 'CutilInit'; If the full external declaration is necessary you'll have to try. I had to when using a dynamic library (.dll in win32 terms).

The "external LIB name FUNC" is wrong in the case of static linking as is "external FUNC" as the poster wrote, cause that is in fact "external LIB". So instead try "external name FUNC" (though I didn't test it). Using the correct calling convention still applies of course.

Regards,
Sven

conlin664
to Sven Barth

Thanks for the suggestions..

I'm pretty sure now, that the problem is that I'm thinking that the C code is being statically linked,
but right now the compiler is going for dynamic.
[ I've been comparing the size of the .exe ]

I also compiled with -va and note:

[0.388] Number of unresolved externals in objects 214 [0.388] Number of unresolved externals after static libraries 214 [0.388] Number of unresolved externals after defining COMMON symbols 214 [0.389] Number of unresolved externals after DLL imports 0 [0.396] There were 1 errors compiling module, stopping

when I don't try and call the C routine the number of unresolved objects is only 213

compiler switches:

-TWin32 -va -Mfpc -vw -Sg -Ci -O1 -Cp386 -OpPENTIUM3 -Ratt -gl -p- -b-

I had -XS in there, but it doesn't seem to change anything.

So I'm just looking to static link external C code to a pascal program on a windows machine

thanks

john

Jonas Maebe
to conlin664
conlin664 wrote 11 lines
when I don't try and call the C routine the number of unresolved objects is only 213 compiler switches: -TWin32 -va -Mfpc -vw -Sg -Ci -O1 -Cp386 -OpPENTIUM3 -Ratt -gl -p- -b- I had -XS in there, but it doesn't seem to change anything. So I'm just looking to static link external C code to a pascal program on a windows machine

https://svn.freepascal.org/svn/fpc/trunk/tests/test/cg/tcalext.pp links ctest.o from
https://svn.freepascal.org/svn/fpc/trunk/tests/test/cg/obj/win32/i386/, which was compiled from
https://svn.freepascal.org/svn/fpc/trunk/tests/test/cg/obj/ctest.c

Jonas

Marc Santhoff
to conlin664: Thanks for the suggestions.. I'm pretty sure now, that the problem is that I'm thinking…
conlin664 wrote 27 lines
Thanks for the suggestions.. I'm pretty sure now, that the problem is that I'm thinking that the C code is being statically linked, but right now the compiler is going for dynamic. [ I've been comparing the size of the .exe ] I also compiled with -va and note: [0.388] Number of unresolved externals in objects 214 [0.388] Number of unresolved externals after static libraries 214 [0.388] Number of unresolved externals after defining COMMON symbols 214 [0.389] Number of unresolved externals after DLL imports 0 [0.396] There were 1 errors compiling module, stopping when I don't try and call the C routine the number of unresolved objects is only 213 compiler switches: -TWin32 -va -Mfpc -vw -Sg -Ci -O1 -Cp386 -OpPENTIUM3 -Ratt -gl -p- -b- I had -XS in there, but it doesn't seem to change anything. So I'm just looking to static link external C code to a pascal program on a windows machine

How do your declaration and compiler switch(es) in the code look like?

Marc Santhoff
conlin664
to Marc Santhoff

ok. I backed up to a simple version.
how I declare the C routine must be the problem,
with nothing,

    procedure HelloC; cdecl; external;
I think it's trying to static link it, and gets an
   pcode.pas(19,1) Error: Undefined symbol: _HelloC

with anything else

   procedure HelloC; cdecl; external 'HelloC';

it links, but dynamically and then the routine is never found.

--------
pcode.pas

program pcode;
{$MODE OBJFPC}
{$R+}
uses
  ctypes, sysutils, dos, math;
procedure HelloC; cdecl; external;
type
	UINT8  = 0..255;
	UINT16 = 0..65535;
	UINT32 = Longword;
begin
	writeln('Test');
	HelloC;
end.

ccode.cpp

#include <stdint.h>
#include <stdio.h>

void HelloC(void)
{

   printf("Hello \n");

}

makeit.bat

@set ToolPath=C:\VCAST63\MinGW\bin
@set cc=%ToolPath%\gcc.exe

@set SAVED_PATH=%PATH%
@set PATH=%ToolPath%;%PATH%

@set BASE=%cd%

%CC% -g -I%BASE% -DGNU_WIN32 -O1 -Wunused-variable -c ccode.c -o ccode.o

fpc -MDelphi -MDelphi -vw -Sg -Ci -O1 -Cp386 -OpPENTIUM3 -Ratt ^ -Fu%FPC_BASE%\units\i386-Win32 ^
-Fu%FPC_BASE%\units\i386-Win32\* ^
-Fu%FPC_BASE%\units\i386-Win32\rtl ^
-FlC:\VCAST63\MinGW\lib ^
pcode.pas

@set PATH=%SAVED_PATH%
@exit /b

so now I'm back to the error of undefined symbol C:\FPC\use_c_with_pas>fpc -MDelphi -MDelphi -vw -Sg -Ci -O1 -Cp386 -OpPENTIUM3 -Ratt -Fu\units\i386-Win32 -Fu\units\i386-Win32\* -F u\units\i386-Win32\rtl -FlC:\VCAST63\MinGW\lib pcode.pas Free Pascal Compiler version 2.4.4 [2011/04/23] for i386 Copyright (c) 1993-2010 by Florian Klaempfl Target OS: Win32 for i386 Compiling pcode.pas Linking pcode.exe pcode.pas(19,1) Error: Undefined symbol: _HelloC pcode.pas(19,1) Fatal: There were 1 errors compiling module, stopping Fatal: Compilation aborted Error: C:\FPC\2.4.4\bin\i386-Win32\ppc386.exe returned an error exitcode (normal if you did not specify a source file to be compiled ) This is on an evil windows machine thanks for the help guys john -- Sent from: http://free-pascal-general.1045716.n5.nabble.com/
Sven Barth
to conlin664
conlin664 wrote 14 lines
ok. I backed up to a simple version. how I declare the C routine must be the problem, with nothing, procedure HelloC; cdecl; external; I think it's trying to static link it, and gets an pcode.pas(19,1) Error: Undefined symbol: _HelloC with anything else procedure HelloC; cdecl; external 'HelloC'; it links, but dynamically and then the routine is never found.

With merely "external" the compiler uses the C variant of the identifier for the platform which on Win32 contains a "_" at the start (for Win64 for example there is none).
"external <NAME>" is used to tell the compiler to look for the C identifier ("_HelloC" on Win32, "HelloC" on Win64) inside the library "HelloC.dll".
To look for "HelloC" in a statically linked object file or library you need to use "external name <NAME>".

This is on an evil windows machine

Windows is one of FPC's main targets, we can do without such "expletives".

Regards,
Sven

Bart
to Sven Barth
AM Sven Barth wrote
> This is on an evil windows machine Windows is one of FPC's main targets, we can do without such "expletives".

Maybe he has WinME ???

Bart
Sven Barth
to Bart

Am Do., 31. Jan. 2019, 15:26 hat Bart geschrieben:

Show quoted text 9 lines
On Thu, Jan 31, 2019 at 7:35 AM Sven Barth via fpc-pascal wrote: > > This is on an evil windows machine > Windows is one of FPC's main targets, we can do without such "expletives". Maybe he has WinME ???

Well, I was rather happy with my WinME. Don't know why everyone is always complaining about it... 🤷‍♀️
Also: FPC doesn't work anymore on Win9x 😝

Regards,
Sven

conlin664
to Sven Barth

sven,

so I just tried, what I think you said:

procedure HelloC; cdecl; external name 'HelloC';
pcode.pas(19,1) Error: Undefined symbol: _HelloC

sorry for complaining about windows, but i feel like this is more difficult on windows.
All of the FPC examples, seem to run without this extra '_' business and i suspect they are on linux Os macOs.

Here at work I'm on a windows machine, but at home I'm happily running FPC on a mac

Marc Santhoff
to conlin664
conlin664 wrote 13 lines
sven, so I just tried, what I think you said: procedure HelloC; cdecl; external name 'HelloC'; pcode.pas(19,1) Error: Undefined symbol: _HelloC sorry for complaining about windows, but i feel like this is more difficult on windows. All of the FPC examples, seem to run without this extra '_' business and i suspect they are on linux Os macOs.

You could rename your "HelloC.o to "_HelloC.o" before archiving inte the library? Not that beautiful, but would be working, wouldn't it?

@Sven:
Maybe it is a later addition, but her on fpc 2.6.4 your syntax is not mentioned in the Programmers Guide (prog.pdf).

If i did look carefully enough there is no description of the syntax for:

"external name <NAME>"

And more, those details of naming and the different name conventions on Win32 and Win64 are missing, too. I think there should be at least a wiki page or better some explanations in the Programmers Guide.

Marc Santhoff
Tomas Hajny
to Marc Santhoff
Marc Santhoff wrote 8 lines
On Thu, 2019-01-31 at 11:00 -0700, conlin664 via fpc-pascal wrote: > sven, > > so I just tried, what I think you said: > > procedure HelloC; cdecl; external name 'HelloC'; > > pcode.pas(19,1) Error: Undefined symbol: _HelloC

.
.

You could rename your "HelloC.o to "_HelloC.o" before archiving inte the library? Not that beautiful, but would be working, wouldn't it?

@Marc: No, because 'HelloC' is name of the procedure, not of the object file.

@John: I noticed that you use a very old FPC version (2.4.4?) Do you get the same problem with the latest release?

Moreover - wouldn't 'stdcall' be more appropriate than 'cdecl' in your case? What does 'objdump -t ccode.o' show about HelloC?

Tomas

Sven Barth
to Marc Santhoff: You could rename your "HelloC.o to "_HelloC.o" before archiving inte the library? Not…

Am Do., 31. Jan. 2019, 22:03 hat Marc Santhoff
geschrieben:

Show quoted text 20 lines
On Thu, 2019-01-31 at 11:00 -0700, conlin664 via fpc-pascal wrote: > sven, > > so I just tried, what I think you said: > > procedure HelloC; cdecl; external name 'HelloC'; > > pcode.pas(19,1) Error: Undefined symbol: _HelloC > > > sorry for complaining about windows, but i feel like this is more difficult > on windows. > All of the FPC examples, seem to run without this extra '_' business and i > suspect they are on linux Os macOs. You could rename your "HelloC.o to "_HelloC.o" before archiving inte the library? Not that beautiful, but would be working, wouldn't it?

That is the object file, not the symbol. The symbol is the important part here.

Show quoted text 8 lines
@Sven: Maybe it is a later addition, but her on fpc 2.6.4 your syntax is not mentioned in the Programmers Guide (prog.pdf). If i did look carefully enough there is no description of the syntax for: "external name <NAME>"

It's an old syntax. Probably it was simply forgotten to be added to the documentation. Happens... 🤷‍♀️

And more, those details of naming and the different name conventions on

Win32 and Win64 are missing, too. I think there should be at least a wiki page or better some explanations in the Programmers Guide.

This is part of the platform's ABI. It's not our job to document that, only to make it usable.

Regards,
Sven

Marc Santhoff
to Tomas Hajny: . . @Marc: No, because 'HelloC' is name of the procedure, not of the object file. @John:…
Tomas Hajny wrote 17 lines
On Thu, January 31, 2019 21:57, Marc Santhoff wrote: > On Thu, 2019-01-31 at 11:00 -0700, conlin664 via fpc-pascal wrote: > > sven, > > > > so I just tried, what I think you said: > > > > procedure HelloC; cdecl; external name 'HelloC'; > > > > pcode.pas(19,1) Error: Undefined symbol: _HelloC . . > You could rename your "HelloC.o to "_HelloC.o" before archiving inte the > library? Not that beautiful, but would be working, wouldn't it? @Marc: No, because 'HelloC' is name of the procedure, not of the object file.

You and Sven are right of course. I played around using nm, which the op should probably do.

Show quoted text 5 lines
@John: I noticed that you use a very old FPC version (2.4.4?) Do you get the same problem with the latest release? Moreover - wouldn't 'stdcall' be more appropriate than 'cdecl' in your case? What does 'objdump -t ccode.o' show about HelloC?

<censored/>

That's what I asked for, then overlooked it...

Marc Santhoff
conlin664
to Marc Santhoff

THANKS GUYS.

This is now working. The 'fix' was to actually install fpc 3.0.4 on this machine.
My trusty 2.4.4 still compiled just fine what I use it for here at my day job.

But it seems 2.4.4 was not really pulling in the static reference. { $L ccode.o }

So for anyone else searching on this:

ccode.cpp

#include <stdint.h>
#include <stdio.h>

void HelloC(void)
{

   printf("Hello \n");

}

pcode.pas

program pcode;
{$L ccode.o }
{$linklib msvcrt}
uses
  ctypes, sysutils, dos, math;
procedure HelloC; cdecl; external name 'HelloC';
type
	UINT8  = 0..255;
	UINT16 = 0..65535;
	UINT32 = Longword;
begin
	writeln('Test');
	HelloC;
end.

compiled on WIN32 with:

@set ToolPath=C:\VCAST63\MinGW\bin
@set cc=%ToolPath%\gcc.exe

@set SAVED_PATH=%PATH%
@set PATH=%ToolPath%;%PATH%

@set BASE=%cd%

%CC% -g -I%BASE% -DGNU_WIN32 -O1 -Wunused-variable -c ccode.c -o ccode.o

rem %cc% -o test.exe ccode.o pcode.o -lwsock32

fpc -MDelphi -vw -Sg -Ci -O1 -OpPENTIUM3 -Ratt ^ -Fu%FPC_BASE%\units\i386-Win32 ^
-Fu%FPC_BASE%\units\i386-Win32\* ^
-Fu%FPC_BASE%\units\i386-Win32\rtl ^
-FlC:\VCAST63\MinGW\lib ^
pcode.pas

@set PATH=%SAVED_PATH%
@exit /b

thanks again!

john

Marc Santhoff
to conlin664
conlin664 wrote 9 lines
THANKS GUYS. This is now working. The 'fix' was to actually install fpc 3.0.4 on this machine. My trusty 2.4.4 still compiled just fine what I use it for here at my day job. But it seems 2.4.4 was not really pulling in the static reference. { $L ccode.o }

[...]

procedure HelloC; cdecl; external name 'HelloC';

[...]

Show quoted text 23 lines
compiled on WIN32 with: @set ToolPath=C:\VCAST63\MinGW\bin @set cc=%ToolPath%\gcc.exe @set SAVED_PATH=%PATH% @set PATH=%ToolPath%;%PATH% @set BASE=%cd% %CC% -g -I%BASE% -DGNU_WIN32 -O1 -Wunused-variable -c ccode.c -o ccode.o rem %cc% -o test.exe ccode.o pcode.o -lwsock32 fpc -MDelphi -vw -Sg -Ci -O1 -OpPENTIUM3 -Ratt ^ -Fu%FPC_BASE%\units\i386-Win32 ^ -Fu%FPC_BASE%\units\i386-Win32\* ^ -Fu%FPC_BASE%\units\i386-Win32\rtl ^ -FlC:\VCAST63\MinGW\lib ^ pcode.pas @set PATH=%SAVED_PATH% @exit /b

Why does this work having 'cdecl' instead of 'stdcall'?

Is it a special case regarding mingW32 that would not have happened using a native compiler like the one from Microsoft or Borland or similar?

Marc Santhoff
conlin664
to Marc Santhoff

Marc,

Hmmm. Okay, I just switched it to be stdcall
and had to slightly alter the name, but it compiled and ran.

So my example is now with "cpp" names, so my HelloC is now:

procedure HelloC; stdcall; external name '__Z6HelloCv';

vs

procedure HelloC; cdecl; external name '_Z6HelloCv';

both link and run.

lol - ok, this routine had no parameters.

So I just added one parameter and both stdcall and cdecl work with only the name change..

even when i have the cpp routine allocate something on the stack. So, I'm not sure who's cleaning up the stack: Caller or callee

Strange.

from the programing guide there should be a difference between cdecl and stdcall

but then we have
"When linking with code blocks compiled with
standard C compilers (such as GCC), the cdecl modifier should be used so as to indicate that the
external routine uses C type calling conventions."

so I'm going to stick with cdecl and for now it's working and will be more compatible when I also use this code on MacOs

cheers

john

Marc Santhoff
to conlin664

Hi John,

thanks a lot for the verbose information.

I was thinking about putting up a wiki page collecting the diffenrent cases of calling conventions, platforms and static vs. dynamic linking. But now I'm totally confused.

Maybe a compiler developer or someone having enough knowlodge can clear things up?

Marc Santhoff
Marc Santhoff
to Marc Santhoff: [...] [...] Why does this work having 'cdecl' instead of 'stdcall'? Is it a special case…
Marc Santhoff wrote 46 lines
On Mon, 2019-02-04 at 15:59 -0700, conlin664 via fpc-pascal wrote: > THANKS GUYS. > > This is now working. The 'fix' was to actually install fpc 3.0.4 on this > machine. > My trusty 2.4.4 still compiled just fine what I use it for here at my day > job. > > But it seems 2.4.4 was not really pulling in the static reference. > { $L ccode.o } [...] > procedure HelloC; cdecl; external name 'HelloC'; > [...] > compiled on WIN32 with: > > @set ToolPath=C:\VCAST63\MinGW\bin > @set cc=%ToolPath%\gcc.exe > > @set SAVED_PATH=%PATH% > @set PATH=%ToolPath%;%PATH% > > @set BASE=%cd% > > %CC% -g -I%BASE% -DGNU_WIN32 -O1 -Wunused-variable -c ccode.c -o > ccode.o > > rem %cc% -o test.exe ccode.o pcode.o -lwsock32 > > fpc -MDelphi -vw -Sg -Ci -O1 -OpPENTIUM3 -Ratt ^ > -Fu%FPC_BASE%\units\i386-Win32 ^ > -Fu%FPC_BASE%\units\i386-Win32\* ^ > -Fu%FPC_BASE%\units\i386-Win32\rtl ^ > -FlC:\VCAST63\MinGW\lib ^ > pcode.pas > > @set PATH=%SAVED_PATH% > @exit /b Why does this work having 'cdecl' instead of 'stdcall'? Is it a special case regarding mingW32 that would not have happened using a native compiler like the one from Microsoft or Borland or similar?

http://willus.com/mingw/yongweiwu_stdcall.html

I will not write anything about that mess, feeling sick already.

This computer is not running MICROS~1.