หากไม่ได้ใช้ CMake หรือ ndk-build แต่ต้องการผสานรวมการสร้าง C/C++ ของปลั๊กอิน Gradle ของ Android (AGP) กับ 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 โดยตรง แต่ก็มีเครื่องมือสร้างโปรเจ็กต์อื่นๆ ที่ระบบไม่รองรับโดยตรง ดังนี้
เครื่องมือสร้างโปรเจ็กต์ประเภทเหล่านี้รองรับ Ninja เป็นการนําเสนอแบ็กเอนด์ของบิลด์ C/C++ หรือปรับให้สร้าง Ninja เป็นการนําเสนอแบ็กเอนด์ได้
เมื่อกําหนดค่าอย่างถูกต้อง โปรเจ็กต์ 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
คือรายการเป้าหมาย Ninja ที่เฉพาะเจาะจงซึ่งควรสร้าง
ขั้นตอนที่ 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
โดยทั่วไปแล้ว โครงสร้างส่วนใหญ่ที่แสดงถึงบิลด์ C/C++ ของ Android อย่างถูกต้องจะใช้งานได้ องค์ประกอบหลักที่ AGP และ Android Studio ต้องการมีดังนี้
รายการไฟล์ต้นทาง C/C++ พร้อมกับ Flag ที่ Clang ต้องใช้เพื่อคอมไพล์
รายการไลบรารีเอาต์พุต โดยปกติแล้วไฟล์เหล่านี้จะเป็นไฟล์
.so
(Shared Object) แต่อาจเป็นไฟล์.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
ระบุวิธีการสร้างอื่น (ไม่บังคับ)
Use Case ขั้นสูงขึ้นคือการรวมระบบการบิลด์ที่มีอยู่ซึ่งไม่ได้อิงตาม Ninja ในกรณีนี้ คุณยังคงต้องแสดงแหล่งที่มาทั้งหมดที่มี Flag ของแหล่งที่มานั้นๆ พร้อมกับไลบรารีเอาต์พุตเพื่อให้ Android Studio นำเสนอฟีเจอร์บริการภาษาที่เหมาะสม เช่น การเติมข้อความอัตโนมัติและคำจำกัดความที่ตรงกับความหมาย แต่คุณต้องการให้ AGP ขึ้นอยู่กับระบบบิลด์ที่ทำงานอยู่เบื้องหลังในระหว่างการสร้างจริง
คุณสามารถใช้เอาต์พุตการสร้างของ Ninja ที่มีนามสกุล .passthrough
ที่เฉพาะเจาะจงเพื่อดำเนินการนี้
ตัวอย่างที่ชัดเจนมากขึ้นคือสมมติว่าคุณต้องการรวม MSBuild สคริปต์การกําหนดค่าจะสร้าง build.ninja
ตามปกติ แต่ก็จะเพิ่มเป้าหมายการส่งผ่านที่กําหนดวิธีเรียกใช้ MSBuild ของ AGP ด้วย
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 ให้รายงานข้อบกพร่องโดยใช้เทมเพลตนี้