เกี่ยวกับการสร้าง debian package
เดเบียนมีระบบแพกเกจที่ค่อนข้างครบเครื่อง และการ build แพกเกจ ก็มีเครื่องมืออำนวยความสะดวกหลายตัว ใครสนใจหัด build deb ก็อ่าน Debian New Maintainers' Guide ได้ครับ เนื้อหาค่อนข้างครบครัน ในบทความนี้ เราจะมาดูเครื่องมือ build deb กันคร่าว ๆ ก่อน
ก่อนอื่น มาดูส่วนประกอบของ source สำหรับ debian package กันก่อน โดยลองดึง source ของแพกเกจสักตัวมาดู:
$ apt-get source package
จะได้ส่วนประกอบของ source ทั้งหมดสำหรับ build แพกเกจ (ถ้าไม่สำเร็จ ลองตรวจดู /etc/apt/sources.list ว่ามีบรรทัด deb-src หรือเปล่า) ซึ่งโดยปกติ source ดังกล่าวจะประกอบด้วย:
package_version-release.dsc เป็นแฟ้มที่ list แฟ้มทั้งหมดที่เกี่ยวข้อง package_version.orig.tar.gz เป็นซอร์สโค้ดต้นฉบับจากต้นน้ำ (upstream) โดยยังไม่มีการแก้ไขใด ๆ บางครั้งเรียกว่า pristine source (ซอร์สบริสุทธิ์) package_version-release.diff.gz เป็น patch ที่จะเพิ่มกฎการ build deb รวมทั้ง patch ที่เปลี่ยนแปลงแก้ไขซอร์สต้นฉบับตามความจำเป็นสำหรับเดเบียน สังเกตว่าเดเบียนจะแยก pristine source กับ debian patch จากกันต่างหาก ซึ่งจะมีประโยชน์สองทาง ทางแรกคือ เพื่อให้ชัดเจน ว่าเดเบียนแก้ไขอะไรไปบ้าง ถ้าพูดถึงข้อกฎหมายก็จะดูได้ง่าย รวมทั้งช่วยให้สะดวกในการตรวจสอบส่วนที่ยังไม่รวมเข้าในซอร์สต้นน้ำด้วย ส่วนอีกทางหนึ่ง คือประหยัดเนื้อที่ในแหล่ง mirror (ถ้าเทียบกับระบบอย่าง rpm) เพราะ release ต่าง ๆ ที่ใช้ upstream version เดียวกัน จะเก็บ pristine source เพียงชุดเดียวใน mirror และแต่ละ release จะต่างกันแค่ส่วน debian patch เท่านั้น
เมื่อได้แฟ้มเหล่านี้มาแล้ว apt-get ก็จะแตก source tarball พร้อมกับ apply patch ให้อย่างเรียบร้อย ซึ่งเมื่อเข้าไปดูเนื้อหาข้างใน จะมีไดเรกทอรี debian/ ซึ่งเก็บข้อมูลต่าง ๆ สำหรับการ build deb โดยแฟ้มที่เป็นศูนย์กลางของกลไกการ build จะอยู่ที่ debian/rules ซึ่งเนื้อหาก็เป็น Makefile ธรรมดานี่เอง แต่จะมี target ชุดหนึ่งที่เดเบียนกำหนดไว้สำหรับการ build แพกเกจ ส่วนแฟ้มอื่น ๆ ที่สำคัญก็คือ debian/control ซึ่งเก็บ metadata ของแพกเกจ เช่น ชื่อแพกเกจ คำบรรยาย ความสัมพันธ์กับแพกเกจอื่น ฯลฯ และ debian/changelog ซึ่งเก็บบันทึกการเปลี่ยนแปลงของ release ต่าง ๆ และ เดเบียนจะถือข้อมูลล่าสุดใน debian/changelog เป็นสำคัญ ในการกำหนดรุ่นของแพกเกจ
สำรวจพอคร่าว ๆ แล้ว ก่อนลงมือ build ก็ทำให้แน่ใจเสียก่อน ว่ามีสิ่งที่ต้องใช้ครบ โดยสั่ง:
# apt-get build-dep package
เป็นการติดตั้งแพกเกจอื่น ๆ ที่จำเป็นสำหรับการ build แพกเกจที่กำหนด จากนั้น เมื่อได้ครบแล้ว ก็ลงมือ build กันเลย คำสั่งที่ใช้ก็คือ dpkg-buildpackage (อยู่ในแพกเกจ dpkg-dev) โดย cd ไปที่ไดเรกทอรีบนสุดของซอร์สโค้ดที่แตกออกมา แล้วก็สั่ง:
$ dpkg-buildpackage -rfakeroot
เมื่อ build เสร็จ จะได้แฟ้ม *.deb อยู่ที่ไดเรกทอรีถัดขึ้นไป
จบตอนแรกนี้ คุณก็สามารถ build debian package จากซอร์สเองได้แล้ว แต่ถ้าคุณต้องการ build แพกเกจระดับคุณภาพ เพื่อใช้เผยแพร่ จะมีเครื่องมืออื่นที่น่าใช้กว่านี้อีก ซึ่งจะกล่าวถึงในตอนต่อไป
คล้าย ๆ กับที่ภาษาซีมี lint เป็นเครื่องมือตรวจสอบปัญหาในซอร์สโค้ด เดเบียนก็มีเครื่องมือที่ล้อชื่อกัน สำหรับตรวจสอบปัญหาในแพกเกจ คือ lintian แล้วก็มีเครื่องมือใหม่อีกชุดหนึ่งที่เกิดขึ้นทีหลัง คือ linda ถ้าคุณจะสร้างแพกเกจที่ใช้เผยแพร่ล่ะก็ คุณต้องไม่พลาดเครื่องมือทั้งสองนี้เด็ดขาด
นอกจากนี้ ในช่วงท้ายของตอนนี้ จะได้กล่าวถึง debuild ซึ่งเป็นเครื่องมือสร้างแพกเกจที่รวมทุกขั้นตอนไว้ให้คุณสั่งได้ง่าย ๆ
เมื่อคุณสร้างแพกเกจด้วยคำสั่ง dpkg-buildpackage แล้ว ก็สามารถตรวจสอบปัญหาด้วย lintian หรือ linda ได้โดยสั่งแบบนี้:
$ lintian -i package_version-release_arch.changes $ linda -i package_version-release_arch.changes
ปัญหาจะมีสองแบบ คือ error จะขึ้นต้นด้วย E: และ warning จะขึ้นต้นด้วย W: ก็เหมือนกับการเขียนโปรแกรมทั่วไป คุณไม่ควรให้มี error เหลืออยู่ และถ้าจะอัปโหลดเข้าเดเบียนอย่างเป็นทางการ ก็ไม่ควรมี warning เหลืออยู่เลย
สังเกตว่าแฟ้ม *.changes นั้น จะถูกสร้างขณะ build แพกเกจ เป็นการสรุปการเปลี่ยนแปลงทั้งหมดที่เกิดขึ้นในการ build ครั้งนี้ เพื่อใช้ในการอัปโหลดเข้าแหล่งของเดเบียนต่อไป เนื้อหาในนั้นจะประกอบด้วยข้อมูลของการ build, รายการ changelog ของรุ่นที่ build และรายการแฟ้มที่จะอัปโหลดทั้งหมด (ได้แก่ debian patch และ *.deb ที่เป็นผลลัพธ์ และถ้าเป็น release *-1 ที่ต้องอัปโหลด *.orig.tar.gz ด้วย ก็จะมีเพิ่มด้วย) ดังนั้น การสั่ง lintian/linda กับแฟ้ม *.changes จึงเป็นการตรวจสอบทุกแฟ้มที่เกี่ยวข้องกับการอัปโหลด มีกี่แพกเกจก็ตรวจสอบครบหมด
หากคุณจะตรวจสอบแยกรายการ ก็ทำได้ เช่น เมื่อจะตรวจสอบ binary package ก็สั่ง lintian/linda กับ *.deb ได้เลย:
$ lintian -i foo.deb $ linda -i foo.deb
หรือถ้าจะตรวจสอบซอร์สของแพกเกจ ก็สั่ง lintian/linda กับ *.dsc:
$ lintian -i foo.dsc $ linda -i foo.dsc
lintian และ linda อยู่ในแพกเกจชื่อเดียวกับโปรแกรม (คือ lintian และ linda ตามลำดับ)
ด้วยมาตรฐานคุณภาพของเดเบียน ขั้นตอนการตรวจสอบคุณภาพนี้จึงไม่ใช่แค่ส่วนเสริม แต่กลายเป็นเรื่องจำเป็นเลยทีเดียว และเพื่ออำนวยความสะดวกแก่ผู้ดูแลแพกเกจ จึงมีสคริปต์ตัวหนึ่งที่ช่วยเรียกทุกขั้นตอน ตั้งแต่ build แพกเกจ, ตรวจสอบคุณภาพด้วย lintian/linda และเซ็นกำกับแฟ้มอัปโหลดด้วย GPG เสร็จในคำสั่งเดียว คือ debuild (อยู่ในแพกเกจ devscripts)
ดังนั้น จึงขอแนะนำผู้ที่จะ build แพกเกจเพื่อเผยแพร่ ว่าควรใช้ debuild ในการสร้างแพกเกจ แทนการสั่ง dpkg-buildpackage โดยตรง วิธีสั่งก็แค่สั่งแบบนี้ที่ไดเรกทอรีซอร์ส:
$ debuild
ถ้าคุณต้องการเซ็น GPG กำกับแฟ้ม *.changes และ *.dsc เพื่อการอัปโหลด ก็ทำได้โดยเพิ่มตัวเลือก -k ตามด้วย key ID เช่น:
$ debuild -kkey-id
แต่จะให้ดี ก็กำหนดแบบถาวรไว้ใน /etc/devscripts.conf หรือ ~/.devscripts เลย เพื่อจะได้ไม่ต้องเพิ่มตัวเลือก -k ทุกครั้งที่ build โดยกำหนดรายการนี้:
DEBSIGN_KEYID="key-id"
ใน New Maintainers' Guide ยังได้แนะนำอีกรายการหนึ่ง ซึ่งมีประโยชน์สำหรับคนที่ build แพกเกจภายใน working copy ของ CVS หรือ SVN:
DEBUILD_DPKG_BUILDPACKAGE_OPTS="-i -ICVS -I.svn"
อาจจะเพิ่ม -I.git หรืออะไรก็แล้วแต่ ตามระบบ version control ที่คุณใช้ จะเป็นการส่งตัวเลือกผ่าน debuild ไปให้ dpkg-buildpackage เสมอ ว่าให้ข้ามไดเรกทอรีของระบบ version control ขณะเก็บแฟ้มต่าง ๆ เข้าแพกเกจ (lintian/linda จะบ่น ถ้าพบไดเรกทอรีดังกล่าวปะปนไปในแพกเกจด้วย)
เครื่องมือ build และตรวจสอบคุณภาพของเดเบียนยังไม่จบแค่นี้ ตอนหน้าจะพูดถึงเครื่องมือ build อีกตัวหนึ่ง ที่ถ้าคุณดูแลแพกเกจไประยะหนึ่ง จะต้องพบกรณีที่ทำให้นึกถึงเครื่องมือแบบนี้ ไม่วันใดก็วันหนึ่ง
หมายเหตุ: นี่คงเป็นรายการสุดท้ายสำหรับการกู้บทความเก่าของผม เขียนครั้งหน้าจะเป็นเนื้อหาใหม่แล้วครับ
เราได้พูดถึงคำสั่งสำหรับ build debian package ไปแล้วสองตัว คือ dpkg-buildpackage และ debuild ซึ่งตัวแรกจะใช้สร้าง .deb ส่วนตัวหลังจะเรียกตัวแรก ตามด้วยการตรวจสอบคุณภาพด้วย lintian/linda พร้อมทั้งเซ็นกำกับ (ถ้าระบุ) ..ครบทุกขั้นตอน
การ build ด้วย debuild เสมอ จะช่วยให้แน่ใจได้ว่าไม่พลาดอะไรไป ไม่ว่าจะเป็น option ต่าง ๆ ที่ใช้ build หรือเป็นความผิดพลาดใน rules เอง หรือกระทั่งความผิดพลาดที่เกิดจากการเซ็ตระบบระหว่าง build เช่น การเผลอไปลิงก์กับไลบรารีใน /usr/local/lib ที่คุณคอมไพล์จากซอร์สเอง แทนที่จะลิงก์กับไลบรารีของ debian ซึ่งความจู้จี้ของลินดาจะช่วยชีวิตคุณไว้ได้ แต่เมื่อคุณ maintain แพกเกจไประยะหนึ่ง ก็จะพบกับกรณีบางอย่าง ที่ทำให้นึกถึงเครื่องมือช่วยเพิ่มเติมอีก เช่น
แน่นอนว่าเรารู้จัก debootstrap มาแล้ว วิธีที่เราจะนึกถึงเป็นอันดับแรก จึงไม่พ้นการสร้าง debootstrap chroot เอาไว้จัดการกับกรณีต่าง ๆ ที่ว่านั้น โดยเก็บ base system ในรูป tarball ไว้ เพื่อจะได้ไม่ต้อง debootstrap บ่อย ๆ อยากทดสอบเมื่อไรก็แตกออกมาเพื่อ chroot เข้าไปทำงานได้ โดยก่อนใช้อาจจะต้องปรับ base system ให้เป็นปัจจุบันก่อนด้วย
โฮะโหย.. ช่างเป็นแผนการที่แนบเนียนเสียนี่กระไร แต่จะบอกให้ว่ามีคนคิดระบบนี้มาเรียบร้อยแล้ว และสร้างเป็นแพกเกจให้คุณสั่งติดตั้งใช้งานได้ง่าย ๆ เลย ระบบที่ว่านั้น เรียกว่า pbuilder (ย่อมาจาก personal builder)
# aptitude install pbuilder
ตั้งค่า base system tarball ที่จะสร้าง รวมทั้งตำแหน่งที่เก็บข้อมูลต่าง ๆ ได้ที่ /etc/pbuilderrc เช่น
BASETGZ/var/cache/pbuilder/base.tgz]BUILDPLACE/var/cache/pbuilder/build/]MIRRORSITE/etc/apt/sources.list]BUILDRESULT/var/cache/pbuilder/result/]DISTRIBUTION"etch" [default ไม่กำหนด และจะยึดตามข้อมูลใน /etc/apt/sources.list]รายละเอียดทั้งหมดดูได้จาก man page pbuilderrc(5) ตามปกติถ้าไม่ตั้งค่าอะไร ค่า default ก็ใช้การได้อยู่แล้ว แต่อาจต้องระวังเรื่องการใช้เนื้อที่ ใครแบ่งพาร์ทิชัน /var ไว้ไม่ใหญ่พออาจมีปัญหา สำหรับผม ผมไปแก้ให้มาลงที่พาร์ทิชัน /home ซึ่งกันไว้สำหรับผู้ใช้อยู่แล้ว
ค่าต่าง ๆ เหล่านี้ จะถูก override ด้วย ~/.pbuilderrc ของผู้ใช้ที่เรียกได้ แต่ก็ไม่ใช่ว่าผู้ใช้จะสามารถ maintain base tarball ได้เอง เพราะอย่างน้อย การ debootstrap หรือ chroot ก็ต้องอาศัยสิทธิ์ root แต่สิ่งที่ผู้ใช้ธรรมดาจะสั่งได้ ก็คือการใช้ base tarball ที่ root ดูแลนั้น มา build package
พูดซะยืดยาว เริ่มลงมือกันดีกว่า พอตั้งค่าต่าง ๆ แล้ว เวลาจะสร้าง tarball ก็
# pbuilder create
รอ debootstrap สักพัก ก็จะได้ base system tarball รอไว้แล้ว
การ build package ถ้าคุณเคยใช้ debuild มาแล้ว การสั่ง build ใน pbuilder ก็แค่เปลี่ยนคำสั่งเป็น pdebuild เท่านั้นเอง
$ cd /path/to/source $ pdebuild
จะเป็นการแตก base tarball แล้ว chroot เข้าไปในนั้นเพื่อ build แพกเกจ (การ chroot จำเป็นต้องทำผ่าน sudo ดังนั้น อย่าลืมกำหนด sudoers ด้วย) โดยเริ่มจาก base system เปล่า ๆ แล้วติดตั้ง Build-Depends ก่อนลงมือ build เมื่อได้ผลลัพธ์เก็บไว้ในที่ที่กำหนดแล้ว ก็ลบ base system ที่แตกออกมานั้นทิ้งให้ด้วยโดยอัตโนมัติ
จะเห็นว่า ด้วยขั้นตอนแบบนี้ ถ้าขาด Build-Depends รายการไหนไป ไม่มีทางหลุดรอดแน่ ๆ รวมทั้งการ build ก็ไม่มีทางเกิดการลิงก์กับสิ่งแปลกปลอมนอกระบบ debian ด้วย
แต่ base system ก็มีการปรับรุ่นอยู่เสมอ ๆ ดังนั้น ถ้าคุณต้องการอัปเดต base system ก็ทำได้โดยสั่ง:
# pbuilder update
จะเป็นการแตก base tarball แล้ว chroot เข้าไปอัปเกรดแพกเกจด้วย apt แล้วแพ็ก tarball กลับ
ในกรณีที่คุณต้องการเปลี่ยน distribution ของ base tarball เช่น จาก sid เป็น etch ก็เพิ่มตัวเลือก
# pbuilder update --distribution etch --override-config
ตัวเลือก --override-config จะแทนที่บรรทัดใน sources.list ของ base system ใน tarball เป็น distribution ที่กำหนดด้วย
แก้ปัญหาได้หลายเรื่องเชียวแหละ ช่วยป้องกันข้อผิดพลาดต่าง ๆ ได้ด้วย พวก debian hacker เขาขี้เกียจอย่างสร้างสรรค์กันครับ ก็เลยทำให้มีเครื่องมือดี ๆ ให้ใช้กันอย่างนี้ :-)