scim-thai 0.1.2
scim-thai 0.1.2 ออกไปแล้วเมื่อวานนี้ ก็คงเป็นตัวสุดท้ายในการปรับรุ่นแพกเกจต่าง ๆ ใน linux.thai.net ระลอกนี้ (แต่ไม่ใช่หมดแค่นี้ อาจมีการออกรุ่นตัวอื่นที่ได้ปรับรุ่นไปแล้วอีกถ้าจำเป็น)
สำหรับ scim-thai รุ่นนี้ ถือเป็น maintenance release คือไม่ได้มีการเพิ่มความสามารถใหม่อะไร แต่เป็นการแก้ปัญหาเล็ก ๆ น้อย ๆ เกี่ยวกับระบบ build ที่ตรวจพบในช่วง 3 ปีที่ผ่านมา กล่าวคือ
- ปรับการ config การแปลข้อความด้วย gettext จาก
gettextize
ให้มาใช้ autopoint แทน ซึ่งทำให้ปรับข้อมูล PO ได้แนบเนียนไร้ร่องรอยมากขึ้น - แก้ปัญหาการคอมไพล์ในกรณีที่ libthai ไม่ได้ติดตั้งไว้ในพาธมาตรฐาน เป็นปัญหาที่พบในระหว่างพัฒนา libthai ซึ่งต้องติดตั้งแยกต่างหากจาก libthai ของระบบ แล้วทำให้พบว่า make rule ของ scim-thai ยังติดปัญหาการคอมไพล์กับ libthai ที่แยกติดตั้งต่างหากนี้อยู่ กลายเป็นกรณีตัวอย่างให้อุดรูรั่ว
- แก้ปัญหาเรื่องการกำหนด
LDFLAGS
ซึ่งพบระหว่างที่จะ build แพกเกจ Debian รุ่นใหม่โดยปรับการ build ให้ใช้แฟล็ก "-Wl,--as-needed
" แล้วพบว่าแฟล็กนี้ไม่มีผล ตรวจสอบแล้วพบว่าเป็นปัญหาการใช้ target*_LDFLAGS
ในMakefile.am
ในการเพิ่มไลบรารีให้กับมอดูล ซึ่งพอสคริปต์configure
กำหนดLDFLAGS=-Wl,--as-needed
แล้ว แฟล็กนี้มันจะไปต่อท้ายค่าใน target*_LDFLAGS
อีกที ซึ่งผมดันไปลิสต์ไลบรารีในนั้นเสียแล้ว ค่าLDFLAGS
จากการ configure ก็เลยไปต่อท้ายอยู่หลังรายชื่อไลบรารี จึงไม่มีผลกับไลบรารี ที่ถูกแล้ว ต้องใช้ target*_LIBADD
ในการเพิ่มไลบรารีแทน ชื่อไลบรารีจึงจะมาอยู่หลังLDFLAGS
ในคำสั่งคอมไพล์ เป็นปัญหาที่มาดูทีหลังก็งง ว่าตอนนั้นผมทำแบบนั้นไปได้อย่างไร ทำให้ต้องมางมอยู่นานกว่าจะเจอ
สำหรับผู้ที่สนใจเรื่องการใช้แฟล็ก --as-needed
ของลิงเกอร์ ก็ขออธิบายสักหน่อย
แฟล็ก --as-needed
ใช้เพื่อให้ object file ที่ได้นั้น ลิงก์เฉพาะกับไลบรารีที่มีการใช้ symbol โดยตรงเท่านั้น (ตรวจสอบการลิงก์ได้ด้วยคำสั่ง objdump -p {so/exe-file}
แล้วดูที่บรรทัด NEEDED
ทั้งหลายใน Dynamic Section)
กล่าวคือ สมมติว่า object file ของเรามีการเรียกใช้ libA และ libB โดย libA ไปลิงก์กับ libP, libQ อีกที เวลาลิงก์จะต้องใส่ไลบรารีทั้งหมดที่ใช้ คือเป็น "-lA -lB -lP -lQ
" และลิงเกอร์ก็จะลิงก์ทุกไลบรารีเข้ามาใน object file ของเรา นี่คือกรณีปกติ
การลิงก์ดังกล่าวมีปัญหาในทางปฏิบัติ เพราะไลบรารีต่าง ๆ มีการต่อยอดกันเป็นทอด ๆ หลายชั้น เช่น เฉพาะ GTK+ ก็มีไลบรารีลูกต่อพ่วงมาอีกถึง 44 ตัว:
$ ldd /usr/lib/libgtk-3.so.0.0.10 | wc -l 44
ในนี้ก็มีตั้งแต่ pango, glib, ati, cairo, freetype, libxcb และพรรคพวกอีกมากมาย และการลิงก์เฉพาะ GTK+ เข้ามาในโปรแกรมของเรา ก็จะต้องลิงก์ไลบรารีเหล่านี้เข้ามาทั้งหมด ทั้งที่ไม่มีการเรียกใช้ฟังก์ชันโดยตรงเลยก็ตาม
ความจริง ตอน run-time ก็จะต้องโหลดไลบรารีเหล่านี้เข้ามาทั้งหมดอยู่แล้ว ไม่งั้น GTK+ ก็ทำงานไม่ได้ อ้าว แล้วถ้างั้นมีปัญหาอะไร?
ปัญหาก็คือ การลิงก์ตรงกับไลบรารีใด ๆ จะหมายถึงการเกิด dependency ระหว่างแพกเกจของไลบรารีที่ลิงก์กันนั้น ทำให้ระบบแพกเกจโดยรวมมี dependency จำนวนมโหฬารเกินความจำเป็น และจะเป็นอุปสรรคต่อการขยับไลบรารีหนึ่ง ๆ ขึ้นสู่ major version ใหม่ (ซึ่งอาจไม่ ABI compatible กับรุ่นเก่า) เพราะจะต้องตามไป rebuild แพกเกจทั้งหมดที่ลิงก์ตรงกับมันอยู่ กลายเป็นปริมาณงานที่มากเกินจำเป็น ในเมื่อโปรแกรมคุณแค่ใช้ฟังก์ชันของ GTK+ เท่านั้น ทำไมจะต้องไป rebuild เมื่อมีการปรับ major version ของ cairo หรือ freetype ด้วย? สู้ให้เรื่องพวกนี้มัน encapsulate อยู่ในแพกเกจ GTK+ เท่านั้นไม่ดีหรือ?
นี่จึงเป็นที่มาของการใช้แฟล็ก --as-needed
ในการ build แพกเกจของ distro ต่าง ๆ เพื่อให้มีการลิงก์เฉพาะกับไลบรารีที่มีการใช้ symbol โดยตรงเท่านั้น แล้วเวลาโหลดหรือติดตั้ง มันก็จะทำงานเป็นทอด ๆ ตามลำดับ dependency เอง ถ้ามีการปรับ major version ก็จะ rebuild เฉพาะแพกเกจที่มีการเรียกใช้ symbol โดยตรงเท่านั้น
บางคนอาจถามว่า แล้วทำไมไม่แค่ลิงก์แบบ "-lgtk-3-0
" กับแพกเกจที่ใช้ GTK+ ก็พอล่ะ? ไม่ต้องแถมพ่วงพวก pango, glib ฯลฯ มาด้วยก็ได้ คำตอบคือการลิงก์แบบนี้ไม่ portable ครับ ลิงเกอร์ของ GNU อาจทำได้ แต่ยูนิกซ์ทั่วไปทำไม่ได้ ต้องใส่ library ที่ต้องการตามลำดับให้ครบด้วยจึงจะลิงก์ผ่าน (เข้าใจว่ามาจากวิธีลิงก์แบบ static ที่ต้องมีไลบรารีครบ) ดังนั้น พวก link flags ที่ได้จาก pkg-config
จึงมีไลบรารีที่ต้องใช้แถมพ่วงมาทั้งหมดเสมอ แล้วลิงเกอร์ของ GNU สามารถมาคัดออกอีกทีด้วยตัวเลือก --as-needed
ได้