คอมไพล์ GNOME ใช้เอง

รวมรวมวิธีการคอมไพล์ GNOME ใช้เอง

คอมไพล์ GNOME ใช้เองด้วย JHBuild - วางแผน

จัดให้ตามคำขอครับ สำหรับผู้สนใจใช้ GNOME แบบ bleeding edge ซึ่งมีหลายวิธี ตามดีกรีความเป็น geek ของคุณ:

บทความนี้จะอธิบายวิธีที่ใช้ JHBuild นะครับ

วางแผนกันก่อน

การติดตั้ง GNOME จาก SVN snapshot ไว้ใช้งาน อาจจะอันตรายเกินกว่าจะเอางานในชีวิตประจำวันเข้าไปเสี่ยงด้วย จึงควรพิจารณาแยกรุ่น โดยใช้ GNOME ที่เสถียรจาก distro ทำงาน แต่แยก GNOME จาก SVN ไว้ทดสอบต่างหาก โดยขอแนะนำว่าอย่าใช้ root account หรือ sudo คอมไพล์และติดตั้ง เพราะความผิดพลาดในการ configure เพียงเล็กน้อย อาจทำให้ระบบคุณมั่วได้ ทางที่ดี ควรสร้างไดเรกทอรีสำหรับ user ธรรมดาไว้รองรับ และ build ในฐานะ user ธรรมดาเท่านั้น ซึ่งก็มีทางเลือกต่าง ๆ เช่น:

เอาล่ะ อ่านแล้วเลือกวิธีที่คุณชอบละกัน ตามความเห็นของผม คิดว่าวิธีสุดท้ายนี่แหละ ที่มีปัญหาน้อยที่สุด จากประสบการณ์ที่ผ่านมา โดยมีเกร็ดอีกอย่างหนึ่งคือ คุณไม่จำเป็นต้อง logout เพื่อเข้าไปทดสอบในอีก account หนึ่ง แต่สามารถสลับผู้ใช้โดยเลือก switch user ที่ logout dialog หรือใช้แอพเพล็ตสลับผู้ใช้ (fast-user-switch-applet) เพื่อล็อกอินในอีกดิสเพลย์หนึ่งได้ หรือจะเรียกใช้ gdm ในหน้าต่างซ้อน (Xnest/Xephr) เลยก็ได้ ซึ่งสำหรับกรณีหลัง ก็เพียงแต่เรียกเมนู Applications > System Tools > New Login in a Window หรือสั่งจาก command line:

$ gdmflexiserver --Xnest

ประเด็นหนึ่งที่คุณจะพบก็คือ เรื่องของ dbus กล่าวคือ โดยปกติ JHBuild จะ build dbus, hal, avahi จาก source ให้ ซึ่งอาจเป็นคนละรุ่นกับ distro แต่ปัญหาก็คือ distro จะเปิด dbus, hal, avahi daemon เอาไว้อยู่แล้ว และบ่อยครั้งที่โปรแกรมที่ config ไว้ให้คอมไพล์กับคนละรุ่นจะทำงานกับ daemon เหล่านี้ไม่ได้ ผลคือเรียกโปรแกรมไม่ขึ้น หรือโปรแกรม crash ไปเฉย ๆ เรื่องแบบนี้ report bug ก็ไม่ได้ด้วย เพราะเป็นความผิดของเราเอง วิธีแก้คือ config JHBuild ให้ไปใช้ dbus ของระบบเสีย ไม่ต้อง build เอง รายละเอียดจะกล่าวต่อไป

ตอนหน้ามาลงมือกันครับ

คอมไพล์ GNOME ใช้เองด้วย JHBuild - ติดตั้ง JHBuild

ตอนที่แล้ว วางแผนกันแล้ว คราวนี้มาเริ่มติดตั้ง JHBuild กัน

Check Out JHBuild

JHBuild รุ่นล่าสุดสำหรับ GNOME สามารถ check out ได้จาก GNOME SVN:

$ svn co http://svn.gnome.org/svn/jhbuild/trunk jhbuild

คุณสามารถใช้โพรโทคอล svn:// ก็ได้ ถ้า http:// ใช้ไม่ได้ในเครือข่ายของคุณ:

$ svn co svn://svn.gnome.org/svn/jhbuild/trunk jhbuild

(สำหรับคนที่มี svn account กับ GNOME ก็ใช้ svn+ssh:// นะครับ)

ติดตั้ง JHBuild

เมื่อ check out มาแล้ว สำรวจดูจะเห็น autogen.sh และ configure.ac ดูเหมือนต้องใช้ autotools แต่ไม่ต้องครับ กรณีนั้นใช้กับการ build พวกเอกสารเท่านั้น ถ้าคุณเพียงแต่จะใช้ build โปรแกรมอย่างเดียว ก็นี่เลย:

$ make -f Makefile.plain install

จะติดตั้ง jhbuild ไว้ที่ $HOME/bin ของคุณ แถมติดตั้งเมนูเรียก jhbuild แบบ GUI ไว้ที่เมนู Applications > Programming อีกต่างหาก.. แต่เอาเข้าจริง ผมไม่ได้ใช้ GUI หรอก เพราะส่วนมากจะสั่ง build แบบ background มากกว่า ดังจะกล่าวต่อไป

ตั้งค่า JHBuild

ค่า config ของ jhbuild กำหนดที่ ~/.jhbuildrc เป็นแฟ้มภาษา python โดยจะมีตัวอย่างของแฟ้มนี้อยู่ในแฟ้ม sample.jhbuildrc ใน source tree ของ jhbuild คัดลอกไปแก้ได้เลย ค่าสำคัญที่น่าสนใจได้แก่:

svnroots['svn.gnome.org']
สำหรับผู้ที่มี SVN account ก็ควรกำหนดเป็น svn+ssh://... URL จะได้ commit ได้ด้วย แต่สำหรับ anonymous user ก็ไม่จำเป็นต้องตั้งค่านี้ ยกเว้นกรณีที่ค่าปริยายใช้ไม่ได้ในเครือข่ายของคุณ
moduleset
คือชุด GNOME ที่จะ build เช่น 'gnome-2.20' คุณสามารถตรวจดู moduleset ทั้งหมดที่มีอยู่ได้จากไดเรกทอรี modulesets/ ใน jhbuild source tree
modules
คือรายการ module ที่จะ build จากบรรดา module ทั้งหมดที่มีใน moduleset โดยทั่วไปก็จะ build meta package ชื่อ 'meta-gnome-desktop' ซึ่งจะไปดึงเอา official GNOME package ทั้งหมดมา ถ้าคุณสนใจ module อื่นนอกเหนือ official GNOME ก็เลือกเพิ่มได้ เช่น 'meta-gnome-proposed' สำหรับ module ที่เสนอเพิ่มในรุ่นถัดไป, 'epiphany-extensions' สำหรับ extention ทั้งหลายของ epiphany ซึ่ง module นี้ยังไม่อยู่ใน official GNOME ฯลฯ
skip
รายการ module ที่จะข้ามไป โดยใช้จากของระบบแทน หรือจะไม่ใช้เลย เช่น ตามปกติ dbus, dbus-glib, hal, avahi จะถูก build เป็นส่วนหนึ่งของ GNOME ในฐานะ external dependency แต่อย่างที่เราวางแผนไว้ว่าจะใช้ของระบบแทน ก็เพิ่มรายการเหล่านี้เข้าไป ใครขี้เกียจรอ build mozilla ก็อาจเพิ่มได้ตรงนี้ แล้วติดตั้ง development package ของ xulrunner แทน เป็นต้น
checkoutroot
คือไดเรกทอรีหลักที่จะเก็บโค้ดที่ check out จากแหล่ง ก็ดูรูปแบบเอาจากตัวอย่างนะครับ
prefix
คือไดเรกทอรีหลักที่จะติดตั้ง GNOME ที่ build แล้ว เช่น ถ้าจะติดตั้งที่ /home/gnome-svn ก็กำหนดที่นี่

ที่เหลือก็มีคำอธิบายใน comment ของแฟ้มตัวอย่างนะครับ หรือจะอ่านจาก manual ของ JHBuild ก็ได้

และเพื่อความสะดวกในการเรียก คุณอาจเพิ่ม $HOME/bin ในตัวแปรสภาพแวดล้อม $PATH ของคุณด้วย

ก่อนจะเริ่มใช้ JHBuild คุณควรตรวจสอบเสียหน่อย ว่าขาดแพกเกจจำเป็นอะไรหรือเปล่า โดยสั่ง:

$ jhbuild sanitycheck

ขาดอะไรก็ติดตั้งเพิ่มให้เขานะครับ ที่สำคัญคือ jhbuild ใช้ python ขาดไม่ได้เป็นอันขาด ส่วนเครื่องมือพื้นฐานอย่าง autoconf, automake ฯลฯ พวกนี้ คุณอาจใช้ของระบบก็ได้ หรือจะ build เองด้วยคำสั่งนี้ก็ได้:

$ jhbuild bootstrap

แต่จากประสบการณ์ ผมแนะนำว่าใช้ของระบบดีกว่า เพราะเอาเข้าจริง คุณก็จะสั่ง bootstrap แค่ครั้งเดียวนี่แหละ ในขณะที่ถ้าใช้ของระบบ จะมีการอัปเกรดตามปกติของ distro อยู่ตลอด ทำให้เครื่องมือของคุณไม่เก่า ฉะนั้น พอเริ่มใช้ JHBuild ในเครื่องหลัง ๆ ของผม ผมไม่ใช้ bootstrap เลย แต่พยายามติดตั้งแพกเกจที่จำเป็นให้ครบในระบบ คือ:

เรียบร้อยละ ตอนหน้ามา build กัน

คอมไพล์ GNOME ใช้เองด้วย JHBuild - คอมไพล์

ติดตั้ง JHBuild พร้อม config ไปแล้วก็ลงมือ build กัน

วิธีที่จะสั่ง build แพกเกจทั้งหมดที่ config ไว้ โดยเริ่มตั้งแต่ check out, configure, make, install ก็คือ:

$ jhbuild build

JHBuild จะตรวจสอบ dependency ของ module ที่กำหนด แล้วไล่ build ตั้งแต่ปลายสุดขึ้นมาตามลำดับ

แต่คุณก็เลือก build เฉพาะสิ่งที่ต้องการ แทนที่จะ build GNOME desktop ทั้งตัวได้เหมือนกัน:

$ jhbuild build gtk+

จะ build สิ่งที่ gtk+ ต้องการตามลำดับขึ้นมาจนถึงตัว gtk+ เอง

ในกรณีที่ build ไม่ผ่านที่บาง module จะมีตัวเลือกขึ้นมาถาม เช่น:

*** error during stage build of ORBit2: ########## Error running make   *** [1/1]


  [1] rerun stage build
  [2] ignore error and continue to install
  [3] give up on module
  [4] start shell
  [5] go to stage force_checkout
  [6] go to stage configure
choice: _

คุณสามารถเลือกตัวเลือกต่าง ๆ ได้ ตามปกติถ้าไม่มีเวลาดู ผมก็อาจจะเลือกข้อ 2 เพื่อฝืนให้มันทำต่อไป แล้ว module ต่อ ๆ ไปก็จะใช้รุ่นเก่าที่ผม build ไว้ครั้งก่อน แต่ถ้าเป็นการ build ครั้งแรก คุณคงเลือกข้อ 3 จะดีกว่า แพกเกจไหนที่ต้องใช้แพกเกจนี้ก็จะไม่ถูก build

ถ้าคิดอยากจะลองแก้บั๊กด้วยตัวเอง ก็เลือกข้อ 4 เพื่อเข้าเชลล์ไปตรวจสอบและแก้บั๊ก แล้ว exit กลับออกมาที่ prompt เดิมนี้ แล้วเลือกข้อ 1 ให้มันพยายาม build ใหม่

คำตอบสำหรับคำถามนี้ คงไม่มีหลักตายตัว อาศัย programming sense ของคุณละกัน :-)

มีวิธี build แบบ non-interactive ด้วย เช่น คุณอาจจะไปสั่ง build แบบ remote ที่เครื่องอื่นในแบบ daemon หรือ cron job ก็ได้ โดยสั่ง:

$ jhbuild tinderbox -o output-dir

โดยมันจะเก็บ build log ในรูป HTML page ลงใน output-dir (ตัวอย่าง) และเลือกตัวเลือก "give up on module" โดยอัตโนมัติสำหรับ module ที่ไม่ผ่าน

ผมชอบใช้แบบ tinderbox มาก เพราะประหยัดเวลาดี ผมสามารถสั่งให้มัน build แบบ background ไว้ แล้วก็ไปทำงานอื่นได้ สักพักก็กลับมาเช็กว่ามี error ที่ module ไหนบ้าง แล้วก็ตามซ่อมเป็นตัว ๆ ไป

การสั่ง build เพียง module เดียวเท่านั้น โดยไม่ต้อง build dependency ของมัน (เช่น ในกรณีที่จะกลับมาซ่อม module ที่ build ไม่ผ่าน) ก็ใช้คำสั่ง:

$ jhbuild buildone module

การใช้งานอีกลักษณะหนึ่งที่หลายคนอาจสนใจ คือการแยกขั้นตอน check out กับการ build ออกจากกัน อาจจะดีสำหรับคนที่ build ในเครื่องที่ไม่ได้ต่อเน็ตตลอดเวลา (คนหิ้วโน้ตบุ๊กอาจจะนึกออก) ก็อาจจะ check out ให้เสร็จทีเดียว แล้วค่อย build แบบ off-line ทีหลัง

สั่ง check out source ทั้งหมดโดยไม่ build ได้โดย:

$ jhbuild update

และ build แบบ off-line ได้โดยเพิ่มตัวเลือก -n หลังคำสั่งของ JHBuild เช่น:

$ jhbuild tinderbox -n -o output-dir

build กันไปก่อนนะครับ คราวหน้ามาดูวิธีเรียกโปรแกรมแบบแบ่งภาคกัน

คอมไพล์ GNOME ใช้เองด้วย JHBuild - เรียกใช้โปรแกรม

build กันเสร็จแล้ว ก็มาเริ่มใช้โปรแกรมที่ build กันนะครับ

เรื่องของ DBus

ก่อนจะเริ่มใช้ มีประเด็นเรื่อง DBus ที่เราวางแผนไว้ว่าจะใช้ของระบบ ปัญหาก็คือ โดยปกติ DBus จะรู้จัก service เฉพาะของระบบเท่านั้น ถ้าบังเอิญ GNOME รุ่นใหม่ที่เรา build มีการสร้าง service ใหม่โดยไม่ได้ register กับ DBus โปรแกรมบางโปรแกรมที่เรา build ก็จะเรียกไม่ขึ้น หรือไม่ก็ crash ไปดื้อ ๆ

เราทำให้ DBus รู้จัก service ของเราได้โดยเพิ่มแฟ้ม /etc/dbus-1/session-local.conf และ /etc/dbus-1/system-local.conf โดยมีเนื้อหาดังนี้:

/etc/dbus-1/session-local.conf:

<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN"
 "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>

  <!-- Include jhbuild gnome session services -->
  <servicedir>/home/gnome-svn/share/dbus-1/services</servicedir>

</busconfig>

/etc/dbus-1/system-local.conf:

<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN"
 "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>

  <!-- Our well-known bus type, do not change this -->
  <type>system</type>

  <!-- Include jhbuild gnome system services -->
  <includedir>/home/gnome-svn/etc/dbus-1/system.d</includedir>

</busconfig>

(ตรงชื่อไดเรกทอรี ผมทำตัวเอนไว้ เพื่อให้แก้เป็นชื่อไดเรกทอรีที่คุณใช้ได้สะดวกนะครับ)

ถ้าสงสัยว่าผมได้สองแฟ้มนี้มายังไง ก็ลองอ่าน /etc/dbus-1/session.conf กับ /etc/dbus-1/system.conf ดูละกันครับ แฟ้ม *-local.conf นี้ ควรจะถูก include มาจากสองแฟ้มนั้น ส่วน syntax ก็ดัดแปลงโค้ด XML เท่านั้นเอง

restart DBus เพื่อให้การแก้ไขมีผล:

# /etc/init.d/dbus restart

ต่อไปนี้ก็พร้อมเรียกโปรแกรมละ

การเรียกโปรแกรมที่ build

ตระเตรียมทุกอย่างเสร็จแล้ว จะทดสอบโปรแกรมที่ build ก็อาจเรียกเป็นรายโปรแกรม หรือเข้า GNOME session ไปเลย

เนื่องจากคุณมี environment สองแบบ คือของ distro และจาก JHBuild การเรียกโปรแกรมที่ build จึงต้องมีการกำหนด environment ต่างหาก ซึ่ง JHBuild ช่วยคุณได้ โดยสั่ง:

$ jhbuild run command-line

จะเรียก command-line ภายใต้ environment ที่กำหนด $PATH ให้ไปชี้ที่ bin และ $LD_LIBRARY_PATH ไปที่ lib ที่ติดตั้งโดย JHBuild รวมถึง environment อื่นที่เกี่ยวข้องด้วย

หรือสั่งอีกแบบ:

$ jhbuild shell

จะสร้าง shell ที่กำหนด environment เหล่านี้ให้เสร็จ จากนั้น command line ที่คุณเรียก ก็จะไปหาโปรแกรมและไลบรารีในแหล่งที่ติดตั้งโดย JHBuild ก่อน

คุณใช้หลักการเดียวกันนี้ในการเข้า GNOME session ทั้ง session จากแหล่งที่ติดตั้งโดย JHBuild ได้ โดยกำหนดใน ~/.xsession ของ user account ที่ใช้ทดสอบ:

#!/bin/sh

exec /home/thep/bin/jhbuild run gnome-session

(ในที่นี้ สมมุติว่าใช้ account "thep" ในการ build ซึ่ง jhbuild จะติดตั้งไว้ที่ $HOME/bin ของ account "thep")

อย่าลืม chmod ให้สคริปต์ executable ด้วยนะครับ

จากนั้น ก็ล็อกอินเป็น user account ที่ใช้ทดสอบนั้น (โดย switch user ที่ logout dialog แทนที่จะ logout หรือใช้ gdm ใน nested window ตามที่กล่าวไปแล้ว) โดยเลือกวาระ (session) เป็น X session (จากปกติที่เป็น GNOME session ซึ่งจะเป็น GNOME ของระบบ)

จบแล้ว ไม่ยากเกินไปใช่ไหมครับ เห็นยาว ๆ นี่ เป็นเกร็ดเล็กเกร็ดน้อยซะเยอะ