Arjen Markus wrote:
But knowing the Fortran name mangling scheme is still crucial (if
interested,  see below why). For now I rely on the user to provide the
case (lower or upper)  and number of appended underscores (none, one,
or two) which determine it. The  defaults I provide (lower case with
one underscore) is probably the most common  one, but I'd be much
happier if I could automatically determine it at  configuration time...
Any suggestions?


Now the fun part:
You can simply provide _both_ of these wrappers in your Fortran-compatible
library. The Fortran compiler will generate a routine with a name that
depends on its mangling scheme, but the linker will pick out the right
version.

The only problem left is Fortran compilers that produce the same
mangled name but different methods for passing the length of character
strings.
Of course, the compatibility library will be bit larger, but it solves
your problem in what I think an elegant way.

Hi Arjen,

That's not what I want for several reasons:
1) I really think this is something that the build system should take care of. I intend to provide cmake only as an alternative to autotools and determining the Fortran name mangling scheme with the later is no problem. 2) A typical Fortran-C interface library (and we provide such libraries for 3 different solvers) contains around 30 different functions which would then require 180 wrappers (for all combinations lower/upper case and none/one/two underscores)! A nightmare of (unnecessary) code duplication. 3) We distribute our solvers open source and we'd like to keep the sources as clean and readable as possible.

In any case, I think I have a solution. I seems to work, but then I've only tried it on my Linux box. It's probably not the cleanest implementation (I've only started using cmake very recently). I copied the relevant portion of my CMakeLists.txt below. I'd appreciate any comments and suggestions, both on whether it can be simplified/cleaned-up and also on whether it's portable.

Thanks,
--Radu

  # Enable Fortran support
  ENABLE_LANGUAGE(Fortran)

  # Determine the Fortran name-mangling scheme. We do this by:
# 1) create a library from a Fortran source file which defines a function "sundials" # 2) attempt to link with this library a C source file which calls the "sundials"
  #     function using various possible schemes (6 different schemes, 
corresponding
  #     to all combinations lower/upper case and none/one/two underscores)

  SET(HAVE_SCHEME FALSE)

  # Create a CMakeLists.txt file which will generate the "flib" library
  FILE(WRITE 
${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CMakeLists.txt
    "PROJECT(FortranTest Fortran)\n"
    "SET(CMAKE_VERBOSE_MAKEFILE ON)\n"
    "ADD_LIBRARY(flib ftest.f)\n"
    )

  # Create a simple Fortran source which defines the subroutine "sundials"
  FILE(WRITE ${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/ftest.f
    "        SUBROUTINE sundials\n"
    "        RETURN\n"
    "        END\n"
    )

  # Use TRY_COMPILE to make the target "flib"
  TRY_COMPILE(
    FTEST_OK
    ${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp
    ${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp
    flib
    OUTPUT_VARIABLE MY_OUTPUT
    )

  # Continue only if we were successful in creating the "flib" library
  IF(FTEST_OK)

    # Overwrite CMakeLists.txt with one which will generate the "ctest" 
executable
FILE(WRITE ${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CMakeLists.txt
      "PROJECT(FortranTest C)\n"
      "#SET(CMAKE_VERBOSE_MAKEFILE ON)\n"
      "ADD_EXECUTABLE(ctest ctest.c)\n"
      "TARGET_LINK_LIBRARIES(ctest \"-L. -lflib\")\n"
      )

    # Define the list "options" of all possible schemes that we want to consider
    # Get its length and initialize the counter "iopt" to zero
    SET(options sundials sundials_ sundials__ SUNDIALS SUNDIALS_ SUNDIALS__)
    LIST(LENGTH options imax)
    SET(iopt 0)

    # We will attempt to sucessfully generate the "ctest" executable as long as
    # there still are entries in the "options" list
    WHILE(${iopt} LESS ${imax})

      # Get the current list entry (current scheme)
      LIST(GET options ${iopt} opt)

      # Generate a simple C source which calls the "sundials" function using the
      # current scheme
      FILE(WRITE ${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/ctest.c
        "int main(){${opt}();return(0);}\n"
        )

      # Use TRY_COMPILE to make the "ctest" executable from the current C source
      # and linking to the previously created "flib" library.
      # QUESTION: Is this method of linking the "flib" library portable?
      TRY_COMPILE(
        CTEST_OK
        ${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp
        ${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp
        ctest
        CMAKE_FLAGS -DLINK_LIBRARIES:STRING="-L. -lflib"
        OUTPUT_VARIABLE MY_OUTPUT
        )

# To ensure we do not use stuff from the previous attempts, we must remove the
      # CMakeFiles directory.
# QUESTION: I didn't think I'll have to do this, but it doesn't work otherwise FILE(REMOVE_RECURSE ${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CMakeFiles)

      MESSAGE("${iopt}  ${opt}  ... ${CTEST_OK}")

      # Test if we successfully created the "ctest" executable.
      # If yes, flag that we have successfuly determined the name mangling 
scheme,
      # save the current scheme, and set the counter "iopt" to "imax" so that we
      # exit the while loop.
      # Otherwise, increment the counter "iopt" and go back in the while loop.
      IF(CTEST_OK)
        SET(SCHEME ${opt})
        SET(HAVE_SCHEME TRUE)
        SET(iopt ${imax})
      ELSE(CTEST_OK)
        MATH(EXPR iopt ${iopt}+1)
      ENDIF(CTEST_OK)

    ENDWHILE(${iopt} LESS ${imax})

  ENDIF(FTEST_OK)

  IF(NOT HAVE_SCHEME)
    message("Unable to determine Fortran name mangling scheme")
  ENDIF(NOT HAVE_SCHEME)
_______________________________________________
CMake mailing list
[email protected]
http://www.cmake.org/mailman/listinfo/cmake

Reply via email to