หากไม่ได้ใช้ CMake หรือ ndk-build แต่ต้องการการผสานรวมปลั๊กอิน Android Gradle (AGP) C/C++ และ Android Studio โดยสมบูรณ์ คุณสามารถสร้างระบบบิลด์ C/C++ ที่กำหนดเองได้ด้วยการสร้างสคริปต์เชลล์ที่เขียนข้อมูลบิลด์ในรูปแบบไฟล์ของ Ninja
เพิ่มการรองรับเวอร์ชันทดลองสำหรับระบบบิลด์ C/C++ ที่กำหนดเองใน Android Studio และ AGP แล้ว ฟีเจอร์นี้พร้อมให้บริการแล้วใน Android Studio Dolphin | 2021.3.1 Canary 4
ภาพรวม
รูปแบบทั่วไปสำหรับโครงการ C/C++ โดยเฉพาะโปรเจ็กต์ที่กำหนดเป้าหมายไปยังหลายแพลตฟอร์ม คือการสร้างโปรเจ็กต์สำหรับแต่ละแพลตฟอร์มจากตัวแทนที่สำคัญ
ตัวอย่างที่ชัดเจนของรูปแบบนี้คือ CMake CMake สามารถสร้างโปรเจ็กต์สำหรับ Android, iOS และแพลตฟอร์มอื่นๆ ได้จากการนำเสนอเดี่ยวๆ ที่สำคัญซึ่งบันทึกไว้ในไฟล์ CMakeLists.txt
แม้ว่า AGP จะรองรับ CMake โดยตรง แต่ก็มีเครื่องมือสร้างโปรเจ็กต์อื่นๆ ที่ไม่ได้รองรับโดยตรง เช่น
เครื่องมือสร้างโปรเจ็กต์ที่สร้างแบบส่วนตัว
เครื่องมือสร้างโปรเจ็กต์ประเภทนี้รองรับนินจาในฐานะตัวแทนแบ็กเอนด์ของบิลด์ C/C++ หรือจะปรับเปลี่ยนเพื่อสร้างนินจาเป็นตัวแทนแบ็กเอนด์ก็ได้
เมื่อกำหนดค่าอย่างถูกต้อง โปรเจ็กต์ AGP ที่มีเครื่องมือสร้างระบบโปรเจ็กต์ C/C++ ที่ผสานรวมจะช่วยให้ผู้ใช้ทำสิ่งต่อไปนี้ได้
สร้างจากบรรทัดคำสั่งและ Android Studio
แก้ไขแหล่งที่มาด้วยการรองรับบริการทุกภาษา (เช่น คำจำกัดความ) ใน 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 Studioninja.configure
เป็นเส้นทางไปยังไฟล์สคริปต์ที่จะเรียกใช้โดย Gradle เมื่อจำเป็นต้องกำหนดค่าโปรเจ็กต์ C/C++ โปรเจ็กต์ได้รับการกำหนดค่าในบิลด์แรก ระหว่างการซิงค์ 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 ที่จะใช้ โดยปกติแล้วจะเป็นค่าที่ส่งไปยัง android.ndkVersion ในไฟล์build.gradle
หรือค่าเริ่มต้นหากไม่มีข้อมูลแสดงอยู่${ndk.minPlatform}
เป็นแพลตฟอร์ม Android เป้าหมายขั้นต่ำที่ AGP ขอ
ninja.targets
คือรายการเป้าหมายนินจาที่ควรสร้างขึ้น
ขั้นตอนที่ 2: สร้างสคริปต์การกำหนดค่า
ความรับผิดชอบขั้นต่ำของสคริปต์การกำหนดค่า (configure-ninja.bat
ในตัวอย่างก่อนหน้านี้) คือการสร้างไฟล์ build.ninja
ซึ่งเมื่อสร้างด้วย Ninja แล้วระบบจะคอมไพล์และลิงก์เอาต์พุตดั้งเดิมทั้งหมดของโปรเจ็กต์ ซึ่งมักจะเป็นไฟล์ .o
(ออบเจ็กต์), .a
(ที่เก็บถาวร) และ .so
(ออบเจ็กต์ที่ใช้ร่วมกัน)
สคริปต์การกำหนดค่าสามารถเขียนไฟล์ build.ninja
ใน 2 ตำแหน่งที่แตกต่างกันตามความต้องการของคุณ
หาก 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
ให้ดูเอาต์พุตของ CMake เมื่อใช้โปรแกรมสร้าง build.ninja
ต่อไปนี้คือตัวอย่างของเทมเพลต 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
ระบุเมธอดบิลด์สำรอง (ไม่บังคับ)
กรณีการใช้งานขั้นสูงกว่าคือการรวมระบบบิลด์ที่มีอยู่ซึ่งไม่ใช่ระบบนินจา ในกรณีนี้ คุณยังคงต้องแสดงแหล่งที่มาทั้งหมดด้วย Flag ของแหล่งที่มานั้นพร้อมกับไลบรารีเอาต์พุตเพื่อให้ Android Studio นำเสนอฟีเจอร์ของบริการภาษาที่เหมาะสมได้ เช่น การเติมข้อความอัตโนมัติและการไปที่คำจำกัดความ อย่างไรก็ตามคุณต้องการให้ AGP เลื่อนไปที่ระบบบิลด์พื้นฐานระหว่างบิลด์จริง
คุณสามารถทำได้โดยใช้เอาต์พุตของบิลด์ Ninja ที่มีส่วนขยายที่เฉพาะเจาะจง .passthrough
เพื่อเป็นตัวอย่างที่เป็นรูปธรรมมากขึ้น สมมติว่าคุณต้องการรวม MSBuild สคริปต์การกำหนดค่าจะสร้าง build.ninja
ตามปกติ แต่จะเพิ่มเป้าหมาย Passthrough ที่กำหนดวิธีที่ 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 แล้วคลิกความช่วยเหลือ > ส่งความคิดเห็น อย่าลืมอ้างอิงถึง "ระบบบิลด์ C/C++ ที่กำหนดเอง" เพื่อช่วยกำหนดเส้นทางข้อบกพร่อง
หากต้องการรายงานข้อบกพร่องหากคุณไม่ได้ติดตั้ง Android Studio ให้รายงานข้อบกพร่องโดยใช้เทมเพลตนี้