I'm working with some legacy code to try and compile it in an updated development environment. This project contains C code which calls on the subroutines of Fortran code in the same project. I'm using the following:
- Visual Studio 2015 with Update 3
- Parallel Studio 2016 with Update 3
I've verified that the Intel Compilers are recognized by Visual Studio and followed the steps described here ( https://software.intel.com/en-us/articles/configuring-visual-studio-for-mixed-language-applications/ ) to configure it for a mixed-language environment but it appears that the Fortran subroutines are not visible to the C code. For example, a .c file with the line:
extern void SETUP(void);
is in reference to a subroutine in a .f90 file in the same project:
but Visual Studio indicates that the subroutine is not found with the message: "Function definition for 'SETUP' not found"
What is the best approach to verify Visual Studio is configured properly for mixed-language compilation and how to get the C code to recognize the Fortran?
Do you have both the Fortran and C code in the same project? That hasn't been supported since VS98.
If the main program is C, you'll need to do the following:
- Add a new Fortran Static Library project to the solution with your Fortran code.
- Right click on the C project, select Build Dependencies > Project Dependencies
- Check the "Depends on" box for your Fortran project, click OK
- In the C project properties, linker, Additional Dependencies, add the path to where the Fortran .lib will be placed
This last part wasn't needed in older VS versions, but Visual C++ no longer pulls in non-C++ dependent projects.
Thanks for the guidance, the Fortran static library is being properly recognized by the C project. This resolved the errors I was experiencing for the project I was working on. However, I've moved to a similar, albeit slightly more complex, C project and have encountered a different error.
I extracted the Fortran code into its own static library project and successfully built the .lib file. After linking I build the C project and get several of the following error:
LNK2019 unresolved external symbol __imp__ELEVATION_DATA_mp_RD_ELEV_DATA referenced in function _RD_ELEV_DATA
The error indicates that the problem lies within the Fortran .lib file. Here's a snippet of one of the subroutines in question:
SUBROUTINE RD_ELEV_DATA(<parameters>) !DEC$ ATTRIBUTES DLLEXPORT :: RD_ELEV_DATA !DEC$ ATTRIBUTES C, REFERENCE, ALIAS:'_RD_ELEV_DATA' :: RD_ELEV_DATA USE ELEVATION_DATA, ONLY: M_RD_ELEV_DATA => RD_ELEV_DATA <initialize parameters> CALL M_RD_ELEV_DATA (<parameters>) END SUBROUTINE RD_ELEV_DATA
I believe the LNK2019 error is related to the 'USE ELEVATION_DATA' portion of this subroutine. There is a module named ELEVATION_DATA that exists in a separate file which contains the subroutine that is being wrapped:
MODULE ELEVATION_DATA ... PUBLIC:RD_ELEV_DATA ... SUBROUTINE RD_ELEV_DATA(<parameters>) CDEC$ ATTRIBUTES DLLEXPORT :: RD_ELEV_DATA ... END SUBROUTINE RD_ELEV_DATA
Why would this error appear when building the C project and not during the compilation of the Fortran library?
This is a link-time error. When you build the library, there is no linking.
Is the object file containing module ELEVATION_DATA included in the linking for the C project? I'll also note that because you DLLEXPORT the module procedure, that turns into a DLLIMPORT of the procedure where it is USEd. Normally if the linker sees a local definition of a DLLIMPORTed procedure it gives a warning but continues. The error message here suggests that the object for the module is not being seen at link time.
Is the object file containing module ELEVATION_DATA included in the linking for the C project?
I only included the Fortran .lib file in the 'Linker -> Input -> Additional Dependencies' of the C project, no object files were explicitly linked.
So the problem appears to be the linking of the Fortran static library with the C project, not the building of the static library, correct?
Correct. Is the module ELEVATION_DATA in that library? It looks as if it isn't, so the linker is looking for the DLL import library from building the DLL. Speaking of that, are you building a static library or a DLL from the Fortran code?
Is the module ELEVATION_DATA in that library?
Yes. Also, the Fortran project contains both .for and .f90 files. The ELEVATION_DATA module is in a .for file and the subroutine that USEs it is in a .f90 file.
are you building a static library or a DLL from the Fortran code?
The project containing the Fortran code is configured to build a static library
In the C project properties, go to Linker > General. For "Show Progress" set it to "Show all progress messages" and then relink the project. Create a zip of the Debug\XXX.tlog folder (or Release\) and attach it to a reply here.
On a side note, out of curiosity in the Linker > Input > Additional Dependencies of the C project I added the .obj files produced by the Fortran project (<absolute path to Fortran Debug directory>/*.obj) and the C project successfully built.
It should not be necessary to add the object files as dependencies for the project to build, correct?
I don't understand why the link-step logs are empty. But your adding the .obj files and it working tells me that you in fact did NOT add the Fortran .lib to the C project's dependencies.
It's possible I incorrectly linked the Fortran lib. Just for clarification, here's how I added the dependency to the C project:
- In Linker > General > Additional Library Directories, I added a relative path to the /Debug directory of the Fortran project
- In Linker > Input > Additional Dependencies, I simply added the name of the lib file (Elevation_FOR.lib) which resides in the /Debug directory of the Fortran project
That should have worked - were there no messages about not finding a library? I'm very puzzled that the .tlog files don't have that info. I really don't like the way MSBUILD creates log files.
Could the issue be related to having mixed Fortran standards in the static library project? In this case, a .f90 file contains a subroutine that USEs a module from a .for file (see above code samples):
- contains the ELEVATION_DATA module
- contains the subroutine that USEs the subroutine from ELEVATION_DATA
I'm not sure if this makes sense, but is it possible that the linker is able to see the .f90 subroutine but cannot interpret the .for module/subroutine that is being USEd?
No, and in fact the file suffixes ".for" and ".f90" simply mean that the former is fixed format source and the latter free format source. They are both compiled using the same default Fortran standard. The module files depend on the content of the file and not the source format.
If you compiled the files separately, and specified (through compiler options, etc.) that different standards should be applied to each, the outcome could be different. The linker does not even look at the .mod files. It only reads .obj, .lib and other files that are completely oblivious to whether the source code was fixed or free format.
I understand, that makes sense. I'm still trying to figure out why the C project fails when linking to the Fortran static library but succeeds when linking directly to the Fortran .obj files.
- Although the Fortran static library builds, could there be a linking issue within the library between .obj files?
- Note that the C project produces a DLL and the Fortran project builds a static library. Could this be an issue when linking?
A library file is simply a collection of OBJ files with, possibly, an extended directory/dictionary added. When you specify object files for linking, normally each of them is loaded, whether the code/data in the OBJ is needed or not.
When you specify a static library, instead, each OBJ in the LIB is loaded (into the EXE or DLL that is being built) only if that OBJ is needed to supply unsatisfied references in previously loaded objects.
Some linkers may provide further optimizations such as not loading code in each OBJ file if the code in that object is not referenced in one of the other objects.