Date: 15-Jan-91 15:39 PST From: Kurt Inman [71141,2330] Subj: pb links tc now Bob, I finally found a way to link TC routines into PB programs! If you use the Huge model (code & data segments of any size, including multiple segments) to compile the C code, it only generates a code segment and a data segment to the .OBJ file, rather than including the BSS segment which PB was tripping up on. Here's how to do it explicitly: 1. Set Options/Compiler/Model to Huge. 2. Set Options/Compiler/Names/Code names/Segment name to CSEG. 3. Set Options/Compiler/Names/Code names/Class name to nothing (it defaults to '*'). 4. Set Options/Compiler/Names/Data names/Segment name to DSEG. 5. Set Options/Compiler/Names/Data names/Class name to nothing (it defaults to '*'). 6. Compile your code (you don't need to change any Group names or BSS names, nor do you have to Options/Linker/Initialize segments). 7. $LINK the .OBJ module into your PB program as usual. Kurt 15-Jan-91 20:19:29 Sb: #Using TC with PB Fm: Kurt Inman (PowerBASIC) 71141,2330 To: All We've identified a problem which occurs when you attempt to $LINK an .OBJ file created with Borland's Turbo C compiler into a PowerBASIC program. Many combinations of Turbo C models and segment names in the .OBJ file will cause PB to generate either Error 510 (Code requires byte alignment) or Error 509 (Invalid segment name) on the $LINK metastatement. In fact, the Error 510 is incorrect in this case, and is generated regardless of whether the code is byte-aligned or not. The cause of the Error 510/509 is that for all memory models except Huge, Turbo C creates definitions for three segments in the .OBJ file: code (_TEXT), initialized data (_DATA), and uninitialized data (_BSS). Even if you force Turbo C to use the same name for both data segments, it will still place three segment definitions in the .OBJ file, causing PowerBASIC to generate Error 510/509 when it encounters a second data segment definition. The solution is to compile your Turbo C code using the Huge memory model, with the code segment named CSEG and the data segment named DSEG. You must also explicitly tell TC not to generate a class name for either segment. Using the Huge model causes TC to generate definitions for only one code and one data segment, both without group names. This is the only configuration which fully conforms to PB's method of linking external routines. Here are the steps to use when compiling your routines with Turbo C version 2.0. Borland's Turbo C++ compiler may also generate PB-compatible code if the corresponding code generation options are enabled. 1. Set Options/Compiler/Model to Huge. 2. Set Options/Compiler/Names/Code names/Segment name to CSEG. 3. Set Options/Compiler/Names/Code names/Class name to nothing (it defaults to '*'). 4. Set Options/Compiler/Names/Data names/Segment name to DSEG. 5. Set Options/Compiler/Names/Data names/Class name to nothing (it defaults to '*'). 6. Compile your code to an .OBJ file (you don't need to change any Group names or BSS names, nor do you have to Options/Linker/Initialize segments). 7. $LINK the resulting .OBJ file into your PB program. To: All (continued from previous "Using TC with PB" message) Please let us know if there are any problems with this method. It works in the limited cases that we've tried, but we haven't tested it exhaustively. We are posting it in an effort to assist those of you who need to link your Turbo C routines into PowerBASIC programs. Kurt Inman (PowerBASIC R&D) Sb: #87182-Using TC with PB Fm: AL MUSELLA 76114,637 To: Kurt Inman (PowerBASIC) 71141,2330 Kurt, I tried this and got rid of the byte alignment problem, but I am now having difficulty getting pb to recognize the c functions. I get error 462"undefined sub/fn". I tried declare function - no help! Can you give a short example on how to pass an integer (and maybe a string) to a c function? Both the c code and pb code. BTW - you have to use tcinst to change the names of the groups in TC++, unlike tc2.0, where you can change them from the enviorment. Al 16-Jan-91 10:13:32 Sb: #87182-#Using TC with PB Fm: AL MUSELLA 76114,637 To: Kurt Inman (PowerBASIC) 71141,2330 (X) Kurt, I finally got a c .obj to work with pb! The trick was to turn off the generate underbars option. There is still a problem with passing parameters though, and if you could demonstrate just passing integers back and forth, it would be a big help. Al There is 1 Reply. 16-Jan-91 13:55:26 Sb: #87261-Using TC with PB Fm: Kurt Inman (PowerBASIC) 71141,2330 To: AL MUSELLA 76114,637 Al, Here's a simple example of a C function which takes an integer as a parameter, adds 17 to it, and returns it to the PB program: TC: /* compile this to MYCCODE.OBJ as per my last message */ int pascal DOCALC (int far *pbvar) { return (*pbvar)+17; } PB: $link "myccode.obj" declare function DOCALC%(integer) print DOCALC%(5) 'prints 22 (5+17) Some things to note: the C function is declared to use PASCAL calling conventions (the C function must clean up the stack after the call, not PB), the parameter PBVAR is declared to be a far pointer to an integer since PB passes all parameters as far pointers, the function has a return type of INT which causes the returned integer to be placed in the AX register upon return (which is what PB expects of an external function that returns an integer), and PB's DECLARE statement must explicitly specify that the C function is an integer function which takes an integer as a parameter. I'll put up an example with strings shortly. Kurt Sb: #87307-#Using TC with PB Fm: Kurt Inman (PowerBASIC) 71141,2330 To: Kurt Inman (PowerBASIC) 71141,2330 (X) Al, Here's a simple example of a C routine which changes the first character of a PB string which is passed to it as a parameter: TC: /* compile as MYCCODE.OBJ as per my earlier message */ #include void pascal DOSTR(unsigned far *stseg, unsigned far *stofs, int far *stlen) { char far *stdata; /* will point to actual string data */ if (*stlen) { /* if string length > 0 */ stdata = (char far *) MK_FP(*stseg, *stofs); /* get data pointer */ if (stdata) /* if valid string */ *stdata = '*'; /* change 1st char of string to '*' */ } } PB: $link "myccode.obj" declare sub DOSTR(integer,integer,integer) a$="hello" call DOSTR(strseg(a$),strptr(a$),len(a$)) 'pass segment/offset/length print a$ 'will print "*ello" Keep in mind that the C routine must not change the length of the string passed to it. Also, this example works for both regular and flex strings. Hope this helps! Kurt There is 1 Reply. 16-Jan-91 17:19:43 Sb: #87316-#Using TC with PB Fm: AL MUSELLA 76114,637 To: Kurt Inman (PowerBASIC) 71141,2330 (X) Kurt, Thanks very much for the help. Your sample programs worked fine. One more question - (although I think this is impossible): I was trying to link in the TC BGI routines, to allow my PB programs to use different fonts. I used tlib to convert the needed routines from the graphics library into .obj files, but the segment names won't work with PB. Is there any way to fix that? I found a strange way around it, but it's very clutzy: I set up an interrupt handler (using 60h) in C, which when called from pb using call interrupt, would print a (constant) string in the correct font. Now that you showed me how to pass variables, this may actually be useful! One last note: I made a mistake in my last message: You can set the segment names from the tc++ enviorment, they are just in a different place on the menu than in tc. Thanks again, Al PS: You should include those 2 examples in the next edition of the manual for PB! There is 1 Reply. 16-Jan-91 17:53:08 Sb: #87351-Using TC with PB Fm: Kurt Inman (PowerBASIC) 71141,2330 To: AL MUSELLA 76114,637 Al, I think the only way around the problem with the BGI segment names would be to attempt to directly modify the .OBJ files, in order to change the names to something that PB could accept. That would be very messy and may not even be possible depending on the lengths of the names used, etc. Maybe PB will be able to handle more segment names in the future, or we or some third party will develop a graphics library for PB similar to BGI. For now, though, I don't see any way around the problem, short of a real kludge. I think we will put the C examples in the next manual (or at least the next README file) -- that's a good idea! Kurt