簡體   English   中英

在Flutter的C++代碼中使用Protobuf 3——如何編譯鏈接?

[英]Use Protobuf 3 In Flutter's C++ Code - How To Compile And Link?

Protobuf 是一個使用非常廣泛的庫,所以我想在 Flutter 的 C++ 代碼中使用它來序列化和反序列化我的數據。 但是,我發現編譯和鏈接 protobuf 庫並不是一件容易的事……我失敗了很多次才找到正確的解決方案,所以我想在這里以問答的方式分享。

准備

首先,當然,您需要生成 protobuf 文件。 這是本教程的scope,大家可以看看官方教程 假設您已經生成了hello.pb.hhello.pb.cc

iOS

如果您正在開發使用需要 protobuf 的 C++ 代碼的包/插件,請將以下內容添加到您的xxx.podspec中。 如果是你的may代碼需要protobuf,情況也是類似的。

Pod::Spec.new do |s|
  ...normal things...

  s.pod_target_xcconfig = {
    'HEADER_SEARCH_PATHS' => '$(SRCROOT)/Protobuf-C++/src',
  }
  
  s.dependency 'Protobuf-C++', '~> 3.18.0'
end

此外,您需要在主項目的Podfile中添加以下內容。 比如你正在開發一個package,有10個項目使用,每個項目都需要添加下面的section。

post_install do |installer|
  ...normal things...
  
  installer.pods_project.targets.each do |target|
    # print "target=", target, "\n"
    if target.name == "Protobuf-C++"
      target.build_configurations.each do |config|
        config.build_settings['HEADER_SEARCH_PATHS'] = '$(SRCROOT)/Protobuf-C++/src'
      end
    end
  end
end

然后清理並構建項目並享受!

備注:為什么我需要破解HEADER_SEARCH_PATHS :最初它出錯並說找不到 protobuf 標頭。 該解決方案建議我們在每次pod install后手動添加路徑。 此外,這個改進的解決方案表明我們可以通過添加幾行代碼來自動化該過程。 這就是我們上面所做的。

另一種方式

這個鏈接基本上工作得很好。 雖然在Cardboard的SDK教程下,但是這個網頁幾乎沒有談Cardboard特有的東西,只談protobuf。 因此,請隨時遵循它。 除了最后一步(“復制文件”)之外的所有步驟之后,您將得到: include/google/*lib/libprotobuf-lite.a

在開始之前,不要忘記make distclean來清理所有東西(如果你已經做過一些事情)。

備注 1:如果您在鏈接時看到錯誤,提示“Undefined symbols”和“ld: warning: ignoring file”,您可以點擊此鏈接來解決。

備注 2:該教程僅創建libprotobuf-lite.a 如果需要libprotobuf.a ,可以類推: lipo $build_dir/arch/arm64/lib/libprotobuf.a $build_dir/arch/armv7/lib/libprotobuf.a -create -output $build_dir/lib/libprotobuf.a

然后,您可以將.a和標頭放入您的 ios xcode 項目中。 我還沒有嘗試過這個,因為我使用上面的方法。

Android

獲取庫和標題

它比 iOS 稍微復雜一點。

在開始之前,不要忘記make distclean來清理所有東西(如果你已經做過一些事情)。

首先,按照與在 iOS 中生成您的 own.a 和標頭的方法相同的鏈接來執行git clonegit checkoutgit submodule./autogen.sh ,但停在那里不要繼續。

接下來,您需要按照這個答案對代碼進行一點修改——否則編譯將失敗。 請參考鏈接使用ltmain.sh.patch打補丁。 (至於fuse-ld標志我已經做了,所以你不需要做任何事情。)

現在是配置和編譯,如下所示。

export NDKDIR=/Users/tom/Library/Android/sdk/ndk/21.1.6352462/toolchains/llvm/prebuilt/darwin-x86_64
export SYSROOT=$NDKDIR/sysroot

./configure \
--prefix=/Users/tom/RefCode/libprotobuf/android \
--host=arm-linux-androideabi \
--with-sysroot="${SYSROOT}" \
--enable-shared \
--enable-cross-compile \
--with-protoc=protoc \
"CC=$NDKDIR/bin/armv7a-linux-androideabi26-clang" \
CFLAGS="-fPIC -fuse-ld=bfd -march=armv7-a -D__ANDROID_API__=26" \
"CXX=$NDKDIR/bin/armv7a-linux-androideabi26-clang++" \
CXXFLAGS="-fPIC -fuse-ld=bfd -frtti -fexceptions -march=armv7-a -D__ANDROID_API__=26" \
"RANLIB=$NDKDIR/bin/x86_64-linux-android-ranlib" \
"C_COMPILER_RANLIB=$NDKDIR/bin/x86_64-linux-android-ranlib" \
"CXX_COMPILER_RANLIB=$NDKDIR/bin/x86_64-linux-android-ranlib" \
"AR=$NDKDIR/bin/x86_64-linux-android-ar" \
LIBS="-llog -lz -lc++_static";
make -j8 && make install

備注:上面的命令與這篇文章相似但不相同,因為該文章中使用的 NDK 獨立工具鏈已被棄用。 當然,你可能需要改變你的版本,比如你自己的ndk的路徑,你的ndk版本等等。

備注:您可能還需要知道上面使用的命名約定。 例如,為什么有時是llvm ,為什么有時是darwin ,為什么是armv7a 它們在官方指南中有詳細描述。

備注:當您使用 Gradle 編譯您的 android 應用程序時,遇到 libprotobuf.a 問題時此鏈接也很有用libprotobuf.a: no archive symbol table (run ranlib)

備注:沒有-fPIC ,像requires unsupported dynamic reloc R_ARM_REL32; recompile with -fPIC requires unsupported dynamic reloc R_ARM_REL32; recompile with -fPIC 所以我點擊了這個鏈接來解決它。

備注:如果你看到錯誤如error: undefined reference to 'stderr' ,你可能需要把你的minSdkVersion大,比如改成23.ref

備注:更換物品后,可能需要多次清洗。 例如gradle sync,gradle clean,make distclean等。

指南類似,下一步是make -j8 ,然后是make install 然后你就完成了,你會看到一些庫,比如libprotobuf-lite.a以及包含的頭文件。

在你的項目中使用它

將以下內容添加到CMakeLists.txt

set(OPENCV_BASE_DIR "/some/absolute/path/to/your/base/dir/that/has/built/just/now")

message("PROTOBUF_BASE_DIR: ${PROTOBUF_BASE_DIR}")

set(PROTOBUF_INCLUDE_DIR "${PROTOBUF_BASE_DIR}/include/")
set(PROTOBUF_STATIC_LIB_DIR "${PROTOBUF_BASE_DIR}/lib")

if (NOT EXISTS ${PROTOBUF_INCLUDE_DIR})
    message(FATAL_ERROR "PROTOBUF_INCLUDE_DIR=${PROTOBUF_INCLUDE_DIR} does not exist - have you provided the correct PROTOBUF_BASE_DIR=${PROTOBUF_BASE_DIR}")
endif ()

include_directories(${PROTOBUF_INCLUDE_DIR})

add_library(protobuf-lite STATIC IMPORTED)
set_target_properties(protobuf-lite PROPERTIES IMPORTED_LOCATION ${PROTOBUF_STATIC_LIB_DIR}/libprotobuf-lite.a)

add_library(protobuf STATIC IMPORTED)
set_target_properties(protobuf PROPERTIES IMPORTED_LOCATION ${PROTOBUF_STATIC_LIB_DIR}/libprotobuf.a)

target_link_libraries(yourapp
        ...others...

        protobuf
        )

由於我在上面的代碼中只為 armv7 而不是 armv8 構建,我們可以添加一個 abi 過濾器,如下所示。 或者,您也可以為 armv8 構建並將它們合並到一個胖庫中,就像我們在 ios 中所做的那樣。

build.gradle :

android {
    defaultConfig {
        externalNativeBuild {
            cmake {
                abiFilters 'armeabi-v7a'
            }
        }
    }
}

獎勵:MacOS

獲取庫和標題

如果你想在你的 mac 電腦上也使用你的 C++ 代碼(帶 protobuf)怎么辦?

在開始之前,不要忘記make distclean來清理所有東西(如果你已經做過一些事情)。

此鏈接類似,您只需要將./configure更改為:

./configure CC=clang CXX="clang++ -std=c++11 -stdlib=libc++" CXXFLAGS="-O3" --disable-shared

其他的和指南幾乎一樣,比如下載、配置、 make ,最后sudo make install (注意這里需要 sudo)。

您將在系統的 include 目錄中看到標頭,在系統的 lib 文件夾中看到 libs。

在你的項目中使用它

如果您使用的是 CMake,它主要是標准的。 首先,將path/to/your/hello.pb.cc到你的add_executable中。 其次,將/usr/local/lib/libprotobuf.a添加到您的target_link_libraries 完整示例:

add_executable(app
        ./main.cpp
        path/to/your/hello.pb.cc
        ... others ...
        )
        
target_link_libraries(app
        /usr/local/lib/libprotobuf.a
        ... others ...
        )

備注: libprotobuf-lite.a有時是不夠的,所以你需要鏈接到 big lib 而不是 lite lib。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM