CMake

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 شما داخلی باشد.

اگر این یک گزینه نیست:

پشتیبانی از YASM در CMake

NDK پشتیبانی از CMake را برای کد اسمبلی ساختمان نوشته شده در YASM برای اجرا در معماری‌های x86 و x86-64 ارائه می‌کند. YASM یک اسمبلر منبع باز برای معماری های x86 و x86-64 است که بر اساس اسمبلر NASM است.

برای ساخت کد اسمبلی با CMake، تغییرات زیر را در CMakeLists.txt پروژه خود اعمال کنید:

  1. با مقدار تنظیم شده روی ASM_NASM با enable_language تماس بگیرید.
  2. بسته به اینکه در حال ساخت یک کتابخانه مشترک یا یک باینری اجرایی هستید، با 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، به جای آن یک اشکال استودیو را گزارش کنید .