VS2008 using mysql.f90 and trying to link libmysql.lib to a Fortran program

VS2008 using mysql.f90 and trying to link libmysql.lib to a Fortran program

imagem de Matthias H.

Hi all,

I am having a problem linking the libmysql.lib and mysqlclient.lib to my Fortran project. I am using the mysql.f90 by Daniel Kraft. I am further using the Intel 11.1 Fortran compiler in VS2008. The errors I am getting are all of this sort:

error LNK2019: unresolved external symbol _mysql_init referenced in function _MYFORTRAN_BINDING_mp_MYFORTRAN_CONNECT

It seems to be missing mysql_init, mysql_close, mysql_real_connect, mysql_real_querry, and so on

I did check with the lib command the contents of the library libmysql.lib and they refer to the libmysql.dll. I did check their content and all the references I am missing are in there. From what I understand that should be fine as this dll is used when executing the program. However, for some reason, this does not work when linking.

I did add to the properties page of the project under Linker -> general the path to the libraries and under -> input the names of the two libraries. I checked if its looking for the libs through changing the name of one lib, and then VS complains that it cannot find the library its looking for. So it should be looking at those two libs, I think.

Any ideas how to fix this problem.

Some more infos, I am running Win7 enterprise (64Bit) but the compiler is using the IA32 stuff, so that should be 32 bit code. I downloaded the mysql libs from the mysql site.

Any idea what the problem could be?

Kind regards, Matthias

23 posts / 0 new
Último post
Para obter mais informações sobre otimizações de compiladores, consulte Aviso sobre otimizações.
imagem de Steve Lionel (Intel)

Keep in mind that capitalization and punctuation matters when the linker is looking for names. Are the names EXACTLY as shown in the library, or do they differ in some small way? Please put the .lib in a ZIP file and attach it here, or point to where it can be found on the net, and I'll take a look.

Steve
imagem de Matthias H.

Hi Steve,

Thanks for the quick answer.

I downloaded the files from http://dev.mysql.com/downloads/connector/c/ and then downloaded mysql-connector-c-noinstall-6.0.2-win32.zip. I extracted the libraries and put them in the appropriate path so visual studio would find them. (its attached)

I used dumpbin to look at the contents of the dll and yes there is a small difference The calls in mysql.f90 ask for e.g. mysql_init, the linker says _mysql_init is not found and in the dll there is a mysql_init@4. I thought that would not matter, but obviously it does. I have to admit I am new to this.

Anyway what do I have to do to resolve this issue. Many thanks in advance.

Matthias

Anexos: 

imagem de Steve Lionel (Intel)

Yes, it does matter. The names with @4, etc., at the end are STDCALL routines that use a different calling convention than Intel Fortran uses as a default. There is also a leading underscore in the name which is important.

You can fix the linking problems by adding directives that look like this:

!DEC$ ATTRIBUTES STDCALL, REFERENCE :: mysql_connect

for each of the routines you are calling. You may want to put these in an INCLUDE file and include them.

This won't solve all your problems, though. You need to figure out, for each argument of each routine you are calling, whether the argument is passed by value or by reference. The lines I suggested above will pass by reference by default, which would match a C declaration of *something, but I expect there are routines that take things by value. You can enclose such arguments in %VAL() to make them passed by value if that's the case.

What you REALLY should do is write a set of interface blocks for these routines and specify the datatypes and passing mechanism for each argument. That's a lot of work but will save you hassle and errors later.

Steve
imagem de mecej4

The library libmysql.lib (included in your zip file) appears to be intended to be called with the STDCALL convention, since the routine names have been decorated with @nn-type suffixes, where nn stands for the number of bytes in the argument list.

Intel Fortran uses a different default calling convention, but a compiler switch allows STDCALL to be used instead. You will need to ascertain the prescribed usage of the Mysql library and, possibly, read the Mixed-Language-Programming chapter of the Intel Fortran User Guide.

imagem de Johannes

Hi Matthias,

I'm using the same mysql.f90 by Daniel Kraft but modified it in some points. I've attached my version of it. In my VS2010 Project I've the following settings:
Fortran --> General --> Addtional include directories: D:\Programme\mysql-5.5.27-winx64\include
Linker --> General --> Additional library directories: D:\Programme\mysql-5.5.27-winx64\lib\
Linker --> Input --> Additional Dependencies: D:\Programme\mysql-5.5.27-winx64\lib\libmysql.lib

Please note, that I'm not using the connectors but the full mysql installation (zip). I use Win7 x64 too, but I compile in x64 also. Calling convention is default of ifort 12.1.

A call in Fortran to the MySQL_binding looks like:

  ! *** Connect to data base

    pwd = ''//C_NULL_CHAR

    db  = ''//C_NULL_CHAR

    MySQLConnect = myfortran_connect(MySQL_DB(1), MySQL_DB(2), pwd, db)

    call mysql_select_db (MySQLConnect, MySQL_DB(3))

  !

  ! *** Search table and check data types

    MySQL_result =  myfortran_query_get(MySQLConnect, 'DESCRIBE '//trim(MySQL_table_name))

    imaxrows = myfortran_num_rows(MySQL_result)

    allocate(data_type(imaxrows))

    do i = 1, imaxrows

      l0success = myfortran_fetch_row(MySQL_result, MySQL_row)

      if(l0success)then

        indexmax     = MySQL_row%num_fields

        data_type(i) = myfortran_get_field(MySQL_row, 2)

      else

        write(*,'("!!! Error in ",a,"! Could not get results of table ",a)') csubr, trim(MySQL_table_name)

        write(*,'("    Abort with ENTER")')

        read(*,*)

        stop

      end if

    end do

It works quite robust and good in Windows with Intel (12.1) and Linux with GCC (4.5 & 4.6.3).

Hope that helps.
Kind regards,
Johannes

Anexos: 

AnexoTamanho
Download mod-mysqlfortran-binding.f9014.28 KB
imagem de Repeat Offender

Having code that works in both ifort and gfortran indicates that you are only attempting to make it work in 64-bit mode. Try the same thing in 32-bit mode and nothing can work because gfortran uses the BIND attribute + a one-line directive to interface with STDCALL functions whereas ifort uses an archaic mechanism they inherited from Microsoft which is totally incompatible. Intel will likely never fix their compiler to work with C interoperability because what they have works already and they may even have licensed their interfaces to other vendors like PGI. You may want to get everything working and tested in 64-bit mode and only later convert to the !DEC$ ATTRIBUTES style interfaces for use on 32-bit mode.

imagem de Steve Lionel (Intel)

Never say never, RO. There's nothing stopping us from allowing STDCALL with BIND(C) and it is something I have proposed to the developers.

As for PGI, they have not licensed anything from us and what Windows API modules they have they created on their own. Last I tried their compiler, it was not compatible with ours in this regard.

Steve
imagem de John Nichols

I tried this software till I was blue in the teeth. Bite the bullet and buy the qe software from Germany it is quick easy and painless to use. I connects to anything with a minimum of fuss.
I have no shares in the company and hopefully by this time our accountants have actually finally paid for it. I used it to run 132 million data sets into SQL Server without a hitch.

imagem de Matthias H.

Hi all,
Many thanks for all the suggestions. I have tried several things none of which worked so far, unfortunately.

As suggested by Steven I included the
!DEC$ ATTRIBUTES STDCALL, REFERENCE ::
but that did not work, it is still missing the references:
error LNK2019: unresolved external symbol _mysql_init referenced in function _MYFORTRAN_BINDING_mp_MYFORTRAN_CONNECT mysql.obj
_mysql_real_connect referenced in function _MYFORTRAN_BINDING_mp_MYFORTRAN_CONNECT
_mysql_close referenced in function _MYFORTRAN_BINDING_mp_MYFORTRAN_DISCONNECT
_mysql_real_query referenced in function _MYFORTRAN_BINDING_mp_MYFORTRAN_QUERY_DO
_mysql_store_result referenced in function _MYFORTRAN_BINDING_mp_MYFORTRAN_QUERY_GET
_mysql_free_result referenced in function _MYFORTRAN_BINDING_mp_MYFORTRAN_FREE_RESULT
_mysql_num_rows referenced in function _MYFORTRAN_BINDING_mp_MYFORTRAN_NUM_ROWS
_mysql_fetch_row referenced in function _MYFORTRAN_BINDING_mp_MYFORTRAN_FETCH_ROW
_mysql_num_fields referenced in function _MYFORTRAN_BINDING_mp_MYFORTRAN_FETCH_ROW
_mysql_fetch_lengths referenced in function _MYFORTRAN_BINDING_mp_MYFORTRAN_FETCH_ROW
_mysql_error referenced in function _MYFORTRAN_BINDING_mp_MYFORTRAN_ERROR
Those are the routines that are defined in the interface blocks in the package mysql.f90 (is attached, looks much like the one that was posted by Johannes later. The attached file includes only the DEC for the mysql_init for testing)

I am not sure where I should add the compiler directive. I have tried it at the beginning of the myfortran_binding module as well as in the main program, it does not make a difference. I have also downloaded the full version of mysql and taken the libraries from there (as suggested by Johannes) also no success.

I assume (ok I have the feeling) I am still doing something wrong with the !DEC statement. Is there any command I have to give when compiling so that it recognizes the directives !DEC commands?

Many thanks for additional help in advance,

Matthias

Anexos: 

AnexoTamanho
Download mysql.f909.62 KB
imagem de Steve Lionel (Intel)

Thanks for attaching your source. It helps. You, reasonably so, have interface blocks for the mysql routines. You also used BIND(C) with NAME=. Ordinarily that would be good, but as discussed above, this doesn't work when calling STDCALL routines in Intel Fortran.

So what you have to do is remove the BIND clause and then add, after each SUBROUTINE or FUNCTION line inside the INTERFACE, a line that looks like this:

!DEC$ ATTRIBUTES STDCALL,REFERENCE,DECORATE,ALIAS:"mysql_connect" :: c_connect

You would change the mysql_connect and c_connect as needed for each of the procedures. I have attached a modified source where I did this for a few of the routines so you can see how it is done. The ALIAS is needed because you call these routines by something other than their external name, and DECORATE takes care of adding the name decoration.

Anexos: 

AnexoTamanho
Download mysql.f9010.06 KB
Steve
imagem de Matthias H.

Dear Steve,

Many thanks again for your help. Unfortunately it still does not link, although I am one step further thanks to your help. When linking it now complains about not finding
_mysql_init@8 referenced in function _MYFORTRAN_BINDING_mp_MYFORTRAN_CONNECT
_mysql_connect@52 referenced in function _MYFORTRAN_BINDING_mp_MYFORTRAN_CONNECT
_mysql_real_query@16 referenced in function _MYFORTRAN_BINDING_mp_MYFORTRAN_QUERY_DO
_mysql_store_result@8 referenced in function _MYFORTRAN_BINDING_mp_MYFORTRAN_QUERY_GET
_mysql_fetch_row@8 referenced in function _MYFORTRAN_BINDING_mp_MYFORTRAN_FETCH_ROW
_mysql_fetch_lengths@8 referenced in function MYFORTRAN_BINDING_mp_MYFORTRAN_FETCH_ROW
_mysql_error@8 referenced in function _MYFORTRAN_BINDING_mp_MYFORTRAN_ERROR

so it did find

_mysql_close referenced in function _MYFORTRAN_BINDING_mp_MYFORTRAN_DISCONNECT
_mysql_free_result referenced in function _MYFORTRAN_BINDING_mp_MYFORTRAN_FREE_RESULT
_mysql_num_fields referenced in function _MYFORTRAN_BINDING_mp_MYFORTRAN_FETCH_ROW
_mysql_num_rows referenced in function _MYFORTRAN_BINDING_mp_MYFORTRAN_NUM_ROWS
two of which are functions and two of which are subroutines.

I tried to find out what the @n means in the module names, but I could not. Maybe you can help me out with this one. I guess I have the wrong library now, but in order to find the correct one it would be great to know what the @n means.

The other thing I do not understand is why Johannes reported that his version of mysql-f90 (including the BIND statement) works with VS2010 and Intel Fortran 12.1. Was there a major change between version 11.1 and 12.1.

Kind regards Matthias

imagem de Steve Lionel (Intel)

The @n means it is a STDCALL routine that neewd n bytes pooped off the stack on exit, based on the number of arguments. It has nothing to do with modules. I'd have to compare your declarations with the ones in the C header to see what is wrong. Probably a wrong number of arguments.

Steve
imagem de Johannes

Hi Matthias,

If I understand repeat offender right the difference is in 32bit vs. 64bit. Ifort seems to use different calling conventions as default for 32bit and 64bit. The 32bit calling convention seems to be a bit tricky with calling C/C++ and requires the !dec$ directives. Steve correct me please, if I'm wrong...

In addition I use not the connectors from "mysql-connector-c-noinstall-6.0.2-win32" but the libraries which are provided in "mysql-5.5.27-winx64.zip". First I tested the connector (64bits) but could not link. With "mysql-5.5.27-winx64.zip" I had no problems... Maybe you can test the "mysql-5.5.27-winx32.zip" libraries?

Maybe ArjenMarkus could help on this? He is maintaining the flibs?

Best regards,
Johannes

imagem de Anthony Richards

I note that the code includes
23 l0success = myfortran_fetch_row(MySQL_result, MySQL_row)
24
25 if(l0success)then
26
27 indexmax = MySQL_row%num_fields

So my question to Steve is, what happens to the name decoration when compiled for 64-bit if the arguments MySQL_result, MySQL_row are 8-byte pointers/adresses? Should you get @16rather than @8?

imagem de arjenmarkus

With 64-bits systems there is no STDCALL convention IIUIC. As that is responsible for the @4 etc decoration, the question you raised
does not actually arise.

imagem de Johannes

Hi Matthias,

Sorry, I've seen too late that you tested the "mysql-5.5.27-winx32.zip" version already. Have you noticed, that there is a special version for VS(2005): "mysql-connector-c-noinstall-6.0.2-win32-vs2005.zip" I don't know where the differences are, but maybe it is something with calling convention? Only a guess...

Is it possible for you to switch to x64? It seems to be the easiest solution?

I've thought also to use the MySQL Fortran interface by QT Software mentioned above, but my software have to run also on Linux and the QT solution is not available for Linux currently.

Kind regards,
Johannes

imagem de Steve Lionel (Intel)

The @n convention and STDCALL does not exist on x64, as noted. The compiler accepts the STDCALL attribute and will apply the other changes (downcase name, pass by value) on x64. I think that's going off on a tangent.

I think I see what the problem is. Let's look at mysql_init for an example. The interface block for this is:

FUNCTION c_init_mysql (mysql)
!DEC$ ATTRIBUTES STDCALL,REFERENCE,DECORATRE,ALIAS:"mysql_init" :: c_init_mysql
USE ISO_C_BINDING
IMPLICIT NONE
TYPE(C_PTR) :: c_init_mysql
TYPE(C_PTR), VALUE :: mysql
END FUNCTION c_init_mysql

Note that the function returns an object of TYPE(C_PTR). In C, the function just returns a pointer which is placed in a register. But in Fortran, without BIND(C), any function returning a derived type passes a "hidden argument" for returning the value. A solution for this is to change the declaration of the return value to:

integer(C_INTPTR_T) :: c_init_mysql

Then when the result is used if you wanted to make it a C_PTR you'd have to do something like:

TRANSFER(retval, C_NULL_PTR)

(this is a function call) to convert the integer pointer to a C_PTR, and then presumably you'd use it in as call to C_F_POINTER.

Steve
imagem de Matthias H.

Hi all,

I did several checks and reprogramming all with no success this morning. I finally tried to compile the stuff using the 64bit version and it complied. I used the equivalent libraries from the mysql version 5.0.95 that I am running , but only the 64 bit ones instead of the 32 bit ones. I also used the mysql.f90 version provide by Johannes in this discussion. It complies fine.

I have tried to connect to the data base using a small program just trying to connect to the database

program Read_database

use mod_MySQLfortran_binding
USE ISO_C_BINDING

implicit none

TYPE (myfortran) :: MySQLConnect

! Variables

! Body of Read_database

! *** Connect to data base
! the *** are placeholders
MySQLConnect = myfortran_connect( 'localhost','***',’****’,'*****' )

End program Read_database

But I get an error: cannot connect to localhost. Took me quite some while to figure out that instead of localhost I have to give it 127.0.0.1 instead. All my other programs (written in c++) use localhost instead. Now I can connect to the database.

I would like to thank everyone who helped so much in solving this problem. Many thanks

Matthias

imagem de Steve Lionel (Intel)

My guess is that it wants NUL-terminated strings. So use 'localhost'C, etc.

Steve
imagem de Matthias H.

Hi Steve,

their is a NUL-terminated string in the call, so it cannot be this, that is at least what I think.

Matthias

imagem de Johannes

Hi Matthias,

good to hear that you have access to the MySQL-DBs know. :-)

The "localhost" thing was not working for me too and I used, like you, the IP directly instead. This occured only if I was running the MySQL service and the "client"-Fortran program on the same machine/virtual machine. Access from a PC to a Server with "someservername" instead "localhost" is running fine.


    MySQL_DB(1) = t0dummy(i2pos(1,1):i2pos(1,2))//C_NULL_CHAR  ! servername

    MySQL_DB(2) = t0dummy(i2pos(2,1):i2pos(2,2))//C_NULL_CHAR  ! user

    MySQL_DB(3) = t0dummy(i2pos(3,1):i2pos(3,2))//C_NULL_CHAR  ! database name


and

    pwd = 'mypassword'//C_NULL_CHAR

    db  = ''//C_NULL_CHAR

    MySQLConnect = myfortran_connect(MySQL_DB(1), MySQL_DB(2), pwd, db)


to connect.
I assume that is some network stuff but no MySQL problem...

Good luck and kind regards,
Johannes

imagem de Steve Lionel (Intel)

Matthias, in the example you posted that I replied to, you weren't using NUL-terminated strings. 'localhost' usually works since it is an alias for 127.0.0.1, but if you need the IP, then fine.

Steve

Faça login para deixar um comentário.