คอมไพล์ด้วย Jack

Jack เป็น Android build toolchain เริ่มต้นสำหรับ Android 6.0 - 8.1 ซึ่งใช้คอมไพล์ซอร์ส Java เป็น Android dex bytecode ดังที่แสดงในรูปที่ 1

ภาพรวมของ Jack

รูปที่ 1 ภาพรวมของ Jack

รูปแบบไฟล์ .jack มีโค้ด dex ที่คอมไพล์ไว้ล่วงหน้าสำหรับไลบรารี ซึ่งช่วยให้คอมไพล์ได้เร็วขึ้น (pre-dex)

เนื้อหาไฟล์ไลบรารี Jack

รูปที่ 2 เนื้อหาไฟล์ไลบรารีของ Jack

เครื่องมือ Jill

เครื่องมือ Jill แปลงไลบรารี .jar ที่มีอยู่เป็นรูปแบบไลบรารี .jack ใหม่ ดังที่แสดงในรูปที่ 3

เวิร์กโฟลว์ในการนำเข้าไลบรารี `jar.` ที่มีอยู่

รูปที่ 3 เวิร์กโฟลว์ในการนำเข้าไลบรารี .jar ที่มีอยู่

เซิร์ฟเวอร์การคอมไพล์ของ Jack

เมื่อใช้ Jack เป็นครั้งแรก ระบบจะเปิดใช้เซิร์ฟเวอร์การคอมไพล์ของ Jack ในเครื่องคอมพิวเตอร์ของคุณ เซิร์ฟเวอร์นี้มีหน้าที่ดังนี้

  • ช่วยเพิ่มความเร็วโดยธรรมชาติเนื่องจากไม่ต้องเปิดใช้ JRE JVM ของโฮสต์ใหม่ โหลดโค้ด Jack เริ่มต้น Jack และวอร์มอัป JIT ในการคอมไพล์แต่ละครั้ง นอกจากนี้ยังช่วยให้คอมไพล์ได้เร็วมากในระหว่างการคอมไพล์ขนาดเล็ก (เช่น ในโหมดเพิ่ม)
  • เป็นโซลูชันระยะสั้นในการควบคุมจำนวนการคอมไพล์ของ Jack แบบขนาน เซิร์ฟเวอร์จะช่วยไม่ให้คอมพิวเตอร์ของคุณทำงานหนักเกินไป (ปัญหาเกี่ยวกับหน่วยความจำหรือดิสก์) เนื่องจากจำกัดจำนวนการคอมไพล์แบบขนาน

เซิร์ฟเวอร์ Jack จะปิดตัวเองหลังจากไม่มีการใช้งานเป็นระยะเวลาหนึ่งโดยไม่มีการคอมไพล์ โดยจะใช้พอร์ต TCP 2 พอร์ตในอินเทอร์เฟซ localhost และไม่สามารถใช้งานภายนอกได้ คุณสามารถแก้ไขพารามิเตอร์ทั้งหมด (เช่น จำนวนการคอมไพล์แบบขนาน การหมดเวลา และหมายเลขพอร์ต) ได้โดยแก้ไขไฟล์ $HOME/.jack

ไฟล์ $HOME/.jack

ไฟล์ $HOME/.jack มีการตั้งค่าต่อไปนี้สำหรับตัวแปรเซิร์ฟเวอร์ Jack ในไวยากรณ์ bash แบบเต็ม

  • SERVER=true จะเปิดใช้ฟีเจอร์เซิร์ฟเวอร์ของ Jack
  • SERVER_PORT_SERVICE=8072 จะตั้งหมายเลขพอร์ต TCP ของเซิร์ฟเวอร์เพื่อวัตถุประสงค์ในการคอมไพล์
  • SERVER_PORT_ADMIN=8073 จะตั้งหมายเลขพอร์ต TCP ของเซิร์ฟเวอร์เพื่อวัตถุประสงค์ในการดูแลระบบ
  • SERVER_COUNT=1 ไม่ได้ใช้
  • SERVER_NB_COMPILE=4 จะตั้งจำนวนการคอมไพล์แบบขนานสูงสุดที่อนุญาต SERVER_TIMEOUT=60 จะตั้งจำนวนวินาทีที่เซิร์ฟเวอร์ต้องรอโดยไม่มีการคอมไพล์ก่อนที่จะปิดตัวเอง SERVER_LOG=${SERVER_LOG:=$SERVER_DIR/jack-$SERVER_PORT_SERVICE.log} จะตั้งไฟล์ที่จะเขียนบันทึกของเซิร์ฟเวอร์ โดยค่าเริ่มต้น ตัวแปรนี้สามารถโหลดมากเกินไปได้ด้วยตัวแปรสภาพแวดล้อม
  • JACK_VM_COMMAND=${JACK_VM_COMMAND:=java} จะตั้งค่าคำสั่งเริ่มต้นที่ใช้เปิดใช้ JVM ในโฮสต์ โดยค่าเริ่มต้น ตัวแปรนี้สามารถโหลดมากเกินไปได้ด้วยตัวแปรสภาพแวดล้อม

แก้ปัญหาการคอมไพล์ของ Jack

ปัญหา การทำงาน
คอมพิวเตอร์ไม่ตอบสนองระหว่างการคอมไพล์ หรือคุณพบว่าการคอมไพล์ของ Jack ล้มเหลวเนื่องจาก ข้อผิดพลาดหน่วยความจำไม่เพียงพอ ลดจำนวนการคอมไพล์ของ Jack พร้อมกันโดยแก้ไข $HOME/.jack และเปลี่ยน SERVER_NB_COMPILE เป็นค่าที่ต่ำลง
การคอมไพล์ล้มเหลวเนื่องจาก ไม่สามารถเปิดใช้เซิร์ฟเวอร์เบื้องหลังได้ สาเหตุที่เป็นไปได้มากที่สุดคือพอร์ต TCP ถูกใช้ในคอมพิวเตอร์ของคุณแล้ว เปลี่ยนพอร์ตโดยแก้ไข $HOME/.jack (ตัวแปร SERVER_PORT_SERVICE และ SERVER_PORT_ADMIN) หากต้องการยกเลิกการบล็อกสถานการณ์นี้ ให้ปิดใช้เซิร์ฟเวอร์การคอมไพล์ของ Jack โดยแก้ไข $HOME/.jack และเปลี่ยน SERVER เป็น false น่าเสียดายที่การดำเนินการนี้จะทำให้การคอมไพล์ช้าลงอย่างมาก และอาจบังคับให้คุณเปิดใช้ make -j ด้วยการควบคุมการโหลด (ตัวเลือก -l ของ make)
การคอมไพล์ค้างโดยไม่มีความคืบหน้า หากต้องการยกเลิกการบล็อกสถานการณ์นี้ ให้หยุดเซิร์ฟเวอร์เบื้องหลังของ Jack โดยใช้ jack-admin kill-server) จากนั้นนำไดเรกทอรีชั่วคราวที่อยู่ใน jack-$USER ของไดเรกทอรีชั่วคราว (/tmp หรือ $TMPDIR) ออก

ค้นหาบันทึกของ Jack

หากคุณเรียกใช้คำสั่ง make ด้วยเป้าหมาย dist บันทึกของ Jack จะอยู่ที่ $ANDROID_BUILD_TOP/out/dist/logs/jack-server.log มิเช่นนั้น คุณสามารถค้นหาบันทึกได้โดยเรียกใช้ jack-admin server-log ในกรณีที่ Jack ล้มเหลวซ้ำได้ คุณสามารถดูบันทึกโดยละเอียดเพิ่มเติมได้โดยตั้งค่าตัวแปรต่อไปนี้

export ANDROID_JACK_EXTRA_ARGS="--verbose debug --sanity-checks on -D sched.runner=single-threaded"

ใช้คำสั่ง makefile มาตรฐานเพื่อคอมไพล์ทรี (หรือโปรเจ็กต์) และแนบเอาต์พุตและข้อผิดพลาดมาตรฐาน หากต้องการนำบันทึกการคอมไพล์โดยละเอียดออก ให้เรียกใช้คำสั่งต่อไปนี้

unset ANDROID_JACK_EXTRA_ARGS

ข้อจำกัดของ Jack

โดยค่าเริ่มต้น ผู้ใช้เพียงคนเดียวในคอมพิวเตอร์เท่านั้นที่ใช้เซิร์ฟเวอร์ Jack ได้ หากต้องการรองรับผู้ใช้เพิ่มเติม ให้เลือกหมายเลขพอร์ตอื่นสำหรับผู้ใช้แต่ละรายและปรับ SERVER_NB_COMPILE ตามความเหมาะสม นอกจากนี้ คุณยังปิดใช้เซิร์ฟเวอร์ Jack ได้โดยตั้งค่า SERVER=false ใน $HOME/.jack การคอมไพล์ CTS ช้าเนื่องจากการผสานรวม vm-tests-tf ในปัจจุบัน ระบบไม่รองรับเครื่องมือจัดการ bytecode (เช่น JaCoCo)

ใช้ Jack

Jack รองรับภาษาโปรแกรม Java 1.7 และผสานรวมฟีเจอร์เพิ่มเติมที่อธิบายไว้ในส่วนนี้ ใช้คำสั่ง makefile มาตรฐานเพื่อคอมไพล์ทรีหรือโปรเจ็กต์

Pre-dex

เมื่อสร้างไฟล์ไลบรารีของ Jack ระบบจะสร้าง .dex ของไลบรารีและจัดเก็บไว้ในไฟล์ไลบรารี .jack เป็น pre-dex เมื่อคอมไพล์ Jack จะใช้ pre-dex จากแต่ละไลบรารีซ้ำ ไลบรารีทั้งหมดจะได้รับการ pre-dex

ไลบรารีของ Jack ที่มีดัชนีล่วงหน้า

รูปที่ 4 ไลบรารีของ Jack ที่มี pre-dex

Jack จะไม่ใช้ pre-dex ของไลบรารีซ้ำหากใช้การลดขนาด การปรับให้ยากต่อการอ่าน หรือการจัดแพ็กเกจใหม่ในการคอมไพล์

การคอมไพล์แบบเพิ่ม

การคอมไพล์แบบเพิ่มหมายความว่าระบบจะคอมไพล์เฉพาะคอมโพเนนต์ที่ได้รับผลกระทบตั้งแต่การคอมไพล์ครั้งล่าสุด (และทรัพยากร Dependency ของคอมโพเนนต์เหล่านั้น) อีกครั้ง การคอมไพล์แบบเพิ่มอาจเร็วกว่าการคอมไพล์แบบเต็มอย่างมากเมื่อการเปลี่ยนแปลงจำกัดอยู่เพียงชุดคอมโพเนนต์

ระบบจะปิดใช้การคอมไพล์แบบเพิ่มโดยค่าเริ่มต้น (และจะปิดใช้งานโดยอัตโนมัติเมื่อเปิดใช้การลดขนาด การปรับให้ยากต่อการอ่าน การจัดแพ็กเกจใหม่ หรือ multidex เดิม) หากต้องการเปิดใช้บิลด์แบบเพิ่ม ให้เพิ่มบรรทัดต่อไปนี้ลงในไฟล์ Android.mk ของโปรเจ็กต์ที่ต้องการคอมไพล์แบบเพิ่ม

LOCAL_JACK_ENABLED := incremental

การลดขนาดและการปรับให้ยากต่อการอ่าน

Jack ใช้ไฟล์การกำหนดค่า ProGuard เพื่อเปิดใช้การลดขนาดและการปรับให้ยากต่อการอ่าน ตัวเลือกทั่วไปมีดังนี้

  • @
  • -include
  • -basedirectory
  • -injars
  • -outjars (รองรับ jar เอาต์พุตเพียง 1 รายการ)
  • -libraryjars
  • -keep
  • -keepclassmembers
  • -keepclasseswithmembers
  • -keepnames
  • -keepclassmembernames
  • -keepclasseswithmembernames
  • -printseeds

ตัวเลือกการลดขนาดมีดังนี้

  • -dontshrink

ตัวเลือกการปรับให้ยากต่อการอ่านมีดังนี้

  • -dontobfuscate
  • -printmapping
  • -applymapping
  • -obfuscationdictionary
  • -classobfuscationdictionary
  • -packageobfuscationdictionary
  • -useuniqueclassmembernames
  • -dontusemixedcaseclassnames
  • -keeppackagenames
  • -flattenpackagehierarchy
  • -repackageclasses
  • -keepattributes
  • -adaptclassstrings

ตัวเลือกที่ระบบไม่สนใจมีดังนี้

  • -dontoptimize (Jack ไม่ได้เพิ่มประสิทธิภาพ)
  • -dontpreverify (Jack ไม่ได้ตรวจสอบล่วงหน้า)
  • -skipnonpubliclibraryclasses
  • -dontskipnonpubliclibraryclasses
  • -dontskipnonpubliclibraryclassmembers
  • -keepdirectories
  • -target
  • -forceprocessing
  • -printusage
  • -whyareyoukeeping
  • -optimizations
  • -optimizationpasses
  • -assumenosideeffects
  • -allowaccessmodification
  • -mergeinterfacesaggressively
  • -overloadaggressively
  • -microedition
  • -verbose
  • -dontnote
  • -dontwarn
  • -ignorewarnings
  • -printconfiguration
  • -dump

การจัดแพ็กเกจใหม่

Jack ใช้ไฟล์การกำหนดค่า jarjar เพื่อจัดแพ็กเกจใหม่ แม้ว่า Jack จะเข้ากันได้กับประเภทกฎ rule แต่ก็ไม่เข้ากันได้กับประเภทกฎ zap หรือ keep

การรองรับ multidex

Jack มีการรองรับ multidex ในตัวและแบบเดิม เนื่องจากไฟล์ dex จำกัดไว้ที่ 65,000 เมธอด แอปที่มีเมธอดมากกว่า 65,000 เมธอดจึงต้องแยกออกเป็นไฟล์ dex หลายไฟล์ ดูข้อมูลเพิ่มเติมได้ที่หัวข้อเปิดใช้ multidex สำหรับแอปที่มีเมธอดมากกว่า 64, 000 เมธอด