WCDB命令行編譯報錯解決方案

目錄

  1. 問題
  2. 嘗試 xcodebuild
  3. 查看 WCDB 是怎麼編譯
  4. 嘗試自動靜態庫
  5. 嘗試手動靜態庫
  6. 總結

1. 問題

因爲項目需求,須要使用一款數據庫,直接使用 sqlite 會手動寫不少 sql 代碼,也容易出錯。使用蘋果官方的 core data,core data 不是線程安全的,須要嚴格區分在不一樣的線程使用不一樣的 manage context,使用上也增長了代碼複雜度,也會更容易出現 bug。因而考慮下基於 sqlite 的開源方案。ios

FMDB: 其實就是 sqlite 的語法糖,多線程訪問須要使用專門的 queue,不支持 ORM。
Realm: 是爲速度而生的數據庫,不少配套設施並不齊全。
WCDB: 性能高,支持線程安全,支持 ORM。缺點:1. 基於objective c++,因此只要使用到了 WCDB 的地方,都須要以 mm 爲文件後綴。2. 增大包體積。

想找到一款易使用有安全的數據庫,最後仍是考慮使用了 WCDB, 雖然它也有本身的不足,可是仍是能夠接受的。c++

因而經過 pod 在項目中使用了 WCDB,並寫了小 demo 熟悉下了使用方式。git

pod 'WCDB'

在熟悉了使用方式以後,就能夠在項目裏使用了,在開發階段都是經過模擬器或者真機測試,覺得都很好。可是在搭建 Bamboo 的 CICD 就會報如下錯。github

fts5_storage.c:305:9: error: 'sqlite3_api_routines' has no member named '__builtin___snprintf_chk'

The following build commands failed:
    CompileC /Users/karosli/Library/Developer/Xcode/DerivedData/xxx-dleyffpkgrddqzfvrhnoakpqgdvz/Build/Intermediates.noindex/ArchiveIntermediates/LefitCoach/IntermediateBuildFilesPath/Pods.build/Debug-iphoneos/WCDB.build/Objects-normal/armv7/fts5.o WCDB/sqlcipher/fts5.c normal armv7 c com.apple.compilers.llvm.clang.1_0.compiler
(1 failure)

<!--more-->sql

2. 嘗試 xcodebuild

因爲 CICD 使用的是基於 flastlane gym 的 shell 腳本,於是懷疑是否是 fastlane 的緣由呢,由於我在 Xcode 上直接運行是好的。因此就嘗試使用 xcodebuild 去編譯打包。shell

# fastlane gym --silent --workspace ${app_workspace} --scheme ${app_schema} --clean --xcargs 'GCC_PREPROCESSOR_DEFINITIONS="$GCC_PREPROCESSOR_DEFINITIONS DEBUG=1 COCOAPODS=1"' --export_method development --output_directory ${outputDir} --output_name ${app_ipa_file}

# 把上面替換成下面的命令
# archive
  xcodebuild archive -sdk iphoneos -workspace ${app_workspace} -scheme ${app_schema} -configuration Debug -archivePath ${outputDir} GCC_PREPROCESSOR_DEFINITIONS="$GCC_PREPROCESSOR_DEFINITIONS DEBUG=1 COCOAPODS=1"
# export ipa
xcodebuild -exportArchive -exportFormat IPA -archivePath ${outputDir} -exportPath ${app_ipa_file} -exportOptionsPlist exportOptions_dev.plist

3. 查看 WCDB 是怎麼編譯

因爲 WCDB 經過 pod 的方式是能夠再 Xcode 上運行的,猜測下是否是 WCDB.podspec 裏面作了額外的事情。數據庫

能夠看到文件裏面多了一個預處理命令 wcdb.prepare_commandmacos

# pod lib lint --verbose --skip-import-validation WCDB.podspec
# pod trunk push WCDB.podspec --verbose --skip-import-validation
Pod::Spec.new do |wcdb|
  wcdb.name         = "WCDB"
  wcdb.version      = "1.0.6"
  wcdb.summary      = "WCDB is a cross-platform database framework developed by WeChat."
  wcdb.description  = <<-DESC
                      The WeChat Database, for Objective-C. (If you want to use WCDB from Objective-C, see the "WCDBSwift" pod.)

                      WCDB is an efficient, complete, easy-to-use mobile database framework used in the WeChat application.
                      It can be a replacement for Core Data, SQLite & FMDB.
                      DESC
  wcdb.homepage     = "https://github.com/Tencent/wcdb"
  wcdb.license      = { :type => "BSD", :file => "LICENSE"}
  wcdb.author             = { "sanhuazhang" => "sanhuazhang@tencent.com" }
  wcdb.ios.deployment_target = "7.0"
  wcdb.osx.deployment_target = "10.9"
  wcdb.watchos.deployment_target = "2.0"
  wcdb.tvos.deployment_target = "9.0"
  wcdb.source       = { :git => "https://github.com/Tencent/wcdb.git", :tag => "v#{wcdb.version}" }
  wcdb.public_header_files = "objc/WCDB/WCDB.h", "objc/WCDB/**/*.{h,hpp}"
  wcdb.source_files  = "objc/WCDB/WCDB.h", "objc/WCDB/**/*.{h,m,hpp,cpp,mm}", "repair"
  wcdb.frameworks = "CoreFoundation", "Security", "Foundation"
  wcdb.ios.frameworks = "UIKit"
  wcdb.libraries = "z", "c++"
  wcdb.requires_arc = true
  wcdb.prepare_command = "git submodule update --init sqlcipher; \
                          cd tools/templates; sh install.sh; cd ../..; \
                          cd sqlcipher; make -f Makefile.preprocessed; cd ..; \
                          cp sqlcipher/ext/fts3/fts3_tokenizer.h sqlcipher/"
  wcdb.xcconfig = {
    "GCC_PREPROCESSOR_DEFINITIONS" => "$(inherited) WCDB_BUILTIN_COLUMN_CODING WCDB_COCOAPODS",
    "HEADER_SEARCH_PATHS" => "$(inherited) ${PODS_ROOT}/WCDB",
    "LIBRARY_SEARCH_PATHS[sdk=macosx*]" => "$(inherited) $(SDKROOT)/usr/lib/system",
    "CLANG_CXX_LANGUAGE_STANDARD" => "gnu++0x",
    "CLANG_CXX_LIBRARY" => "libc++",
  }

  wcdb.subspec 'sqlcipher' do |sqlcipher|
    sqlcipher.public_header_files = "sqlcipher/sqlite3.h", "sqlcipher/fts3_tokenizer.h"
    sqlcipher.source_files = "sqlcipher/src/callback.c", "sqlcipher/src/loadext.c", "sqlcipher/src/rowset.c", "sqlcipher/src/treeview.c", "sqlcipher/ext/userauth.c", "sqlcipher/src/vtab.c", "sqlcipher/src/btmutex.c", "sqlcipher/src/btree.c", "sqlcipher/src/btreeInt.h", "sqlcipher/src/btree.h", "sqlcipher/fts5.c", "sqlcipher/fts5.h", "sqlcipher/ext/fts3/fts3_aux.c", "sqlcipher/ext/fts3/fts3_expr.c", "sqlcipher/ext/fts3/fts3_hash.c", "sqlcipher/ext/fts3/fts3_hash.h", "sqlcipher/ext/fts3/fts3_icu.c", "sqlcipher/ext/fts3/fts3_porter.c", "sqlcipher/ext/fts3/fts3_snippet.c", "sqlcipher/ext/fts3/fts3_tokenize_vtab.c", "sqlcipher/ext/fts3/fts3_tokenizer.c", "sqlcipher/ext/fts3/fts3_tokenizer1.c", "sqlcipher/ext/fts3/fts3_unicode.c", "sqlcipher/ext/fts3/fts3_unicode2.c", "sqlcipher/ext/fts3/fts3_write.c", "sqlcipher/ext/fts3/fts3.c", "sqlcipher/ext/fts3/fts3.h", "sqlcipher/ext/fts3/fts3Int.h", "sqlcipher/src/backup.c", "sqlcipher/src/legacy.c", "sqlcipher/src/main.c", "sqlcipher/src/notify.c", "sqlcipher/src/vdbeapi.c", "sqlcipher/src/table.c", "sqlcipher/src/wal.c", "sqlcipher/src/wal.h", "sqlcipher/src/status.c", "sqlcipher/src/prepare.c", "sqlcipher/src/malloc.c", "sqlcipher/src/mem0.c", "sqlcipher/src/mem1.c", "sqlcipher/src/mem2.c", "sqlcipher/src/mem3.c", "sqlcipher/src/mem5.c", "sqlcipher/src/memjournal.c", "sqlcipher/src/mutex_unix.c", "sqlcipher/src/mutex_noop.c", "sqlcipher/src/mutex.c", "sqlcipher/src/mutex.h", "sqlcipher/src/os_common.h", "sqlcipher/src/os_setup.h", "sqlcipher/src/os_unix.c", "sqlcipher/src/queue.c", "sqlcipher/src/queue.h", "sqlcipher/src/os_wcdb.c", "sqlcipher/src/os_wcdb.h", "sqlcipher/src/mutex_wcdb.c", "sqlcipher/src/mutex_wcdb.h", "sqlcipher/src/os.c", "sqlcipher/src/os.h", "sqlcipher/src/threads.c", "sqlcipher/src/bitvec.c", "sqlcipher/src/pager.c", "sqlcipher/src/pager.h", "sqlcipher/src/pcache.c", "sqlcipher/src/pcache.h", "sqlcipher/src/pcache1.c", "sqlcipher/ext/rtree/rtree.c", "sqlcipher/ext/rtree/rtree.h", "sqlcipher/ext/rtree/sqlite3rtree.h", "sqlcipher/src/complete.c", "sqlcipher/src/tokenize.c", "sqlcipher/src/resolve.c", "sqlcipher/parse.c", "sqlcipher/parse.h", "sqlcipher/src/analyze.c", "sqlcipher/src/func.c", "sqlcipher/src/wherecode.c", "sqlcipher/src/whereexpr.c", "sqlcipher/src/whereInt.h", "sqlcipher/src/alter.c", "sqlcipher/src/attach.c", "sqlcipher/src/auth.c", "sqlcipher/src/build.c", "sqlcipher/src/delete.c", "sqlcipher/src/expr.c", "sqlcipher/src/insert.c", "sqlcipher/src/pragma.c", "sqlcipher/src/pragma.h", "sqlcipher/src/select.c", "sqlcipher/src/trigger.c", "sqlcipher/src/update.c", "sqlcipher/src/vacuum.c", "sqlcipher/src/walker.c", "sqlcipher/src/where.c", "sqlcipher/opcodes.c", "sqlcipher/opcodes.h", "sqlcipher/src/sqlcipher.h", "sqlcipher/sqlite3.h", "sqlcipher/ext/rbu/sqlite3rbu.c", "sqlcipher/ext/rbu/sqlite3rbu.h", "sqlcipher/ext/userauth/sqlite3userauth.h", "sqlcipher/ext/misu/json1.c", "sqlcipher/ext/icu/icu.c", "sqlcipher/ext/icu/sqliteicu.h", "sqlcipher/src/global.c", "sqlcipher/src/ctime.c", "sqlcipher/src/hwtime.h", "sqlcipher/src/date.c", "sqlcipher/src/dbstat.c", "sqlcipher/src/fault.c", "sqlcipher/src/fkey.c", "sqlcipher/src/sqliteInt.h", "sqlcipher/src/sqliteLimit.h", "sqlcipher/src/sqlite3ext.h", "sqlcipher/src/hash.c", "sqlcipher/src/hash.h", "sqlcipher/src/printf.c", "sqlcipher/src/random.c", "sqlcipher/src/utf.c", "sqlcipher/src/util.c", "sqlcipher/src/crypto_cc.c", "sqlcipher/src/crypto_impl.c", "sqlcipher/src/crypto_libtomcrypt.c", "sqlcipher/src/crypto.c", "sqlcipher/src/crypto.h", "sqlcipher/src/vdbe.c", "sqlcipher/src/vdbe.h", "sqlcipher/src/vdbeaux.c", "sqlcipher/src/vdbeblob.c", "sqlcipher/src/vdbeInt.h", "sqlcipher/src/vdbemem.c", "sqlcipher/src/vdbesort.c", "sqlcipher/src/vdbetrace.c", "sqlcipher/src/msvc.h", "sqlcipher/src/vxworks.h", "sqlcipher/fts3_tokenizer.h", "sqlcipher/keywordhash.h"
    sqlcipher.ios.deployment_target = "8.0"
    sqlcipher.osx.deployment_target = "10.9"
    sqlcipher.watchos.deployment_target = "2.0"
    sqlcipher.tvos.deployment_target = "9.0"
    sqlcipher.xcconfig = {
      "GCC_PREPROCESSOR_DEFINITIONS" => "$(inherited) SQLITE_ENABLE_FTS3 SQLITE_ENABLE_FTS3_PARENTHESIS SQLITE_ENABLE_API_ARMOR SQLITE_OMIT_BUILTIN_TEST SQLITE_OMIT_AUTORESET SQLITE_ENABLE_UPDATE_DELETE_LIMIT SQLITE_ENABLE_RTREE SQLITE_ENABLE_LOCKING_STYLE=1 SQLITE_SYSTEM_MALLOC SQLITE_OMIT_LOAD_EXTENSION SQLITE_CORE SQLITE_THREADSAFE=2 SQLITE_DEFAULT_CACHE_SIZE=250 SQLITE_DEFAULT_CKPTFULLFSYNC=1 SQLITE_DEFAULT_PAGE_SIZE=4096 SQLITE_OMIT_SHARED_CACHE SQLITE_HAS_CODEC SQLCIPHER_CRYPTO_CC USE_PREAD=1 SQLITE_TEMP_STORE=2 SQLCIPHER_PREPROCESSED HAVE_USLEEP SQLITE_MALLOC_SOFT_LIMIT=0 SQLITE_WCDB_SIGNAL_RETRY=1 SQLITE_DEFAULT_MEMSTATUS=0 SQLITE_ENABLE_COLUMN_METADATA SQLITE_DEFAULT_WAL_SYNCHRONOUS=1 SQLITE_LIKE_DOESNT_MATCH_BLOBS SQLITE_MAX_EXPR_DEPTH=0 SQLITE_OMIT_DEPRECATED SQLITE_OMIT_PROGRESS_CALLBACK SQLITE_OMIT_SHARED_CACHE OMIT_CONSTTIME_MEM OMIT_MEMLOCK SQLITE_ENABLE_FTS3_TOKENIZER",
      "CLANG_WARN_CONSTANT_CONVERSION" => "YES",
      "GCC_WARN_64_TO_32_BIT_CONVERSION" => "NO",
      "CLANG_WARN_UNREACHABLE_CODE" => "NO",
      "GCC_WARN_UNUSED_FUNCTION" => "NO",
      "GCC_WARN_UNUSED_VARIABLE" => "NO",
    }
  end
end

Makefile.preprocessedjson

./configure --enable-tempstore=yes --with-crypto-lib=commoncrypto CFLAGS="-DSQLITE_HAS_CODEC -DSQLITE_TEMP_STORE=2 -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT" --disable-amalgamation
    make opcodes.h opcodes.c keywordhash.h fts5.c fts5.h sqlite3.h parse.h parse.c

這裏裏面作了預編譯處理。因而就想怎麼在命令行裏面加入這樣的命令,嘗試了不少了方式,發現沒有那麼簡單,因此就擱淺在這裏了,不要打我,還請大神能幫我解答下。api

4. 嘗試自動靜態庫

因而就另闢蹊徑,想到了靜態庫,把 WCDB 作成靜態庫的形式,那麼再命令行打包的時候,不會再次編譯了。

因而想到了 cocoapod package,去自動打成靜態庫,須要創建一個殼工程,裏面用 pod 安裝 WCDB,而後用命令行打靜態庫。教程在這裏

sudo gem install cocoapods-packager
pod package XXDatabase.podspec --force

成功後,會生成一個帶版本號的庫目錄,而後把裏面的 framework 放到單獨的測試工程師測試,最後發現編譯是經過的,可是找不到 WCDB 的頭文件(即便 podspec 文件配置了 s.public_header_files = 'Pods/**/*.h'),此路不通。

5. 嘗試手動靜態庫

因而嘗試用手動的方式去打靜態庫,手動方式就有兩種方案了。

方案一: 使用 WCDB 官方的教程是打靜態庫。
方案二: 經過 lipo 命令合併模擬器和真機靜態庫。

使用方案一打出來的靜態庫,若是在主工程裏使用沒有問題,一旦放入到單獨的 pod 裏,檢測的時候,就會上傳失敗。因此放棄了。

而後嘗試方案二,打出的包能夠引入工程,代碼編譯沒有錯,可是一運行就報錯了。
9551AE95-F6FA-4919-9B67-DD25DC1031CA.png

真是懵逼,百思不得解,後來想一想,我如今打開的工程是 WCDB 的 master 分支,而 pod repo 裏面的是 1.0.6 的 tag,因此就切換到 1.0.6 上從新進行方案二。

果真經過這個 tag 打出來的靜態庫是沒有問題的,放入到測試工程(須要加上 other linker flags: $(inherited) -ObjC -all_load),模擬器和真機測試皆可經過。靜態庫製做教程

剩下就是用一個單獨的 pod 基礎組件去包含這個靜態庫,而後
讓其餘業務組件引入這個 pod 基礎組件就能夠避免這個靜態庫存在多份。

6. 總結

雖然最後是問題是解決了,但也說明本身在編譯原理上的欠缺,因此後面仍是要補充這塊的姿式啊。

參考

https://github.com/Tencent/wc...
http://www.sqlite.org/src/inf...
https://www.jianshu.com/p/815...
https://www.jianshu.com/p/50e...
https://www.jianshu.com/p/283...
https://www.jianshu.com/p/7f6...

相關文章
相關標籤/搜索