วันศุกร์ที่ 4 พฤษภาคม พ.ศ. 2555

สร้างโปรแกรม ภาษา C บน Google Sketchup


-อ.ธนะพันธ์ อินทรเกสร

ปัญหาของผู้ที่สร้างโปรแกรมบน Sketchup ต้องใช้ ruby ในการเขียนโปรแกรม จะพบว่า การ Debug ยากมาก ใน Project ใหญ่แทบจะหา ไม่เจอเลยว่า โปรแกรม Bug อยู่ที่ใหน เป็นคำถามที่นักศึกษาที่ทำ Project โปรแกรม ด้วย ruby sketchup กลัวกันมาก ผมไปศึกษาเพื่อที่ว่าจะได้ง่ายขึ้น และอีกอย่างเป็นการนำ Library เช่น Database หรือ Graphic หลายอย่างที่พัฒนาบน C มาใช้ ได้โดยไม่ต้อง เขียนใหม่บน ruby
Ruby C Extension
ต้องเข้าใจก่อนว่า ruby ที่อยู่ใน Sketckup ไม่ได้เป็นภาษาเฉพาะของ Sketchup คนเดียว แต่เป็นภาษาที่มีคนใช้ในโปรแกรมหลาย Application เช่น RubyOnRail ใช้ในการทำ Web Server , หรือ Ruby สำหรับ DBMS ในการจัดการฐานข้อมูล เป็นต้น Ruby พัฒนาแกนภาษาโดย
กลุ่ม Opensource

ซึ่งจะพัฒนาเรื่องภาษาเป็นหลัก สำหรับการต่อเชื่อมเข้ากับ Application ต่างๆ จะเป็นเรื่องของโปรแกรมแต่ละคนไปทำกันเอง สำหรับ Sketckup จะใช้ โปรแกรม Ruby Version 1.8.6 เป็น core Language เหมือนกับทุกภาษา แก่นของภาษา ruby พัฒนาบนภาษา C ดังนั้น ถ้าเขียน Application บนภาษา C ก็จะต่อกับ Ruby ได้
การต่อเชื่อมกับ ruby ใน Sketckup ใช้วิธีเดียวกับ การต่อกับ RubyOnRail โดยการสร้างเป็น .so สำหรับบน MAC(OSX) และ .dll สำหรับ Windows และนำเข้าใช้คำสั่ง require ‘ชื่อโปรแกรม’
มีบทความที่น่าจะช่วยได้มาก

และสำหรับ Sketckup

ลุยกันเลยดีกว่า
แล้วจะเริ่มเขียนโปรแกรมอย่างไร เลือก Windows จะสะดวกกว่า เพราะใช้ Visual Studio 2010 ในการพัฒนา
ให้ไป Download Visual Studio 2010 มาจาก www.microsoft.com ใช้ Standard C/C++ ก็พอเพราะฟรี
ต่อไป ต้องไป Download Ruby มากก่อน เลือก Version 1.8.6
และทำการ แตกโปรแกรมลงใน c:\ruby
ทีนี้ต้องใช้ Dos หรือ cmd ผู้ที่ไม่คุ้นเคย จะลำบากพอสมควร แต่ใช้ไม่กีคำสั่ง
เข้าไปที่  path ที่กำหนดเช่น
cd \ruby\ruby-rhg\win32
และเรียกคำสั่ง
configure.bat
และเรียก nmake ต่อ โปรแกรมจะ  compile ruby ให้



ที่สำคัญโปรแกรมจะสร้าง msvcrt-ruby18.lib ที่จะเป็นตัวเชื่อมกับ ruby sketckup ซึ่งต้องตรง version กับใน Sketckup

สร้างโปรแกรมตัวอย่าง
เปิด ​Visual Studio เลือกสร้าง New project เป็น win32 project และเลือกเป็น Empty ในชื่อ sx_hello คือไม่มี Source จากนั้น ให้ Add New Item เป็น C source ชื่อ sxhelloworld.c และ Def ในชื่อ sx_hello.def
ตั้งค่า ใน Project property
General->Configuration Type
Dynamic Library (.dll)
C/C++->Additional Include Directories
"C:\ruby\ruby-rhg";"C:\ruby\ruby-rhg\win32"
C/C++->Command Line
-MD -Ot -Ox -W4
Linker->Output
C:/Program Files/Google/Google SketchUp 8/Plugins/sx_hello.dll
Linker->Additional Dependencies
msvcrt-ruby18.lib
เลือก Output ไปที Plugins ของ google จะ ใช้ Require ได้

Source ของ sxhelloworld.c
///// Ruby Headers /////

#include <ruby.h>


///// Global References ////

static VALUE g_TI_ExtTest; // module


///// Ruby Extension Methods /////

static VALUE f_Hello( VALUE self )
{
    return rb_str_new2( "Hello SketchUp Work!!" );
}


///// Initializer /////

__declspec( dllexport ) void Init_sx_hello( void )
{
   // define Module
    g_TI_ExtTest = rb_define_module( "THANAPHAN" );
   
    // Constants
    // > THANAPHAN::VERSION
    rb_define_const( g_TI_ExtTest, "VERSION", rb_str_new2( "1.0" ) );
   
    // Methods
    // > THANAPHAN.hi
    rb_define_module_function( g_TI_ExtTest, "hi", (VALUE*)f_Hello, 0 );
}

และใน sx_hello.def
LIBRARY     "sx_hello"
EXPORTS
Init_sx_hello


ทั้งใน Source C และ def ต้อง  Export ในชื่อ Init_ชื่อไฟล์ ไม่นั้นจะ ใช้ ruby->require ไม่ได้
ทำการ compile ใน Visual studio  ต้องจบด้วย 1 succeeded จึงจะได้ โปรแกรม
..\..\sxhelloworld.c(32) : warning C4024: 'rb_define_module_function' : different types for formal and actual parameter 3
Linking...
External build tool process set to low priority...
   Creating library C:/Program Files/Google/Google SketchUp 8/Plugins/sx_hello.lib and object C:/Program Files/Google/Google SketchUp 8/Plugins/sx_hello.exp
Embedding manifest...
External build tool process set to low priority...
External build tool process set to low priority...
Build log was saved at "file://c:\ruby\hello\sx_hello\sx_hello\Debug\BuildLog.htm"
sx_hello - 0 error(s), 8 warning(s)
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========



ทดลองใน Sketchup เปิด Ruby Console พิมพ์ ตัวหนังสือตามสีฟ้า

require "sx_hello"
true
THANAPHAN::VERSION
1.0
THANAPHAN.hi
Hello SketchUp Work!!


เมื่อ Require จะทำการ load sx_hello.dll เข้ามาในโปรแกรม โดย ruby จะตอบกลับเป็น true  THANAPHAN จะเป็นชื่อ Module และประกอบด้วย constant VERSION และ โปรแกรมใต้ Module ชื่อ hi จะตอบกลับด้วย Hello SketchUp Work!! ส่วนต่อของ Ruby Sketchup และ C ทำงานได้แล้ว
เรื่องที่น่าสนใจคือ C++ ได้หรือไม่ ไม่ยาก เพราะ Syntax ไม่ต่างกัน แต่ถ้าเป็น C# ต้องทำ Class Wrapper ก่อน จึงจะ ต่อได้ ถ้ามีเวลาผมจะ ทดลองมาให้อ่านกัน

ในกรณี Debug โปรแกรม ก็ให้กดที่ปุ่ม Start Debugging ใน Visual Studio และเลือก โปรแกรม Sketchup.exe ใน Folder  Sketckup ก็จะทำงาน ได้ เหมือนการ Debug ปรกติ








4 ความคิดเห็น:

  1. สำหรับ Sketup 2015,2016 การ Compile จะใช้ Rub 2.0.0 p648 ต้องเลือกให้ถูกว่าจะเป็น win32 หรือ x64 ที่ www.ruby-lang.org และเมื่อ compile แล้ว จะใช้ นามสกุลเป็น .so
    จึงจะ load ได้

    ตอบลบ
  2. Header ของ ruby.h อาจจะใช้ ของ 1.8 ได้ แต่ Lib ต้องเปลี่ยนเป็นของ 2.0.0 นามสกุล ของ lib จะเป็น .a

    ตอบลบ
  3. อยากศึกษาเรื่องการเขียน Plugin ภาษา Ruby พอจะมีหนังสือแนะนำไหมครับ ขอบคุณมากครับ

    ตอบลบ
  4. กำลังจะฝึกอยู่เหมือนกันครับอาจารย์ เริ่มยังไงดีครับ

    ตอบลบ