ForestDB linker errors during iOS app build

Using Xcode’s “iOS single view” template, I created a simple app and successfully linked CouchbaseLite. The app runs fine using the SQLite storage backend.

Now I want to try ForestDB. I added libCBLForestDBStorage.a and libc++ to the link. I ensure that -ObjC is included in “Other Linker Flags”. The link fails with the errors shown below. Basically it appears that the ForestDB library wants to link against symbols in the CouchbaseLite framework that are there, but are not external symbols. For example, nm shows us that CBLStemmerNameForCurrentLocale is not an externally visible symbol (the ‘t’ isn’t a ‘T’):

$ nm CouchbaseLite | grep CBLStemmerNameForCurrentLocale
0000000000046020 t _CBLStemmerNameForCurrentLocale

Is that really what is going on? Am I missing something basic here? Why won’t the link work?

Platform: iOS Xcode: 8.2.1 CouchbaseLite/ForestDB: 1.3.2 (locally compiled), 1.3.1 (when I tried via CocoaPods)

    Undefined symbols for architecture x86_64:
      "_sqlite3_prepare_v2", referenced from:
          _register_unicodesn_tokenizer in libCBLForestDBStorage.a(sqlite3_unicodesn_tokenizer.o)
      "_CBLWithStringBytes", referenced from:
          -[CBL_ForestDBStorage getC4Doc:status:] in libCBLForestDBStorage.a(CBL_ForestDBStorage.o)
      "_sqlite3_bind_text", referenced from:
          _register_unicodesn_tokenizer in libCBLForestDBStorage.a(sqlite3_unicodesn_tokenizer.o)
      "__dictof", referenced from:
          -[CBL_ForestDBDocEnumerator generateNextRow] in libCBLForestDBStorage.a(CBL_ForestDBDocEnumerator.o)
          -[CBL_ForestDBViewStorage dump] in libCBLForestDBStorage.a(CBL_ForestDBViewStorage.o)
      "_sqlite3_malloc", referenced from:
          _unicodeCreate in libCBLForestDBStorage.a(fts3_unicodesn.o)
          _unicodeOpen in libCBLForestDBStorage.a(fts3_unicodesn.o)
          _create_s in libCBLForestDBStorage.a(utilities_sq3.o)
          _local_calloc in libCBLForestDBStorage.a(api_sq3.o)
      "_sqlite3_finalize", referenced from:
          _register_unicodesn_tokenizer in libCBLForestDBStorage.a(sqlite3_unicodesn_tokenizer.o)
      "__AssertFailed", referenced from:
          +[CBL_ForestDBViewStorage initialize] in libCBLForestDBStorage.a(CBL_ForestDBViewStorage.o)
          -[CBL_ForestDBViewStorage initWithDBStorage:name:create:] in libCBLForestDBStorage.a(CBL_ForestDBViewStorage.o)
          CBL::addToKey(c4Key*, objc_object*) in libCBLForestDBStorage.a(CBLForestBridge.o)
          CBL::key2id_(C4KeyReader*) in libCBLForestDBStorage.a(CBLForestBridge.o)
          CBL::err2status(C4Error) in libCBLForestDBStorage.a(CBLForestBridge.o)
          CBL::symmetricKey2Forest(CBLSymmetricKey*) in libCBLForestDBStorage.a(CBLForestBridge.o)
          +[CBLForestBridge bodyOfSelectedRevision:] in libCBLForestDBStorage.a(CBLForestBridge.o)
          ...
      "_sqlite3_bind_blob", referenced from:
          _register_unicodesn_tokenizer in libCBLForestDBStorage.a(sqlite3_unicodesn_tokenizer.o)
      "_sqlite3_step", referenced from:
          _register_unicodesn_tokenizer in libCBLForestDBStorage.a(sqlite3_unicodesn_tokenizer.o)
      "_MYReportException", referenced from:
          -[CBL_ForestDBViewStorage updateIndexes:] in libCBLForestDBStorage.a(CBL_ForestDBViewStorage.o)
          -[CBL_ForestDBQueryEnumerator callReduce] in libCBLForestDBStorage.a(CBL_ForestDBQueryEnumerator.o)
      "_OBJC_CLASS_$_CBL_RevID", referenced from:
          objc-class-ref in libCBLForestDBStorage.a(CBL_ForestDBStorage.o)
          objc-class-ref in libCBLForestDBStorage.a(CBLForestBridge.o)
      "_sqlite3_realloc", referenced from:
          _unicodeNext in libCBLForestDBStorage.a(fts3_unicodesn.o)
          _unicodeAddExceptions in libCBLForestDBStorage.a(fts3_unicodesn.o)
          _increase_size in libCBLForestDBStorage.a(utilities_sq3.o)
      "_OBJC_CLASS_$_MYAction", referenced from:
          objc-class-ref in libCBLForestDBStorage.a(CBL_ForestDBStorage.o)
          objc-class-ref in libCBLForestDBStorage.a(CBL_ForestDBViewStorage.o)
      "_sqlite3_free", referenced from:
          _unicodeDestroy in libCBLForestDBStorage.a(fts3_unicodesn.o)
          _unicodeOpen in libCBLForestDBStorage.a(fts3_unicodesn.o)
          _unicodeClose in libCBLForestDBStorage.a(fts3_unicodesn.o)
          _lose_s in libCBLForestDBStorage.a(utilities_sq3.o)
          _SN_close_env in libCBLForestDBStorage.a(api_sq3.o)
      "_Database_LogDomain", referenced from:
          +[CBL_ForestDBStorage initialize] in libCBLForestDBStorage.a(CBL_ForestDBStorage.o)
          FDBLogCallback(C4LogLevel, C4Slice) in libCBLForestDBStorage.a(CBL_ForestDBStorage.o)
          -[CBL_ForestDBStorage reopen:] in libCBLForestDBStorage.a(CBL_ForestDBStorage.o)
          -[CBL_ForestDBStorage inTransaction:] in libCBLForestDBStorage.a(CBL_ForestDBStorage.o)
          -[CBL_ForestDBStorage getDocumentWithID:revisionID:withBody:status:] in libCBLForestDBStorage.a(CBL_ForestDBStorage.o)
          -[CBL_ForestDBStorage getBodyWithID:sequence:status:] in libCBLForestDBStorage.a(CBL_ForestDBStorage.o)
          -[CBL_ForestDBStorage purgeRevisions:result:] in libCBLForestDBStorage.a(CBL_ForestDBStorage.o)
          ...
      "_OBJC_CLASS_$_MYBackgroundMonitor", referenced from:
          objc-class-ref in libCBLForestDBStorage.a(CBL_ForestDBStorage.o)
      "__castIf", referenced from:
          ___45-[CBL_ForestDBStorage purgeRevisions:result:]_block_invoke in libCBLForestDBStorage.a(CBL_ForestDBStorage.o)
          -[CBL_ForestDBQueryEnumerator generateNextRow] in libCBLForestDBStorage.a(CBL_ForestDBQueryEnumerator.o)
      "__mdictof", referenced from:
          -[CBL_ForestDBStorage purgeRevisions:result:] in libCBLForestDBStorage.a(CBL_ForestDBStorage.o)
      "_gMYWarnRaisesException", referenced from:
          FDBLogCallback(C4LogLevel, C4Slice) in libCBLForestDBStorage.a(CBL_ForestDBStorage.o)
      "_$equal", referenced from:
          -[CBL_ForestDBStorage findMissingRevisions:status:] in libCBLForestDBStorage.a(CBL_ForestDBStorage.o)
          -[CBL_ForestDBStorage getLocalDocumentWithID:revisionID:] in libCBLForestDBStorage.a(CBL_ForestDBStorage.o)
          ___71-[CBL_ForestDBStorage putLocalRevision:prevRevisionID:obeyMVCC:status:]_block_invoke in libCBLForestDBStorage.a(CBL_ForestDBStorage.o)
          ___69-[CBL_ForestDBStorage deleteLocalDocumentWithID:revisionID:obeyMVCC:]_block_invoke in libCBLForestDBStorage.a(CBL_ForestDBStorage.o)
          +[CBL_ForestDBViewStorage initialize] in libCBLForestDBStorage.a(CBL_ForestDBViewStorage.o)
      "_CBLKeyForPrefixMatch", referenced from:
          -[CBL_ForestDBDocEnumerator initWithStorage:options:error:] in libCBLForestDBStorage.a(CBL_ForestDBDocEnumerator.o)
          -[CBL_ForestDBQueryEnumerator _createQueryWithOptions:customSkipOrLimit:onView:error:] in libCBLForestDBStorage.a(CBL_ForestDBQueryEnumerator.o)
      "__castArrayOf", referenced from:
          -[CBL_ForestDBStorage findCommonAncestorOf:withRevIDs:] in libCBLForestDBStorage.a(CBL_ForestDBStorage.o)
          -[CBL_ForestDBStorage forceInsert:revisionHistory:validationBlock:source:error:] in libCBLForestDBStorage.a(CBL_ForestDBStorage.o)
      "_CBLStemmerNameForCurrentLocale", referenced from:
          +[CBL_ForestDBViewStorage initialize] in libCBLForestDBStorage.a(CBL_ForestDBViewStorage.o)
      "_Query_LogDomain", referenced from:
          -[CBL_ForestDBDocEnumerator generateNextRow] in libCBLForestDBStorage.a(CBL_ForestDBDocEnumerator.o)
          -[CBL_ForestDBQueryEnumerator generateNextRow] in libCBLForestDBStorage.a(CBL_ForestDBQueryEnumerator.o)
          -[CBL_ForestDBQueryEnumerator nextObjectReduced] in libCBLForestDBStorage.a(CBL_ForestDBQueryEnumerator.o)

I suspect you’re using the dynamic-library version of Couchbase Lite, not the static library. We don’t distribute builds of the dynamic library (because it’s not compatible with iOS 7), but if you’re building yourself, the “CBL iOS Framework” target builds it.

You can tell the difference by running file CouchbaseLite.framework/CouchbaseLite – this will tell you whether it’s a Mach-O dynamic library or a “ranlib current archive” (static).

Anyway, the dynamic library doesn’t currently support ForestDB. (This could be fixed, but there hasn’t been a high priority need to, so it hasn’t been done yet.) I suggest you build the “CBL iOS” target instead, which builds the static library; that will allow you to link in ForestDB.

The two frameworks look identical, but you will probably need to remove the old framework from your app target and then add the new one; otherwise I think Xcode gets confused about the library changing from dynamic to static.

Reply if you have any further problems and I’ll try to help out.

hi @jens I was trying to build the CouchbaseLite iOS using Carthage. Does it return dynamic or static framework? We want to forestDB in our project. We have Carthage setup in all our CI. Please suggest the steps to use forestDB in swift with Carthage .

Thanks,

IIRC, Carthage always builds dynamic frameworks. You’ll need to choose between Carthage and using ForestDB.

It’s worth noting that in CBL 2.0 we’ve stopped using ForestDB, and gone with SQLite only. We were able to greatly improve our performance with SQLite (by literally 5x to 10x), and we’re also using more of the advanced query features it provides.

thank you @jens We will wait for 2.0 :slight_smile:

You could continue to work with 1.4 using SQLite (the only difference is performance, really), or since you’re just starting a project, you could use the current 2.0 developer builds now.

We are already using 1.4. To improve the performance of the current application, we plan on trying the ForestDB but since Carthage and ForestDB will not work together (at least v1.4) we will continue with 1.4 for now

As Jens mentioned, Developer Builds of 2.0 are available for download and use . So you can start developing with them right away and leverage the huge performance improvements and other capabilities that we’ve included in 2.0. As a headsup, the next Developer Build should be out in a day or two (The one thats out there is from two weeks ago).

1 Like