我创建了一个简单的应用程序,它使用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文件,以支持这个?)。
答案 0 :(得分:2)
不确定是否是错误,但错误来自sqlite包的sqlite3.h
包含。
文件中的外观显示了这个
/*
** 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等变量。
在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",
".",
};
它尝试按顺序访问它们,它可以写入它的那个用来生成一个临时文件夹。
对于Windows,但第一行之一是:
if( sqlite3_temp_directory ){
sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", sqlite3_temp_directory);
}else if( isNT() ){
因此实际上使用了Windows sqlite3_temp_directory
。这就是为什么它无法编译,如果它找不到它。