Android NDK আপনার অ্যাপ্লিকেশনের জন্য C এবং C++ কোড কম্পাইল করতে CMake ব্যবহার করা সমর্থন করে। এই পৃষ্ঠায় আলোচনা করা হয়েছে যে কীভাবে Android Gradle প্লাগ-ইনের ExternalNativeBuild-এর মাধ্যমে
NDK-এর সাথে CMake ব্যবহার করতে হয় অথবা সরাসরি CMake
কল করতে হয়।
CMake টুলচেন ফাইল
NDK, টুলচেন ফাইলের মাধ্যমে CMake-কে সাপোর্ট করে। টুলচেন ফাইল হল CMake ফাইল
যা ক্রস-কম্পাইলিংয়ের জন্য টুলচেনের আচরণ কাস্টমাইজ করে। NDK-এর জন্য ব্যবহৃত টুলচেন
ফাইলটি NDK-তে
<NDK>/build/cmake/android.toolchain.cmake-এ অবস্থিত।
cmake কল করার সময় কমান্ড লাইনে ABI, minSdkVersion ইত্যাদির মতো বিল্ড প্যারামিটার দেওয়া হয়। কাজ করে এমন আর্গুমেন্টের তালিকা দেখতে,
টুলচেন আর্গুমেন্ট বিভাগ দেখুন।
"নতুন" টুলচেন ফাইল
আগের NDK-তে টুলচেন ফাইলের নতুন ইমপ্লিমেন্টেশন নিয়ে পরীক্ষা করা হয়েছিল যা NDK-এর টুলচেন ফাইল ব্যবহার করা এবং বিল্ট-ইন CMake সাপোর্ট ব্যবহার করার মধ্যে আচরণের পার্থক্য কমাবে। এর ফলে অনেক কাজ করতে হয়েছে (যা এখনও সম্পূর্ণ হয়নি), কিন্তু আসলে আচরণে কোনও উন্নতি হয়নি, তাই আমরা আর এটি নিয়ে কাজ করছি না।
"নতুন" টুলচেন ফাইলের আচরণ "পুরনো" টুলচেন ফাইলের তুলনায় খারাপ। ডিফল্ট অ্যাকশন হল সাজেস্ট করা ওয়ার্কফ্লো। আপনি যদি
-DANDROID_USE_LEGACY_TOOLCHAIN_FILE=OFF ব্যবহার করেন, তাহলে আপনার বিল্ড থেকে সেই ফ্ল্যাগ
সরিয়ে দেওয়ার সাজেশন আমরা দিই। নতুন টুলচেন ফাইলটি কখনই লিগ্যাসি টুলচেন ফাইলের সাথে সমতা অর্জন করেনি, তাই আচরণগত রিগ্রেশন হওয়ার সম্ভাবনা রয়েছে।
যদিও আমরা নতুন টুলচেন ফাইল ব্যবহার করার বিরুদ্ধে সাজেশন দিই, বর্তমানে NDK থেকে এটি সরানোর কোনও পরিকল্পনা নেই। এটি করলে, নতুন ও পুরনো টুলচেন ফাইলের মধ্যে আচরণের পার্থক্যের উপর নির্ভর করে এমন বিল্ড ভেঙে যাবে এবং দুর্ভাগ্যবশত, "পুরনো" বিকল্পটি যে আসলে সাজেস্ট করা হচ্ছে তা স্পষ্ট করার জন্য বিকল্পটির নাম পরিবর্তন করলে, সেই বিকল্প ব্যবহারকারীদেরও ক্ষতি হবে। আপনি যদি নতুন টুলচেন ফাইল ব্যবহার করে সন্তুষ্ট হন, তাহলে আপনাকে মাইগ্রেট করতে হবে না। তবে মনে রাখবেন, নতুন টুলচেন ফাইলের আচরণ সংক্রান্ত কোনও সমস্যা থাকলে তা সম্ভবত সমাধান করা হবে না এবং তার পরিবর্তে আপনাকে মাইগ্রেট করতে হবে।
ব্যবহার
Gradle
externalNativeBuild ব্যবহার করার সময় CMake টুলচেন ফাইল অটোমেটিক ব্যবহার করা হয়। আরও তথ্যের জন্য Android Studio-এর আপনার প্রোজেক্টে C এবং C++ কোড যোগ করুন
গাইড দেখুন।
কম্যান্ড লাইন
Gradle-এর বাইরে CMake-এর সাহায্যে তৈরি করার সময়, টুলচেন ফাইল এবং এর আর্গুমেন্ট CMake-এ পাস করতে হবে। যেমন:
$ cmake \
-DCMAKE_TOOLCHAIN_FILE=$NDK/build/cmake/android.toolchain.cmake \
-DANDROID_ABI=$ABI \
-DANDROID_PLATFORM=android-$MINSDKVERSION \
$OTHER_ARGS
টুলচেন আর্গুমেন্ট
CMake টুলচেন ফাইলে নিম্নলিখিত আর্গুমেন্ট পাস করা যেতে পারে। Gradle-এর সাহায্যে
বিল্ডিং করলে, ExternalNativeBuild ডকুমেন্ট-এ
বর্ণনা করা অনুযায়ী android.defaultConfig.externalNativeBuild.cmake.arguments-এ
আর্গুমেন্ট যোগ করুন। কমান্ড লাইন থেকে তৈরি করলে, -D-এর সাথে CMake-এ
আর্গুমেন্ট পাস করুন। যেমন, Neon সাপোর্ট ছাড়া armeabi-v7a বিল্ড করতে -DANDROID_ARM_NEON=FALSE পাস করুন।
ANDROID_ABI
টার্গেট ABI. কোন কোন ABI কাজ করে সেই সম্পর্কে জানতে, Android ABI দেখুন।
Gradle
Gradle অটোমেটিক এই আর্গুমেন্ট প্রদান করে। আপনার build.gradle ফাইলে এই আর্গুমেন্ট
নির্দিষ্টভাবে সেট করবেন না। Gradle কোন ABI টার্গেট করবে তা নিয়ন্ত্রণ করতে,
Android ABI-তে যেভাবে বর্ণনা করা হয়েছে সেইভাবে abiFilters ব্যবহার করুন।
কম্যান্ড লাইন
CMake প্রতিটি বিল্ডের জন্য একটি টার্গেট বিল্ড করে। একাধিক Android ABI টার্গেট করতে, আপনাকে প্রতিটি ABI-এর জন্য একবার করে বিল্ড করতে হবে। বিল্ডের মধ্যে সংঘর্ষ এড়াতে প্রতিটি ABI-এর জন্য আলাদা বিল্ড ডিরেক্টরি ব্যবহার করার সাজেশন দেওয়া হয়।
| মান | নোট |
|---|---|
armeabi-v7a |
|
armeabi-v7a with NEON |
armeabi-v7a-এর মতো একই রকমের। |
arm64-v8a |
|
x86 |
|
x86_64 |
ANDROID_ARM_MODE
armeabi-v7a-এর জন্য arm বা থাম্ব নির্দেশাবলী তৈরি করতে হবে কিনা তা নির্দিষ্ট করে। অন্যান্য ABI-এর উপর কোনও প্রভাব পড়ে না। আরও তথ্যের জন্য, Android ABI ডকুমেন্টেশন দেখুন।
| মান | নোট |
|---|---|
| পরীক্ষার জন্য তৈরি করা গ্রুপ | |
| বুড়ো আঙুল | ডিফল্ট অ্যাকশন। |
ANDROID_NATIVE_API_LEVEL
ANDROID_PLATFORM-এর জন্য উপনাম।
ANDROID_PLATFORM
অ্যাপ্লিকেশন বা লাইব্রেরির মাধ্যমে কাজ করে এমন ন্যূনতম API লেভেল নির্দিষ্ট করে। এই
ভ্যালু অ্যাপ্লিকেশনের minSdkVersion-এর সাথে সম্পর্কিত।
Gradle
Android Gradle প্লাগ-ইন ব্যবহার করার সময়, এই ভ্যালু অটোমেটিক সেট করা হয় যাতে
অ্যাপ্লিকেশনের minSdkVersion-এর সাথে ম্যাচ করে এবং এটি ম্যানুয়ালি সেট করা উচিত নয়।
কম্যান্ড লাইন
সরাসরি CMake কল করার সময়, এই ভ্যালু ডিফল্ট হিসেবে ব্যবহার করা NDK-এর মাধ্যমে সমর্থিত সর্বনিম্ন API লেভেলে সেট করা হয়। যেমন, NDK r20-এর ক্ষেত্রে এই ভ্যালু ডিফল্ট হিসেবে API লেভেল ১৬-এ সেট করা থাকে।
এই প্যারামিটারের জন্য একাধিক ফর্ম্যাট গ্রহণ করা হয়:
android-$API_LEVEL$API_LEVELandroid-$API_LETTER
$API_LETTER ফর্ম্যাট আপনাকে android-N নির্দিষ্ট করার অনুমতি দেয়, এর জন্য
সেই রিলিজের সাথে যুক্ত নম্বর নির্ধারণ করার প্রয়োজন হয় না। মনে রাখবেন, কিছু রিলিজের ক্ষেত্রে
লেটার না বাড়িয়ে API বাড়ানো হয়েছে। -MR1 প্রত্যয় যোগ করে
এইসব API নির্দিষ্ট করা যেতে পারে। যেমন, API লেভেল ২৫ হল android-N-MR1।
ANDROID_STL
এই অ্যাপ্লিকেশনের জন্য কোন STL ব্যবহার করতে হবে তা উল্লেখ করে। আরও তথ্যের জন্য, C++
লাইব্রেরি সহায়তা দেখুন। ডিফল্ট হিসেবে, c++_static ব্যবহার করা হবে।
| মান | নোট |
|---|---|
| c++_shared | libc++-এর শেয়ার করা লাইব্রেরি ভ্যারিয়েন্ট। |
| c++_static | libc++-এর স্ট্যাটিক লাইব্রেরি ভ্যারিয়েন্ট। |
| কিছুই নেই | C++ স্ট্যান্ডার্ড লাইব্রেরি কাজ করে না। |
| সিস্টেম | সিস্টেম STL |
কম্পাইলার ফ্ল্যাগ ম্যানেজ করুন
আপনার বিল্ডের জন্য কম্পাইলার বা লিঙ্কারে নির্দিষ্ট ফ্ল্যাগ পাস করতে হলে, set_target_compile_options এবং সম্পর্কিত বিকল্পের ফ্যামিলির জন্য CMake ডকুমেন্টেশন দেখুন। সেই পৃষ্ঠার নিচে "আরও দেখুন" বিভাগে কিছু সহায়ক ইঙ্গিত দেওয়া আছে।
সাধারণত, কম্পাইলার ফ্ল্যাগকে উপলভ্য সবচেয়ে সংকীর্ণ স্কোপ হিসেবে প্রয়োগ করা
পেশাদার পদ্ধতি হিসেবে বিবেচিত হয়। আপনার সব টার্গেটে (যেমন
-Werror) যেসব ফ্ল্যাগ প্রয়োগ করতে চান, সেগুলি প্রতি মডিউলে পুনরাবৃত্তি করা অসুবিধাজনক, তবে এখনও খুব কমই
গ্লোবালি (CMAKE_CXX_FLAGS) প্রয়োগ করা উচিত, কারণ আপনার প্রোজেক্টে থার্ড-পার্টি ডিপেন্ডেন্সির উপর
সেগুলির অবাঞ্ছিত প্রভাব থাকতে পারে। এই ধরনের ক্ষেত্রে, ডিরেক্টরি-স্কোপে (add_compile_options)
ফ্ল্যাগ প্রয়োগ করা যেতে পারে।
কম্পাইলার ফ্ল্যাগের একটি ছোট সাবসেটের জন্য, সেগুলি আপনার build.gradle
ফাইলে cppFlags বা একই ধরনের প্রপার্টি ব্যবহার করে সেট করা যেতে পারে। আপনার এটি করা উচিত নয়। Gradle থেকে CMake-এ পাস করা ফ্ল্যাগগুলির
অপ্রত্যাশিত অগ্রাধিকার আচরণ থাকবে, কিছু ক্ষেত্রে
বাস্তবায়নের মাধ্যমে পাস করা ফ্ল্যাগগুলিকে ওভাররাইড করা হবে যা
Android কোড তৈরি করার জন্য প্রয়োজন। CMake-এর আচরণ সরাসরি CMake-এ
ম্যানেজ করা সবসময় ভালো। প্রতি AGP buildType-এর জন্য কম্পাইলার ফ্ল্যাগ নিয়ন্ত্রণ করতে হলে,
CMake-এ AGP বিল্ড টাইপ নিয়ে কাজ করা দেখুন।
CMake-এ AGP বিল্ড টাইপ নিয়ে কাজ করা
আপনাকে যদি কাস্টম Gradle buildType-এর জন্য CMake-এর আচরণ কাস্টমাইজ করতে হয়, তাহলে
অতিরিক্ত CMake ফ্ল্যাগ (কম্পাইলার ফ্ল্যাগ নয়) পাস করার জন্য সেই বিল্ড টাইপ ব্যবহার করুন, যা আপনার
CMake বিল্ড স্ক্রিপ্ট পড়তে পারবে। যেমন, আপনার কাছে "ফ্রি" এবং "প্রিমিয়াম"
বিল্ড ভেরিয়েন্ট থাকলে যা আপনার build.gradle.kts দ্বারা নিয়ন্ত্রিত হয় এবং আপনাকে
সেই ডেটা CMake-এ পাস করতে হবে:
android {
buildTypes {
free {
externalNativeBuild {
cmake {
arguments.add("-DPRODUCT_VARIANT_PREMIUM=OFF")
}
}
}
premium {
externalNativeBuild {
cmake {
arguments.add("-DPRODUCT_VARIANT_PREMIUM=ON")
}
}
}
}
}
তারপর, আপনার CMakeLists.txt-এ:
if (DPRODUCT_VARIANT_PREMIUM)
# Do stuff for the premium build.
else()
# Do stuff for the free build.
endif()
আপনি ভেরিয়েবলের নাম নিজের পছন্দমতো দিতে পারেন, তবে আগে থেকে থাকা ফ্ল্যাগের সাথে যাতে কোনও সংঘর্ষ বা বিভ্রান্তি না হয়, তার জন্য
ANDROID_, APP_ বা CMAKE_ প্রিফিক্স দিয়ে শুরু হয় এমন কিছু এড়িয়ে চলুন।
উদাহরণ হিসেবে Sanitizers NDK স্যাম্পেল দেখুন।
CMake বিল্ড কমান্ড সম্পর্কে বোঝা
CMake বিল্ড সংক্রান্ত সমস্যার ডিবাগিং করার সময়, Android-এর জন্য ক্রস-কম্পাইল করার সময় Gradle যে নির্দিষ্ট বিল্ড আর্গুমেন্ট ব্যবহার করে তা জানা থাকলে সুবিধা হয়।
Android Gradle প্লাগ-ইন, প্রতিটি ABI এবং বিল্ডের ধরন
পেয়ারের জন্য CMake বিল্ড এক্সিকিউট করতে যে বিল্ড আর্গুমেন্ট ব্যবহার করে তা build_command.txt-এ সেভ করে। এই ফাইলগুলি নিম্নলিখিত ডিরেক্টরিতে
পাওয়া গেছে:
<project-root>/<module-root>/.cxx/cmake/<build-type>/<ABI>/
নিচের স্নিপেট থেকে CMake আর্গুমেন্টের উদাহরণ দেখানো হয়েছে যা armeabi-v7a আর্কিটেকচারকে টার্গেট করে hello-jni স্যাম্পেলের ডিবাগ করা যায় এমন রিলিজ তৈরি করে।
Executable : ${HOME}/Android/Sdk/cmake/3.10.2.4988404/bin/cmake
arguments :
-H${HOME}/Dev/github-projects/googlesamples/ndk-samples/hello-jni/app/src/main/cpp
-DCMAKE_FIND_ROOT_PATH=${HOME}/Dev/github-projects/googlesamples/ndk-samples/hello-jni/app/.cxx/cmake/universalDebug/prefab/armeabi-v7a/prefab
-DCMAKE_BUILD_TYPE=Debug
-DCMAKE_TOOLCHAIN_FILE=${HOME}/Android/Sdk/ndk/22.1.7171670/build/cmake/android.toolchain.cmake
-DANDROID_ABI=armeabi-v7a
-DANDROID_NDK=${HOME}/Android/Sdk/ndk/22.1.7171670
-DANDROID_PLATFORM=android-23
-DCMAKE_ANDROID_ARCH_ABI=armeabi-v7a
-DCMAKE_ANDROID_NDK=${HOME}/Android/Sdk/ndk/22.1.7171670
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON
-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=${HOME}/Dev/github-projects/googlesamples/ndk-samples/hello-jni/app/build/intermediates/cmake/universalDebug/obj/armeabi-v7a
-DCMAKE_RUNTIME_OUTPUT_DIRECTORY=${HOME}/Dev/github-projects/googlesamples/ndk-samples/hello-jni/app/build/intermediates/cmake/universalDebug/obj/armeabi-v7a
-DCMAKE_MAKE_PROGRAM=${HOME}/Android/Sdk/cmake/3.10.2.4988404/bin/ninja
-DCMAKE_SYSTEM_NAME=Android
-DCMAKE_SYSTEM_VERSION=23
-B${HOME}/Dev/github-projects/googlesamples/ndk-samples/hello-jni/app/.cxx/cmake/universalDebug/armeabi-v7a
-GNinja
jvmArgs :
Build command args: []
Version: 1
আগে থেকে তৈরি লাইব্রেরি ব্যবহার করুন
আপনি যে প্রি-বিল্ট লাইব্রেরি ইমপোর্ট করতে চান সেটি যদি AAR হিসেবে ডিস্ট্রিবিউট করা হয়, তাহলে Studio-এর ডিপেন্ডেন্সি ডকুমেন্ট অনুসরণ করে সেটি ইমপোর্ট ও ব্যবহার করুন। আপনি AGP ব্যবহার না করলে, https://google.github.io/prefab/example-workflow.html অনুসরণ করতে পারেন, তবে AGP-তে মাইগ্রেট করা অনেক সহজ হতে পারে।
AAR হিসেবে ডিস্ট্রিবিউট করা হয়নি এমন লাইব্রেরির ক্ষেত্রে, CMake সহ আগে থেকে তৈরি লাইব্রেরি ব্যবহার করার নির্দেশাবলী, CMake ম্যানুয়াল-এ IMPORTED টার্গেট সংক্রান্ত add_library ডকুমেন্টেশন দেখুন।
থার্ড-পার্টি কোড তৈরি করা
আপনার CMake প্রোজেক্টের অংশ হিসেবে থার্ড-পার্টি কোড তৈরি করার কয়েকটি উপায় আছে এবং কোন বিকল্পটি সবচেয়ে ভালো কাজ করবে তা আপনার পরিস্থিতির উপর নির্ভর করবে। সবচেয়ে ভালো বিকল্প হল, এটি একেবারেই না করা। পরিবর্তে, লাইব্রেরির জন্য একটি AAR তৈরি করুন এবং আপনার অ্যাপ্লিকেশনে সেটি ব্যবহার করুন। আপনাকে সেই AAR প্রকাশ করতেই হবে এমন কোনও বাধ্যবাধকতা নেই। এটি আপনার Gradle প্রোজেক্টের ইন্টার্নাল হতে পারে।
যদি সেটি কোনও বিকল্প না হয়:
- আপনার রিপোজিটরিতে থার্ড-পার্টি সোর্স ভেন্ডর (অর্থাৎ কপি) করুন এবং এটি তৈরি করতে add_subdirectory ব্যবহার করুন। অন্য লাইব্রেরিও CMake দিয়ে তৈরি হলে তবেই এটি কাজ করে।
- ExternalProject সংজ্ঞায়িত করুন।
- আপনার প্রোজেক্ট থেকে আলাদা করে লাইব্রেরি তৈরি করুন এবং আগে থেকে তৈরি লাইব্রেরি ব্যবহার করুন বিকল্প অনুসরণ করে এটি আগে থেকে তৈরি হিসেবে ইমপোর্ট করুন।
CMake-এ YASM সাপোর্ট
NDK, x86 এবং x86-64 আর্কিটেকচারে চালানোর জন্য YASM-এ লেখা অ্যাসেম্বলি কোড তৈরি করার জন্য CMake সহায়তা প্রদান করে। YASM হল x86 এবং x86-64 আর্কিটেকচারের জন্য একটি ওপেন-সোর্স অ্যাসেম্বলার, যা NASM অ্যাসেম্বলারের উপর ভিত্তি করে তৈরি।
CMake-এর সাহায্যে অ্যাসেম্বলি কোড তৈরি করতে, আপনার প্রোজেক্টের CMakeLists.txt-এ নিম্নলিখিত পরিবর্তনগুলি করুন:
ASM_NASM-এ সেট করা ভ্যালু সহenable_languageকল করুন।- আপনি শেয়ার করা লাইব্রেরি নাকি এক্সিকিউটেবল বাইনারি তৈরি করছেন তার উপর নির্ভর করে,
add_libraryবাadd_executableকল করুন। আর্গুমেন্টে, YASM-এ অ্যাসেম্বলি প্রোগ্রামের জন্য.asmফাইল এবং সংশ্লিষ্ট C লাইব্রেরি বা ফাংশনের জন্য.cফাইল সহ সোর্স ফাইলের একটি তালিকা পাস করুন।
শেয়ার করা লাইব্রেরি হিসেবে YASM প্রোগ্রাম তৈরি করতে কীভাবে আপনার CMakeLists.txt কনফিগার করবেন তা নিম্নলিখিত স্নিপেট থেকে জানতে পারবেন।
cmake_minimum_required(VERSION 3.6.0)
enable_language(ASM_NASM)
add_library(test-yasm SHARED jni/test-yasm.c jni/print_hello.asm)
এক্সিকিউটেবল হিসেবে YASM প্রোগ্রাম কীভাবে তৈরি করতে হয় তার উদাহরণ দেখতে, NDK git রিপোজিটরিতে yasm টেস্ট দেখুন।
সমস্যা সম্পর্কে অভিযোগ জানানো
NDK বা এর CMake টুলচেন ফাইল নিয়ে কোনও সমস্যা হলে, GitHub-এ android-ndk/ndk সমস্যা ট্র্যাকারের মাধ্যমে অভিযোগ জানান। Gradle বা Android Gradle প্লাগ-ইন সংক্রান্ত সমস্যার জন্য, এর পরিবর্তে Studio-র কোনও সমস্যার ব্যাপারে অভিযোগ জানান।