Bug #59082 Lib in Server install statically linked; Connector/C Lib is dynamically linked
Submitted: 21 Dec 2010 6:56 Modified: 25 Dec 2010 8:59
Reporter: Dave Kelly Email Updates:
Status: Not a Bug Impact on me:
None 
Category:Connector / C Severity:S3 (Non-critical)
Version:6.0.2 GA OS:Windows (MySQL Server 5.5.8 GA)
Assigned to: CPU Architecture:Any
Tags: link, linker error, mysqlclient.lib, object library, static

[21 Dec 2010 6:56] Dave Kelly
Description:
When using the MySQL headers and object libraries to build Apache 2.2.15 http server with MySQL (apr_dbd_mysql) functionality, apr_dbd_mysql-1.dll fails to build due to the fact that mysqlclient.lib is statically linked with the MSVCRT runtime libraries via LIBCMT.lib.  This causes myriad duplicate function definition conflict errors during linking.

How to repeat:
Try to build the Apache 2.2.15 http server project with MySQL functionality (i.e., DBD_LIST="mysql") using the MySQL Server 5.5.8 GA headers and libraries.

Note:  you must include both the libmysql.lib and mysqlclient.lib object libraries for the linker because the my_init() function implementation is no longer included in the libmysql.lib object library file.

Suggested fix:
You can successfully work around this problem by telling the linker to Ignore the LIBCMT.lib object library in the apr_dbd_mysql project (only).

However, statically linking the mysqlclient.lib object library to the MSVCRT runtime via LIBCMT.lib seems unnecessary.  Perhaps that could be changed.

At the very least, a note could be included detailing the problem and the work around.
[21 Dec 2010 12:04] Vladislav Vaintroub
Looking at http://dev.mysql.com/doc/refman/5.5/en/c-api-functions.html, my_init() is not listed here.  Actually , it does not belong to client API and should be not listed here http://dev.mysql.com/doc/refman/5.5/en/c-api-thread-functions.html either.

There is never need to call this function, as mysql_xxx_init() would implicitely call it. 

Linking both static and shared library is definitely something that can't work.
And /MT was used for building static library at least since 5.0, so there is no change here.
[21 Dec 2010 13:23] Dave Kelly
Perhaps I should have elaborated more on this.  I was not trying to use the my_init() function explicitly.  The linker was failing with an 'unresolved external symbol' for _my_init when I only included libmysql.lib.  Including mysqlclient.lib solved that problem (because it defines my_init), but that caused the function redefinition conflicts due to having the MSVCRT runtime statically linked into mysqlclient.lib.

I never had either of these problems with the 5.1.x headers and libraries, so I can't explain your comment about having static linkage since 5.0.

In any event, this is a problem when building the Apache http server.  I know it's not my place to say, but I don't see the need for the static linkage.
[21 Dec 2010 13:56] Vladislav Vaintroub
Right, static linkage is almost never a correct thing to do. Mainly because static libraries produced by MSVC can be used with only single version  Visual Studio (the same one they were compiled with), and hey require the same settings of /MT /MTd /MD /MDd.
[21 Dec 2010 14:30] Vladislav Vaintroub
Wondering what happens if you fix apache, and remove my_init() completely for the sake of experiment (replacing by mysql_init(NULL) would be a safer bet, but very likely this is not needed).
[21 Dec 2010 22:10] Dave Kelly
I don't think the Apache code is the problem (i.e., needs fixing).  The my_init() function is being referenced in the MySQL header file include/my_sys.h on line 57:

#define MY_INIT(name) { my_progname= name; my_init(); }

That reference alone will cause a linker 'unresolved external symbol' error unless mysqlclient.lib is included (since MY_INIT(name) is called elsewhere in the headers/libraries); and I'm pretty sure there are other instances in the MySQL headers/libraries code that call the my_init() function as well.

IMHO, changing the MySQL libraries to dynamically linked would be the best fix.
[21 Dec 2010 22:18] Vladislav Vaintroub
well, actually only mysql.h is the client API header (and by necessity its includes, as I believe it is not really standalone).

But those do not include my_sys.h. my_sys.h might become necessity in other cases, if you're writing something like storage engine and need half of the server functionality to accomplish it.
[21 Dec 2010 22:38] Dave Kelly
Well, I'm not really an Apache developer per se, I'm just trying to build the server on Windows.  So, what side-effects might be caused by removing MySQL header includes is a risky question for me--mainly because of the time involved in tracking them down and fixing them.

Still, the best option would seem to be Dynamic linking of mysqlclient.lib to the MSVCRT runtime libraries.  Here again, I'm not on the MySQL development team, so it's not my decision to make.
[21 Dec 2010 22:53] Vladislav Vaintroub
I sysbench can serve as a good reference on how to write Apache-style  the without need to escape to private headers.

mysql_xxx only  functions are used, mysql.h + mysqld_error.h as header files (the later to get symbolic constants for error messages). Instead of my_init() they use mysql_library_init(0, NULL, NULL)

http://bazaar.launchpad.net/~sysbench-developers/sysbench/0.5/annotate/head%3A/sysbench/dr...

To be fair, I would not really blame Apache DBD for what they have done, as my_init() appears to be lightly documented. I rather see it as a bug in MySQL documentation (i.e it should not have been documented at all since it is not in mysql.h and does not start with mysql_ prefix)
[21 Dec 2010 23:06] Vladislav Vaintroub
Well, I'm not Oracle anymore either, just tracking bugs out of pure curiousity (what could I have broken in my very recent past)

Linking with static CRT (/MT and /MTd rather than /MD or /MDd) was there for long time, before my time. I believe the main problem with dynamic CRT (/MD) was the need  to redistribute the C runtime itself (and perhaps install it).

mysql traditionally could run just after unpacking the ZIP and had zero requirements for prerequisites on the target systems
[21 Dec 2010 23:38] Dave Kelly
It's pretty rare for a Windows machine to not have the latest MSVCRT runtime libraries already installed.  Most if not all Windows machines have them right off the shelf, and if not they get installed either by Windows Update (for Internet Explorer and Windows Mail), or by some other commercial software, such as MS Office, etc.  Those updates usually only become a "breaking change" once in a blue moon and then everybody has to deal with it anyway.
[22 Dec 2010 0:22] Vladislav Vaintroub
I bet not many machines would have latest msvcr100.dll right now, and many would not have the latest msvcr90.dll either. Since ever Visual Studio started to bind to versioned libraries (VS2002), redistribution became a problem, which was complicated to almost impenetrable state  in VS2005 and VS2008.
[22 Dec 2010 1:30] Dave Kelly
I suppose, but at the very least there is always some version of the MS C runtime library on every version of Windows that comes as part of the operating system.  If version specific capabilities are wanted (or necessary), it becomes necessary to use #if defined() directives.  That can be a pain too.

Anyway...enough said...
[23 Dec 2010 14:35] Vladislav Vaintroub
@Dave, rioght there is always an unversioned msvcrt.dll on every Windows. It is just so that MSVC uses tricks to bind to a specific version of CRT, such that the final executable or dll needs this VS version-specific C runtime on target system.

The user of unversioned C runtime is Windows itself, and probably drivers built with driver toolkit. If I recall correctly, MinGW would  also bind to the unversioned CRT.But MSVC lacks this possibility.
[25 Dec 2010 8:59] Dave Kelly
Changed Synopsis, Category, Status, Version and details.  Hopefully, someone may find this info useful.

OK, although my work-around of excluding LIBCMT.lib from the Apache apr_dbd_mysql build enabled it to compile/link OK, the resulting apr_dbd_mysql dll did not function correctly (Internal Server Error).  However, I found that the Connector/C API has a dynamically linked version.  I was previously using the libraries included with the MySQL Server installation, which are statically linked.  Just a suggestion--shouldn't they both be the same?

Using the Connector/C libraries, including only libmysql.lib, I still got the 'unresolved external symbol _my_init' linker error.  After searching around, I finally found a pending patch (suggested by Raul Salitrero) for the Apache apr_dbd_mysql module and it seems to work OK.

Vladislav, you were right, it was a mistake in the Apache code.  The patch essentially did what you suggested, removing the call to my_init() and replacing it with slightly different code:

// Apache httpd project file:
//   httpd-2.2.15/srclib/apr-util/dbd/apr_dbd_mysql.c
// In function dbd_mysql_init, around line 1265:
// ***** begin patch suggested by Raul Salitrero
  /* Remove the following two lines
  my_init();
  mysql_thread_init();
  */
  // Add the following four lines
  MYSQL * temp_ptr = NULL;
  temp_ptr = mysql_init(temp_ptr);
  mysql_thread_init();
  mysql_close(temp_ptr);
// ***** end patch suggested by Raul Salitrero

Bottom line:  this is not a MySQL bug.  Sorry for any inconvenience, and thank you for your input and guidance.