I have a legacy static library written in Pascal which I need to call from a C++ application targeting both PowerPC and x86 processors on the Mac OS X platform ( a so-called universal binary). After compiling and linking everything together, I'm having trouble calling the Pascal runtime libraries: i.e. I crash.
Software used:
glenn% gpc -v Reading specs from /Developer/Pascal/gpc345u2/lib/gcc/powerpc-apple- darwin8/3.4.5/specs Configured with: ../gcc-3.4.5/configure --enable-languages=pascal,c -- enable-threads=posix --target=powerpc-apple-darwin8 --host=powerpc- apple-darwin8 --build=powerpc-apple-darwin8 --prefix=/Developer/ Pascal/gpc345u2 Thread model: posix gpc version 20051116, based on gcc-3.4.5
gpc-i386 -vReading specs from /Developer/Pascal/gpc345u2/lib/gcc/i386- apple-darwin8/3.4.5/specs Configured with: ../gcc-3.4.5/configure --enable-languages=pascal,c -- enable-threads=posix --target=i386-apple-darwin8 --host=powerpc-apple- darwin8 --build=powerpc-apple-darwin8 --prefix=/Developer/Pascal/ gpc345u2 --with-sysroot=/Developer/SDKs/MacOSX10.4u.sdk/ --with- arch=pentium-m --with-tune=prescott Thread model: posix gpc version 20051116, based on gcc-3.4.5
Mac OS X 10.4.4 XCode 2.2.1
Source: 34 files of legacy Pascal which I've gone through and fixed all of the compiler errorss and most of the warnings.
Steps I've taken. 1) Compiled and packaged using gpc, libtool, and lipo: gpc -c --automake -Wl,-framework,Carbon -funit-path=/Developer/Pascal/ GPCPInterfaces/ MySrc.p libtool -static *.o -o MyLibPPC.a rm *.gpi rm *.o gpc-i386 -c --automake -Wl,-framework,Carbon -funit-path=/Developer/ Pascal/GPCPInterfaces/ MySrc.p libtool -static *.o -o MyLibx86.a
lipo *.a -create -output MyLib.a
2) Made a universal version of the gpc.a library
lipo /Developer/Pascal/gpc345u2/lib/gcc/i386-apple-darwin8/3.4.5/ libgpc.a /Developer/Pascal/gpc345u2/lib/gcc/powerpc-apple- darwin8/3.4.5/libgpc.a -create -output gpc.a
3) Added both libraries to my XCode 2.2.1 C++ application
4) Compile and Links without running, crashes as soon as it tries to call WriteLn, if I remove the WriteLn, it crashes later in a call to the file routine Assign, which might be the first runtime library call.
I declare the entry in C++ as: extern "C" short MyEntry(const char *path);
In Pascal, I declare it as
const MaxPointerChars = 20000; Type PAPointerChar=^APointerChar; APointerChar = Packed Array [0..MaxPointerChars] of Char; Int16 = Integer attribute ( size = 16); ...
function MyEntry(DllPathC:PAPointerChar):Int16; attribute (name = 'MyEntry');
...
function MyEntry(aCString:PAPointerChar):Int16; var DLLPath:String2048; pathLength:Int32; i:Int32; begin pathLength := StrLen(aCString); if pathLength > 2048 then pathLength := 2048; DLLPath := ''; for i := 1 to pathLength do begin DLLPath := DLLPath + aCString^[i-1]; end; WriteLn(DLLPath); { crashes here}
...
gdb gives me the following console output: Running… Program received signal: "EXC_BAD_ACCESS".
Unable to disassemble _p_Write_Init.
5) I've written a little test application in Pascal to debug the libraries code (when it is not packaged as a library but compiled directly into the application) and the code works perfectly well in that environment. The debugging was done with XCode 2.1 as I believe there is a problem with gpc and XCode 2.2.
So how do I fix this?
Glenn Howes wrote:
I have a legacy static library written in Pascal which I need to call from a C++ application targeting both PowerPC and x86 processors on the Mac OS X platform ( a so-called universal binary). After compiling and linking everything together, I'm having trouble calling the Pascal runtime libraries: i.e. I crash.
Software used:
glenn% gpc -v Reading specs from /Developer/Pascal/gpc345u2/lib/gcc/powerpc-apple-darwin8/3.4.5/specs Configured with: ../gcc-3.4.5/configure --enable-languages=pascal,c --enable-threads=posix --target=powerpc-apple-darwin8 --host=powerpc-apple-darwin8 --build=powerpc-apple-darwin8 --prefix=/Developer/Pascal/gpc345u2 Thread model: posix gpc version 20051116, based on gcc-3.4.5
gpc-i386 -vReading specs from /Developer/Pascal/gpc345u2/lib/gcc/i386-apple-darwin8/3.4.5/specs Configured with: ../gcc-3.4.5/configure --enable-languages=pascal,c --enable-threads=posix --target=i386-apple-darwin8 --host=powerpc-apple-darwin8 --build=powerpc-apple-darwin8 --prefix=/Developer/Pascal/gpc345u2 --with-sysroot=/Developer/SDKs/MacOSX10.4u.sdk/ --with-arch=pentium-m --with-tune=prescott Thread model: posix gpc version 20051116, based on gcc-3.4.5
Mac OS X 10.4.4 XCode 2.2.1
Source: 34 files of legacy Pascal which I've gone through and fixed all of the compiler errorss and most of the warnings.
Steps I've taken.
- Compiled and packaged using gpc, libtool, and lipo:
gpc -c --automake -Wl,-framework,Carbon -funit-path=/Developer/Pascal/GPCPInterfaces/ MySrc.p libtool -static *.o -o MyLibPPC.a rm *.gpi rm *.o gpc-i386 -c --automake -Wl,-framework,Carbon -funit-path=/Developer/Pascal/GPCPInterfaces/ MySrc.p libtool -static *.o -o MyLibx86.a
Sidebar - when linking a framework to i386 code on powerpc-darwin (Mac OS X), you generally have to add -Wl,-syslibroot,/Developer/SDKs/MacOSX10.4u.sdk/. In this specific case, the linker doesn't complain about it, because you are creating a static library.
lipo *.a -create -output MyLib.a
- Made a universal version of the gpc.a library
lipo /Developer/Pascal/gpc345u2/lib/gcc/i386-apple-darwin8/3.4.5/ libgpc.a /Developer/Pascal/gpc345u2/lib/gcc/powerpc-apple-darwin8/ 3.4.5/libgpc.a -create -output gpc.a
Added both libraries to my XCode 2.2.1 C++ application
Compile and Links without running, crashes as soon as it tries to
call WriteLn, if I remove the WriteLn, it crashes later in a call to the file routine Assign, which might be the first runtime library call.
I declare the entry in C++ as: extern "C" short MyEntry(const char *path);
In Pascal, I declare it as
const MaxPointerChars = 20000; Type PAPointerChar=^APointerChar; APointerChar = Packed Array [0..MaxPointerChars] of Char; Int16 = Integer attribute ( size = 16); ...
function MyEntry(DllPathC:PAPointerChar):Int16; attribute (name = 'MyEntry');
...
function MyEntry(aCString:PAPointerChar):Int16; var DLLPath:String2048; pathLength:Int32; i:Int32; begin pathLength := StrLen(aCString); if pathLength > 2048 then pathLength := 2048; DLLPath := ''; for i := 1 to pathLength do begin DLLPath := DLLPath + aCString^[i-1]; end; WriteLn(DLLPath); { crashes here}
...
gdb gives me the following console output: Running… Program received signal: "EXC_BAD_ACCESS".
Unable to disassemble _p_Write_Init.
What you have done is all fine (I am glad there are people who *do* read README files), except that you have to initialize the GPC runtime library, see /Developer/Pascal/gpc345u2/doc/gpc/demos/gpc_c_c.c and the gpc mailing list archive at http://www.gnu-pascal.de/crystal/gpc/en/.
- I've written a little test application in Pascal to debug the
libraries code (when it is not packaged as a library but compiled directly into the application) and the code works perfectly well in that environment. The debugging was done with XCode 2.1 as I believe there is a problem with gpc and XCode 2.2.
Oh, there is a workaround for the bug in Xcode 2.2 and Xcode 2.2.1, see recent postings in the macpascal mailing list archive at http://www.pascal-central.com/archives.html.
Regards,
Adriaan van Os
Adriann, Thank you very much for the quick reply.
I applied your fix and I got further, at least, before crashing again. Running… Program received signal: "EXC_BAD_ACCESS".
Unable to disassemble _p_Unbind.
(partial stack trace) _p_Unbind _p_AssignFile _p_Assign (my code)
Does this appear to be a problem with initialization or linking?
One further issue, we have a Netscape plugin version of this application. I assume that I should call _p_initialize from the module's init method instead of the non-existent main method, and if so what should I pass in as dummy parameters?
--glenn
Glenn Howes wrote:
I applied your fix and I got further, at least, before crashing again. Running… Program received signal: "EXC_BAD_ACCESS".
Unable to disassemble _p_Unbind.
(partial stack trace) _p_Unbind _p_AssignFile _p_Assign (my code)
Does this appear to be a problem with initialization or linking?
I can't say without knowing more about the application and circumstances (and also see the crash log from the /Applications/Utilities/Console utility).
You can try to locate the problem yourself in Xcode - to enable debug info for Pascal application code, add "-g" to the gpc (or gp) command line options - to get useful debug info for the GPC runtime library, build the Pascal compiler from sources (see my website, it's not difficult anymore) - in Xcode, uncheck the "load symbols lazily" preference setting.
One further issue, we have a Netscape plugin version of this application. I assume that I should call _p_initialize from the module's init method instead of the non-existent main method,
Probably yes, but I have never written a Netscape plugin myself.
and if so what should I pass in as dummy parameters?
See the template for a "Carbon Dynamic Library" in the GPC Xcode Kit for Mac OS X (but adding 0 for the new Options parameter).
procedure GPC_Initialize (ArgumentCount: CInteger; Arguments, StartEnvironment: PCStrings; Options: CInteger); attribute (name = '_p_initialize');
Regards,
Adriaan van Os
Glenn Howes wrote:
I applied your fix and I got further, at least, before crashing again. Running… Program received signal: "EXC_BAD_ACCESS".
Unable to disassemble _p_Unbind.
(partial stack trace) _p_Unbind _p_AssignFile _p_Assign (my code)
Does this appear to be a problem with initialization or linking?
I can't say without knowing more about the application and circumstances (and also see the crash log from the /Applications/Utilities/Console utility).
You can try to locate the problem yourself in Xcode
- to enable debug info for Pascal application code, add "-g" to the
gpc (or gp) command line options
- to get useful debug info for the GPC runtime library, build the
Pascal compiler from sources (see my website, it's not difficult anymore)
- in Xcode, uncheck the "load symbols lazily" preference setting.
Still, I can't resist to fire a blind shot in the dark - what kind of strings are you using to interface between Pascal and C ? If you are using UCSD-Pascal strings (\p in the Apple gcc compiler and Str255, Str63 or Str31 in the Mac OS X Pascal interfaces) then any interfacing between Pascal and C must be done with const or var parameters, value parameters will crash (the UCSD-Pascal strings in the Mac OS X Pascal interfaces are tricked).
A question, did linking GPC to C/C++ on powerpc work without adding darwin-fpsave.o ? Not related to the above problem, just curious.
Regards,
Adriaan van Os