NextI need to know step-by-step how to import the add2i, add2r, and simpson functions from this DLL located in C:\temp into my current Fortran project. I do not want examples with *.lib, since the actual DLL I want to use once I get past this example does not have a companion *.lib. This is my Fortran code which is supposed to generate an EXE that is linked to the DLL file:
made the foo.lib file. Note that I used the foo.f90 from Quote #3; the modifications in Quote #12 are wrong because, firstly, the reason for the DECORATE attribute is to avoid the conditional compilation with !DEC$ IF DEFINED(_WIN32), so you don't need them both. Secondly, you don't need DECORATE here unless the calling convention of the DLL is set to STDCALL. Third, the ALIAS of 'add2i_' is wrong anyway. Just use dumpbin /exports to see what the symbols from your target DLL look like and see if what this test DLL exports look similar. Can you disclose as much as one symbol exported by the target DLL as seen by dumpbin /exports?
Ok, now start Visual Studio, start a new project, and under Intel(R) Visual Fortran, Console Application, select Empty Project, Name: fdllrun, check Create directory for solution, then OK. Now open a couple of Windows explorers +E + +E + and navigate to where your original fdllrun.f90 file as you modified it with DECORATE is and copy it over to D:\blahblahblah\fdllrun\fdllrun . Then you should be able to add it as an existing source file.
Then you have to go to Project -> fdllrun properties -> Linker -> general, and set the directory where that foo.lib that you made resides as an Additional Library Directory. Also under Linker -> Input, set foo.lib as an additional dependency. Then select OK.
Then you can do build -> rebuild solution and it should build but not run because that DLL isn't on your path. To fix this, go back to your two copies of Windows Explorer and copy foo.lib from where it is to D:\blahblahblah\fdllrun\fdllrun, and also copy foo.dll to D:\blahblahblah\fdllrun\fdllrun\release (I assumed a release build here; maybe you need debug instead of release?) Then you can go back to Project -> fdllrun properties -> Linker -> general -> Additional Library Directories and change that directory to D:\blahblahblah\fdllrun\fdllrun\release (or debug as the case may be).
Now you can do build -> rebuild all, and it should build, then debug -> start without debugging, and it should run to completion. If I can figure out how to do this in Visual Studio, anyone can do it.
There are two mechanisms for an exe to link to a DLL - load time linking (happens automatically when the executable is loaded) and run time linking (happens until the control of specific code in the executable).
(I lie a bit - there is also a third mechanism - delay load linking - a hybrid of those two, but I am not familiar with it, so, like all things I am mostly ignorant of, I just pretend it doesn't exist.)
To do run time linking you use the LoadLibrary and GetProcAddress Win32 API's (or some wrapper around them) to load the library (by name0 and get the relevant procedure address (by name or ordinal) - storing the procedure address in a procedure or integer pointer, and invoking it through that. Fortran examples of the use of those API's should be relatively easy to discover.
To do load time linking (which is what I guess you want to do, given the interface blocks), at the time you build your executable you tell the linker that particular procedures are in a particular DLL. You do that by providing the linker with an import library... i.e. a lib file. Without such a library, the linker has no idea where the implementation of that procedure lives, so you get the error message you see. If you want to use this mechanism and don't have an import library, then you need to make or get one.
You can make an import library by hand by writing a module definition file or by compiling and linking a pretend DLL - see -us/kb/131313 for starters. There are tools out there that will do this from the information in the DLL, given certain assumptions, for you - I think I've seen such a tool in the mingw distribution of gcc.
Now we compile it with ifort /nologo /dll foo.f90 . Then we delete the foo.lib, foo.exp, and foo.obj files, just so that there is nothing in our hands, nothing up our sleeves. Now we need a *.DEF file, in this case foo.def is
That's the Visual Studio only command prompt (hence it has no idea about Fortran). The command prompts for the Fortran compiler are accessible under the Intel Parallel Studio > Compilers and Libraries (or similar, depending on version) start menu items.
Ok, so after renaming foo.a to foo.lib, where do I put it when I Add Existing Item? I tried both foo.lib alone, as well as it along with fdlltest.dll and placed them beneath the "fdllrun" project tree. Same errors, all to no avail.
Well, it worked for me. I used the latest ifort, along with the dlltool.exe that came with gfortran 5.2, both 64-bit. I tried 32-bit ifort and apparently 32-bit dlltool.exe and I got the same error that you did. Here is my CMD.EXE session, given foo.f90, foo.def, and fdllrun.f90 as in Quote #3
OK, I found out what went wrong with the 32-bit build. In that case, dlltool.exe prepends underscores to the names but ifort, since you are using the ALIAS attribute, does not. It might be possible to fix this by using BIND(C) instead of !DEC$ ATTRIBUTES, or by adding the DECORATE attribute (I didn't check) but certainly putting underscores in there works. Here is the file that worked for the 32-bit build, fdllrun32.f90
Now I could compile with ifort /nologo fdllrun32.f90 foo.a, and the resulting fdllrun32.exe produces the output 3, as before. I just checked and the DECORATE attribute works in your case, so your best option, rather than maintaining a separate function ALIAS for 32- and 64-bit versions, is to add the DECORATE attribute to each function name in each interface body in the calling program unit.
I don't think you actually need that dlltool to do this - the windows system linker (moonlighting as lib.exe) can generate import libraries from def files (lib.exe /def:foo.def /out:foo.lib). You will have the same extraneous underscore issue on x86 though. The workaround for that is just to compile the dummy dll that you had in #3... delete the resulting dll and just use its lib file.
I next tried to use mesej4's method for creating a *.lib file and added it to the main Visual Studio program (inside the fdllrun tree) and attempted to build within Visual Studio, but that did not work. mesej4, perhaps you could clarify how you set up Visual Studio and the loading of files that got it working for you within the GUI?
Hopefully the last thing, but how do you choose a 32 bit compilation in Intel Fortran Visual Studio? When I go to Configuration Manager and try to change the Platform from Win32, my only option for New platform is "x64". I need to be able to select 32 bit as the actual DLL files I'm trying to use were compiled in 32 bit. I guess the only way to choose between one or the other is with Intel Compiler version you launch, IA-32 or Intel 64?
Oops, that last additional library directory should have been D:\blahblahblah\fdllrun\fdllrun, the directory where you put foo.lib. You can't put foo.lib in the release or debug directory because is then gets trashed by Rebuild All.
I should add one more thing. I had to tweak some things to get C++ DLL imports to work. But the same concepts with making lib and def files, then moving the lib and dll file into the same directory as the code and changing the linker settings still applied.
Good to hear that things are going well, and also that you changed over to BIND(C) instead of !DEC$ ATTRIBUTES to handle interfacing issues. The only reason I couched my replies in terms of !DEC$ ATTRIBUTES was on the off-chance that the DLL you were trying to interface to was itself written in Intel Fortran, in which case it might prove awkward to match up assumed-shape arguments, for example, with BIND(C). In just about all other cases (VARYING being one exception) BIND(C) is much more straightforward and transportable.
3a8082e126