หลักการเขียนโปรแกรมยุคใหม่ๆ ในช่วงหลังๆ มานี้นิยมที่จะลดการเขียนโปรแกรมส่วนใหญ่ในภาษาระดับต่ำๆ เช่นภาษา C/C++ เนื่องจากเสี่ยงต่อการมีบั๊กค่อนข้างมาก และการพัฒนาที่ช้า เพื่อความเร็วในการพัฒนาแล้ว จึงมักนิยมใช้การพัฒนาในภาษาระดับสูงๆ เช่น Python, Ruby, PHP ฯลฯ แล้วทดสอบประสิทธิภาพ หากมีส่วนไหนทำงานช้าเกินยอมรับได้ จึงลงมือพัฒนาส่วนนั้นๆ เป็นภาษา C/C++ เพื่อความเร็ว แล้วจึงสร้างอินเทอร์เฟช เพื่อโมดูล C/C++ นั้นเข้ากับโปรแกรมหลัก
ปัญหาคือการเรียนรู้ และการเขียนโค้ดเพื่อเชื่อมต่อโมดูลต่างๆ เข้ากับภาษาระดับสูงนั้นเป็นงานที่สิ้นเปลืองพลังงานไม่ใช่น้อย และส่วนใหญ่กลับเป็นงานที่ต้องทำซ้ำไปมา สร้างความน่าเบื่อหน่าย ทางเลือกที่ดีกว่าคือการใช้โปรแกรมสร้างอินเทอร์เฟซอัตโนมัติ เช่น SWIG เพื่อทำงานส่วนที่น่าเบื่อทั้งหลายแทนที่เรา โดยใช้การคอนฟิกค่าเพียงเล็กน้อย
บทความนี้จะสมมติเหตุการณ์ที่เราต้องการสร้างฟังก์ชั่นที่เราทำเองฟังก์ชั่นหนึ่งที่ชื่อว่า toInt ที่แปลงค่าจากสตริงมาเป็นค่าเลขจำนวนเต็ม โดยในบทความจะถือว่าผู้อ่านมี Cygwin และ Python Win32 อยู่ในเครื่องอยู่ก่อนแล้ว
int toInt(char *s){
return atoi(s);
}
ก่อนอื่นที่เราต้องการคือโปรแกรม SWIG (ดาวน์โหลดที่นี่) หรืออาจเลือกลงตอนลง Cygwin เลยก็ได้ ถึงตอนนี้ก็แอบดูกันก่อนว่าเราจะเขียนให้ SWIG มันรู้จักฟัังก์ชั่นของเราได้ยังไง
%module example
%typemap(in) (char*s){
$1 = PyString_AsString($input);
}
%inline{
int toInt(char* s){
return atoi(s);
}
}
สั้นและง่ายอย่างไม่น่าเชื่อ โดยบรรทัดแรกนั้นคือชื่อโมดูลที่เราต้องการสร้าง ซึ่งจะไปมีผลเอาตอนที่เรา import เข้าโปรแกรม Python ของเรา
บรรทัดที่สองเป็น typemap ที่แปลงอาร์กิวเมนต์ข้ามภาษากัน ส่วนของ (in) นั้นคือระบุว่าเราต้องการสร้างส่วนแปลงข้อมูลอาร์กิวเมนต์ขาเข้าฟังก์ชั่นของเรา เนื่องจากฟังก์ชั่นของเราให้ค่าผลลัพธ์เป็น int ซึ่ง SWIG สามารถแปลงค่าได้เอง จึงไม่ต้องทำอะไรกับส่วนการส่งค่าออก (out) ส่วนต่อมาคือชื่อและ type ของฟังก์ชั่น ในกรณีนี้คือ (char*) ในกรณีที่เรามีฟังก์ชั่นที่ต้องการหลายอาร์กิวเมนต์ แต่สามารถแทนที่ได้ด้วยอาร์กิวเมนต์ในภาษา Python เพียงอาร์กิวเมนต์เดียว เราสามา่รถระบุได้ โดยการใส่หลา่ยอาร์กิวเมนต์ในวงเล็บ แบบเดียวกับการประกาศฟังก์ชั่นในภาษา C/C++
บรรทัดที่สามคือการประกาศการแปลงอาร์กิวเมนต์จากที่ได้รับมาจากภาษา Python โดยหนึ่งอาิร์กิวเมนต์ที่ได้รับจะมาในรูปของตัวแปรที่ชื่อว่า $input ซึ่งในส่วนนี้ SWIG จะนำสตริง $input ไปแปลงเป็นชื่อตัวแรกที่เป็น (PyObject *) ให้เอง ส่วน $1 นั้นหมายถึงอาร์กิวเมนต์ตัวแรกในรายการที่เราระบุ หากเรามีการใช้หลายอาร์กิวเมนต์ที่สร้างจาก อาร์กิวเมนต์ในภาษา Python เพีัยงหนึ่งอาร์กิวเมนต์ได้ เราก็อาจจะใช้ $2 หรือมากกว่านี้ขึ้นไปเรื่อยๆ ได้
ส่วนบรรทัดที่ 5 เรื่อยมานั้น คือการประกาศฟังก์ชั่นของเรา โดยการประกาศแบบ inline นั้นคือการประกาศทั้งฟังก์ชั่นมาอยู่ในไฟล์เดียวกัน แต่ถ้าต้องการใช้ฟังก์ชั่นจากไฟล์ภายนอกก็สามารถทำได้เช่นกัน
ถึงตอนนี้ ใ้ห้เราเซฟไฟล์นี้ในชื่อว่า example.i แล้วเรียก SWIG
swig -python example.i
เราจะได้ไฟล์ออกมาสองไฟล์คือ example_wrap.c และ example.py ต่อไปจะเป็นขั้นตอนการคอมไพล์
เนื่องจากเราต้องการใช้ Cygwin ในการคอมไพล์ทั้งหมด จึงทำให้เราไม่สามารถลิงก์เข้ากับ python24.dll ได้โดยตรง แต่ต้องการไฟล์ *.a ซึ่งคนใช้คอมไพล์เลอร์ตระกูล gcc คงคุ้นเคยกันดี
- เริ่มจากการก๊อปปี้ไฟล์ python24.dll จาก C:\Windows\system32 มาไว้ในที่ที่เราจะทำงาน
- ดาวน์โหลด pexports.exe มาไว้ในเครื่องให้พร้อม
- สั่ง pexports python22.dll > python22.def
- ใช้คำสั่ง dlltool ที่มีมาใน Cygwin เพื่อสร้าง libpython24.a ดังนี้ dlltool --dllname python24.dll --def python24.def --output-lib libpython24.a
- ถึงตอนนี้ก็ถึงเวลาคอมไพล์ โดยเริ่มจากการคอมไพล์ example_wrap.c ออกมาเป็น example_wrap.o ด้วยคำสั่ง gcc -c -mno-cygwin example_wrap.c -I/cygdrive/c/python24/include โดยการ สั่ง -mno-cygwin นั่นเพื่อให้ไฟล์ที่ออกมาใช้งานกับ dll ที่เป็น win32 native ได้ ส่วนการสั่ง -I ก็เพื่อดึงเอาไฟล์ header ของ Python ที่มาพร้อมอยู่ในตอนที่เราลง Python มาใช้งาน
- อย่าเพิ่งดีใจว่าเสร็จแล้ว เพราะเรายังไม่ได้ใช้ไฟล์ libpython24.a ที่เราสร้างขึ้นมา โดยการสั่ง gcc -shared -mno-cygwin example_wrap.o libpython24.a -o _example.dll โดยอาร์กิวเมนต์ -shared คือการสั่งให้ gcc สร้างไฟล์ dll นั่นเอง ส่วนการตั้งชื่อ dll ที่ได้นั้นสำคัญมากกว่าต้องตั้งชื่อเริ่มต้นด้วย underscore และตามด้วยชื่อโมดูลของเรา
เสร็จแล้ว!!! ในตอนนี้เราได้โค้ดที่เราเขียนในภาษาซีมาทำงาน ใน pyhton ได้ ดังตัวอย่าง
>>> import example
>>> example.toInt("10")
10
หากเราต้องการให้เรียกใช้โมดูลนี้ได้ไม่ว่าเราจะรัน Python จากที่ใดในเครื่อง ก็เพียงนำไฟล์ example.py และ _example.dll ไปวางไว้ในโฟลเดอร์ C:\Python24\Lib\site-packages เป็นอันเรียบร้อย
อ้างอิง
on
เจ๋งมากคร
wd Sun, 11/06/2006 - 14:36
เจ๋งมากครับ ชอบมาก ๆ :)
---
ผมไม่ได้ใ
chaba_bkk Tue, 13/06/2006 - 09:19
ผมไม่ได้ใช้ Python อ่ะ ใช้แต่ Java ไม่รู้ว่ามีตัวจัดการอย่างนี้ใช้รึเปล่า Let's play Ubuntu 5.10
chaba_bkk -SWIG
lew Tue, 13/06/2006 - 17:01
chaba_bkk -SWIG ใช้กับ Java ได้ครับ แต่ผมใช้ไม่เป็น...
ผมก็เป็นแ
bow_der_kleine Wed, 14/06/2006 - 06:49
ผมก็เป็นแฟน python เหมือนกันครับ ส่วนมากผมใช้ pyrex (ซึ่งไม่ใช่ extension) ในการเพิ่มความเร็วให้ python แต่เจ้า SWIG นี่ยังไม่เคยลอง อ่านแล้วน่าสนใจครับ แน่นอนเลยครับว่าต้องลอง
(ขอบ่นหน่อยครับ) การคอมไพล์พวก extension บนวินโดวส์นี่ยากมากครับ เมื่อเทียบกับบน GNU/Linux ยิ่งไม่ได้ใช้ .NET Stupido ด้วยแล้ว มันร้องจะเอานู่นเอานี่เยอะเหลือเกิน กว่าจะคอมไพล์ผ่านนี่เสียเวลาไปหลายวันเลยครับ (เอ... หรือว่าเราโง่เองหว่า)
bow_der_kleine -
lew Wed, 14/06/2006 - 12:08
bow_der_kleine - ได้ยินชื่อ pyrex มานานเหมือนกันครับว่าเร็วกว่า SWIG พอตัวเลย แต่ผมเลือกใช้ SWIG เพราะดูเว็บแ้ล้วมันน่าเชื่อถือกว่า ระบบ Document อะไรต่างๆ ค่อนข้างเป็นรูปเป็นร่างกว่า แถมอ่านไว้ทีเดียวใช้กับภาษาอื่นได้ด้วยครับ
ctypes
sake Sat, 21/05/2016 - 12:51
ctypes ไม่ต้อง compile
>>> import ctypes >>> toInt = ctypes.cdll.msvcrt.atoi >>> toInt("10") 10
Python 2.5 จะมี ctypes รวมมาด้วยเลย