Ninja kullanarak özel C/C++ derleme sistemlerini entegre edin (deneysel)

CMake veya ndk-build kullanmıyor, ancak Android Gradle eklentisi (AGP) C/C++ derlemesi ile Android Studio'nun tam entegrasyonunu istiyorsanız yapı bilgilerini Ninja derleme dosya biçiminde yazan bir kabuk komut dosyası oluşturarak özel bir C/C++ derleme sistemi oluşturabilirsiniz.

Android Studio ve AGP'ye özel C/C++ derleme sistemleri için deneysel destek eklendi. Bu özellik, Android Studio Dolphin | 2021.3.1 Canary 4 sürümünden itibaren kullanılabilir.

Genel bakış

Özellikle birden fazla platformu hedefleyen C/C++ projelerindeki yaygın yaklaşım, bu platformların her biri için temel bazı temsillerden projeler oluşturmaktır. Bu durumun belirgin bir örneği CMake'dır. CMake, CMakeLists.txt dosyasına kaydedilen tek bir temel temsilden Android, iOS ve diğer platformlar için projeler oluşturabilir.

CMake doğrudan AGP tarafından desteklense de doğrudan desteklenmeyen başka proje oluşturma araçları da mevcuttur:

Bu tür proje oluşturucuları ya C/C++ derlemesinin arka uç temsili olarak Ninja'yı destekler ya da Ninja'yı arka uç temsili olarak oluşturmak üzere uyarlanabilir.

Entegre C/C++ proje sistemi oluşturucuya sahip bir AGP projesi doğru yapılandırıldığında kullanıcıların şunları yapmasına olanak tanır:

  • Komut satırından ve Android Studio'dan derleme yapın.

  • Kaynakları Android Studio'da tam dil hizmeti desteğiyle (ör. tanıma git) düzenleyin.

  • Yerel ve karma işlemlerde hata ayıklamak için Android Studio hata ayıklayıcılarını kullanın.

Derlemenizi özel bir C/C++ derleme yapılandırma komut dosyası kullanacak şekilde değiştirme

Bu bölümde, AGP'den özel bir C/C++ derleme yapılandırması komut dosyası kullanma adımları açıklanmaktadır.

1. Adım: Modül düzeyindeki build.gradle dosyasını, bir yapılandırma komut dosyasına referans verecek şekilde değiştirin

AGP'de Ninja desteğini etkinleştirmek için modül düzeyindeki build.gradle dosyasında experimentalProperties politikasını yapılandırın:

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}"
       ]
     }
   }

Özellikler AGP tarafından aşağıdaki gibi yorumlanır:

  • ninja.abiFilters, oluşturulacak ABI'lerin listesidir. Geçerli değerler şunlardır: x86, x86-64, armeabi-v7a ve arm64-v8a.

  • ninja.path, bir C/C++ proje dosyasının yoludur. Bu dosyanın biçimi istediğiniz herhangi bir biçim olabilir. Bu dosyada yapılan değişiklikler, Android Studio'da Gradle senkronizasyonu istemini tetikler.

  • ninja.configure, C/C++ projesini yapılandırmak gerektiğinde Gradle tarafından yürütülecek bir komut dosyası yoludur. Proje ilk derlemede, Android Studio'daki bir Gradle senkronizasyonu sırasında veya yapılandırma komut dosyası girişlerinden biri değiştiğinde yapılandırılır.

  • ninja.arguments, ninja.configure tarafından tanımlanan komut dosyasına aktarılacak bir bağımsız değişken listesidir. Bu listedeki öğeler, değerleri AGP'deki geçerli yapılandırma bağlamına bağlı olan bir makro grubuna başvurabilir:

    • ${ndk.moduleMakeFile}, ninja.configure dosyasının tam yoludur. Örnekte bu değer C:\path\to\configure-ninja.bat olacaktır.

    • ${ndk.variantName}, oluşturulmakta olan mevcut AGP varyantının adıdır. Örneğin, hata ayıklama veya sürüm.

    • ${ndk.abi}, oluşturulmakta olan geçerli AGP ABI'nın adıdır. Örneğin, x86 veya arm64-v8a.

    • ${ndk.buildRoot}, komut dosyasının çıktısını yazdığı, AGP tarafından oluşturulan bir klasörün adıdır. Bununla ilgili ayrıntılar, 2. Adım: Yapılandırma komut dosyasını oluşturma bölümünde açıklanmıştır.

    • ${ndk.ndkVersion}, kullanılacak NDK'nın sürümüdür. Bu genellikle build.gradle dosyasında android.ndkVersion öğesine iletilen değer veya mevcut değilse varsayılan bir değerdir.

    • ${ndk.minPlatform}, AGP tarafından istenen minimum hedef Android platformudur.

  • ninja.targets, oluşturulması gereken belirli Ninja hedeflerinin listesidir.

2. Adım: Yapılandırma komut dosyasını oluşturun

Yapılandırma komut dosyasının minimum sorumluluğu (önceki örnekte configure-ninja.bat), Ninja ile oluşturulduğunda projenin tüm yerel çıkışlarını derleyip bağlayacak bir build.ninja dosyası oluşturmaktır. Bunlar genellikle .o (Nesne), .a (Arşiv) ve .so (Paylaşılan Nesne) dosyalarıdır.

Yapılandırma komut dosyası, ihtiyaçlarınıza bağlı olarak build.ninja dosyasını iki farklı yere yazabilir.

  • AGP'nin konum seçmesinde bir sakınca yoksa yapılandırma komut dosyası, ${ndk.buildRoot} makrosunda ayarlanan konuma build.ninja yazar.

  • Yapılandırma komut dosyasının build.ninja dosyasının konumunu seçmesi gerekiyorsa ${ndk.buildRoot} makrosunda ayarlanan konuma build.ninja.txt adlı bir dosya da yazar. Bu dosya, yapılandırma komut dosyasının yazdığı build.ninja dosyasının tam yolunu içerir.

build.ninja dosyasının yapısı

Genellikle, bir Android C/C++ derlemesini doğru şekilde temsil eden çoğu yapı işe yarayacaktır. AGP ve Android Studio için gereken temel öğeler şunlardır:

  • Clang'ın derlemek için ihtiyaç duyduğu işaretlerle birlikte C/C++ kaynak dosyalarının listesi.

  • Çıkış kitaplıklarının listesi. Bunlar genellikle .so (paylaşılan nesne) dosyalarıdır, ancak aynı zamanda .a (arşiv) veya yürütülebilir (uzantısız) olabilir.

build.ninja dosyasının nasıl oluşturulacağına ilişkin örneklere ihtiyacınız varsa build.ninja oluşturucu kullanıldığında CMake'in çıktısına bakabilirsiniz.

Aşağıda, minimal bir build.ninja şablonu örneği verilmiştir.

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

En iyi uygulamalar

Koşulların (kaynak dosyaları ve çıkış kitaplıkları listesi) yanı sıra önerilen en iyi uygulamalardan bazıları aşağıda verilmiştir.

phony kuralla adlandırılmış çıkışlar bildir

Mümkün olduğunda, derleme çıktılarına kullanıcıların okuyabileceği adlar vermek için build.ninja yapısının phony kuralları kullanması önerilir. Örneğin, c:/path/to/lib.so adlı bir çıkışınız varsa buna aşağıdaki gibi kullanıcılar tarafından okunabilir bir ad verebilirsiniz.

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

Bunu yapmanın avantajı, bu adı build.gradle dosyasında bir derleme hedefi olarak belirtebilmenizdir. Örneğin,

android {
  defaultConfig {
    externalNativeBuild {
      ...
      experimentalProperties["ninja.targets"] = [ "curl" ]

Bir "tümü" hedefi belirtme

Bir all hedefi belirlediğinizde, build.gradle dosyasında açıkça hedef belirtilmediğinde AGP tarafından oluşturulan varsayılan kitaplık grubu bu olur.

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

Alternatif bir derleme yöntemi belirtin (isteğe bağlı)

Daha gelişmiş bir kullanım alanı, Ninja tabanlı olmayan mevcut bir derleme sistemini sarmalamaktır. Bu durumda, Android Studio'nun otomatik tamamlama ve tanıma git gibi doğru dil hizmeti özelliklerini sunabilmesi için tüm kaynakları çıkış kitaplıklarıyla birlikte işaretleriyle temsil etmeniz gerekir. Ancak, AGP'nin gerçek derleme sırasında temel derleme sistemini dikkate almasını istersiniz.

Bunu yapmak için belirli bir uzantıya (.passthrough) sahip bir Ninja derleme çıkışı kullanabilirsiniz.

Daha somut bir örnek olarak, bir MSBuild'i sarmalamak istediğinizi varsayalım. Yapılandırma komut dosyanız build.ninja öğesini her zamanki gibi oluşturur ancak AGP'nin MSBuild'i nasıl çağıracağını tanımlayan bir geçiş hedefi de ekler.

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

Geri bildirim gönder

Bu özellik deneysel olduğundan geri bildirimleriniz bizim için çok önemlidir. Aşağıdaki kanallar üzerinden geri bildirimde bulunabilirsiniz:

  • Genel geri bildirim için bu hataya yorum ekleyin.

  • Bir hatayı bildirmek için Android Studio'yu açın ve Yardım > Geri Bildirim Gönder'i tıklayın. Hatanın yönlendirilmesine yardımcı olması için "Özel C/C++ Derleme Sistemleri"ni referans almayı unutmayın.

  • Android Studio yüklü değilse hataları bildirmek için bu şablonu kullanarak hata bildiriminde bulunun.