یکپارچه سازی سیستم های ساخت سفارشی C/C++ با استفاده از Ninja (تجربی)

اگر از CMake یا ndk-build استفاده نمی‌کنید، اما می‌خواهید پلاگین Android Gradle (AGP) C/C++ و Android Studio یکپارچه‌سازی شود، می‌توانید با ساخت یک اسکریپت پوسته که اطلاعات ساخت را در آن می‌نویسد، یک سیستم ساخت سفارشی C/C++ ایجاد کنید. فرمت فایل ساخت Ninja

پشتیبانی آزمایشی از سیستم‌های ساخت C/C++ سفارشی به Android Studio و AGP اضافه شده است. این ویژگی با شروع در Android Studio Dolphin | در دسترس است 2021.3.1 قناری 4.

نمای کلی

یک الگوی رایج برای پروژه‌های C/C++، به‌ویژه آنهایی که چندین پلتفرم را هدف قرار می‌دهند، تولید پروژه‌ها برای هر یک از آن پلتفرم‌ها از برخی نمایندگی‌های اساسی است. نمونه بارز این الگو CMake است. CMake می‌تواند پروژه‌هایی را برای Android، iOS و دیگر پلتفرم‌ها از یک نمایش زیربنایی، ذخیره شده در فایل CMakeLists.txt ایجاد کند.

در حالی که CMake مستقیماً توسط AGP پشتیبانی می شود، تولیدکنندگان پروژه دیگری نیز در دسترس هستند که مستقیماً پشتیبانی نمی شوند:

این نوع از مولدهای پروژه یا از Ninja به عنوان یک نمایش پشتیبان ساخت C/C++ پشتیبانی می کنند یا می توانند برای تولید Ninja به عنوان یک نمایش باطنی سازگار شوند.

هنگامی که به درستی پیکربندی شود، یک پروژه AGP با یک مولد سیستم پروژه C/C++ یکپارچه، کاربران را قادر می‌سازد:

  • ساخت از خط فرمان و اندروید استودیو.

  • منابع را با پشتیبانی کامل از خدمات زبان (به عنوان مثال، تعریف رفتن به تعریف) در Android Studio ویرایش کنید.

  • از دیباگرهای Android Studio برای اشکال زدایی فرآیندهای بومی و ترکیبی استفاده کنید.

چگونه بیلد خود را برای استفاده از اسکریپت پیکربندی ساخت سفارشی C/C++ تغییر دهید

این بخش مراحل استفاده از اسکریپت پیکربندی ساخت C/C++ سفارشی از AGP را طی می‌کند.

مرحله 1: فایل build.gradle سطح ماژول را برای ارجاع به یک اسکریپت پیکربندی تغییر دهید

برای فعال کردن پشتیبانی Ninja در AGP، experimentalProperties را در فایل build.gradle سطح ماژول پیکربندی کنید:

android {
  defaultConfig {
    externalNativeBuild {
      experimentalProperties["ninja.abiFilters"] = [ "x86", "arm64-v8a" ]
      experimentalProperties["ninja.path"] = "source-file-list.txt"
      experimentalProperties["ninja.configure"] = "configure-ninja"
      experimentalProperties["ninja.arguments"] = [
            "\${ndk.moduleMakeFile}",
            "--variant=\${ndk.variantName}",
            "--abi=Android-\${ndk.abi}",
            "--configuration-dir=\${ndk.configurationDir}",
            "--ndk-version=\${ndk.moduleNdkVersion}",
            "--min-sdk-version=\${ndk.minSdkVersion}"
       ]
     }
   }

ویژگی ها توسط AGP به صورت زیر تفسیر می شوند:

  • ninja.abiFilters فهرستی از ABI برای ساخت است. مقادیر معتبر عبارتند از: x86 ، x86-64 ، armeabi-v7a ، و arm64-v8a .

  • ninja.path مسیری به فایل پروژه C/C++ است. فرمت این فایل می تواند هر چیزی که می خواهید باشد. تغییراتی که در این فایل ایجاد می‌شود، یک درخواست برای همگام‌سازی Gradle در Android Studio ایجاد می‌کند.

  • ninja.configure مسیری به فایل اسکریپت است که زمانی که نیاز به پیکربندی پروژه C/C++ باشد توسط Gradle اجرا می شود. یک پروژه در اولین ساخت، در حین همگام سازی Gradle در Android Studio، یا زمانی که یکی از ورودی های پیکربندی اسکریپت تغییر می کند، پیکربندی می شود.

  • ninja.arguments لیستی از آرگومان هایی است که به اسکریپت تعریف شده توسط ninja.configure ارسال می شود. عناصر موجود در این لیست می توانند به مجموعه ای از ماکروها اشاره کنند که مقادیر آنها به زمینه پیکربندی فعلی در AGP بستگی دارد:

    • ${ndk.moduleMakeFile} مسیر کامل فایل ninja.configure است. بنابراین در مثال، C:\path\to\configure-ninja.bat خواهد بود.

    • ${ndk.variantName} نام نوع فعلی AGP است که در حال ساخت است. به عنوان مثال، اشکال زدایی یا انتشار.

    • ${ndk.abi} نام AGP ABI فعلی است که در حال ساخت است. به عنوان مثال، x86 یا arm64-v8a .

    • ${ndk.buildRoot} نام پوشه ای است که توسط AGP تولید شده است و اسکریپت خروجی خود را در آن می نویسد. جزئیات این مورد در مرحله 2 توضیح داده خواهد شد: اسکریپت پیکربندی را ایجاد کنید .

    • ${ndk.ndkVersion} نسخه NDK مورد استفاده است. این مقدار معمولاً مقداری است که در فایل build.gradle به android.ndkVersion ارسال می‌شود یا اگر هیچ کدام وجود نداشته باشد، یک مقدار پیش‌فرض است.

    • ${ndk.minPlatform} حداقل پلتفرم Android هدف درخواست شده توسط AGP است.

  • ninja.targets لیستی از اهداف خاص نینجا است که باید ساخته شوند.

مرحله 2: اسکریپت پیکربندی را ایجاد کنید

حداقل مسئولیت اسکریپت پیکربندی ( configure-ninja.bat در مثال قبلی) تولید یک فایل build.ninja است که وقتی با Ninja ساخته می‌شود، تمام خروجی‌های بومی پروژه را کامپایل و پیوند می‌دهد. معمولاً اینها فایل‌های .o (Object)، .a (Archive) و .so (Shared Object) هستند.

اسکریپت configure می تواند بسته به نیاز شما فایل build.ninja را در دو مکان مختلف بنویسد.

  • اگر انتخاب مکان برای AGP اشکالی ندارد، اسکریپت پیکربندی build.ninja در مکان تنظیم شده در ماکرو ${ndk.buildRoot} می نویسد.

  • اگر اسکریپت پیکربندی باید محل فایل build.ninja را انتخاب کند، فایلی به نام build.ninja.txt را نیز در محل تنظیم شده در ماکرو ${ndk.buildRoot} می نویسد. این فایل حاوی مسیر کامل فایل build.ninja است که اسکریپت پیکربندی نوشته است.

ساختار فایل build.ninja

به طور کلی، ساختار اکثری که به طور دقیق یک ساخت Android C/C++ را نشان می‌دهند، کار خواهند کرد. عناصر کلیدی مورد نیاز AGP و Android Studio عبارتند از:

  • لیست فایل های منبع C/C++ به همراه پرچم های مورد نیاز Clang برای کامپایل آنها.

  • فهرست کتابخانه های خروجی اینها معمولاً فایل‌های .so (اشیاء مشترک) هستند اما می‌توانند .a (بایگانی) یا قابل اجرا (بدون پسوند) باشند.

اگر به مثال‌هایی در مورد نحوه تولید فایل build.ninja نیاز دارید، می‌توانید هنگام استفاده از ژنراتور build.ninja به خروجی CMake نگاه کنید.

در اینجا نمونه ای از قالب build.ninja مینیمال است.

rule COMPILE
   command = /path/to/ndk/clang -c $in -o $out {other flags}
rule LINK
   command = /path/to/ndk/clang $in -o $out {other flags}

build source.o : COMPILE source.cpp
build lib.so : LINK source.o
بهترین شیوه ها

علاوه بر الزامات (فهرست فایل های منبع و کتابخانه های خروجی)، در اینجا برخی از بهترین روش های توصیه شده وجود دارد.

خروجی های نامگذاری شده را با قوانین phony اعلام کنید

در صورت امکان، توصیه می‌شود که ساختار build.ninja از قوانین phony برای دادن نام‌های قابل خواندن توسط انسان به خروجی‌های ساخت استفاده کند. بنابراین برای مثال، اگر خروجی‌ای به نام c:/path/to/lib.so دارید، می‌توانید به صورت زیر به آن یک نام قابل خواندن برای انسان بدهید.

build curl: phony /path/to/lib.so

مزیت انجام این کار این است که می توانید این نام را به عنوان هدف ساخت در فایل build.gradle مشخص کنید. به عنوان مثال،

android {
  defaultConfig {
    externalNativeBuild {
      ...
      experimentalProperties["ninja.targets"] = [ "curl" ]
یک هدف "همه" را مشخص کنید

وقتی یک all را مشخص می‌کنید، این مجموعه پیش‌فرض کتابخانه‌های ساخته‌شده توسط AGP خواهد بود، زمانی که هیچ هدفی به‌صراحت در فایل build.gradle مشخص نشده باشد.

rule COMPILE
   command = /path/to/ndk/clang $in -o $out {other flags}
rule LINK
   command = /path/to/ndk/clang $in -o $out {other flags}

build foo.o : COMPILE foo.cpp
build bar.o : COMPILE bar.cpp
build libfoo.so : LINK foo.o
build libbar.so : LINK bar.o
build all: phony libfoo.so libbar.so
یک روش ساخت جایگزین را مشخص کنید (اختیاری)

یک مورد استفاده پیشرفته تر، بسته بندی یک سیستم ساخت موجود است که مبتنی بر نینجا نیست. در این مورد، شما هنوز باید همه منابع را با پرچم‌هایشان به همراه کتابخانه‌های خروجی نشان دهید تا اندروید استودیو بتواند ویژگی‌های خدمات زبانی مناسبی مانند تکمیل خودکار و تعریف رفتن را ارائه دهد. با این حال، می‌خواهید AGP در طول ساخت واقعی، به سیستم ساخت زیربنایی موکول شود.

برای انجام این کار، می توانید از یک خروجی ساخت نینجا با پسوند خاص .passthrough استفاده کنید.

به عنوان مثال ملموس تر، فرض کنید می خواهید یک MSBuild را بپیچید. اسکریپت پیکربندی شما طبق معمول build.ninja را ایجاد می کند، اما همچنین یک هدف عبوری اضافه می کند که نحوه فراخوانی AGP MSBuild را مشخص می کند.

rule COMPILE
   command = /path/to/ndk/clang $in -o $out {other flags}
rule LINK
   command = /path/to/ndk/clang $in -o $out {other flags}

rule MBSUILD_CURL
  command = /path/to/msbuild {flags to build curl with MSBuild}

build source.o : COMPILE source.cpp
build lib.so : LINK source.o
build curl : phony lib.so
build curl.passthrough : MBSUILD_CURL
بازخورد بدهید

این ویژگی آزمایشی است، بنابراین بازخورد بسیار قابل قدردانی است. از طریق کانال های زیر می توانید نظرات خود را اعلام کنید:

  • برای بازخورد کلی، یک نظر به این اشکال اضافه کنید.

  • برای گزارش یک اشکال، Android Studio را باز کنید و روی Help > Submit Feedback کلیک کنید. حتماً به «Custom C/C++ Build Systems» رجوع کنید تا به رفع اشکال کمک کنید.

  • برای گزارش یک اشکال در صورتی که Android Studio را نصب نکرده‌اید، با استفاده از این الگو یک اشکال را ثبت کنید.