Ruby 3 is coming - headers and libs available

Since SketchUp got acquired by Trimble the team has made sure to keep the Ruby interpreter embedded in the application somewhat up to date.

We’ve chosen a conservative update cadence since every upgrade require extensions with Ruby C extensions to recompile their binaries. We’ve also chosen use a version that has had time to soak, allowing for the version to stabilize as much as possible before we ship it with the application.

The Ruby 2.x version branch stopped at Ruby 2.7. Moving forward it’s Ruby 3.x.

Any major version upgrade require some extra attention, but the good news is that in our experience the upgrade from Ruby 2.7 to 3.1 was much the same as any minor version upgrade (at least of you heeded the warnings Ruby might have given you in the past.)

This time we’re trying something new; we’re making header and libraries to compile against available much earlier than before. There is no SketchUp build available to test, but simply being able to setup your build environment will help those that need to rebuild their binaries. We created a dev/3.1 branch in our Ruby C Extension example:

Noteworthy Information

We’ve collected a few notes on our own experience on using Ruby 3.1:

  • The upgrade process for building against Ruby 3.1 felt similar to the process of upgrading between previous Ruby 2’s minor upgrades. If you addressed warnings you’re probably good to go.
  • We did try to use Ruby 3.0 at first, because we thought it would have had more time to soak up changes and possibly be less disruptive given it’s a major version upgrade. But it turned out that there were more compatibility issues for Ruby C extensions (and SketchUp itself) with Ruby 3.0 compared to 3.1. It appear that the Ruby community smoothened out some API compatibilities with Ruby 2.x between these versions.
  • On macOS we had to add declspec to “Other C Flags” in X-Code:
  • We didn’t encounter any breaking changes in pure Ruby extensions that we tested.
  • In my case (thomthom), the majority of the work was that Ruby 3.x finally removed the Win32API that had been deprecated since Ruby 1.9. I finally had to switch to Fiddle (which is a much better API btw.). If you are curious you can have a look at TT_Lib to get an idea of what I did: Bitbucket In order to aid this migration work I first wrote a set of TestUp tests against the existing code. Then I split the old and new implementation into separate implementation files which I could replace upon load depending on SketchUp/Ruby version. This made it a lot easier to ensure that my new Fiddle implementation behaved the same as the old Win32 implementation.

It’s worth giving the release notes for Ruby 3.0 and 3.1 a read.

Quick Summary

Ruby 3.0.0

Ruby-3.0.0 finishes the transition to UTF-8 as the primary character encoding on Windows. This enables full Unicode character set for filesystem and environment variables and increases compatibility with other tools and operating systems.

Ruby 3.0.1

Enabled ruby to support path length of more than 260 characters. See commit 829ab9d Added racc, rbs and typeprof executables to the /bin folder. See #231

Ruby 3.1.0

RubyInstaller-3.1.0-x64 has a changed C-runtime called UCRT replacing the old MSVCRT. The modern C-runtime brings better compatibility to C standards and to libraries compiled with Microsoft Visual Studio. See the feature request here. There are several platform strings that change with the new release. In particular the ruby and gem platform is now x64-mingw-ucrt instead of x64-mingw32 and the MSYS2 package prefix is now mingw-w64-ucrt-x86_64-. The Devkit version of RubyInstaller now bundles the UCRT based MINGW packages. ridk install can be used to install these packages into a previous or a shared location of MSYS2. There are some subsequent issues like seamless integration into Github Actions and cross compiler support regarding UCRT.

The new RBS format

If you have ever used TypeScript you’ll be familiar with Type Definition files. Ruby 3 introduces it’s own variant of this. This in the form of a new fileformat; .rbs. Those of you that have been around for a while might recognize that as the file format for the old scrambled Ruby files that SketchUp previously offered. While we no longer offer this fileformat, it’s still found in older extensions that will continue to work and that users still use, so SketchUp continues to read these files for compatibility.

This presents a challenge for developers who would like to make use of this new type definition feature in Ruby. The type definition files aren’t something you’d distribute with your extension, but it is something you’d have along your .rb files while developing. At the moment this would cause issues for SketchUp because when you perform a Sketchup.require it will look for .rbe, .rbs and .rb files in that order. If you are using the Ruby 3 .rbs files SketchUp would attempt to load that as a scrambled Ruby file, which off course won’t work.

Upcoming version of SketchUp will be smarter in terms of handling .rbs files, it will sniff out the headers of the files and decide if it’s a scrambled Ruby file or of it’s a Ruby 3.x type definition.

For more information about Ruby 3.x’s type definition files refer to the various documentation and articles out there.

11 Likes

Glad to here. If you’re jumping to Ruby 3, 3.1 is much better, as you’ve found. You mentioned the RubyInstaller release(s) of 3.1. I assume SU will still use an ‘mswin’ build? And the SU Ruby dll will be x64-ucrt-ruby310.dll?

There are some subsequent issues like seamless integration into GitHub Actions

Just to clarify, are you finding GitHub Actions works well with 3.1? Not sure if you’re using it or just saw some notes…

It looks like v3.1.1 has quite a few bug fixes and v3.1.2 has a couple of security fixes, … that would be desirable for the SketchUp application release.

2 Likes

Further what Dan mentioned.

3 digit versions are normally referred to as major.minor.patch. A lot of software companies won’t use a patch zero version. So, SU should definitely use the latest 3.1 release. It should be binary compatible anyway…

2 Likes

Right, this thread allows the C extension consumers to get a head start on compiling their products, no matter what the final “teeny” version that the upcoming application release uses. (We know that, by this notice, it will not be 3.2 as it is still in the pre-release preview cycle.)


Musing …

I’m looking at the v3.1.0 release notes and it’s TypeProf subsection,
under the Other Notable New Features section.

It shows what the experimental “TypeProf for IDE” looks like in MS VS Code.

I’m wondering if it can sniff out method signatures like this, then (perhaps in the future) can a dependent IDE extension help the coder by inserting doc generative comments, such as YARD comments?

It certainly would help take the tedium out of entering YARD parameter and result comments. (For coders like myself with arthritis in the hands, this could cut down on wear and tear.)

(Probably at a later time would be deserving of it’s own topic thread.)

The repo listed x64-msvcrt-ruby310.lib in Ruby 3.1 (x64).props.

Don’t have a 310 mswin build, but 320 is showing x64-vcruntime140-ruby320.lib? You can name files however you want, but I would think either match ucrt 3.1 or mswin 3.1…

That’s a good question. I had assumed we’d get the ucrt, but maybe we have to do something in our build. (We name the binary to follow pattern of older DLLs, regardless of build settings.)

I’ll see if I can figure out what the current CRT dependency is.

1 Like

Pretty sure SU is built with ucrt, which is what the RubyInstaller (RI) version of Ruby 3.1 is built with. But, SU is using what is often called an ‘mswin build’.

Since both the RI 3.1 build and SU are using the same VC runtime, there is a good change that extension gems built with the stand-alone RI version would work with SU. Hence, making the SU Ruby appear to be a ucrt build might make it easier for some users/plugin authors.

Conversely, with MSFT’s vcpkg system, one can build dependencies for most packages, and Ruby is using those packages to test mswin builds in its CI. I recall people wanting to use Nokogiri, and, at present, it cannot be built with mswin, but it is building with ucrt (Ruby 3.1). Note that the Nokogiri mswin issues may get addressed in the future, as some of the other repos in that organization are building against mswin.

Anyway, these issues don’t affect most plugin authors. Feel free to ping me, as I’m certainly interested, and I like to see SU using current Ruby versions…

This build question is why I always tested for platform using a logical not darwin (in the fallback clause for older SketchUp version), as in:

WIN ||= Sketchup.platform == :platform_win rescue RUBY_PLATFORM !~ /darwin/

rescue statements have a bit of overhead.

I’d use the following, which should cover all publicly available Ruby builds and also all SU builds.

RUBY_PLATFORM =~ /mingw|mswin/

If one can assume Ruby 2.5 and later:

RUBY_PLATFORM.match?(/mingw|mswin/)

… except SketchUp 2014 (Ruby 2.0.0) and later have the module method so really if a coder is no longer supporting older SketchUp versions with Ruby 1.8, then the rescue clause is unneeded. (I was just mainly mentioning what I did in the past circa 2015/16.)

@tt_su

See ruby-loco on GitHub and the logs in the most recent mswin build.

Note the manifest handling re dll’s. All dependent packages are vcpkg. Also, the current vcpkg OpenSSL is 3.0.4.

The build(s) can be downloaded from the release page

These are all Ruby master builds, done three times a day. They are used for Windows CI, both in the Ruby org (std lib gems, including Ruby OpenSSL, etc), and other repos. Some popular gems are using the mswin build in CI, sqlite3, Puma, etc

Feel free to clone. Many of the files are only used with the mingw & ucrt builds.

I didn’t think Ruby 3.1 had migrated to OpenSSL 3…?

I tried dumpbin /DEPENDENTS on the Ruby dll, but it reports no dependencies. Not for the Ruby 3.1 dll, nor for the older. I thought that would show up… :thinking:

Since Ruby 3.0. Ubuntu 22.04 uses OpenSSL 3 as the default install. vcpkg has changed to it, and MSYS2 has had discussions about moving to it. It will compile with MSYS2 mingw & ucrt, I’ve built both. Ruby 3 can also be compiled with OpenSSL 1.1.1.

I often use the MSYS2 objdump, so from the exe/dll directory, using ruby.exe:

C:/msys64/ucrt64/bin/objdump.exe -p ruby.exe | Select-String -Pattern 'DLL Name:' | Sort-Object

        DLL Name: api-ms-win-crt-environment-l1-1-0.dll
        DLL Name: api-ms-win-crt-heap-l1-1-0.dll
        DLL Name: api-ms-win-crt-locale-l1-1-0.dll
        DLL Name: api-ms-win-crt-math-l1-1-0.dll
        DLL Name: api-ms-win-crt-private-l1-1-0.dll
        DLL Name: api-ms-win-crt-runtime-l1-1-0.dll
        DLL Name: api-ms-win-crt-stdio-l1-1-0.dll
        DLL Name: api-ms-win-crt-string-l1-1-0.dll
        DLL Name: api-ms-win-crt-time-l1-1-0.dll
        DLL Name: KERNEL32.dll
        DLL Name: libssp-0.dll
        DLL Name: x64-ucrt-ruby310.dll

Using x64-ucrt-ruby310.dll

C:/msys64/ucrt64/bin/objdump.exe -p x64-ucrt-ruby310.dll | Select-String -Pattern 'DLL Name:' | Sort-Object

        DLL Name: ADVAPI32.dll
        DLL Name: api-ms-win-crt-convert-l1-1-0.dll
        DLL Name: api-ms-win-crt-environment-l1-1-0.dll
        DLL Name: api-ms-win-crt-filesystem-l1-1-0.dll
        DLL Name: api-ms-win-crt-heap-l1-1-0.dll
        DLL Name: api-ms-win-crt-locale-l1-1-0.dll
        DLL Name: api-ms-win-crt-math-l1-1-0.dll
        DLL Name: api-ms-win-crt-private-l1-1-0.dll
        DLL Name: api-ms-win-crt-runtime-l1-1-0.dll
        DLL Name: api-ms-win-crt-stdio-l1-1-0.dll
        DLL Name: api-ms-win-crt-string-l1-1-0.dll
        DLL Name: api-ms-win-crt-time-l1-1-0.dll
        DLL Name: api-ms-win-crt-utility-l1-1-0.dll
        DLL Name: bcrypt.dll
        DLL Name: imagehlp.dll
        DLL Name: IPHLPAPI.DLL
        DLL Name: KERNEL32.dll
        DLL Name: libgmp-10.dll
        DLL Name: libssp-0.dll
        DLL Name: SHELL32.dll
        DLL Name: USER32.dll
        DLL Name: WS2_32.dll

It can use either one?

We’d been tracking this issue, which indicated support wasn’t completed: Support OpenSSL 3.0 · Issue #369 · ruby/openssl · GitHub

Yes. The dll’s have different names, so the choice is at build time. I’ve been meaning to build a vcpkg OpenSSL 1.1.1 package, but haven’t gotten around to it.

We’d been tracking this issue, which indicated support wasn’t completed: Support OpenSSL 3.0 · Issue #369 · ruby/openssl · GitHub

What is considered full OpenSSL 3 support is messy. Many of the functions that were deprecated deal with cipher/crypto operations, which are not commonly used. Additionally, some of the cipher suites were deprecated or removed.

If you review comment, there is also the ‘legacy provider’, which can be enabled. Don’t recall if the standard vcpkg OpenSSL does so, but it’s just a config change.

Also, several repos are testing with both OpenSSL 3 and the Ruby mswin master build.

See most recent ‘master/main’ Actions jobs in ruby/openssl, ruby/digest, puma/puma

Three items I should have mentioned:

  1. Many Ruby repos are testing with Ubuntu 22.04, which uses OpenSSL 3.

  2. From the OpenSSL download page

    “The latest stable version is the 3.0 series supported until 7th September 2026.”

    and, importantly:

    “The previous LTS version (the 1.1.1 series) is also available and is supported until 11th September 2023.”

    So, if I remember typical SU release schedule, OpenSSL 1.1.1 will be EOL before SU 2024 is released?

  3. ruby/openssl CI - currently, there is one skipped test when using OpenSSL 3. Using ruby/openssl master with Ruby 3.1 & master, the test is now passing.

    I also tested Ruby 3.1.2 on WSL2/Ubuntu 22.04 (using OpenSSL 3), and the equivalent of the test passes.

So, it would seem that Ruby 3.x and OpenSSL 3 are ready for use…