- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Scenario:
A visual Studio solution with two very simple projects:
1) A "C" project with the following main routine:
#include <stdio.h>
void hello_world();
int main(int argc, char* arg[])
{
hello_world();
printf("Finished\n");
return 0;
}
2: A "F90" static library project with the following routine:
subroutine hello_world()
write(*,*) 'hello world'
end subroutine hello_world
Problem:
The F90 static library builds OK.
Building the "C" client project yields:
1>------ Build started: Project: CMAIN, Configuration: Debug Win32 ------
1> main.c
1>main.obj : error LNK2019: unresolved external symbol _hello_world referenced in function _main
1>C:\LOCAL\CODE\LANGUAGES\FORTRAN\IVF\INTEROP\VSP12.C.F.INTEROP.S1\Debug\CMAIN.exe : fatal error LNK1120: 1 unresolved externals
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Properties configuration:
The C project link property page has the location of the Fortran library as well as the library name specified.
Any suggestions?
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You need to tell the Fortran compiler (via your source code) that the subroutine will be called from C.
Add the suffix BIND(C, NAME='hello_world') to the subroutine statement in the Fortran code. This is a feature from the Fortran 2003 language standard. (The NAME specifier might be redundant given the name on the C side is already lower case, but it doesn't hurt.)
Otherwise you need to match the name of the function in C with the name that the Fortran compiler generates without the BIND(C) suffix. That name is platform/compiler/compiler options specific.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Besides the primary points IanH mentioned, you should expect surprises writing to stdout with multiple languages.
If you don't want to follow Ian's advice, dumpbin et al should become your friends so you can see the results of default mangling and upper-casing.
Within Fortran, a procedure with empty arguments has undefined results without explicit interface.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
TimP (Intel) wrote:
Within Fortran, a procedure with empty arguments has undefined results without explicit interface.
What do you mean by that?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
That will work.
But, suppose I now add a third project - one with a Fortran client that calls the same function within rhe Fortran static library:
(In other words - both C and Fortran clients will call into this static library)
Project #3 follows:
program main
call hello_world()
write(*,*) "Finished"
end
Again, We specify the static lib name and path in the "linker" property page
Now this one will NOT link to the static library's "hello_world" function with the "bind" annotation.
If I remove the "bind" annotation, project #3 (Fortran main) will then compile and link without errors. - But then the C project wont link!
Catch-22?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
That's because you need to explicitly tell the compiler when it is compiling Project #3 that hello_world is a subroutine that has been compiled to be interoperable with C. You do this by having an explicit interface for the procedure accessible in the scope where the procedure is referenced. Then the compiler has explicit knowledge about the characteristics of the procedure (as opposed to implicit knowledge obtained by looking at the procedure call).
The easiest (and in my opinion, best, by far) way of providing an explicit interface is to put the subroutine in a module, and then use that module in the program unit in Project #3. A module procedure automatically has an explicit interface in program units that use the module.
(Internal procedures also automatically get an explicit interface, but use of BIND(C) with internal procedures is a Fortran 2008 standard feature.)
An alternative is to provide an interface block for the subroutine in the specification part of the the scope where the the subroutine is called. Something like:
[fortran]INTERFACE
SUBROUTINE hello_world() BIND(C,NAME='hello_world')
END SUBROUTINE hello_world
END INTERFACE[/fortran]
In my opinion (and some disagree) the module approach is much more robust, to the extent that "stand-alone" external subprograms should only really be used where absolutely necessary.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
That worked.
The missing ingredient to the recipe is the interface statement WITH the "bind" annotation.
BTW timP, the above code is only to illustrate the problem I was encountering - I dont need a "hello world" routine buried in a Fortran static lib.
And dumpbin does report the Fortran hello_world subroutine name as "_HELLO_WORLD" - the presence of the"bind" attribute does not appear to "mangle" the name. Also, note the leading underscore.
For folks visiting this thread in the future, here is the code. ( I am using one Visual Studio solution with three projects):
The working version of the Fortran main linking to the Fortran static lib (that can also link to a C main) is:
program main
interface
subroutine hello_world() bind(c,name='hello_world')
end subroutine hello_world
end interface
call hello_world()
write(*,*) "Finished"
end
And the working version of the Fortran static library subroutine is:
subroutine hello_world() bind(c, name='hello_world')
write(*,*) 'hello world'
end subroutine hello_world
And the working version of a C language main that calls the Fortran static library's subroutine is:
#include <stdio.h>
void hello_world();
int main(int argc, char* arg[])
{
hello_world();
printf("Finished\n");
return 0;
}
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Perhaps, part of your (Terry G.) confusion is traceable to how external symbols that are defined or referenced in Fortran and C source files are given name decoration by the Fortran and C compilers.
Unless you are using and adhering to the tight rules of Fortran-C Interoperability, you may not assume that either compiler knows or cares about how the other compiler does name decoration. Rather, you, the programmer, are in control. Most of your linker problems are related to mismatches such as Fortran producing _HELLO_WORLD as an unsatisfied reference, if you leave out the "bind(C)..." qualifier, and C producing _hello_world as a globally visible text section symbol.
For the linker to succeed in producing an EXE or DLL, the decorated symbols output by both compilers must match exactly (unless you tell the linker to ignore the case of symbols).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
mecej4, Can you provide a link to a description of the complete linkage process when interface between C and Fortran?
Might be a good read tonight.
Your comments lead me to another experiment.
First, remove the bind annotation from the Fortran static library subroutine.
subroutine hello_world()
write(*,*) 'hello world'
end subroutine hello_world
Next modify the C main routine to:
#include <stdio.h>
void HELLO_WORLD();
int main(int argc, char* arg[])
{
HELLO_WORLD();
printf("Finished\n");
return 0;
}
And modify the Fortran main routine by removing the "bind" annotation:
program main
interface
subroutine hello_world()
end subroutine hello_world
end interface
call hello_world()
write(*,*) "Finished"
end
Issue a "build solution" command....
Result:
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
Now, we can run both the C main and the Fortran main using the Fortran static lib subroutine without using the bind annotation.
So if you use uppercase for Fortran subroutine names in your C code, you cant slip by without the "bind" annotation!
Which means I dont have to change anything in the actual Fortran static library (which is quite large and is maintained by anther group) Ito use in my real code.
Probably not the "appropriate" way - but it works! :)
Lesson: External names are CASE SENSITIVE during the linkage process
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Be mindful that if you take out the BIND(C), then tomorrow if you change the platform, compiler, compiler version, compiler options or the direction that you are facing while compiling, then your program may fail to link again. BIND(C) was added to the language for good reasons. While it is a Fortran 2003 language standard feature, it is pretty widely supported across actively maintained Fortran compilers.
You can always write an interface layer that links your C code with your third party static library. Your Fortran code can either call into the C interface layer or go directly to the Fortran library. For example:
[fortran]MODULE my_c_interface_layer
IMPLICIT NONE
CONTAINS
SUBROUTINE hello_world_c() BIND(C, NAME='hello_world_c')
INTERFACE
! Interface for the Fortran subroutine in the static library
! that doesn't have BIND(C)
SUBROUTINE hello_world()
END SUBROUTINE hello_world
END INTERFACE
CALL hello_world
END SUBROUTINE hello_world_c
END MODULE my_c_interface_layer
[/fortran]
[cpp]void hello_world_c();
int main()
{
hello_world_c();
return 0;
}[/cpp]
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page