GHC:: Привязка против sqlite3 не работает в Windows

Я создал простое приложение, которое использует 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, чтобы поддержать это?).

1 ответ

Решение

Не уверен, что это ошибка или нет, но ошибка исходит от sqlite3.h включить пакет sqlite.

Взгляд в файл показывает это

/*
** 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, а затем передаю файл c во время компиляции исходного кода haskell.

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

а затем запустить его также возвращает ожидаемый результат

$ ./test
done

Таким образом, кажется, что вам просто нужно дать значение для sqlite3_temp_directory, которое, если вы установите его в NULL-указатель, будет использовать переменные TMP/TEMP и т. Д., Как определено в руководстве SQLLITE.

отредактируйте, выясните, почему это работает в Linux, но не в Windows

В пакете sqlite есть файл sqlite3.c в папке sqlite3.6. Это обеспечивает кучу значений по умолчанию для пакета sqlite.

когда в linux определяется OS_UNIX и когда в linux используются определения в OS_WIN. Интересующая нас функция - это функция, которая устанавливает временный каталог. для Unix это будет unixGetTempname и для окон winGetTempname,

Если вы посмотрите на реализацию обеих этих функций, то для unix у него есть список каталогов, которые он попробует

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

он пытается получить к ним доступ по порядку, а тот, который он может записать, использует для создания временной папки.

Для окон, однако, одна из первых строк:

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

так для окон sqlite3_temp_directory на самом деле используется. Вот почему он не компилируется, если не может его найти.

Другие вопросы по тегам