specklesystems / speckle-sketchup

https://speckle.systems/tag/sketchup/
Apache License 2.0
15 stars 9 forks source link

🔧 Compile sqlite3 from C++ as sketchup compatible #71

Closed oguzhankoral closed 1 year ago

oguzhankoral commented 1 year ago

Currently the way of using sqlite3 in sketchup is installing gem on runtime which is not something sketchup suggests, and it might be the reason it is not working as desired always. See SketchupRequirements/GemInstall

# This is a current workaround.
begin
  require('sqlite3')
rescue LoadError
  # ty msp-greg! https://github.com/MSP-Greg/SUMisc/releases/tag/sqlite3-mingw-1
  Gem.install(File.join(File.dirname(File.expand_path(__FILE__)), '../../utils/sqlite3-1.4.2.mspgreg-x64-mingw32.gem'))
  require('sqlite3')
end

The way to go follow instructions of @thomthom on the repo to create sketchup compatible compiled .so and .bundle library to use as below.

require_relative 'ext/sqlite3'
oguzhankoral commented 1 year ago

🌟 THE WAY - Conversion from sqlite3 C/C++ to Ruby 🌟

Sample transition file as below, so then we will fill the Init_sqlite3 method;

#include "Database.h"
#include "RubyUtils/RubyUtils.h"
#include "ruby.h"

// Load this module from Ruby using:
//   require 'Sqlite3'
extern "C" {
        // Conversion method from C/C++ to Ruby
        // Proof of concept to test it on Sketchup. Call;
    //  SpeckleConnector::Sqlite3.greetings!
    static VALUE hi_from_c_sqlite3() {
        char message[] = "hi from c sqlite3!";
        VALUE str_val = rb_str_new2(message);
        return str_val;
    }

        // Conversion method from C/C++ to Ruby
        static void rbsqlite3_free(void* ptr) {
        delete (SQLite::Database*)ptr;
    }

        // Conversion method from C/C++ to Ruby
    static VALUE rbsqlite3_new(VALUE klass) {
                // TODO: below line should be taken by arguments
        const char* path = "C:/Users/sotas/AppData/Roaming/Speckle/Accounts.db";
        SQLite::Database* database = new SQLite::Database(path);
        VALUE obj = Data_Wrap_Struct(klass, 0, rbsqlite3_free, database);
        rb_obj_call_init(obj, 0, 0);
        return obj;
    }
}

void Init_sqlite3()
{
    // Init modules
    VALUE speckle_connector = rb_define_module("SpeckleConnector");
    VALUE speckle_connector_sqlite3 = rb_define_class_under(speckle_connector, "Sqlite3", rb_cObject);
    VALUE speckle_connector_sqlite3_database = rb_define_class_under(speckle_connector_sqlite3, "Database", rb_cObject);

    rb_define_singleton_method(speckle_connector_sqlite3, "greetings!", (ruby_method)hi_from_c_sqlite3, 0);

        // Definition of conversion and assigning method to modules and classes
    rb_define_singleton_method(speckle_connector_sqlite3_database, "new", (ruby_method)rbsqlite3_new, 1);
}

void Init_sqlite3_20()
{
    Init_sqlite3();
}

void Init_sqlite3_22()
{
    Init_sqlite3();
}

void Init_sqlite3_25()
{
    Init_sqlite3();
}

void Init_sqlite3_27()
{
    Init_sqlite3();
}

The workflow is defined above is not converted yet, there is a problem with getting argument from initializing method. This should be figured it out.

The key method here rb_obj_call_init and argument to pass it from VALUE to string path

oguzhankoral commented 1 year ago

This issue is ongoing for now,

Current solution is implemented by ruby files which is stored in speckle_connector/src/ext/sqlite3. By this way we do not have to install Gem on Runtime, which is good.