আপনি যদি 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
ফাইলটি নিম্নলিখিত লক্ষ্য গ্রাফে ফলাফল দেয়:
চিত্র 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
থেকে স্বয়ংক্রিয় কনফিগারেশন ট্রানজিশনের উপর নির্ভর করুন যেখানে আপনি অনেকগুলি লক্ষ্য তৈরি করার আশা করছেন যা আপনি নিয়ন্ত্রণ করেন না।