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

Generated Interface Checking required to build with Intel Fortran 2017

Timothy_W_
Beginner
1,081 Views

Hi

I am using Intel Fortran Parallel Studio 2017 and Visual Studio 2015.

The code is a mix of C/C++ and Fortran.  There are many fortran projects in the Visual Studio solution.  The Fortran code has been around a while and it is mostly Fortran 77.  I don't have much experience with Fortran but I have been programming for many years, mostly C++.

I have /gen-interfaces turned on and dictate the location of the module files.  My understanding is this command is for diagnostics only.  If Diagnostics::Check Routine Interfaces is Yes, then the generated interfaces ( func_genmod.mod files ) are used to confirm the usage of subroutines are consistent.  It is not used as a replacement for user created modules to define subroutines.

However, I am having linker problems that I can reproduce consistently if I let the mod files be written to the intermediate results directory of each project.  Then externals can't be resolved.  If I store all the mod files in a common modules directory, the program compiles.

I see something like the following in a example.for file:

C Start of example.for

Complex Function somefunction (V, IERR)
...

include 'if/neededfunc'
..

call neededfunc()
..

complex function get_something(fromid, toid, ckt, n)

C No include 'if/neededfunc'

call neededfunc()

C End of example.for

The Microsoft linker complains that:

unresolved external symbol _NEEDEDFUNC@## referenced in function get_something.  The use of neededfunc in the first function defined works because of the include.  The compiler only complains about the second use in function get_something()

The neededfunc subroutine is defined in the same library (but different file) that includes example.for.

C neededfunc file

interface to subroutiine neededfunc 
...
C End of neededfunc file

If I add include 'if/neededfunc' after the  "complex function get_something", then linker resolves neededfunc and it works.

All exported functions are specified in a hand generated project.def file.  neededfunc is in lower case without a @## in the def file.

What is going on here?  is /gen_interfaces just a diagnostic tool or something more?

I might try to reproduce this problem in a small example.  It has bitten me too many times.

I am trying to understand how the dependencies are resolved.

Thanks

Tim

 

0 Kudos
12 Replies
Steven_L_Intel1
Employee
1,081 Views

First of all, /gen_interface is an obsolete option - its effect is included in /warn:interface.

Nevertheless, generated interface checking is supposed to be diagnostic-only. There have been compiler bugs where it actually changed the behavior of generated code. I'm not aware of such issues in the 17.0 compiler, so if you can provide a small but complete test case that shows the problem we'll be glad to look into it.

Are you also building with STDCALL calling convention specified?

0 Kudos
Timothy_W_
Beginner
1,081 Views

Thanks Steve.  

I did not know that /gen_interface was obsolete.  I converted old build scripts using Intel Fortran version 11 I think to Visual Studio and Intel 2017 and was told that was important so brought it along as a command line option.

My concern is that the code is dependent on some unintended behavior of the fortran compiler.  I will look into the calling convention.

I am working on the example now.

Regards

Tim

0 Kudos
Steven_L_Intel1
Employee
1,081 Views

In version 11 you did need both /gen_interface and /warn:interface, but that has not been the case for several releases now. It doesn't hurt.

I asked about STDCALL because of the @## suffix in the unresolved symbol.

0 Kudos
Timothy_W_
Beginner
1,081 Views

I think I have an example.

In the attached zip file there is a solution file with two projects:  a Fortran lib project and a C++ dll project. The C++ dll project is dependent on the object files created by the fortran lib project.  So to built it I did the following:

Select the fortran lib project and rebuild only lib1.

Then select the dll project and build only the dll project.  The dll project can't be rebuild, it will delete the files it depends on.

I compiled in the Debug configuration.

If I rebuild the lib1 project with Diagnostics->CheckRoutine Interfaces to No, then lib1 compiles successfully.

But the dll does not:

1>------ Build started: Project: lib1_dll, Configuration: Debug Win32 ------
1>function1a.obj : error LNK2019: unresolved external symbol _FUNCTION1B@0 referenced in function _function1a
1>C:\Users\tim\Documents\Visual Studio 2015\Projects\FortranTest2\Debug\lib1_dll.dll : fatal error LNK1120: 1 unresolved externals
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

If I rebuild the lib1 project with Diagnostics->Check Routine Interfaces to Yes, then lib1 compiles successfully.

Then build the the lib1_dll project, then it compiles successfully.

1>------ Build started: Project: lib1_dll, Configuration: Debug Win32 ------
1>  lib1_dll.vcxproj -> C:\Users\tim\Documents\Visual Studio 2015\Projects\FortranTest2\Debug\lib1_dll.dll
1>  lib1_dll.vcxproj -> C:\Users\tim\Documents\Visual Studio 2015\Projects\FortranTest2\Debug\lib1_dll.pdb (Full PDB)
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

This code is mostly Fortran 77.  It uses CVT calling convention which I don't know anything about.  The code does have lines like:

$IF DEFINED (CVF)
      include 'function1a.fi'
$ENDIF

all over.

I hope you see the same thing as I do.  It was very touchy to get working consistently.  This could be because of my weak Fortran skills.

Thanks

Tim

 

0 Kudos
Steven_L_Intel1
Employee
1,081 Views

Oh my - this has Microsoft Powerstation-specific syntax in it. At first glance, /warn:interface is not involved - it may seem that it is because of build order dependencies, but I can get the link error either way.

This code was built earlier using Compaq Visual Fortran (CVF). It has /iface:cvf set in the project properties but also seems to assume that a CVF preprocessor variable will be defined in the project, which it isn't. But if you do define it, so that some of that PowerStation code gets included, then the compiler is not happy for other reasons. I will look at this closer tomorrow.

0 Kudos
Timothy_W_
Beginner
1,081 Views

 

I can consistently fail without /warn:interface but pass with /warn:interface as me on my machine.  However, when I try to build the code inside Jenkins, a continuous integration server, using devenv then it always fails.  It fails the same way as if I remove /warn:interface.  We are at a loss why it always fails when compiled under Jenkins but pass when I build it with Visual Studio IDE or with devenv.com command line.

As for CVF, the IF DEFINED statements are all over the code, but CVF as a preprocessor macro is not defined.

Many of the unresolved externals can be fixed by adding the missing the include 'file.fi' line.  All the *.fi files define interfaces most of them as C language portable with the "" setting.

But when /warn:interface is set with /gen_interface the code does compile and gets shipped.

Thanks for all your help.

Regards

Tim

 

0 Kudos
Timothy_W_
Beginner
1,081 Views

Another question on the same topic:

When I build without /warn:interface, no mod files generated, then I get a long list of unresolved external symbols, a list for each of the dlls I am building.

If I look at the build done by a continuous integration server (with /warn:interface set), I see another long list of unresolved external symbols.  But the list is sometimes different for each dlls compared to the build on my machine. 

Should the order of compiling the fortran files to object files matter?  It seems like it is.

Most of the unresolved external symbols are because of a missing include file in a subroutine definition.  So how, sometimes, does a subroutine know about another subroutine it calls and sometimes it does not.

The order of the build of the object files seems to matter but the unresolved error comes in linking.  If I build the code under the continuous integration server and fails.  Then I open that solution in Visual Studio IDE, and build just a dll, then I get unresolved errors.  If I clean the solution then build, no errors.

Thanks!

Tim

 

0 Kudos
Steven_L_Intel1
Employee
1,081 Views

Here's what's going on with the example.

function1a has "!DEC$ ATTRIBUTES C :: function1a" and function1b has "!DEC$ ATTRIBUTES C :: function1b". This changes the conventions for these routines to specify C calling mechanism, which would otherwise be STDCALL because of /iface:CVF, and downcasing the global name; it also changes argument passing to be by-value. function1a has a call to function1b, but because there is no ATTRIBUTES C for function1b visible in function1a, it gets the CVF default name and tries to call _FUNCTION1B@0. Since that's not defined, you get the linker error. 

I can now reproduce the issue with generated interfaces. What happens here is that if function1b has been compiled by the time function1a is compiled, the generated interface seems to carry with it the ATTRIBUTES C and this is being used by the compiler, which it shouldn't. It doesn't appear in the __genmod.f90, but that isn't necessarily a complete representation of what's in the .mod. I will send this on to the developers. Issue ID is DPD200415283.

Now if one defines the preprocessor macro CVF, two include files are inserted that use the old Microsoft "interface to" syntax and as an attribute. We do support this. However, the example incorrectly includes the interface for function1a in function1a and the interface for function1b in function1b. This "interface to self" is not allowed, and isn't what you want, anyway. If you swap these, so that function1a includes function1b.fi and function1b includes function1a.fi, it builds whether or not you have /iface:cvf enabled.

You need to make sure that any calls to procedures with non-default calling conventions have visible an interface or a directive specifying that same non-default convention. If you do this, then the bug of generated interface checking won't be an issue.

 

0 Kudos
Timothy_W_
Beginner
1,081 Views

Thanks Steve!  Let me stew on your answer, I might have more questions later.

Tim

0 Kudos
Timothy_W_
Beginner
1,081 Views

 

Steve, thanks again for your answer.  It explains a lot of what we are seeing.  The code depended on the generated modules to resolve external dependencies.  But since each module is not created until the file is compiled, the code needed two passes to compile.  The first pass would fail, the second pass could use the generated mod files to resolve dependencies and pass.

How does setting the CVF preprocessor macro work to generate the interface files?  My colleague tried it but it did not work.  Does it generate the interface file and include it in all files that use the subroutine?  Is there documentation on how to use this feature?  We are looking for ways to reduce the work generating interface files for each subroutine.  

Thanks

Tim

0 Kudos
Steven_L_Intel1
Employee
1,081 Views

The CVF macro simply enables the inclusion of the .fi files which were previously written - not compiler generated. They are using obsolete syntax that we still support. My guess is that the intent here was to be compatible with other compilers that used C defaults, though if the program was all-Fortran I have to wonder why.

0 Kudos
Steven_L_Intel1
Employee
1,081 Views

This has been fixed for a future major release.

0 Kudos
Reply