ব্যাজেলের সাথে অ্যান্ড্রয়েড নেটিভ ডেভেলপমেন্ট কিট ব্যবহার করা হচ্ছে

আপনি যদি Bazel-এ নতুন হয়ে থাকেন, অনুগ্রহ করে বিল্ডিং অ্যান্ড্রয়েড উইথ বেজেল টিউটোরিয়াল দিয়ে শুরু করুন।

ওভারভিউ

Bazel অনেকগুলি বিভিন্ন বিল্ড কনফিগারেশনে চলতে পারে, যার মধ্যে অনেকগুলি রয়েছে যা Android নেটিভ ডেভেলপমেন্ট কিট (NDK) টুলচেন ব্যবহার করে। এর মানে হল যে সাধারণ cc_library এবং cc_binary নিয়মগুলি সরাসরি Bazel-এর মধ্যে Android-এর জন্য কম্পাইল করা যেতে পারে। Bazel android_ndk_repository রিপোজিটরি নিয়ম ব্যবহার করে এটি সম্পন্ন করে।

পূর্বশর্ত

আপনি Android SDK এবং NDK ইনস্টল করেছেন তা নিশ্চিত করুন।

SDK এবং NDK সেট আপ করতে, আপনার WORKSPACE নিম্নলিখিত স্নিপেট যোগ করুন:

android_sdk_repository(
    name = "androidsdk", # Required. Name *must* be "androidsdk".
    path = "/path/to/sdk", # Optional. Can be omitted if `ANDROID_HOME` environment variable is set.
)

android_ndk_repository(
    name = "androidndk", # Required. Name *must* be "androidndk".
    path = "/path/to/ndk", # Optional. Can be omitted if `ANDROID_NDK_HOME` environment variable is set.
)

android_ndk_repository নিয়ম সম্পর্কে আরও তথ্যের জন্য, বিল্ড এনসাইক্লোপিডিয়া এন্ট্রি দেখুন।

দ্রুত শুরু

Android এর জন্য C++ তৈরি করতে, আপনার android_binary বা android_library নিয়মে cc_library নির্ভরতা যোগ করুন।

উদাহরণস্বরূপ, একটি Android অ্যাপের জন্য নিম্নলিখিত BUILD ফাইল দেওয়া হয়েছে:

# In <project>/app/src/main/BUILD.bazel

cc_library(
    name = "jni_lib",
    srcs = ["cpp/native-lib.cpp"],
)

android_library(
    name = "lib",
    srcs = ["java/com/example/android/bazel/MainActivity.java"],
    resource_files = glob(["res/**/*"]),
    custom_package = "com.example.android.bazel",
    manifest = "LibraryManifest.xml",
    deps = [":jni_lib"],
)

android_binary(
    name = "app",
    deps = [":lib"],
    manifest = "AndroidManifest.xml",
)

এই BUILD ফাইলটি নিম্নলিখিত লক্ষ্য গ্রাফে ফলাফল দেয়:

Example results

চিত্র 1. cc_library নির্ভরতা সহ Android প্রকল্পের গ্রাফ তৈরি করুন।

অ্যাপটি তৈরি করতে, কেবল চালান:

bazel build //app/src/main:app

bazel build কমান্ড জাভা ফাইল, অ্যান্ড্রয়েড রিসোর্স ফাইল এবং cc_library নিয়মগুলি সংকলন করে এবং সবকিছুকে একটি APK-তে প্যাকেজ করে:

$ zipinfo -1 bazel-bin/app/src/main/app.apk
nativedeps
lib/armeabi-v7a/libapp.so
classes.dex
AndroidManifest.xml
...
res/...
...
META-INF/CERT.SF
META-INF/CERT.RSA
META-INF/MANIFEST.MF

ব্যাজেল সমস্ত cc_লাইব্রেরিকে একটি একক ভাগ করা বস্তু ( .so ) ফাইলে কম্পাইল করে, যা ডিফল্টরূপে armeabi-v7a ABI-এর জন্য লক্ষ্য করা হয়। এটি পরিবর্তন করতে বা একই সময়ে একাধিক ABI-এর জন্য তৈরি করতে, লক্ষ্য ABI কনফিগার করার বিভাগটি দেখুন।

উদাহরণ সেটআপ

এই উদাহরণটি Bazel উদাহরণ সংগ্রহস্থলে পাওয়া যায়।

BUILD.bazel ফাইলে, তিনটি লক্ষ্য android_binary , android_library , এবং cc_library নিয়ম দিয়ে সংজ্ঞায়িত করা হয়েছে।

android_binary টপ-লেভেল টার্গেট APK তৈরি করে।

cc_library লক্ষ্যে একটি JNI ফাংশন বাস্তবায়নের সাথে একটি একক C++ উৎস ফাইল রয়েছে:

#include <jni.h>
#include <string>

extern "C"
JNIEXPORT jstring

JNICALL
Java_com_example_android_bazel_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

android_library টার্গেট জাভা সোর্স, রিসোর্স ফাইল এবং cc_library টার্গেটের উপর নির্ভরতা নির্দিষ্ট করে। এই উদাহরণের জন্য, MainActivity.java শেয়ার করা অবজেক্ট ফাইল libapp.so লোড করে এবং JNI ফাংশনের জন্য পদ্ধতি স্বাক্ষর সংজ্ঞায়িত করে:

public class MainActivity extends AppCompatActivity {

    static {
        System.loadLibrary("app");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
       // ...
    }

    public native String stringFromJNI();

}

STL কনফিগার করা হচ্ছে

C++ STL কনফিগার করতে, পতাকা ব্যবহার করুন --android_crosstool_top

bazel build //:app --android_crosstool_top=target label

@ @androidndk এ উপলব্ধ STLগুলি হল:

STL লক্ষ্য লেবেল
STLport @androidndk//:toolchain-stlport
libc++ @androidndk//:toolchain-libcpp
gnustl @androidndk//:toolchain-gnu-libstdcpp

r16 এবং নীচের জন্য, ডিফল্ট STL হল gnustl । r17 এবং তার উপরে, এটি libc libc++ । সুবিধার জন্য, টার্গেট @androidndk//:default_crosstool সংশ্লিষ্ট ডিফল্ট STL-এর সাথে উপনাম করা হয়েছে।

অনুগ্রহ করে মনে রাখবেন যে r18 এর পর থেকে, STLport এবং gnustl সরানো হবে , যার ফলে libc++ NDK-এর একমাত্র STL হবে।

এই STL সম্পর্কে আরও তথ্যের জন্য NDK ডকুমেন্টেশন দেখুন।

লক্ষ্য ABI কনফিগার করা হচ্ছে

লক্ষ্য ABI কনফিগার করতে, নিম্নরূপ --fat_apk_cpu পতাকা ব্যবহার করুন:

bazel build //:app --fat_apk_cpu=comma-separated list of ABIs

ডিফল্টরূপে, Bazel armeabi-v7a জন্য নেটিভ অ্যান্ড্রয়েড কোড তৈরি করে। x86 তৈরি করতে (যেমন এমুলেটরদের জন্য), --fat_apk_cpu=x86 পাস করুন। একাধিক আর্কিটেকচারের জন্য একটি ফ্যাট APK তৈরি করতে, আপনি একাধিক CPU নির্দিষ্ট করতে পারেন: --fat_apk_cpu=armeabi-v7a,x86

যদি একাধিক ABI নির্দিষ্ট করা থাকে, Bazel প্রতিটি ABI-এর জন্য একটি শেয়ার করা বস্তু সমন্বিত একটি APK তৈরি করবে।

NDK সংশোধন এবং Android API স্তরের উপর নির্ভর করে, নিম্নলিখিত ABIগুলি উপলব্ধ:

NDK সংশোধন ABIs
16 এবং কম armeabi, armeabi-v7a, arm64-v8a, mips, mips64, x86, x86_64
17 এবং তার উপরে armeabi-v7a, arm64-v8a, x86, x86_64

এই ABI সম্পর্কে আরও তথ্যের জন্য NDK ডক্স দেখুন।

মাল্টি-এবিআই ফ্যাট APK রিলিজ বিল্ডের জন্য সুপারিশ করা হয় না যেহেতু তারা APK-এর আকার বাড়ায়, কিন্তু বিকাশ এবং QA বিল্ডের জন্য উপযোগী হতে পারে।

একটি C++ মান নির্বাচন করা হচ্ছে

একটি C++ মান অনুযায়ী তৈরি করতে নিম্নলিখিত পতাকাগুলি ব্যবহার করুন:

C++ স্ট্যান্ডার্ড পতাকা
সি++৯৮ ডিফল্ট, কোন পতাকা প্রয়োজন
C++11 --cxxopt=-std=c++11
সি++১৪ --cxxopt=-std=c++14

উদাহরণ স্বরূপ:

bazel build //:app --cxxopt=-std=c++11

ইউজার ম্যানুয়াল -এ --cxxopt , --copt , এবং --linkopt দিয়ে কম্পাইলার এবং লিঙ্কার ফ্ল্যাগ পাস করার বিষয়ে আরও পড়ুন।

copts এবং cc_library ব্যবহার করে linkopts এ কম্পাইলার এবং লিঙ্কার ফ্ল্যাগগুলিকেও বৈশিষ্ট্য হিসাবে নির্দিষ্ট করা যেতে পারে। উদাহরণ স্বরূপ:

cc_library(
    name = "jni_lib",
    srcs = ["cpp/native-lib.cpp"],
    copts = ["-std=c++11"],
    linkopts = ["-ldl"], # link against libdl
)

প্ল্যাটফর্ম এবং টুলচেইনের সাথে একীকরণ

Bazel এর কনফিগারেশন মডেল প্ল্যাটফর্ম এবং টুলচেইনের দিকে এগিয়ে যাচ্ছে। আপনার বিল্ড যদি --platforms পতাকা ব্যবহার করে আর্কিটেকচার বা অপারেটিং সিস্টেম নির্মাণের জন্য নির্বাচন করতে, তাহলে NDK ব্যবহার করার জন্য আপনাকে --extra_toolchains পতাকাটি Bazel-এ পাস করতে হবে।

উদাহরণস্বরূপ, Go নিয়ম দ্বারা প্রদত্ত android_arm64_cgo টুলচেইনের সাথে একীভূত করতে, --platforms পতাকা ছাড়াও --extra_toolchains=@androidndk//:all পাস করুন।

bazel build //my/cc:lib \
  --platforms=@io_bazel_rules_go//go/toolchain:android_arm64_cgo \
  --extra_toolchains=@androidndk//:all

এছাড়াও আপনি সরাসরি WORKSPACE ফাইলে তাদের নিবন্ধন করতে পারেন:

android_ndk_repository(name = "androidndk")
register_toolchains("@androidndk//:all")

আর্কিটেকচার এবং অপারেটিং সিস্টেমের সীমাবদ্ধতাগুলি সমাধান করার সময় এই টুলচেনগুলিকে নিবন্ধন করা বাজেলকে NDK BUILD ফাইলে (NDK 20 এর জন্য) তাদের সন্ধান করতে বলে:

toolchain(
  name = "x86-clang8.0.7-libcpp_toolchain",
  toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
  target_compatible_with = [
      "@platforms//os:android",
      "@platforms//cpu:x86_32",
  ],
  toolchain = "@androidndk//:x86-clang8.0.7-libcpp",
)

toolchain(
  name = "x86_64-clang8.0.7-libcpp_toolchain",
  toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
  target_compatible_with = [
      "@platforms//os:android",
      "@platforms//cpu:x86_64",
  ],
  toolchain = "@androidndk//:x86_64-clang8.0.7-libcpp",
)

toolchain(
  name = "arm-linux-androideabi-clang8.0.7-v7a-libcpp_toolchain",
  toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
  target_compatible_with = [
      "@platforms//os:android",
      "@platforms//cpu:arm",
  ],
  toolchain = "@androidndk//:arm-linux-androideabi-clang8.0.7-v7a-libcpp",
)

toolchain(
  name = "aarch64-linux-android-clang8.0.7-libcpp_toolchain",
  toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
  target_compatible_with = [
      "@platforms//os:android",
      "@platforms//cpu:aarch64",
  ],
  toolchain = "@androidndk//:aarch64-linux-android-clang8.0.7-libcpp",
)

এটি কিভাবে কাজ করে: Android কনফিগারেশন ট্রানজিশন প্রবর্তন

android_binary নিয়মটি স্পষ্টভাবে Bazel কে একটি Android- সামঞ্জস্যপূর্ণ কনফিগারেশনে তার নির্ভরতা তৈরি করতে বলতে পারে যাতে Bazel বিল্ডটি ABI এবং STL কনফিগারেশনের জন্য --fat_apk_cpu এবং --android_crosstool_top ছাড়া কোনো বিশেষ ফ্ল্যাগ ছাড়াই কাজ করে।

পর্দার আড়ালে, এই স্বয়ংক্রিয় কনফিগারেশন অ্যান্ড্রয়েড কনফিগারেশন ট্রানজিশন ব্যবহার করে।

একটি সামঞ্জস্যপূর্ণ নিয়ম, যেমন android_binary , স্বয়ংক্রিয়ভাবে তার নির্ভরতাগুলির কনফিগারেশনকে একটি Android কনফিগারেশনে পরিবর্তন করে, তাই বিল্ডের শুধুমাত্র Android-নির্দিষ্ট সাবট্রিগুলি প্রভাবিত হয়৷ বিল্ড গ্রাফের অন্যান্য অংশগুলি টপ-লেভেল টার্গেট কনফিগারেশন ব্যবহার করে প্রক্রিয়া করা হয়। এটি উভয় কনফিগারেশনে একটি একক লক্ষ্য প্রক্রিয়াও করতে পারে, যদি এটি সমর্থন করার জন্য বিল্ড গ্রাফের মাধ্যমে পথ থাকে।

একবার Bazel একটি Android-সামঞ্জস্যপূর্ণ কনফিগারেশনে থাকলে, হয় শীর্ষ স্তরে নির্দিষ্ট করা হয় বা একটি উচ্চ-স্তরের ট্রানজিশন পয়েন্টের কারণে, অতিরিক্ত ট্রানজিশন পয়েন্টের সম্মুখীন হওয়াগুলি কনফিগারেশনটিকে আর পরিবর্তন করে না।

একমাত্র অন্তর্নির্মিত অবস্থান যা অ্যান্ড্রয়েড কনফিগারেশনে রূপান্তরকে ট্রিগার করে তা হল android_binary এর deps বৈশিষ্ট্য।

উদাহরণস্বরূপ, আপনি যদি কোনো ফ্ল্যাগ ছাড়াই একটি cc_library নির্ভরতা সহ একটি android_library টার্গেট তৈরি করার চেষ্টা করেন, তাহলে আপনি একটি অনুপস্থিত JNI হেডার সম্পর্কে একটি ত্রুটির সম্মুখীন হতে পারেন:

ERROR: project/app/src/main/BUILD.bazel:16:1: C++ compilation of rule '//app/src/main:jni_lib' failed (Exit 1)
app/src/main/cpp/native-lib.cpp:1:10: fatal error: 'jni.h' file not found
#include <jni.h>
         ^~~~~~~
1 error generated.
Target //app/src/main:lib failed to build
Use --verbose_failures to see the command lines of failed build steps.

আদর্শভাবে, এই স্বয়ংক্রিয় রূপান্তরগুলি বেশিরভাগ ক্ষেত্রেই Bazelকে সঠিক কাজটি করতে বাধ্য করবে৷ যাইহোক, যদি Bazel কমান্ড-লাইনে লক্ষ্যমাত্রা ইতিমধ্যেই এই ট্রানজিশন নিয়মগুলির যেকোনো একটির নিচে থাকে, যেমন C++ বিকাশকারীরা একটি নির্দিষ্ট cc_library পরীক্ষা করছে, তাহলে একটি কাস্টম --crosstool_top ব্যবহার করতে হবে।

android_binary ব্যবহার না করে Android এর জন্য একটি cc_library তৈরি করা

একটি android_binary ব্যবহার না করে Android এর জন্য একটি স্বতন্ত্র cc_binary বা cc_library তৈরি করতে, --crosstool_top , --cpu এবং --host_crosstool_top ফ্ল্যাগগুলি ব্যবহার করুন৷

উদাহরণ স্বরূপ:

bazel build //my/cc/jni:target \
      --crosstool_top=@androidndk//:default_crosstool \
      --cpu=<abi> \
      --host_crosstool_top=@bazel_tools//tools/cpp:toolchain

এই উদাহরণে, শীর্ষ-স্তরের cc_library এবং cc_binary লক্ষ্যগুলি NDK টুলচেন ব্যবহার করে তৈরি করা হয়েছে। যাইহোক, এর ফলে Bazel-এর নিজস্ব হোস্ট টুল NDK টুলচেন (এবং এইভাবে অ্যান্ড্রয়েডের জন্য) দিয়ে তৈরি করা হয়, কারণ হোস্ট টুলচেন টার্গেট টুলচেন থেকে কপি করা হয়। এই বিষয়ে কাজ করার জন্য, হোস্টের C++ টুলচেন স্পষ্টভাবে সেট করতে --host_crosstool_top এর মান @bazel_tools//tools/cpp:toolchain এর মান উল্লেখ করুন।

এই পদ্ধতির সাথে, সমগ্র বিল্ড গাছ প্রভাবিত হয়।

এই পতাকাগুলিকে একটি bazelrc কনফিগারেশনে (প্রতিটি ABI-এর জন্য একটি), project /.bazelrc :

common:android_x86 --crosstool_top=@androidndk//:default_crosstool
common:android_x86 --cpu=x86
common:android_x86 --host_crosstool_top=@bazel_tools//tools/cpp:toolchain

common:android_armeabi-v7a --crosstool_top=@androidndk//:default_crosstool
common:android_armeabi-v7a --cpu=armeabi-v7a
common:android_armeabi-v7a --host_crosstool_top=@bazel_tools//tools/cpp:toolchain

# In general
common:android_<abi> --crosstool_top=@androidndk//:default_crosstool
common:android_<abi> --cpu=<abi>
common:android_<abi> --host_crosstool_top=@bazel_tools//tools/cpp:toolchain

তারপরে, উদাহরণস্বরূপ x86 এর জন্য একটি cc_library তৈরি করতে, চালান:

bazel build //my/cc/jni:target --config=android_x86

সাধারণভাবে, নিম্ন-স্তরের লক্ষ্যগুলির জন্য এই পদ্ধতিটি ব্যবহার করুন (যেমন cc_library ) বা যখন আপনি জানেন যে আপনি ঠিক কী তৈরি করছেন; উচ্চ-স্তরের লক্ষ্যগুলির জন্য android_binary থেকে স্বয়ংক্রিয় কনফিগারেশন ট্রানজিশনের উপর নির্ভর করুন যেখানে আপনি অনেকগুলি লক্ষ্য তৈরি করার আশা করছেন যা আপনি নিয়ন্ত্রণ করেন না।