Android NDK از استفاده از CMake برای کامپایل کدهای C و C++ برای برنامه شما پشتیبانی می کند. در این صفحه نحوه استفاده از CMake با NDK از طریق ExternalNativeBuild
پلاگین Android Gradle یا هنگام فراخوانی مستقیم CMake بحث میشود.
فایل زنجیره ابزار CMake
NDK از CMake از طریق یک فایل زنجیره ابزار پشتیبانی می کند. فایلهای Toolchain فایلهای CMake هستند که رفتار زنجیره ابزار را برای کامپایل متقابل سفارشی میکنند. فایل زنجیره ابزار مورد استفاده برای NDK در NDK در <NDK>/build/cmake/android.toolchain.cmake
قرار دارد.
هنگام فراخوانی cmake
پارامترهای ساخت مانند ABI، minSdkVersion
و غیره در خط فرمان داده می شوند. برای فهرستی از آرگومان های پشتیبانی شده، به بخش آرگومان های زنجیره ابزار مراجعه کنید.
فایل Toolchain "جدید".
NDKهای قبلی با اجرای جدیدی از فایل toolchain آزمایش کردند که تفاوت های رفتاری بین استفاده از فایل زنجیره ابزار NDK و استفاده از پشتیبانی داخلی CMake را کاهش می داد. این کار به مقدار قابل توجهی کار نیاز داشت (که تکمیل نشده است)، اما در واقع رفتار را بهبود نمی بخشد، بنابراین ما دیگر این کار را دنبال نمی کنیم.
فایل زنجیره ابزار "جدید" دارای رگرسیون های رفتاری در مقایسه با فایل زنجیره ابزار "میراث" است. رفتار پیش فرض گردش کار توصیه شده است. اگر از -DANDROID_USE_LEGACY_TOOLCHAIN_FILE=OFF
استفاده می کنید، توصیه می کنیم آن پرچم را از ساخت خود حذف کنید. فایل Toolchain جدید هرگز با فایل Toolchain قدیمی برابری نکرد، بنابراین احتمالاً رگرسیون های رفتاری وجود دارد.
اگرچه توصیه می کنیم از فایل جدید تولچین استفاده نکنید، اما در حال حاضر هیچ برنامه ای برای حذف آن از NDK وجود ندارد. انجام این کار، ساختهایی را که به تفاوتهای رفتاری بین فایلهای زنجیره ابزار جدید و قدیمی متکی هستند، از بین میبرد و متأسفانه تغییر نام گزینه برای روشن کردن اینکه «میراث» واقعاً توصیه میشود، کاربران آن گزینه را نیز از بین میبرد. اگر با خوشحالی از فایل زنجیره ابزار جدید استفاده می کنید، نیازی به مهاجرت ندارید، اما بدانید که هر گونه اشکالی که علیه رفتار فایل زنجیره ابزار جدید ثبت شده است، احتمالاً برطرف نخواهد شد و در عوض باید مهاجرت کنید.
استفاده
گریدل
استفاده از فایل زنجیره ابزار CMake هنگام استفاده از externalNativeBuild
خودکار است. برای اطلاعات بیشتر ، کدهای C و C++ Android Studio را به راهنمای پروژه خود اضافه کنید .
خط فرمان
هنگام ساخت با CMake خارج از Gradle، خود فایل Toolchain و آرگومان های آن باید به CMake ارسال شوند. به عنوان مثال:
$ cmake \
-DCMAKE_TOOLCHAIN_FILE=$NDK/build/cmake/android.toolchain.cmake \
-DANDROID_ABI=$ABI \
-DANDROID_PLATFORM=android-$MINSDKVERSION \
$OTHER_ARGS
استدلال های زنجیره ابزار
آرگومان های زیر را می توان به فایل زنجیره ابزار CMake منتقل کرد. اگر با Gradle میسازید، آرگومانهایی را به android.defaultConfig.externalNativeBuild.cmake.arguments
اضافه کنید همانطور که در اسناد ExternalNativeBuild توضیح داده شده است. اگر از خط فرمان ساخت می کنید، آرگومان ها را با -D
به CMake ارسال کنید. برای مثال، برای اینکه armeabi-v7a را مجبور به ساخت با پشتیبانی نئون نکنید، -DANDROID_ARM_NEON=FALSE
را پاس کنید.
ANDROID_ABI
ABI هدف. برای اطلاعات در مورد ABI های پشتیبانی شده، ABI های Android را ببینید.
گریدل
Gradle این آرگومان را به صورت خودکار ارائه می کند. این آرگومان را به صراحت در فایل build.gradle
خود قرار ندهید. برای کنترل اینکه چه ABI هایی را Gradle هدف قرار می دهد، از abiFilters
همانطور که در ABI های Android توضیح داده شده است استفاده کنید.
خط فرمان
CMake برای هر ساخت یک هدف واحد می سازد. برای هدف قرار دادن بیش از یک ABI Android، باید یک بار در هر ABI بسازید. توصیه می شود برای جلوگیری از برخورد بین ساخت ها، از دایرکتوری های ساخت مختلف برای هر ABI استفاده کنید.
ارزش | یادداشت ها |
---|---|
armeabi-v7a | |
armeabi-v7a with NEON | مانند armeabi-v7a . |
arm64-v8a | |
x86 | |
x86_64 |
ANDROID_ARM_MODE
تعیین می کند که آیا دستورالعمل های بازو یا انگشت شست برای armeabi-v7a تولید شود. برای سایر ABI ها تاثیری ندارد. برای اطلاعات بیشتر، به مستندات Android ABIs مراجعه کنید.
ارزش | یادداشت ها |
---|---|
بازو | |
انگشت شست | رفتار پیش فرض |
ANDROID_NATIVE_API_LEVEL
نام مستعار برای ANDROID_PLATFORM .
ANDROID_PLATFORM
حداقل سطح API پشتیبانی شده توسط برنامه یا کتابخانه را مشخص می کند. این مقدار با minSdkVersion
برنامه مطابقت دارد.
گریدل
هنگام استفاده از پلاگین Android Gradle، این مقدار به طور خودکار مطابق با minSdkVersion
برنامه تنظیم می شود و نباید به صورت دستی تنظیم شود.
خط فرمان
هنگام فراخوانی مستقیم CMake، این مقدار به طور پیش فرض روی پایین ترین سطح API پشتیبانی شده توسط NDK در حال استفاده قرار می گیرد. به عنوان مثال، با NDK r20 این مقدار به طور پیش فرض در سطح API 16 قرار می گیرد.
چندین فرمت برای این پارامتر پذیرفته شده است:
-
android-$API_LEVEL
-
$API_LEVEL
-
android-$API_LETTER
فرمت $API_LETTER
به شما امکان می دهد تا android-N
بدون نیاز به تعیین شماره مربوط به آن نسخه مشخص کنید. توجه داشته باشید که برخی از نسخه ها افزایش API را بدون افزایش حرف دریافت کردند. این API ها را می توان با اضافه کردن پسوند -MR1
مشخص کرد. به عنوان مثال، API سطح 25 android-N-MR1
است.
ANDROID_STL
مشخص می کند که از کدام STL برای این برنامه استفاده شود. برای اطلاعات بیشتر، به پشتیبانی از کتابخانه C++ مراجعه کنید. به طور پیش فرض c++_static
استفاده خواهد شد.
ارزش | یادداشت ها |
---|---|
c++_shared | نوع کتابخانه مشترک libc++ . |
c++_static | نوع کتابخانه ایستا libc++ . |
هیچ کدام | بدون پشتیبانی از کتابخانه استاندارد C++. |
سیستم | سیستم STL |
پرچم های کامپایلر را مدیریت کنید
اگر میخواهید پرچمهای خاصی را به کامپایلر یا پیوند دهنده برای ساخت خود ارسال کنید، به مستندات CMake برای set_target_compile_options و خانواده گزینههای مرتبط مراجعه کنید. بخش «همچنین ببینید» در پایین آن صفحه دارای سرنخهای مفیدی است.
به طور کلی، بهترین روش استفاده از پرچم های کامپایلر به عنوان باریک ترین محدوده موجود است. پرچم هایی که می خواهید برای همه اهداف خود اعمال کنید (مانند -Werror
) برای تکرار در هر ماژول ناخوشایند هستند، اما به ندرت باید در سطح جهانی اعمال شوند ( CMAKE_CXX_FLAGS
)، زیرا ممکن است اثرات نامطلوبی بر وابستگی های شخص ثالث در پروژه شما داشته باشند. . برای چنین مواردی، پرچم ها را می توان در دایرکتوری-scope اعمال کرد ( add_compile_options
).
برای زیرمجموعهای باریک از پرچمهای کامپایلر، میتوان آنها را با استفاده از cppFlags
یا ویژگیهای مشابه در فایل build.gradle شما نیز تنظیم کرد. شما نباید این کار را انجام دهید. پرچمهایی که از Gradle به CMake ارسال میشوند، رفتارهای تقدم شگفتانگیزی دارند، در برخی موارد پرچمهایی که به طور ضمنی توسط پیادهسازی ارسال میشوند و برای ساخت کد اندروید مورد نیاز هستند. همیشه رفتار CMake را مستقیماً در CMake مدیریت کنید. اگر نیاز به کنترل پرچم های کامپایلر در هر buildType
AGP دارید، به کار با انواع ساخت AGP در CMake مراجعه کنید.
با انواع ساخت AGP در CMake کار کنید
اگر میخواهید رفتار CMake را برای یک Gradle buildType
سفارشی تنظیم کنید، از آن نوع ساخت برای ارسال یک پرچم اضافی 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، دانستن آرگومان های ساخت خاصی که Gradle هنگام کامپایل متقابل برای اندروید استفاده می کند، مفید است.
افزونه Android Gradle آرگومانهای ساختی را که برای اجرای یک ساخت CMake برای هر جفت ABI و بیلد استفاده میکند در build_command.txt
ذخیره میکند. این فایل ها در دایرکتوری زیر یافت می شوند:
<project-root>/<module-root>/.cxx/cmake/<build-type>/<ABI>/
قطعه زیر نمونهای از آرگومانهای CMake را برای ساخت نسخه قابل اشکالزدایی از نمونه hello-jni
با هدف قرار دادن معماری armeabi-v7a
نشان میدهد.
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 توزیع شده است، برای وارد کردن و استفاده از آنها ، اسناد وابستگی استودیو را دنبال کنید. اگر از AGP استفاده نمی کنید، می توانید https://google.github.io/prefab/example-workflow.html را دنبال کنید، اما به احتمال زیاد انتقال به AGP بسیار ساده تر است.
برای کتابخانههایی که بهعنوان AAR توزیع نمیشوند، دستورالعملهای استفاده از کتابخانههای از پیش ساخته شده با CMake، به مستندات add_library
در رابطه با اهداف IMPORTED
در کتابچه راهنمای CMake مراجعه کنید.
ساخت کد شخص ثالث
روشهای انگشت شماری برای ساخت کد شخص ثالث به عنوان بخشی از پروژه CMake شما وجود دارد، و اینکه کدام گزینه بهتر عمل میکند به وضعیت شما بستگی دارد. بهترین گزینه اغلب این است که اصلاً این کار را انجام ندهید. در عوض، یک AAR برای کتابخانه بسازید و آن را در برنامه خود مصرف کنید. شما لزوماً نیازی به انتشار آن AAR ندارید. می تواند در پروژه Gradle شما داخلی باشد.
اگر این یک گزینه نیست:
- فروشنده (یعنی کپی کنید) منبع شخص ثالث را در مخزن خود و از add_subdirectory برای ساخت آن استفاده کنید. این تنها در صورتی کار می کند که کتابخانه دیگر نیز با CMake ساخته شده باشد.
- یک پروژه خارجی را تعریف کنید.
- کتابخانه را جدا از پروژه خود بسازید و برای وارد کردن آن به عنوان پیش ساخته ، از کتابخانه های از پیش ساخته شده استفاده کنید .
پشتیبانی از YASM در CMake
NDK پشتیبانی از CMake را برای کد اسمبلی ساختمان نوشته شده در YASM برای اجرا در معماریهای x86 و x86-64 ارائه میکند. YASM یک اسمبلر منبع باز برای معماری های x86 و x86-64 است که بر اساس اسمبلر NASM است.
برای ساخت کد اسمبلی با CMake، تغییرات زیر را در CMakeLists.txt
پروژه خود اعمال کنید:
- با مقدار تنظیم شده روی
ASM_NASM
باenable_language
تماس بگیرید. - بسته به اینکه در حال ساخت یک کتابخانه مشترک یا یک باینری اجرایی هستید، با
add_library
یاadd_executable
تماس بگیرید. در آرگومانها، فهرستی از فایلهای منبع شامل فایلهای.asm
برای برنامه اسمبلی در YASM و فایلهای.c
برای کتابخانهها یا توابع C مرتبط ارسال کنید.
قطعه زیر نشان می دهد که چگونه می توانید CMakeLists.txt
خود را برای ساخت یک برنامه YASM به عنوان یک کتابخانه مشترک پیکربندی کنید.
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 به عنوان یک فایل اجرایی، تست yasm را در مخزن NDK git ببینید.
مشکلات را گزارش کنید
اگر با NDK یا فایل زنجیره ابزار CMake آن به مشکل برخوردید، آن را از طریق ردیاب مشکل android-ndk/ndk در GitHub گزارش دهید. برای مشکلات پلاگین Gradle یا Android Gradle، به جای آن یک اشکال استودیو را گزارش کنید .