My solution has suddenly stopped honoring the dllexport directive. We have many functions of the form
INTEGER *4 FUNCTION GETNTGRID() !DEC$ ATTRIBUTES DLLEXPORT::GETNTGRID GETNTGRID = 3 END FUNCTION GETNTGRID
The structure is to build a .lib file from the Fortran code then build a .dll from the .lib (and other C++ code). Procedures called with this structure are not a problem, the problem is with those procedures that are only used externally. I have used dumpbin to show that there are no external symbols in the .exp file corresponding to DLLEXPORT directives, the only symbols are those corresponding to entries in the .def file.
Is there a compiler switch that controls the interpretation of DLLEXPORT either directly or indirectly? With the same code base and Version 22.214.171.124 I do not get this behaviour (both with VS2010).
No, there's no switch that controls this and I'm not aware of any changes. Can you provide a short but complete example that shows the problem? I took your snippet and it created a DLL with exported name normally.
Generally there needs to be "something" to tell the linker that it needs to pull a chunk of object code out of a static library and link it into a DLL (or EXE). This could be an explicit reference to the chunk of object code ultimately from an object file supplied in the linker command line, or an explicit mention of a symbol in the linker command line (/INCLUDE or /EXPORT) or the appearance of the symbol in a module definition file supplied to the linker.
The granularity of a stretch of object code generated by a compiler for a particular source file can vary - [very] historically one source file resulted in one monolithic chunk of object code that the linker then dealt with - if one thing in that chunk was referenced then the entire chunk was linked in. However, compilers can package object code - perhaps putting each procedure in its own chunk - such that the linker can be quite selective about what it includes. I'm not sure what ifort does in this regard, but this capability of the linker is controlled by the /OPT:REF or /OPT:NOREF options.
Perhaps the lack of (or change in) an explicit "something" to tell the linker that a particular stretch of object code from the library, perhaps combined with a relatively subtle change in how the compiler packages object code, now means that the linker is not including the object code from your static library that contains the procedures you intended to export. If so, providing an explicit reference in the linker command line or module definition file is the simple fix.
To supplement my blather - here are some tests (I don't have 14.0 installed to contrast and this is with the tools of VS2015). Here's the file that will make up the pretend static library.
MODULE my_procedures IMPLICIT NONE CONTAINS SUBROUTINE foo() BIND(C, NAME='foo') !DEC$ ATTRIBUTES DLLEXPORT :: foo PRINT *, 'my_procedures%%foo' END SUBROUTINE foo SUBROUTINE bar() BIND(C, NAME='bar') !DEC$ ATTRIBUTES DLLEXPORT :: bar PRINT *, 'my_procedures%%bar' END SUBROUTINE bar END MODULE my_procedures SUBROUTINE myexternal() BIND(C,NAME='myexternal') !DEC$ ATTRIBUTES DLLEXPORT :: myexternal PRINT *, 'myexternal' END SUBROUTINE myexternal
Compile and archive that to a library, then link to a dll (dummy.f90 contains only a comment - so the compiler still bothers actually trying to compile and link).
>ifort /c /MD my_procedures.f90 Intel(R) Visual Fortran Compiler for applications running on IA-32, Version 126.96.36.199 Build 20160204 ... >lib my_procedures.obj Microsoft (R) Library Manager Version 14.00.23506.0 ... >echo ! A comment to stop the compiler complaining > dummy.f90 >ifort /dll /MD dummy.f90 my_procedures.lib ... >dumpbin /exports dummy.dll Microsoft (R) COFF/PE Dumper Version 14.00.23506.0 ... Dump of file dummy.dll File Type: DLL Summary 2000 .data 1000 .gfids 6000 .rdata 1000 .reloc A000 .text
...and there are no exported procedures.
But if we explicitly ask to include a symbol in the link (ditch the leading underscore on the symbol name for x64):
>ifort /dll /MD dummy.f90 my_procedures.lib /link /include:_foo ... >dumpbin /exports dummy.dll ... ordinal hint RVA name 1 0 00001060 bar 2 1 00001010 foo 3 2 000010B0 myexternal
All three exported procedures from the static library are now in the DLL - and which also suggests that ifort generates object code that has a granularity of the entire source file. Maybe that shoots my granularity theory down in flames, but regardless, I'd still recommend explicitly specifying what you want to go into the DLL.
ATTRIBUTES DLLEXPORT turns into an "object directive". As soon as the linker pulls in the object file, no matter how many routines are in that object, all of the directives are processed. In Intel Fortran, you have to put the DLLEXPORT directive in the routine you want to export, otherwise it is ignored.
I tried to find a simple way of reproducing this but failed. Using dumpbin, fgrep, sort and comm I was able to get a list of those symbols that have suddenly gone AWOL (about 270) but why it's started happening I've got no idea. If I can find a way or reproducing it I'll probably have to submit it to Premier Support since there are restrictions on what I can post to a public site. If I do ever find a solution I'll post it here.