RMANGALD%CLARKU.BITNET@wiscvm.wisc.EDU (10/27/87)
I am writing a program in C and I need to call routines in the IMSL Library, which were written in FORTRAN. Could all you nice folks out there share your experiences on this topic -- especially the tricks and traps in doing this? I'd particularly appreciate hearing from people who've done this (i.e., called IMSL from C). Thanks. Rahul Mangaldas. rmangaldas@clarku.bitnet
chris@mimsy.UUCP (Chris Torek) (10/27/87)
In article <9976@brl-adm.ARPA> RMANGALD%CLARKU.BITNET@wiscvm.wisc.EDU writes: >I am writing a program in C and I need to call routines in the >IMSL Library.... Every topic comes around again at most once every few years. Some time ago I started saving my discourses.... Relay-Version: version B 2.10.3 4.3bsd-beta 6/6/85; site maryland.UUCP Posting-Version: version B 2.10.3 4.3bsd-beta 6/6/85; site umcp-cs.UUCP Path: maryland!umcp-cs!chris From: chris@umcp-cs.UUCP (Chris Torek) Newsgroups: net.unix-wizards,net.lang.c,net.lang.f77,net.lang.pascal Subject: Re: linking C and Fortran, and Pascal Message-ID: <2719@umcp-cs.UUCP> Date: 3 Aug 86 21:34:31 GMT Date-Received: 3 Aug 86 21:34:31 GMT References: <2662@brl-smoke.ARPA> Reply-To: chris@maryland.UUCP (Chris Torek) Followup-To: net.unix-wizards Organization: University of Maryland, Dept. of Computer Sci. Lines: 259 In article <2662@brl-smoke.ARPA> johnston@lbl-csam.arpa (Bill Johnston [csam]) writes: >What needs to be done (other than ensuring consistent data types >for args) in order to link C and/or Fortran main programs and >routines with each other? I am going to attempt to produce the definitive article on mixed language linking under 4BSD Vax Unix. Stand back! First, there is the matter of names: The symbols in the object files must match, that the linker may resolve the right references. Yet each compiler has its own methods for mapping from source to object. Within one language we may safely ignore this mapping; but when mixing tongues, it becomes important indeed. The C compiler takes any global symbol and prepends an underscore character, `_'. Names are not limited in length---though in fact there is a limit of about a thousand characters, no one seems to run into it. Thus int global_var; char * somefunc() { ... generates the symbols `_global_var' and `_somefunc'. The F77 compiler limits names to six characters, then prepends and appends an underscore: subroutine sub integer var common /com/ var ... names the subroutine `_sub_' and creates a global `variable' containing one integer. The `variable' is called `_com_'. Variables that are not part of a common block do not have global names. F77 does not allow underscores in source-level names: `subroutine sub_1' is illegal. The compiler also ignores any PROGRAM name: program prog ... creates the symbol `_MAIN_'. The Berkeley Pascal compiler strings together the names of all nested procedures to concoct unique global names. Only variables defined in the `program' part are global (no surprise here), and these names are constructed in the same way as C's globals. However, the program name is ignored, and the compiler uses the name `_program': program foo; { symbol _program } var v: integer; { symbol _v } procedure proc; { symbol _proc } function func; { symbol _proc_func } begin func := 0 end; { end proc's func } begin end; { end proc } begin end. { end program } generates the symbols `_program', `_v', `_proc', and `_proc_func'. (It also generates the names `___proc_func' and `___proc', but we shall ignore these for the moment.) The Pascal compiler does not permit source-level names to contain `_': i.e., `procedure proc_a' is illegal. It should be clear at this point that C programs can call any F77 or Pascal subroutines (procedures) or functions, and that Pascal can call many C routines---not all, for names with underscores are out of reach---while F77 routines can call only specially-named C routines, namely those that end with an underscore, are less than seven other characters, and contain no internal underscores. F77 and Pascal routines can never call each other directly. Even with a compatible set of names, the task is not yet done. There remain two problems, each bound up with the other. Every program must have an entry point (`main'); and every language has its libraries. C's is the simplest of the three, for its main looks like every other C routine and needs no libraries not used by both F77 and Pascal as well. F77's main is a C routine that initialises its I/O system, traps signals, and calls the program's _MAIN_. Pascal's main is similar to F77's, but does not trap signals and calls _program, not _MAIN_. Both F77's and Pascal's mains also save argc and argv, F77's in `_xargc' and `_xargv' and Pascal's in __argc and __argv. Now if you intend to call C routines from F77 or Pascal, and assuming that these routines are entirely self-contained, all you need do is compile the C code to object, and mention the `.o' file in the linking command. Of course, you must also use the proper parameter passing conventions---but I anticipate. Calling F77 or Pascal routines from C, however, is a bit more difficult. If the routines will do no I/O, you can simply compile the routines to object, and mention them in the linking command. If they may do I/O, you will need not only to initialise the I/O system, but also to clean up afterward. This becomes quite tricky and is best avoided whenever possible. F77's I/O system is initialised by the C routine `f_init' (F77's support library is written almost entirely in C) and torn down by the routine `f_exit'. Both take no parameters. Indeed, the F77 main program consists mainly of the three lines f_init(); MAIN_(); /* recall that C prepends an underscore */ f_exit(); though there is much other code dealing with signals, and of course with argc and argv. Pascal's I/O system is initialised by the C routine `PCSTART'. (Yes, Pascal's support library too is written in C. I find it amusing to note that other language libraries can be written in C, but C's language libraries cannot, for the most part, be written in the other languages.) Pascal's main can be written in C as extern int _argc; extern char **_argv; main(argc, argv) int argc; char **argv; { PCSTART(0); _argc = argc; _argv = argv; program(); PCEXIT(0); /*NOTREACHED*/ } ---though the compiler in fact generates this directly, eliminating an unnecessary return instruction. PCEXIT, unfortunately, terminates the program as well as flushing any pending output. As to the various libraries themselves, there are many: Library Used by ------- ------- -lF77 F77 -lI77 F77 -lU77 F77 -lpc Pascal -lm F77, Pascal -lc C, F77, Pascal In other words, all the linking commands pass `-lc' to the linker `ld'; the others depend on the command. `f77' calls ld with all except `-lpc'; `pc' calls ld with `-lpc -lm -lc'. `cc' calls ld with only `-lc', so to use an F77 routine with a C main, one must link with cc main.o f77sub.o -lF77 -lI77 -lU77 -lm Moreover, the order of the libraries specified is also important. `-lF77' builds on `-lI77', and `-lI77' builds on `-lU77'; all build on `-lm' and `-lc'. `-lpc' builds on `-lm' and `-lc'. Thus `-lpc' may be put anywhere with respect to `-lI77', for example; but both must appear before `-lm'. You should now be able to compile and link mixed language sources. But this is not the whole story: There is still the matter of parameter passing. The F77 compiler uses call by reference; the Pascal compiler uses call by value or call by reference, depending on the declaration of the called routine. The C compiler invariably uses call by value, but the language is powerful enough to simulate other parameter mechanisms using only call by value. One thing that can be done in Pascal but not C is to pass arrays by value. (This can be simulated in C using structures.) Pretty words, those: but what do they mean? For a strict definition I will tell you only to consult any good compiler book; but here are some examples: [f77sub.f] SUBROUTINE SUB (A) INTEGER A DOUBLE PRECISION D C Mixed mode arithmetic is legal in Unix F77 D = A + 2.0 CALL CSUB(D) RETURN END [psub.p] { declare external C subroutine } procedure csub2(i: integer); external; procedure psub(var i: integer); begin i := 3 end; function pfunc(i: integer): integer; begin pfunc := i + 2; csub(i) end; [cmain.c] /*ARGSUSED*/ main(argc, argv) int argc; char **argv; { int i; psub(&i); /* call Pascal subroutine with var parameter */ sub_(&i); /* call F77 subroutine: call by reference */ i = pfunc(7); /* call Pascal function with value parameter */ exit(0); } /* called from F77: call by reference */ csub_(d) double *d; { printf("%g\n", *d); } /* called from Pascal by value */ csub2(i) int i; { printf("%d\n", i); } Fortunately, function return values are all done the same way for simple-valued functions. Structure-valued functions should simply be avoided. Since the above example does no I/O in its F77 and Pascal routines, and in fact calls no F77 or Pascal intrinsics, this can be compiled with the commands: f77 -c f77sub.f pc -c psub.p cc -c cmain.c cc -o example cmain.o psub.o f77sub.o Appending `-lF77 -lI77 -lU77 -lpc -lm' to the last command would not hurt, and might be required in more complex cases. There is one remaining trick in linking Pascal and C/F77 routines, and that has to do with nested procedures and functions, and nonlocal variable access. Neither C nor F77 have these, and there is no provision in the runtime environment for them. Pascal, however, uses something called a `display' to be able to get at nonlocal variables. The display manipulation is normally compiled in-line; for procedure parameters, the compiler uses those `extra' names. In the earlier example, these were `___proc' and `___proc_func'. These routines do display winding for entry to _proc and _proc_func. The unwinding after procedure parameter calls is generated in-line. If you never use nested procedures, or nonlocal variables, you can safely ignore this. If you do, but do not know what a display is all about, again I will tell you only to consult a good compiler book. Look at the assembly code generated by `pc -S' for details on the display format. Indeed, looking at the assembly code is a good way to determine just what the compiler is really doing for all three of these compilers. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
dmocsny@minerva.che.uc.edu (Daniel Mocsny) (12/11/90)
In keeping with the holiday spirit of peace on earth and goodwill toward language partisans, I have been toying with the possibility of linking C and FORTRAN compiled objects together. To my surprise, C and FORTRAN can coexist in harmony greater than their proponents often do. However, all is not bliss. Consider the following example. Suppose I have a library of compiled objects originally written in FORTRAN, and I have no access to source code. I wish to call some functions in this library from a C program, and I want to use functions that calculate and return single precision (float) values. To test this, I am using the following toy program: /* file: main.c * * This is a C language main program which is supposed to call a * function in a FORTRAN file test.f. */ #include <stdio.h> float xsquar_( /* float x */ ); main() { float x, z; x = 5.0; z = xsquar_( &x ); printf("The square of %g should be: %g\n", x, z ); } Next, the FORTRAN file containing the XSQUAR function: C file: test1.f C C This is a FORTRAN file containing a function I am trying to call from C a C program. REAL FUNCTION XSQUAR( X ) REAL X XSQUAR = X * X WRITE(6,10) X, XSQUAR 10 FORMAT( "X: ",F10.3," XSQUAR: ",F10.3 ) RETURN END The underscore "_" character after xsquar in main.c is necessary on several systems where I have tested this example, because the f77 compiler appends an underscore to identifier names on these systems. On a DEC MicroVAX II running Ultrix-32 v3.0, and on an HP machine runnin HP-UX Release A.B3.10C, this example does what it it should, i.e. (except that HP-UX doesn't need the underscore...sigh): X: 5.000 XSQUAR: 25.000 The square of 5 should be: 25 However, under SunOS 4.0.3, I get the following: X: 5.000 XSQUAR: 25.000 The square of 5 should be: 8.05306e+08 As nearly as I can tell, the Sun C compiler is having a little trouble with the return value from xsquar_(). I have already tried the obvious things: compiling with the -fsingle option (this doesn't help, because it doesn't affect function return values); and trying all manner of casts and declarations to double in main.c (maybe I haven't hit on the right combinations, but I tried a few). I did try the following, where I changed XSQUAR to a SUBROUTINE and got the return value by passing a pointer to float from a file main2.c: /* file: main2.c * * This is a C language main program which is supposed to call a * subroutine in a FORTRAN file test2.f. */ #include <stdio.h> void xsquar_( /* float x, float y */ ); main() { float x, y; x = 5.0; xsquar_( &x, &y ); printf("The square of %g should be: %g\n", x, y ); } The corresponding FORTRAN file is: C file: test2.f C SUBROUTINE XSQUAR( X, Y ) REAL X, Y Y = X * X WRITE(6,10) X, Y 10 FORMAT( "X: ",F10.3," X squared: ",F10.3 ) RETURN END And the output is: X: 5.000 X squared: 25.000 The square of 5 should be: 25 Here is the Makefile I used on the Sun, in case anybody wants to try this out: # This is a Makefile to test calling a FORTRAN function from a # C language main program. FORTLIB=/home/f77/SC0.0/libF77.a test: main.o test.o cc test.o main.o $(FORTLIB) -o test test2: main2.o test2.o cc test2.o main2.o $(FORTLIB) -o test2 (The libF77.a FORTRAN library is in a non-standard location on the machine I used. Change to the location on your machine. The WRITE statement in test.f and test2.f will cause a link error unless "ld" knows where to look for libF77.a. Since I used "cc" to generate the "ld" command, and let "make" use its default rules on the targets *.o, "ld" doesn't automatically find libF77.a.) Does anybody have any suggestions about how to call FORTRAN functions that return single-precision values from a C program under SunOS, or is this an insurmountable problem? And does it occur under other compiler combinations? Already this is looking uglier and less portable than I would like. -- Dan Mocsny Snail: Internet: dmocsny@minerva.che.uc.edu Dept. of Chemical Engng. M.L. 171 dmocsny@uceng.uc.edu University of Cincinnati 513/751-6824 (home) 513/556-2007 (lab) Cincinnati, Ohio 45221-0171