2

データストアのバックエンドとして sqlite3 を使用する単純なアプリケーションを作成しました。Linux でビルドして実行するときには問題はありませんでしたが、Windows でビルドしようとすると、奇妙なリンク エラーが表示されます。

Linking dist\build\hnotes\hnotes.exe ...
C:\Documents and Settings\Admin\Application Data\cabal\sqlite-0.5.2.2\ghc-7.0.4/libHSsqlite-0.5.2.2.
a(sqlite3-local.o):sqlite3-local.c:(.text+0x21): undefined reference to `sqlite3_temp_directory'
C:\Documents and Settings\Admin\Application Data\cabal\sqlite-0.5.2.2\ghc-7.0.4/libHSsqlite-0.5.2.2.
a(sqlite3-local.o):sqlite3-local.c:(.text+0x40): undefined reference to `sqlite3_temp_directory'
collect2: v ld     1
cabal.EXE: Error: some packages failed to install:
hnotes-0.1 failed during the building phase. The exception was:
ExitFailure 1

何が間違っている可能性がありますか?qalite3.dll をリンク段階に追加する必要があると思われますが、その方法がわかりません。--extra-lib-dirs=path-to-sqlite-dll を追加しても役に立ちません (おそらく、これをサポートするために何らかの方法で cabal ファイルを更新する必要があるためですか?)。

4

1 に答える 1

2

バグかどうかはわかりませんが、エラーはsqlite3.hsqlite パッケージのインクルードによるものです。

ファイルを見ると、これが示されています

/*
** CAPI3REF: Name Of The Folder Holding Temporary Files {H10310} <S20000>
**
** If this global variable is made to point to a string which is
** the name of a folder (a.k.a. directory), then all temporary files
** created by SQLite will be placed in that directory.  If this variable
** is a NULL pointer, then SQLite performs a search for an appropriate
** temporary file directory.
**
** It is not safe to modify this variable once a [database connection]
** has been opened.  It is intended that this variable be set once
** as part of process initialization and before any SQLite interface
** routines have been call and remain unchanged thereafter.
*/
SQLITE_EXTERN char *sqlite3_temp_directory;

そのため、extern として宣言されます。とても簡単なテスト:

module Main where

import Database.SQLite

main 
 = do hwd <- openConnection "test"
      closeConnection hwd
      putStrLn "done"

これは、上記のエラーで予想どおりリンク中にクラッシュします。だから私は小さなCテストファイルを作成しましたfoo.c

#include "sqlite-0.5.2.2\\include\\sqlite3-local.h"

char* sqlite3_temp_directory = "C:\\test2";

したがって、temp_directory を定義してから、haskell ソースのコンパイル中に c ファイルを渡します。

$ ghc test.hs foo.c
[1 of 1] Compiling Main             ( test.hs, test.o )
Linking test.exe ...

そしてそれを実行すると、期待される結果も返されます

$ ./test
done

したがって、sqlite3_temp_directory の値を指定するだけでよいようです。値を NULL ポインターに設定すると、SQLLITE マニュアルで定義されている TMP/TEMP などの変数が使用されます。

編集、Linuxでは機能したがWindowsでは機能しなかった理由をフォローアップ

sqlite パッケージには、sqlite3.6 フォルダーの下にファイル sqlite3.c があります。これにより、sqlite パッケージの一連のデフォルトが提供されます。

Linux では OS_UNIX が定義され、Linux では OS_WIN の下の定義が使用されます。私たちが興味を持っている関数は、一時ディレクトリを設定する関数です。UNIXの場合はunixGetTempname、Windows の場合は になりますwinGetTempname

これらの両方の機能の実装を見ると、UNIX の場合、試行するディレクトリのリストがあります。

  static const char *azDirs[] = {
     0,
     "/var/tmp",
     "/usr/tmp",
     "/tmp",
     ".",
  };

それらに順番にアクセスしようとし、書き込み可能なものを使用して一時フォルダーを生成します。

ただし、ウィンドウの場合、最初の行の 1 つは次のとおりです。

  if( sqlite3_temp_directory ){
    sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", sqlite3_temp_directory);
  }else if( isNT() ){

sqlite3_temp_directoryそのため、実際にはfor windowsが使用されます。これが、見つからない場合にコンパイルされない理由です。

于 2012-07-09T15:15:49.010 に答える