Bug #45113 mysql_config returns incorrect path if built with prefix != execprefix
Submitted: 27 May 2009 5:59 Modified: 1 Oct 2009 14:03
Reporter: Andrew Dalgleish Email Updates:
Status: Patch pending Impact on me:
None 
Category:MySQL Server: Compiling Severity:S3 (Non-critical)
Version:5.1 OS:Any
Assigned to: Assigned Account
Triage: Triaged: D2 (Serious)

[27 May 2009 5:59] Andrew Dalgleish
Description:
A customer reports:
----------
The fix_path routine in mysql_config uses the execprefix as the basedir (since it gets it from $0). This makes the script pick $execprefix/include instead of $prefix/include/mysql when installed. This makes it much harder to install packages from source that depend on mysql.
----------

Tracing through fix_path shows it does not check the supplied pkgincludedir, but uses $execprefix/include (which is the same value in most cases).

How to repeat:
Build from source with prefix and execprefix set to non-standard locations, eg:
configure --prefix=$HOME/test/prefix --execprefix=$HOME/test/execprefix

Suggested fix:
Check the current value of pkgincludedir before using the heuristic to find the directory.

--- mysql_config.sh.orig        Wed Apr  1 01:38:52 2009
+++ mysql_config.sh     Wed May 27 15:52:37 2009
@@ -90,7 +90,7 @@
 plugindir='@pkgplugindir@'
 
 pkgincludedir='@pkgincludedir@'
-fix_path pkgincludedir include/mysql include
+fix_path pkgincludedir $pkgincludedir include/mysql include
 
 version='@VERSION@'
 socket='@MYSQL_UNIX_ADDR@'
[27 May 2009 11:30] Sveta Smirnova
Thank you for the report.

I can not repeat described behavior with current development sources:

 ./configure  --enable-assembler --with-extra-charsets=complex --enable-thread-safe-client --with-big-tables --with-readline --with-debug=full --with-ssl --with-plugins=max-no-ndb --with-embedded-server --enable-local-infile --prefix=/users/ssmirnova/build/bug45113/mysql-5.1 --exec-prefix=/users/ssmirnova/build/bug45113/exec
...
$ /users/ssmirnova/build/bug45113/exec/bin/mysql_config 
Usage: /users/ssmirnova/build/bug45113/exec/bin/mysql_config [OPTIONS]
Options:
        --cflags         [-I/users/ssmirnova/build/bug45113/mysql-5.1/include/mysql -g -DUNIV_LINUX]
        --include        [-I/users/ssmirnova/build/bug45113/mysql-5.1/include/mysql]
        --libs           [-rdynamic -L/users/ssmirnova/build/bug45113/exec/lib/mysql -lmysqlclient -lz -lcrypt -lnsl -lm]
        --libs_r         [-rdynamic -L/users/ssmirnova/build/bug45113/exec/lib/mysql -lmysqlclient_r -lz -lpthread -lcrypt -lnsl -lm -lpthread]
        --plugindir      [/users/ssmirnova/build/bug45113/exec/lib/mysql/plugin]
        --socket         [/tmp/mysql.sock]
        --port           [0]
        --version        [5.1.36]
        --libmysqld-libs [-rdynamic -L/users/ssmirnova/build/bug45113/exec/lib/mysql -lmysqld -ldl -lz -lpthread -lcrypt -lnsl -lm -lpthread -lrt]

Please indicate accurate minor version of MySQL which customer uses and provide full configuration line.
[27 May 2009 14:14] Andrew Dalgleish
Sorry Sveta, I checked my shell's history and see that I left out a step.

This only happens if $execprefix/include or $execprefix/include/mysql already exists. (eg if execprefix=/usr/local)

This is how I reproduced it using the 5.1.34 source:

mkdir -p $HOME/test/execprefix/include
sh configure --prefix=$HOME/test/prefix --execprefix=$HOME/test/execprefix
make
make install
$HOME/test/execprefix/bin/mysql_config
[27 May 2009 15:32] Sveta Smirnova
Thank you for the feedback.

Verified as described:

$mkdir build/bug45113/exec/include

$mkdir build/bug45113/exec/include/mysql

$ /users/ssmirnova/build/bug45113/exec/bin/mysql_config 
Usage: /users/ssmirnova/build/bug45113/exec/bin/mysql_config [OPTIONS]
Options:
        --cflags         [-I/users/ssmirnova/build/bug45113/exec/include/mysql -g -DUNIV_LINUX]
        --include        [-I/users/ssmirnova/build/bug45113/exec/include/mysql]
        --libs           [-rdynamic -L/users/ssmirnova/build/bug45113/exec/lib/mysql -lmysqlclient -lz -lcrypt -lnsl -lm]
        --libs_r         [-rdynamic -L/users/ssmirnova/build/bug45113/exec/lib/mysql -lmysqlclient_r -lz -lpthread -lcrypt -lnsl -lm -lpthread]
        --plugindir      [/users/ssmirnova/build/bug45113/exec/lib/mysql/plugin]
        --socket         [/tmp/mysql.sock]
        --port           [0]
        --version        [5.1.36]
        --libmysqld-libs [-rdynamic -L/users/ssmirnova/build/bug45113/exec/lib/mysql -lmysqld -ldl -lz -lpthread -lcrypt -lnsl -lm -lpthread -lrt]
[30 Sep 2009 11:10] Jonathan Perkin
The problem with making it look in $pkgincludedir first is that this will be hardcoded in our binary packages to be under /usr/local, and therefore this change would mean that any global mysql instance installed there will be picked first before the current package.  I imagine this would break in a lot of environments.

Could you expand on the actual problem?  While I can see how making these include directories triggers different output, I don't understand why someone would actually want to do that (FWIW there are plenty of other ways to break this script, for example set --bindir to something which doesn't end in 'bin')

Thanks.
[30 Sep 2009 22:13] Sveta Smirnova
Jonathan,

Look in my example:

--prefix=/users/ssmirnova/build/bug45113/mysql-5.1
--exec-prefix=/users/ssmirnova/build/bug45113/exec

So includes should be in "users/ssmirnova/build/bug45113/mysql-5.1/include/mysql" and libraries in "/users/ssmirnova/build/bug45113/mysql-5.1/include/mysql" (in prefix)

If no directory /users/ssmirnova/build/bug45113/exec/include or /users/ssmirnova/build/bug45113/exec/include/mysql exists everything works fine, but if I create them

mysql_config outputs:

  --cflags         [-I/users/ssmirnova/build/bug45113/exec/include/mysql -g
-DUNIV_LINUX]
        --include        [-I/users/ssmirnova/build/bug45113/exec/include/mysql]
        --libs           [-rdynamic -L/users/ssmirnova/build/bug45113/exec/lib/mysql
-lmysqlclient -lz -lcrypt -lnsl -lm]

...

While /users/ssmirnova/build/bug45113/exec/lib/mysql even does not exists.

Regarding to why to do this for example I have all binaries in my homedir and want to place mysql into this directory, but want to place libraries of particular version in some custom location. For example, for not to overwrite existing libraries.
[1 Oct 2009 11:31] Andrew Dalgleish
The main issue with this bug is that the behaviour is incorrect if an external directory exists, and there is a reasonably high chance that is does.

The most common reason to set prefix and execprefix to different directories is to put architecture-independent files in a shared location, while keeping architecture-dependent files separated. There's reference to this in the autobook docs, and also in the examples for automount or autofs, for example.

I don't understand Jonathon's comment about $pkgincludedir as when the directory is checked, pkgincludedir is set to $prefix/include. This won't be affected by what is already installed unless prefix is set to the same location, in which case it would behave correctly anyway with the suggested patch.
[1 Oct 2009 11:49] Jonathan Perkin
Sure, I understand why you would want to split execprefix and prefix, but still do not see in which situation you would have an includes directory (which is architecture-independant) inside execprefix (which is architecture-dependant), when you've already configured the architecture-independant files to be installed elsewhere.

The only one I can think of is where you have not followed this rule for all your installs, and happen to have another package installed in the same location which you did not split up and just used --prefix=execprefix and it installs its own header files, in this case the final check for just the 'include' directory will match.  To handle this case, it should be sufficient to change mysql_config to actually look for a mysql header rather than just a directory.

The issue with $pkgincludedir is that our official tar.gz packages are built with --prefix=/usr/local/mysql.  Therefore if:

 a) user has existing installation of mysql in /usr/local/mysql
 b) user downloads new package including the $pkgincludedir change and installs under /some/other/dir
 c) runs /some/other/dir/bin/mysql_config

it will look in the hardcoded /usr/local/mysql/include first and pick the wrong directory.
[1 Oct 2009 14:03] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/85389

3146 Jonathan Perkin	2009-10-01
      bug#45113: mysql_config returns incorrect path if built with prefix != execprefix
      
      Catch the corner case where prefix != exec-prefix and exec-prefix happens
      to have an include directory (e.g. from another package) by searching
      specifically for mysql.h.
      
      Add a note explaining that this will still fail if running from a different
      DESTDIR and the compiled-in file exists.
[2 Oct 2009 6:45] Andrew Dalgleish
I've tested Jonathon's patch - works in every odd case I could think of.

Thanks.
[2 Feb 2010 18:36] Sveta Smirnova
See also bug #50837