【问题标题】:Sqlite FTS doesn't work when compiling with LLVM on iOS在 iOS 上使用 LLVM 编译时,Sqlite FTS 不起作用
【发布时间】:2012-06-20 19:01:45
【问题描述】:

我开发企业级 iPad 应用程序已有一段时间了。由于应用程序开发大约在 2 年前开始,我需要从源代码编译我自己的 SQLite 版本,因为默认的 SQLite 库(sqlite3.dylib)默认没有启用 FTS。

好的,从那时起一切正常。我一直使用 GCC 作为项目编译器。

问题是现在我正在尝试将我的整个项目转换为使用ARC。为此,我需要使用 Apple 的 LLVM 编译器。

就是这样。当我更改编译器(从 GCC 4.2 到 LLVM 3.1 或 4.0,不转换为 ARC,也不更改任何其他内容)时,我的应用程序构建良好,一切运行正常,除了我的 FTS 查询,它根本不起作用甚至最简单的。它们运行并返回总是没有结果(不过使用 SQLITE_OK 代码)。

我被困在这里了。我已经在 WWDC'12 上与一位 Apple 工程师交谈过,但我们找不到任何解决方案。

我保证它不太可能是格式错误的查询或类似的东西,因为该应用程序在 GCC 上运行良好。此外,我可以在终端版本的 SQLite(或使用其他应用程序,如 Base)上运行查询

我也在使用旧版本的 SQLite,但我已更新到迄今为止的最新版本 (3.7.13)。一切都保持不变。我还注意到,现在(我不知道从什么时候开始)mac 附带的 sqlite 支持 FTS(!!!),我能够删除自己的版本并使用 Apple 的版本。问题是,我的行为完全相同。

我一直在寻找解决方案,但找不到。我发现了一些与 armv6 和编译器优化相关的错误(可以使用 -mno-thumb 标志修复),但这不是我的情况。我还注意到,当我使用 Clang 分析我的自定义 sqlite 文件时,它会指出很多很多“潜在错误”。

我对此持非怀疑态度,但我(仍然)不相信这是 LLVM 或 SQLite 错误。我更喜欢在解决它们之前检查所有可能的错误。也许我忘记配置某些东西或需要向编译器添加一些我没有做的标志。

感谢您的帮助。同样,该错误仅发生在使用 LLVM 编译的项目上(即使使用默认的 sqlite)。如果我在终端版本的 sqlite3 上运行相同的查询,一切都会正常。

更新:

此代码有效。它创建一个新数据库,一个使用 fts 的新虚拟表,插入几个项目,然后执行选择。稍后我会尝试更复杂的查询,但目前看来,我的应用程序的问题可能正如预期的那样是我的代码中的错误。

NSArray *dirPaths = dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docsDir = [dirPaths objectAtIndex:0];
sqlite3 *database;

// Build the path to the database file
NSString *databasePath = [[NSString alloc] initWithString: [docsDir stringByAppendingPathComponent: @"test.db"]];

NSFileManager *filemgr = [NSFileManager defaultManager];
NSError *error = nil;
[filemgr removeItemAtPath:databasePath error:&error];

const char *dbpath = [databasePath UTF8String];

if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
    char *errMsg;
    const char *sql_stmt = "CREATE VIRTUAL TABLE IF NOT EXISTS pages USING fts3(title, body);";

    if (sqlite3_exec(database, sql_stmt, NULL, NULL, &errMsg) != SQLITE_OK)
    {
        NSLog(@"Failed to create table");
    } else {

        sql_stmt = "INSERT INTO pages(docid, title, body) VALUES(53, 'Home Page', 'SQLite is a software...');";
        if (sqlite3_exec(database, sql_stmt, NULL, NULL, &errMsg) != SQLITE_OK)
        {
            NSLog(@"Failed to insert");
        }

        sql_stmt = "INSERT INTO pages(title, body) VALUES('Download', 'All SQLite source code...');";
        if (sqlite3_exec(database, sql_stmt, NULL, NULL, &errMsg) != SQLITE_OK)
        {
            NSLog(@"Failed to insert");
        }
    }

    sqlite3_stmt *statement;
    const char *query_stmt = "select * from pages where body match 'soft*';";

    if (sqlite3_prepare_v2(database, query_stmt, -1, &statement, NULL) == SQLITE_OK)
    {
        if (sqlite3_step(statement) == SQLITE_ROW)
        {
            NSLog(@"%@ - %@", [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 0)],
                  [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 1)]);
        } else {
            NSLog(@"no results");
        }
        sqlite3_finalize(statement);
    }

    sqlite3_close(database);

} else {
    NSLog(@"Failed to open/create database");
}

【问题讨论】:

  • 你有没有试过把 sqlite3 放在单独的静态库中,并用 llvm-gcc 而不是 clang 编译这个库?那它有用吗?
  • 是的,我有。有趣的是,如果我这样做,也会出现同样的问题。如果我做相反的事情(用 Clang 编译我的静态 SQLite 库,然后用 GCC 编译我的整个项目),它就可以工作。我不知道这背后的逻辑在哪里。
  • 也许它是由clang编译器触发的其余代码中的一些内存损坏(但gcc编译器生成的代码不会触发内存损坏)。
  • 是的,苹果工程师是这么说的。但问题是我只是在尝试一个简单的查询。本周晚些时候,我将分享一个简单的项目,以举例说明我的问题。非常感谢您的回复!

标签: ios sqlite full-text-search llvm


【解决方案1】:

毕竟,我已经找到了错误。它在我的代码中。总之,我发现: 如果我有类似的东西(我知道这很奇怪/错误):

int a = 0;
a = a++;
NSLog(@"%d", a);

如果此代码使用 gcc 编译,则记录值为 1,如果使用 llvm 编译,则记录值为 0。

我不知道为什么,但这是另一个问题:)

【讨论】:

  • 这看起来像是对旧编译器的错误修复。如果你有 a = ++a 它会按预期工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-22
  • 1970-01-01
  • 2011-11-25
  • 2011-08-31
相关资源
最近更新 更多