[CMake] Extension proposal: CheckFortranFuinctionExists.cmake

Arjen Markus arjen.markus at wldelft.nl
Thu Jun 26 00:19:27 EDT 2008


> On 2008-06-25 16:32+0200 Bernd Schubert wrote:
>
>> No, it is really no problem to link fortran libraries and to call their
>> functions. It is onkly a bit nasty sometimes to write the proto types of
>> the
>> blas/lapack functions, since nobody seems to have created a complete set
>> of
>> these, afaik. For real number crunching one also uses the intel/amd or
>> goto
>> libraries and there is always only one library of these, for both C and
>> Fortran (afaik, these optimized libraries are also not written in
>> fortran
>> anymore, they just have this stupid interface to be compatible with
>> fortran.
>> The other issue with fortran libraries is to figure out, how these have
>> been
>> compiled (additional underscores, etc).
>
> You have described issues which illustrate and support my point. They may
> be
> considered fairly trivial on one fixed platform but become important if
> you
> are trying to make a multi-platform build system.  For example, what do
> you
> do about the underscore issue if you are testing the linking of C code
> with
> the fortran blas library? On one platform you will have to test sgemm, on
> another you will have to test sgemm_.  These cross-platform build-system
> issues all disappear if you test C/C++ code against the C version of blas.
>
>>
>> On the other hand, cblas even has a slightly different interface than
>> nativ
>> blas, so without changing the existing code it is not suitable for
>> linking.
>>
>
> Changing your existing code once to link to cblas may be a smaller price
> to
> pay. If your existing C/C++ code linked to the fortran BLAS library is to
> work on multiple platforms, what do you do about the cross-platform issue
> involving underscores?  You will end up doing a lot of extra work to
> support
> the platform variations that is not required if you link to the C version
> of
> BLAS.
>

With regards to the differences in calling and naming conventions
between Fortran and C, I recently posted a program on the comp.lang.fortran
newsgroup to solve that issue automatically, at least for the platforms
I have access to. It is part of my Ftcl project, the combination of Fortran
and Tcl - http://ftcl.sf.net. I post it below, as it may help solving the
current issue.

The idea is very simple:
Let the linker decide which version of a C routine will be called
by the Fortran program and let that version write its properties
to a header file.

Regards,

Arjen

----- probe.f90 -----
! probe.f90 --
!     Try and identify the Fortran naming and calling convention
!     - part of Ftcl
!
!     Note:
!     This is the Fortran part of a program  that uses a few tricks
!     to determine:
!     - The naming convention for the Fortran compiler (including
!       the current options that influence this convention).
!       The result will be:
!       - One of FOR_ALL_LOWER, FOR_ALL_CAPS, FOR_UNDERSCORE or
FOR_DBL_UNDERSCORE
!         will be defined. These are the most common naming conventions
!     - The macro IN_BETWEEN is defined or undefined so that string
!       arguments can be properly passed
!     - The macro FOR_CALL is defined to capture the correct calling
!       convention vis-a-vis stack clean-up
!     - The values of these macros are stored in a file "ftcl_conventions.h"
!
!     If the program fails, it will need to be expanded, as that is an
!     indication that this particular combination of Fortran and C
!     compilers is not yet supported.
!
program probe

    character(len=7) :: first  = 'Fortran'
    character(len=3) :: second = 'Tcl'

    call probe_c( first, second )

end program probe

----- probe_c.c -----
/* probe_c.c --
 *     Companion to the file probe.f90. Together they form a program
 *     that will write a header file with the right macros for
 *     setting up the interface between Fortran and C.
 *
 */

#include <stdio.h>
#include <stdlib.h>

/* probe_c --
       Plainly named version
*/

void probe_c( char *first, int len_first, char *second, int len_second ) {

    FILE *outfile ;

    outfile = fopen( "ftcl_conventions.h", "w" ) ;

    fprintf( outfile, "#define FOR_ALL_LOWER\n" ) ;
    fprintf( outfile, "#define FOR_CALL\n" ) ;

    /* If hidden length argument in between, then len_first must be 7 */
    if ( len_first == 7 ) {
        fprintf( outfile, "#define IN_BETWEEN\n" ) ;
    } else if ( (int) second == 7 ) {
        fprintf( outfile, "#undef IN_BETWEEN\n" ) ;
    } else {
        fprintf( stderr, "Unknown expected calling convention - assuming
NOT IN_BETWEEN!\n" ) ;
        fprintf( outfile, "#undef IN_BETWEEN\n" ) ;
    }

    fclose( outfile ) ;
}

/* PROBE_C --
       All capitals version - possibly __stdcall too
*/
#ifdef _MSC_VER
#define FOR_CALL __stdcall
#else
#define FOR_CALL
#endif

void FOR_CALL PROBE_C( char *first, int len_first, char *second, int
len_second ) {

    FILE *outfile ;

    outfile = fopen( "ftcl_conventions.h", "w" ) ;

    fprintf( outfile, "#define FOR_ALL_CAPS\n" ) ;
#ifdef _MSC_VER
    fprintf( outfile, "#define FOR_CALL __stdcall\n" ) ;
#else
    fprintf( outfile, "#define FOR_CALL\n" ) ;
#endif

    /* If hidden length argument in between, then len_first must be 7 */
    if ( len_first == 7 ) {
        fprintf( outfile, "#define IN_BETWEEN\n" ) ;
    } else if ( (int) second == 7 ) {
        fprintf( outfile, "#undef IN_BETWEEN\n" ) ;
    } else {
        fprintf( stderr, "Unknown expected calling convention - assuming
NOT IN_BETWEEN!\n" ) ;
        fprintf( outfile, "#undef IN_BETWEEN\n" ) ;
    }

    fclose( outfile ) ;
}

/* probe_c_ --
       Single underscore
*/
void FOR_CALL probe_c_( char *first, int len_first, char *second, int
len_second ) {

    FILE *outfile ;

    outfile = fopen( "ftcl_conventions.h", "w" ) ;

    fprintf( outfile, "#define FOR_UNDERSCORE\n" ) ;
    fprintf( outfile, "#define FOR_CALL\n" ) ;

    /* If hidden length argument in between, then len_first must be 7 */
    if ( len_first == 7 ) {
        fprintf( outfile, "#define IN_BETWEEN\n" ) ;
    } else if ( (int) second == 7 ) {
        fprintf( outfile, "#undef IN_BETWEEN\n" ) ;
    } else {
        fprintf( stderr, "Unknown expected calling convention - assuming
NOT IN_BETWEEN!\n" ) ;
        fprintf( outfile, "#undef IN_BETWEEN\n" ) ;
    }

    fclose( outfile ) ;
}

/* probe_c__ --
       Double underscore (for Fortran names that have an embedded underscore)
*/
void FOR_CALL probe_c__( char *first, int len_first, char *second, int
len_second ) {

    FILE *outfile ;

    outfile = fopen( "ftcl_conventions.h", "w" ) ;

    fprintf( outfile, "#define FOR_DBL_UNDERSCORE\n" ) ;
    fprintf( outfile, "#define FOR_CALL\n" ) ;

    /* If hidden length argument in between, then len_first must be 7 */
    if ( len_first == 7 ) {
        fprintf( outfile, "#define IN_BETWEEN\n" ) ;
    } else if ( (int) second == 7 ) {
        fprintf( outfile, "#undef IN_BETWEEN\n" ) ;
    } else {
        fprintf( stderr, "Unknown expected calling convention - assuming
NOT IN_BETWEEN!\n" ) ;
        fprintf( outfile, "#undef IN_BETWEEN\n" ) ;
    }

    fclose( outfile ) ;
}




More information about the CMake mailing list