[目次] (https://qiita.com/Yutaka_Aoki/items/9d38ea98406f4096435b)
Inside Wine; WINEDLLPATH
WINEDLLPATH の不具合
調べてみると、/wine/libs/wine/loader.c の中の build_dll_path() 関数の中で、環境変数 WINEDLLPATH が、読み取られ、: を 0x00 に変えてから、dll_paths[] 配列に : で区切られたそれぞれの文字列の先頭アドレスを代入している。
しかし、その処理に入る前に、get_dlldir() 関数が NULL 以外を返した場合、dll_paths[0] にその関数が返した文字列のアドレスを入れてしまう。
そして、実際の get_dlldir() は、"/usr/local/bin/../lib/wine" という文字列を返してくるので、そっちのパスの方が、WINEDLLPATH の優先順位よりも上になってしまう。
get_dlldir() は、
/* retrieve the default dll dir */
const char *get_dlldir( const char **default_dlldir )
{
*default_dlldir = DLLDIR;
return dlldir;
}
となっているが、DLLDIR は、Makefile の中で、gcc に -D オプションによってコンパイル開始時の #define マクロ として文字列が渡されている。
修正箇所
c:~/wine/libs/wine/loader.c
の build_dll_path() 関数を変更する。
make すると、c:~/wine/libs/wine/
に libwine.so.1.0
が作成される。
これを、自分のアプリの場合にだけは使われるようにする。
旧関数
/* build the dll load path from the WINEDLLPATH variable */
static void build_dll_path(void)
{
int len, count = 0;
char *p, *path = getenv( "WINEDLLPATH" );
const char *dlldir = get_dlldir( &default_dlldir );
if (path)
{
/* count how many path elements we need */
path = strdup(path);
p = path;
while (*p)
{
while (*p == ':') p++;
if (!*p) break;
count++;
while (*p && *p != ':') p++;
}
}
dll_paths = malloc( (count+2) * sizeof(*dll_paths) );
nb_dll_paths = 0;
if (dlldir)
{
dll_path_maxlen = strlen(dlldir);
dll_paths[nb_dll_paths++] = dlldir;
}
else if ((build_dir = wine_get_build_dir()))
{
dll_path_maxlen = strlen(build_dir) + sizeof("/programs");
}
if (count)
{
p = path;
while (*p)
{
while (*p == ':') *p++ = 0;
if (!*p) break;
dll_paths[nb_dll_paths] = p;
while (*p && *p != ':') p++;
if (p - dll_paths[nb_dll_paths] > dll_path_maxlen)
dll_path_maxlen = p - dll_paths[nb_dll_paths];
nb_dll_paths++;
}
}
/* append default dll dir (if not empty) to path */
if ((len = strlen(default_dlldir)) > 0)
{
if (len > dll_path_maxlen) dll_path_maxlen = len;
dll_paths[nb_dll_paths++] = default_dlldir;
}
}
新関数
/* build the dll load path from the WINEDLLPATH variable */
static void build_dll_path(void)
{
int len, count = 0;
char *p, *path = getenv( "WINEDLLPATH" );
const char *dlldir = get_dlldir( &default_dlldir );
if (path)
{
/* count how many path elements we need */
path = strdup(path);
p = path;
while (*p)
{
while (*p == ':') p++;
if (!*p) break;
count++;
while (*p && *p != ':') p++;
}
}
dll_paths = malloc( (count+2) * sizeof(*dll_paths) );
nb_dll_paths = 0;
dll_path_maxlen = 0;
if (count)
{
p = path;
while (*p)
{
while (*p == ':') *p++ = 0;
if (!*p) break;
dll_paths[nb_dll_paths] = p;
while (*p && *p != ':') p++;
if (p - dll_paths[nb_dll_paths] > dll_path_maxlen)
dll_path_maxlen = p - dll_paths[nb_dll_paths];
nb_dll_paths++;
}
}
if (dlldir) {
int len = strlen(dlldir);
if ( len > dll_path_maxlen ) {
dll_path_maxlen = len;
}
dll_paths[nb_dll_paths++] = dlldir;
}
else if ((build_dir = wine_get_build_dir())) {
int len = strlen(build_dir) + sizeof("/programs");
if ( len > dll_path_maxlen ) {
dll_path_maxlen = len;
}
}
/* append default dll dir (if not empty) to path */
if ((len = strlen(default_dlldir)) > 0) {
if (len > dll_path_maxlen) {
dll_path_maxlen = len;
}
dll_paths[nb_dll_paths++] = default_dlldir;
}
#if 1
int cnt;
for ( cnt = 0; cnt < nb_dll_paths; cnt++ ) {
fprintf( stderr, "%d: %s\n", cnt, dll_paths[cnt] );
}
#endif
}
以下のようなスクリプトを作っておく。
自分のアプリを実行する前に、
$ . myenv
として、先頭に 「.」を付けて環境変数が設定されるようにする。
export LD_LIBRARY_PATH=.
によって、カレント・ディレクトリにある、libwine.so.1
が探されるようになる。
$ ln -s /media/Yyyy/my_winedev/wine/libs/wine/libwine.so.1.0 libwine.so.1
などとして、カレント・ディレクトリに本体へのリンクを作っておく。
パスに付いては、詳細は省略する。以下のスクリプトは自分の場合。
WINEDLLPATH の設定の仕方は、ソースを検索すると、英語だが、自然言語で書かれているので読む。
#!/bin/sh
#
# $ . myenv [ret]
#
# として読みこます事。冒頭の「. 」(ドットと空白) が重要
#
PATH=/media/Yyyy/my_winedev/bin2/bin:$PATH
DLL=/media/Yyyy/my_winedev/wine/dlls
WINEDLLPATH=$DLL/winex11.drv
WINEDLLPATH+=:$DLL/gdi32
WINEDLLPATH+=:$DLL/user32
WINEDLLPATH+=:/media/Yyyy/my_winedev/bin2/lib/wine
export WINEDLLPATH
export WINESERVER=/media/Yyyy/my_winedev/wine/server/wineserver
export LD_LIBRARY_PATH=.