Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

need help calling C from Fortran

Brian_Murphy
New Contributor II
6,086 Views

I am trying to use a numerical library called UMFPACK.  20 years ago it was all fortran, but today it's in C.  The attached fortran file is a supplied sample Main program to demonstrate calling umfpack from a fortran program.  The attached C file contains C wrapper routines being called from fortran.  When I build it, I get unresolved externals for all the C routines being called from fortran.

I looked at the Intel sample project called "Fortran-Calls-C", but the Microsoft C compiler wouldn't let me put  extern "C" into umfpack's c file.  Maybe that's a good thing, because I really don't want to be editing their C files because there is a large number of them.

How do I get this to work?

0 Kudos
36 Replies
JVanB
Valued Contributor II
3,910 Views

Since it's a *.c file, extern "C" is already implicit. You could write your own wrappers in Fortran. Here is a start:

module M
   use ISO_C_BINDING
   implicit none
   private
   integer, parameter, public :: K1 = C_INT64_T
   integer, parameter, public :: UMFPACK_CONTROL = 17 ! Or whatever
   integer, parameter, public :: UMFPACK_INFO = 5 ! Or whatever
end module M

module N
   use M
   use ISO_C_BINDING
   implicit none
   private
   character(*), parameter, public :: CODE = merge('di','dl',K1 == C_INT)
   public umf4def
   interface
      subroutine umf4def(Control) bind(C,name='umfpack_'//CODE//'_defaults')
         import
         implicit none
         real(C_DOUBLE) Control(UMFPACK_CONTROL)
      end subroutine umf4def
   end interface
   public umf4pcon
   interface
      subroutine UMFPACK_report_control(Control) bind(C,name='umfpack_'//CODE//'report_control')
         import
         implicit none
         real(C_DOUBLE) Control(UMFPACK_CONTROL)
      end subroutine UMFPACK_report_control
   end interface
   public umf4sym
   interface
      subroutine umf4sym(m,n,Ap,Ai,Ax,Symbolic,Control,Info)
         import
         implicit none
         integer(K1) m,n,Ap(*),Ai(*)
         real(C_DOUBLE) Ax(*)
         type(C_PTR) Symbolic(*) ! Need context to be sure of translation
         real(C_DOUBLE) Control(UMFPACK_CONTROL)
         real(C_DOUBLE) Info(UMFPACK_INFO)
      end subroutine umf4sym
   end interface
   contains
      subroutine make_filename(filenum,prefix,filename) bind(C,name='make_filename')
         use ISO_C_BINDING
         use M
         implicit none
         integer(K1), value :: filenum
         character(kind=C_CHAR) prefix(*)
         character(kind=C_CHAR) filename(*)
         character(len=40,kind=C_CHAR) number
         integer i, j

         write(number,'(i0,a)') filenum,C_NULL_CHAR
         i = 1
         j = 1
         do
            if(prefix(i) == C_NULL_CHAR) then
               exit
            else if(any(prefix(i) == &
               [C_FORM_FEED,C_NEW_LINE,C_CARRIAGE_RETURN,C_HORIZONTAL_TAB])) then
            else
               filename(j) = filename(i)
               j = j+1
            end if
               i = i+1
         end do
         filename(i:i+len_trim(number)-1) = transfer(number,C_NULL_CHAR,len_trim(number))
      end subroutine make_filename
      subroutine umf4pcon(Control)
         use ISO_FORTRAN_ENV
         implicit none
         real(C_DOUBLE) Control(UMFPACK_CONTROL)
         flush(OUTPUT_UNIT)
         call UMFPACK_report_control(Control)
         flush(OUTPUT_UNIT)
      end subroutine umf4pcon
end module N

 

0 Kudos
mecej4
Honored Contributor III
3,917 Views

You have to select one of several routes, depending on your objectives. Typically, open-source packages tell you how to build mixed-language programs using GNU compilers.

If you are using the 64-bit versions of IFort and VC, for example, it should suffice to use the /names:lowercase option when compiling your Fortran sources. 

The extern "C" {} mechanism is meant to be used in C++ source code.

0 Kudos
Brian_Murphy
New Contributor II
3,917 Views

Thanks to both for the replies (and on the weekend, too!).

My intel fortran is installed in Program Files (x86), so I think that means it must be a 32-bit version.  So I guess /names:lowercase won't work.

I put in an INTERFACE thing for the first umfpack routine which is called, and that got rid of the unresolved external for that item.

I did some more googling thinking plenty of people must have already tackled this problem.  I found http://geo.mff.cuni.cz/~lh/Fortran/UMFPACK/README.html# ; where this fellow says he's made f90 style interfaces.  I have downloaded them, but have not yet tried them.  Even with this, though, there's a lot of work to do for me to figure it all out.

Another option is to go back to the fortran version of umfpack and try to fix what appears to be a bug that popped up while I was running a set of test cases.  The fortran version worked really well with compaq fortran.

At this point I will try to find the fortran bug.  Depending on how that goes, I might again tackle trying to use the C version of umfpack.

0 Kudos
JVanB
Valued Contributor II
3,916 Views

Following the link in Quote #4 I see that the interfaces are f2003 rather than f90. I recommend that you try to make them fly because f2003 interfaces are in the opinion of many (see Quote #2) the easy way for a Fortran programmer to perform this sort of task.

 

0 Kudos
Brian_Murphy
New Contributor II
3,917 Views

Thanks, RO.  I'm going to try that guy's stuff today.

BTW.  I'm a runner, too, and my hair's as white as yours.  May your miles bring smiles.

0 Kudos
Brian_Murphy
New Contributor II
3,917 Views
Error	106	 error LNK2019: unresolved external symbol _umfpack_zi_symbolic referenced in function _MUMFPACK_mp_UMFPACK_ZI_SYMBOLIC	umfpack.obj	

I've spent the last hour trying to build one of the umfpack example programs.  I can't figure out why I'm getting build errors like the above.  What does this error mean?  There is a file named umfpack.f90.  It compiles without errors, and it has a CONTAINS block containing a routine named umfpack_zi_symbolic.  I have no clue what _MUMFPACK_mp_UMFPACK_ZI_SYMBOLIC refers to as there is no routine by that name or anything close to it that I can find.

The VS 2012 project is attached.  I hope it's something really simple I'm doing wrong.

0 Kudos
jimdempseyatthecove
Honored Contributor III
3,917 Views

The ..._mp_ refers to a module variable and/or entry point (subroutine or function).

My guess is a library that you created is NOT including an .OBJ file produced when compiling a Fortran source that contains a module (whose module name is mumfpack). The fix, is to add the .OBJ produced when compiling the source containing the memfpack (either to the library or to the link).

Jim Dempsey

0 Kudos
jimdempseyatthecove
Honored Contributor III
3,917 Views

One other oddity, the error message contains "_umfpack_zi_symbolic"

Note the zi

The source code listed above concatenates \\CODE\\ in the middle of the name (none of which contains suffix of symbolic). The oddity is the values for CODE are 'di' and 'dl'. So... this is coming in from something else linked into your program.

Jim Dempsey

0 Kudos
JVanB
Valued Contributor II
3,917 Views

Jim, you are conflating the code I posted in Quote #2 (and which the O.P. is not using) with the umfpack.f90 which he is using in the umfpack_simple.zip file from Quote #7. There is a function umfpack_zi_symbolic in there which is being compiled and the linker is calling _MUMFPACK_mp_UMFPACK_ZI_SYMBOLIC because it is a module procedure of module mUMFPACK. That function references function c_umfpack_zi_symbolic which is actually the name of a Fortran interface to umfpack_zi_symbolic from the library he is trying to interface to. So the library isn't getting included in the linking phase or the linker is seeing a 64-bit library (the mangled name for the symbol umfpack_zi_symbolic indicates the Fortran is getting compiled for 32 bits).

MK200 Brian Murphy M59 29315 147/222 15372/21032 12:05 - - 14:02 12:40 14:46 1:22:10 13:13 

(?)

 

0 Kudos
Brian_Murphy
New Contributor II
3,914 Views

The \\CODE\\ stuff was something proposed by RO.  I'm not using that approach.  Instead I'm trying to use the f2003 interface downloaded from the link in Quote #4.

I've continued trying whatever I can think of, but I only get more build errors instead of fewer.  I really don't know what I'm doing.  If it were all fortran, I'd stand half chance.  But trying to use the C version of umfpack is over my head.

The only thing I'm using from this library is to LU factor (and solve) real and complex asymmetric matrices which are very sparse and are stored that way.  Does the Intel MKL have routines for this?  I have IMSL, but I can't use it because the IMSL salesman told me to forget it because he said an IMSL distribution license is too expensive.

0 Kudos
mecej4
Honored Contributor III
3,914 Views

Here is a way of working around the problem.

The undefined _umfpack_zi_* symbols are a nuisance in the present circumstances. They probably would only be needed if you were using UmfPack to solve equations whose coefficients are complex numbers. The example code does not actually call those routines, but the Fortran 90 interfaces include them, so  the linker wants them. However, the libraries that you have produced may not include these unnecessary routines. 

How to tell the linker not to bother about these routines? I can think of two simple solutions. One is to edit (or add #ifdef COMPLEX...#endif) umfpack.f90 to remove/hide the _zi_ interface blocks and declarations. The other is to provide dummy code for the missing routines, relying upon the assumption that those are never called in the example code. I chose the latter option since it required less work.

Here is the dummy.c source code:

void umfpack_zi_symbolic(){}
void umfpack_zi_numeric(){}
void umfpack_zi_solve(){}
void umfpack_zi_free_symbolic(){}
void umfpack_zi_free_numeric(){}
void umfpack_zi_scale(){}
void umfpack_zi_defaults(){}
void umfpack_zi_report_control(){}
void umfpack_zi_report_info(){}
void umfpack_zi_save_numeric(){}
void umfpack_zi_save_symbolic(){}
void umfpack_zi_load_numeric(){}
void umfpack_zi_load_symbolic(){}

Just to test this, I downloaded SuiteSparse-2.4.0.tar.gz (old, but smaller than the huge current release, and sufficient for the present test) and built the umfpack.lib and amd.lib using Intel C. I then compiled umfpack.f90 and umfpack_simple_1basic.f90 (files in your zip file) using Intel Fortran and linked all of these with mkl_rt.lib. The EXE that was produced ran and output seemingly good results.

If you want to add an extra measure of safety, you can print a "missing routine called" message to stderr and return or call exit(1) in the body of each of these dummy routines.

Of course, the proper solution is to build a version of the UmfPack library that includes the umfpack_zi* routines. To me, that would be something that should be done only if it turns out to be necessary. Your zip files contained amd.lib but not umfpack.lib, so I don't know if the complex routines are actually within umfpack.lib. I was unable to build these libraries from the C sources in your zip since some required C header files were missing.

Intel MKL contains the Pardiso solver, which can solve linear equations with complex coefficients, and the MKL libraries have good support for multiple threads and high performance. See https://software.intel.com/en-us/node/470284 .

0 Kudos
Brian_Murphy
New Contributor II
3,914 Views

mecej4, you're amazing!  I wish I knew this stuff like you do.

When you built and ran 2.4.0 did you need to put in placeholder code for the "zi" routines? 

I need to do Complex*16 matrices, but I think the "ci" versions are what I want, and not the "zi".

Tomorrow I will try to retrace your steps using 2.4.0.  I will be using Microsoft C and Intel Fortran in either visual studio 2010 or 2012.  If there was anything else you needed to do to get an error-free build, please let me know.

0 Kudos
mecej4
Honored Contributor III
3,914 Views

The 2.4.0 distribution did not contain any Fortran 90 examples or interface code. It came with Fortran 77 examples, and I could build one of them without needing any dummy routines, but I needed to provide an interface to account for the different name mangling of GNU and Intel compilers. 

The Lapack naming conversion is to use 's' as an indicator for single-precision-real, 'd' for double-precision-real, 'c' for single-precision complex and 'z' for double-precision complex.

Which version of SuiteSparse did you use? Older versions are easier to build but have fewer features, so a compromise would help. Users, of course, want the latest version, but building Unix/Linux-oriented packages on Windows sometimes takes quite a bit of work. Are you building for IA32 or X64? 

I urge you to consider using MKL-Pardiso instead, unless you know reasons for preferring UmfPack over Pardiso. Pardiso is already available in pre-built libraries, and can be called from source code that is compiled with Intel Fortran and Intel C.

0 Kudos
Brian_Murphy
New Contributor II
3,914 Views

I need to build for Windows only, but for both 32 and 64 bit.  My eventual build target is a DLL which will be called from Excel visual basic, both 32 and 64 bit versions of Excel.

I have been trying with the "latest" SparseSuite which goes by 4.4.5.  I thought their naming convention was "ci" for regular fortran style complex variables (re/im interleaved), and "zi" stood for the real and imag components being passed in using separate real arrays.  But I have  seen that other libraries like Lapack use "c" and "z" the way you described it.

Anyhow, if tomorrow I can get 2.4.0 to build and run, I will try to use that with my app.

0 Kudos
Brian_Murphy
New Contributor II
3,914 Views

I just noticed your comment about MKL-Pardiso.  I've heard of Pardiso but I don't know what it is.  I will look for documentation about it.  I hope it's royalty-free.

 

0 Kudos
mecej4
Honored Contributor III
3,914 Views

A version of Pardiso is included in MKL. If you have the Intel Fortran and/or C compilers, you have MKL, therefore you have Pardiso. See https://software.intel.com/en-us/node/470282#88F30007-9094-42EB-A4B1-8401F0C43ABE .

0 Kudos
Brian_Murphy
New Contributor II
3,914 Views

Thanks, mecej4.  I do have intel fortran, and I found the examples folder containing DSS and Pardiso examples.  If I understand it right, DSS is just an alternative interface to running the Pardiso algorithms.  I will try to run the examples, hopefully tomorrow.

One of the things I use the sparse LU factorization for is to compute eigensolutions with Arnoldi reverse communication.  For my particular field (dynamics of damped rotating systems like compressors and turbines), it works great.

0 Kudos
mecej4
Honored Contributor III
3,914 Views

Just today, Intel announced that MKL would be available as a free download (with registration), see https://software.intel.com/en-us/articles/free_mkl .

For solving sparse eigenvalue problems, MKL now provides the FEAST algorithm, see https://software.intel.com/en-us/node/470372 .

0 Kudos
LRaim
New Contributor I
3,914 Views

I am using PARDISO for solving a band matrix linear system. It replace another library algorithm. Improve in the solution speed is significant. No problems in writing the calling interface.

 

0 Kudos
Brian_Murphy
New Contributor II
3,797 Views

My eigenvalue situation is with asymmetric matrices.  The FEAST web pages say it is for symmetric matrices only.  I have been using an Arnoldi algorithm which, when coupled with LU factoring, is blazing fast for the matrix types I work with.

0 Kudos
Reply