Unable to solve external symbol (error LNK2019) when linking multi language project

Unable to solve external symbol (error LNK2019) when linking multi language project

Imagen de Stefan S.

Hello,

due to migration to Windows 7 by our IT department, I had to switch from VC++ 6.0 and Compaq Visual Fortan to Visual Studio 2010 with Microsoft Visual Cüü 2010 and Intel Visual Fortran Composer XE 2013.

Trying to recompile the existing mixed language project I solved all issues except one.
When linking the project I get this error message:

Fehler 1 error LNK2019: Verweis auf nicht aufgelöstes externes Symbol "_DORN2ZSDT@268" in Funktion "_main".

I assume than in the header file which declares the FORTRAN subroutine DORN2ZSDT to C++ I use the wrong name. When I used the old set of compilers I had to declare
the subroutine this way:

extern "C" { void __stdcall DORN2ZSDT ( ................. ); } 

In the FORTRAN source the subroutine looks like this:

subroutine dorn2zsdt ( .....................) 

Since I allway had to compile this project for different platforms (Windows and Linux) with different compilers I know the the different compilers use different naming conventions for the compiled objects and wrote my headers with conditional compilation directives in respect to this. For instance for the NAGWare Fortran compilers objects I have to use this declaration in the header:

extern "C" { void dorn2zsdt_ ( ..... );} 

Now my problem is that I simply cannot find out which naming convention the Intel Visual Fortran Composer XE 2013 uses.

Can someone tell me the naming convetion or how to solve this linker error in another way.

Kind regards
Stefan

publicaciones de 11 / 0 nuevos
Último envío
Para obtener más información sobre las optimizaciones del compilador, consulte el aviso sobre la optimización.
Imagen de Steve Lionel (Intel)

You want:

extern "C" { void DORN2ZSDT ...)

The NAGware compiler is using Linux conventions.  The conventions used are documented in the "Mixed Language" section of the on-disk documentation, but the basics are:

1. Names are uppercase

2. The C convention and not STDCALL is used

3. Character lengths are passed at the end of the argument list, not interspersed

As with CVF, there is full control over this with directives and compiler options.

You can also use the C interoperability features of Fortran 2003. So if your C routine was called dorn2zsdt, you could write:

subroutine dorn2zsdt (...) BIND(C)

You may or may not be able to use this depending on what the arguments are.

Steve
Imagen de Stefan S.

Hello Steve,

after using your suggestion

extern "C" { void DORN2ZSDT ...)
but additionally chaning the subroutine name to lower case resulting in
extern "C" { void dorn2zsdt ...)
I'm sure to remember that I sould successfully link the program.

Then I had some other trouble causing Visual Studio 2010 to crash.

After restarting I'm not able to link the program anymore with a similar error message as in the beginning:
error LNK2019: Verweis auf nicht aufgelöstes externes Symbol "_dorn2zsdt" in Funktion "_main".
error LNK1120: 1 nicht aufgelöste externe Verweise.

Now I'm totally confused about what is going on.

Here is the declaration of the FORTRAN subroutin:

      subroutine dorn2zsdt (walze,gamma,h,dbk,dhsoll,shsoll,
     *                                   dh2db2zmax,nrho,nfe,nfueb,nfd,
     *                                   deltarho,festuf,fuebstuf,fakf,
     *                                   plugtipfollowsbillet,
     *                                   dzm,npb,np,wkrit,maxsim,epsdh,deltadhkorr,
     *                                   rotdir,gshoe,dschei,fuehrung,deltazhpf,etaa,
     *                                   dzms,nps,
     *                                   simkoeffk,simkoeffg,nsimkoeff,
     *                                   korrtemp,korrkf,mg,mf,mdst,ff2fw,fdst2fw,
     *                                   optplug,optbewert,eopt,aopt,abmopt,
     *                                   umfopt,lkwe,lkwa,lkfe,lkfa,
     *                                   xwsp,kw,kf,kmaw,kmiw,kmaf,kmif,kdw,kdf,
     *                                   ekorr,akorr,ld1korr,deltadh,chsoll,warn,err)
     type(t_walze),intent(in)::walze
     integer*4,intent(in)::nrho,nfd,npb,np,nps
     integer*4,intent(in)::fuehrung,rotdir,nsimkoeff
     integer*4,intent(inout)::maxsim,nfe,nfueb
     real*8,intent(in)::gamma,h,dbk,dhsoll,shsoll,dzm,epsdh,deltadhkorr
     real*8,intent(in)::deltazhpf,etaa,dzms,korrtemp,korrkf,mg,mf,mdst
     real*8,intent(in)::ff2fw,fdst2fw,dh2db2zmax
     real*8,intent(in)::deltarho(nrho),fakf(nfd)
     integer*4,intent(in)::plugtipfollowsbillet
     real*8,intent(inout)::fuebstuf(nfueb),festuf(nfe)
     real*8,intent(in)::simkoeffk(nsimkoeff),simkoeffg(nsimkoeff)
     type(t_guideshoe),intent(in)::gshoe
     type(t_dieschei),intent(inout)::dschei
     type(t_allwkrit),intent(inout)::wkrit
     type(t_plug),intent(out)::optplug
     real*8,intent(out)::optbewert,eopt,aopt
     type(t_abmessung),intent(out)::abmopt
     type(t_umformwerte),intent(out)::umfopt
     real*8,intent(out)::xwsp(nps-3),kw(nps-3),kf(nps-3)
     real*8,intent(out)::kmaw(nps-3),kmiw(nps-3)
     real*8,intent(out)::kmaf(nps-3),kmif(nps-3),kdw(nps-3),kdf(nps-3)
     real*8,intent(out)::lkwe,lkwa,lkfe,lkfa
     real*8,intent(out)::ekorr,akorr,ld1korr,deltadh,chsoll
     integer*4,intent(out)::warn,err

This is my declaration in the C++ header file:

extern "C"{voiddorn2zsdt (
                                           t_walze     *walze,
                                          double      *gamma,
                                          double      *h,
                                          double      *dbk,
                                          double      *dhsoll,
                                          double      *shsoll,
                                          double      *dh2db2zmax,
                                          int         *nrho,
                                          int         *nfe,
                                          int         *nfueb,
                                          int         *nfd,
                                          double      deltarho[],
                                          double      festuf[],
                                          double      fuebstuf[],
                                          double      fakf[],
                                          int         *plugtipfollowsbillet,
                                          double      *dzm,
                                          int         *npb,
                                          int         *np,
                                           t_allwkrit  *wkrit,
                                          int         *maxsim,
                                          double      *epsdh,
                                          double      *deltadhkorr,
                                          int         *rotdir,
                                          t_guideshoe *gshoe,
                                          t_dieschei  *dieschei,
                                          int         *fuehrung,
                                          double      *deltazhpf,
                                          double      *etaa,
                                          double      *dzms,
                                          int         *nps,
                                          double      simkoeffk[],
                                          double      simkoeffg[],
                                          int         *nsimkoeff,
                                          double      *korrtemp,
                                          double      *korrkf,
                                          double      *mg,
                                          double      *mf,
                                          double      *mdst,
                                          double      *ff2fw,
                                          double      *fdst2fw,
                                          t_plug      *optplug,
                                          double      *optbewert,
                                          double      *eopt,
                                          double      *aopt,
                                           t_abmessung *abmopt,
                                           t_umformw   *umfopt,
                                          double      *lkwe,
                                          double      *lkwa,
                                          double      *lkfe,
                                          double      *lkfa,
                                          double      xwsp[],
                                          double      kw[],
                                          double      kf[],
                                          double      kmaw[],
                                          double      kmiw[],
                                          double      kmaf[],
                                          double      kmif[],
                                          double      kdw[],
                                          double      kdf[],
                                          double      *ekorr,
                                          double      *akorr,
                                          double      *ld1korr,
                                          double      *deltadh,
                                          double      *chsoll,
                                          int         *warn,
                                          int         *err
                                          ); }

and finally my call statement in the main C++ program:

dorn2zsdt (&walze, &gamma, &h, &dbk,&dhsoll, &shsoll, &dh2db2zmax, &nrho, &nfe, &nfueb, &nfd, deltarho, festuf, fuebstuf, fakf, 
                  &plugtipfollowsbillet, &dzm,  &npb, &np, &wkrit, &maxsim, &epsdh, &deltadhkorr, &rotdir, &gshoe, &dieschei, &fuehrung, &deltazhpf,
                  &etaa, &dzmsim, &npsim, simkoeffk, simkoeffg, &nsimkoeff, &korrtemp, &korrkf, &mg, &mf, &mdst, &ff2fw, &fdst2fw, &optplug, 
                  &optbewert, &eopt, &aopt, &abmopt, &umfopt, &lkwe, &lkwa, &lkfe, &lkfa, xwsp, kw, kf, kmaw, kmiw, kmaf, kmif, kdw, kdf, &ekorr, 
                  &akorr, &ld1korr, &deltadh, &chsoll, &warn, &err);

Calling convention in the properties of my FORTRAN library project is: CVF (/iface:cvf)
Calling convention in the properties of my C++ man project is: __cdecl (/Gd)

What else do I have to do to make it link correctly, I don't have a clue.

Regards
Stefan

Imagen de Steve Lionel (Intel)

I said you shoukd use uppercase in the C++ declaration, but you changed it to lowercase.

Either of the following shoud work:

1. Add after line 13 in the Fortran source (after the right parenthesis ending the argument list):

     * bind(C)

2. Add somewhere in the Fortran routine (such as after the subroutine statement:

!DEC$ ATTRIBUTES DECORATE,ALIAS:"dorn2zsdt " :: dorn2zsdt 

Steve
Imagen de Stefan S.

Hello Steve,

thanks for your help, but nothing worked so far. Not in uppercase and not in lowercase writing of the subroutine name in c.
Also applying "bind(C)" or the "!DEC$" attributes didn't help. I tried all this using all possible combinations of uppercase, lowercase with the two declaration attributes.

So, to find out what is going on, I set up a brand new project with a simple fortran subroutine and a cpp main program.
Also this simple project doesn't link giving the same error message. Neither using "bind(C)" nor "!DEC$ ..." works for this too.
In the error message the subroutines name is prefixed with an underscore, if the name declated in my header is "F" the symbol name mentioned in the error message is "_F", but my FORTRAN subroutine is named "f"

This time I attached the test project completely in a single zip file. Please have a look at it, maybe you can check if you can successfully link it and tell me what you had to change to make it link.

Regards
Stefan

Adjuntos: 

AdjuntoTamaño
Descargar mixed-language-test.zip2.54 MB
Imagen de Steve Lionel (Intel)

The reason the error message names F is that is what you called it in the C++ code. Without bind(c) in Fortran, F would be correct, but with it, a lowercase name is required. (You can also specify a mixed-case name in the BIND clause, such as bind(C,NAME='MixedCaseName').

In addition to the name conflict, The C++ project doesn't know about the Fortran project at all - it's not a dependent and not linked in. A third problem is that the run-time library settings are inconsistent.

So, here's what you need to do:

  1. In the C++ code, change the name of the Fortran function from F to f in both places it appears.
  2. Right click on the C++ project, select Dependencies.  Check the box for the Fortran project to make it a dependent. Click OK.
  3. Right click on the C++ project, select Properties, Linker, Input. From the Configuration pulldown, select All Configurations. Click on Additional Dependencies. Click the black triangle to the right of Additional Dependencies and select Edit. Insert as the first line:
    $(SolutionDir)lib-fortran-test\$(Configuration)\lib-fortran-test.lib. Click OK.
  4. Right click on the Fortran project, select Properties, Fortran, Libraries. For Runtime Library, change it to "Debug Multithreaded DLL". Click Apply.  Change the Configuration to Release and change that one to "Multithreaded DLL".

That should take care of it.

Steve
Imagen de Stefan S.

Hello Steve,

thanks for the advice, this almost did the job.

Now I get this error message: error LNK1104: Datei "ifconsol.lib" kann nicht geöffnet werden.
In english: File "ifconsole.lib" cannot be opened.

What's wrong now?
I attached the project again as zip file to be sure no information is left out.

I already found out that I had to set dependencies, like you wrote in step 2. In my original project this was done by the "Extract Compaq Visual Fortran Items" tool automatically, so I forgot to do it manually in this test project.
But I do not really understand why I MUST do the rest.
Step 3 seems to be like a double definition to me because I already defined a dependency in step 2? It should be obious that this dependency is an input for the linker.
In step 4 I have to tell the compiler to use dynamic runtime libraries, why can't the linker, in the end, just link the static libraries needed? With this setting I will have to distribute the runtime DLLs.

I'm somehow dispointed by Visual Studio 2010. All this just because Visual Studio cannot handle mixed languages in a single project anymore. Nobody ever defined that a library or an executable must consist of code written in a single high level language. This is a artificial restriction set up by microsoft :-(

Do I have all this restrictions too if I would use Intel C Composer XE and Intel Visual FORTRAN Composer XE together with Eclipse unter Linux?
Is it possible to use both Intel Compilers together with Exlipse unter Windows? I allready tried, but found that the directories containing the eclipse support are missing in the windows installation of the compilers.

Thanks in advance
Stefan

Adjuntos: 

AdjuntoTamaño
Descargar mixed-language-test.zip2.53 MB
Imagen de Steve Lionel (Intel)

If the main program is C++, you have to tell MSVC where to find the Intel Fortran libraries such as ifconsol.lib.  See http://software.intel.com/en-us/articles/configuring-visual-studio-for-m...

I agree it is too bad that Microsoft removed the ability to have mixed languages in a project - this happened in Visual Studio.NET 2002. It wasn't too bad until they also broke linking in dependent libraries from non-C++ projects in VS2010, which accounts for step 3.

Step 4 is because C++ and Fortran have different defaults for the kind of run-time library. At one time they were the same - static - but Microsoft switched C++ to defaulting to the DLL libraries and Intel stayed with static.

Linux is quite a different environment. We don't support Intel Fortran (we don't use "Visual" on Linux) in Eclipse, but there is a Fortran Development Tool for Eclipse called PHOTRAN that is said to work with Intel Fortran. I don't know how one does mixed-language projects in Eclipse, though.

I have never tried Eclipse on Windows so can't comment there.

Steve
Imagen de Stefan S.

Hello Steve,

adding $(IFORT_COMPILERvv)compiler\lib\ia32 to the library path in the project properties of my main c++ project doesn't help.

The location of the "library files" property differs from the description in the article you reference in VS 2010.
Here is a description of what I did:

In the Project Explorer I right clicked on the "main-cpp-test" project and the clicked the properties menu.
Then I selected "VC++ Files" in the left panel and added "$(IFORT_COMPILERvv)compiler\lib\ia32" to the "Library files"
I did this for the "Debug" as well as for the "Release" version.

Result: I still get the same error message concerning "ifconsol.lib".

I would have liked to paste a screenshot of the configuratin window but I was not able to find out how to do this here, instead I attached the project again.

In the previous version of the project I did this declaration in the "Properties Manager" in the "Microsoft.Cpp.Win32.user" section.
I found a description to do this in another forum article.

Both doesn't help! So what is wrong?

Regards Stefan

 

Adjuntos: 

AdjuntoTamaño
Descargar mixed-language-test.zip2.53 MB
Imagen de Steve Lionel (Intel)

Did you change the "vv" to "13"? (or "12" if using Composer XE 2011).

Steve
Imagen de Stefan S.

Thanks Steve, that's it.

My fault was to not read the Introduction part carefully. "Sometimes" I tend to fly over the documents to get to the core quickly.

 

Inicie sesión para dejar un comentario.