rcee_precompiled 0.5.1-x86_64-linux-gnu
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/Gemfile +13 -0
- data/README.md +215 -0
- data/Rakefile +110 -0
- data/ext/precompiled/extconf.rb +78 -0
- data/ext/precompiled/precompiled.c +25 -0
- data/ext/precompiled/precompiled.h +7 -0
- data/lib/rcee/precompiled/3.0/precompiled.so +0 -0
- data/lib/rcee/precompiled/3.1/precompiled.so +0 -0
- data/lib/rcee/precompiled/3.2/precompiled.so +0 -0
- data/lib/rcee/precompiled/3.3/precompiled.so +0 -0
- data/lib/rcee/precompiled/version.rb +7 -0
- data/lib/rcee/precompiled.rb +23 -0
- data/rcee_precompiled.gemspec +46 -0
- metadata +63 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d02dbbb9a55406596e891b4f864118da52c9e71dc953074be2ab9943038d716f
|
4
|
+
data.tar.gz: 348d08c0b2e603634d2041c8cae0633628ec1a054a6327e191ef0256aa35bf0a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 71374e1ff1f02d142efbc2eb5c4eae44b2b0989208865c75bb8c216dddedcc7e40f200fc444703c7236d73bf19847fdfa0eaebfe08a7f1f62048175b67904171
|
7
|
+
data.tar.gz: 67f979b289965046631942af19fba460a63f2f3f7be1441c88bd263b8a02338a335078dab669ded8c1897b69f1d5a4e07cd288bac033af94cc1eaafb2d834edb
|
data/.gitignore
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
# Specify your gem's dependencies in precompiled.gemspec
|
6
|
+
gemspec
|
7
|
+
|
8
|
+
gem "rake", "~> 13.0"
|
9
|
+
|
10
|
+
gem "rake-compiler"
|
11
|
+
gem "rake-compiler-dock", "1.5.0.rc1"
|
12
|
+
|
13
|
+
gem "minitest", "~> 5.0"
|
data/README.md
ADDED
@@ -0,0 +1,215 @@
|
|
1
|
+
# RCEE::Precompiled
|
2
|
+
|
3
|
+
This gem is part of the Ruby C Extensions Explained project at https://github.com/flavorjones/ruby-c-extensions-explained
|
4
|
+
|
5
|
+
## Summary
|
6
|
+
|
7
|
+
Installation time is an important aspect of developer happiness, and the Packaged strategies can make your users very unhappy.
|
8
|
+
|
9
|
+
One way to speed up installation time is to precompile the extension, so that during `gem install` files are simply being unpacked, and the entire configure/compile/link process is avoided completely. This can be tricky to set up, and requires that you test across all the target platforms; but makes for much happier users.
|
10
|
+
|
11
|
+
Note, however, that it's necessary to _also_ ship the vanilla (platform=ruby) gem as a fallback for platforms you haven't pre-compiled for.
|
12
|
+
|
13
|
+
In the nine months since Nokogiri v1.11 started shipping precompiled native gems, we've seen over 45 million gem installations, and essentially zero support issues have been opened. Twitter complaints dropped to near zero. Page views of the Nokogiri installation tutorial dropped by half.
|
14
|
+
|
15
|
+
Precompiled Nokogiri gems have been an unmitigated success and have made both users and maintainers happy.
|
16
|
+
|
17
|
+
|
18
|
+
## Details
|
19
|
+
|
20
|
+
An important tool we rely on for precompiling is [`rake-compiler/rake-compiler-dock`](https://github.com/rake-compiler/rake-compiler-dock), maintained by Lars Kanis. `rake-compiler-dock` is a Docker-based build environment that uses `rake-compiler` to _cross compile_ for all of these major platforms.
|
21
|
+
|
22
|
+
What this means is, I can run my normal gem build process in a docker container on my Linux machine, and it will build gems that I run on Windows and MacOS.
|
23
|
+
|
24
|
+
This is really powerful stuff, and once we assume that we can cross-compile reliably, the remaining problems boil down to modifying how we build the gemfile and making sure we test gems adequately on the target platforms.
|
25
|
+
|
26
|
+
First, we need to add some features to our `Rake::ExtensionTask` in `Rakefile`:
|
27
|
+
|
28
|
+
``` ruby
|
29
|
+
cross_rubies = ["3.3.0", "3.2.0", "3.1.0", "3.0.0"]
|
30
|
+
cross_platforms = [
|
31
|
+
"aarch64-linux-gnu",
|
32
|
+
"aarch64-linux-musl",
|
33
|
+
"arm-linux-gnu",
|
34
|
+
"arm-linux-musl",
|
35
|
+
"arm64-darwin",
|
36
|
+
"x64-mingw-ucrt",
|
37
|
+
"x64-mingw32",
|
38
|
+
"x86-linux-gnu",
|
39
|
+
"x86-linux-musl",
|
40
|
+
"x86_64-darwin",
|
41
|
+
"x86_64-linux-gnu",
|
42
|
+
"x86_64-linux-musl",
|
43
|
+
]
|
44
|
+
ENV["RUBY_CC_VERSION"] = cross_rubies.join(":")
|
45
|
+
|
46
|
+
Rake::ExtensionTask.new("precompiled", rcee_precompiled_spec) do |ext|
|
47
|
+
ext.lib_dir = "lib/rcee/precompiled"
|
48
|
+
ext.cross_compile = true
|
49
|
+
ext.cross_platform = cross_platforms
|
50
|
+
ext.cross_config_options << "--enable-cross-build" # so extconf.rb knows we're cross-compiling
|
51
|
+
ext.cross_compiling do |spec|
|
52
|
+
# remove things not needed for precompiled gems
|
53
|
+
spec.dependencies.reject! { |dep| dep.name == "mini_portile2" }
|
54
|
+
spec.files.reject! { |file| File.fnmatch?("*.tar.gz", file) }
|
55
|
+
end
|
56
|
+
end
|
57
|
+
```
|
58
|
+
|
59
|
+
This does the following:
|
60
|
+
|
61
|
+
- set up some local variables to indicate what ruby versions and which platforms we will build for
|
62
|
+
- set an environment variable to let rake-compiler know which ruby versions we'll build
|
63
|
+
- tell the extension task to turn on cross-compiling features, including additional rake tasks
|
64
|
+
- signal to our `extconf.rb` when we're cross-compiling (in case its behavior needs to change)
|
65
|
+
- finally, in a block that is only run when cross-compiling, we modify the gemspec to remove things we don't need in native gems:
|
66
|
+
- the tarball
|
67
|
+
- the dependency on `mini_portile`
|
68
|
+
|
69
|
+
Next we need some new rake tasks:
|
70
|
+
|
71
|
+
``` ruby
|
72
|
+
namespace "gem" do
|
73
|
+
cross_platforms.each do |platform|
|
74
|
+
desc "build native gem for #{platform}"
|
75
|
+
task platform do
|
76
|
+
RakeCompilerDock.sh(<<~EOF, platform: platform)
|
77
|
+
gem install bundler --no-document &&
|
78
|
+
bundle &&
|
79
|
+
bundle exec rake gem:#{platform}:buildit
|
80
|
+
EOF
|
81
|
+
end
|
82
|
+
|
83
|
+
namespace platform do
|
84
|
+
# this runs in the rake-compiler-dock docker container
|
85
|
+
task "buildit" do
|
86
|
+
# use Task#invoke because the pkg/*gem task is defined at runtime
|
87
|
+
Rake::Task["native:#{platform}"].invoke
|
88
|
+
Rake::Task["pkg/#{rcee_precompiled_spec.full_name}-#{Gem::Platform.new(platform)}.gem"].invoke
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
```
|
94
|
+
|
95
|
+
The top task (or, really, _set_ of tasks) runs on the host system, and invokes the lower task within the appropriate docker container to cross-compile for that platform. So the bottom task is doing most of the work, and it's doing it inside a guest container. Please note that the worker is both building the extension *and* packaging the gem according to the gemspec that was just modified by our extensiontask cross-compiling block.
|
96
|
+
|
97
|
+
Changes to the `extconf.rb`:
|
98
|
+
|
99
|
+
``` ruby
|
100
|
+
def configure_cross_compilers
|
101
|
+
RbConfig::CONFIG["CC"] = RbConfig::MAKEFILE_CONFIG["CC"] = ENV["CC"] if ENV["CC"]
|
102
|
+
ENV["CC"] = RbConfig::CONFIG["CC"]
|
103
|
+
end
|
104
|
+
```
|
105
|
+
|
106
|
+
This makes sure that the cross-compiler is the compiler used within the guest container (and not the native linux compiler).
|
107
|
+
|
108
|
+
``` ruby
|
109
|
+
def cross_build?
|
110
|
+
enable_config("cross-build")
|
111
|
+
end
|
112
|
+
```
|
113
|
+
|
114
|
+
The cross-compile rake task signals to `extconf.rb` that it's cross-compiling by using a commandline flag that we can inspect. We'll need this for `libyaml` to make sure that set the appropriate flags during precompilation (flags which shouldn't be set when compiling natively).
|
115
|
+
|
116
|
+
``` ruby
|
117
|
+
# pass some environment variables to the libyaml configuration for cross-compilation
|
118
|
+
if cross_build?
|
119
|
+
ENV.to_h.tap do |env|
|
120
|
+
# -fPIC is necessary for linking into a shared library
|
121
|
+
env["CFLAGS"] = [env["CFLAGS"], "-fPIC"].join(" ")
|
122
|
+
env["SUBDIRS"] = "include src" # libyaml: skip tests
|
123
|
+
|
124
|
+
recipe.configure_options += env.map { |key, value| "#{key}=#{value.strip}" }
|
125
|
+
end
|
126
|
+
end
|
127
|
+
```
|
128
|
+
|
129
|
+
The rest of the extconf changes are related to configuring libyaml at build time. We need to set the -fPIC option so we can mix static and shared libraries together. (This should probably always be set.)
|
130
|
+
|
131
|
+
The "SUBDIRS" environment variable is something that's very specific to libyaml, though: it tells libyaml's autoconf build system to skip running the tests. We have to do this because although we can *generate* binaries for other platforms, we can't actually *run* them.
|
132
|
+
|
133
|
+
We have one more small change we'll need to make to how the extension is required. Let's take a look at the directory structure in the packaged gem:
|
134
|
+
|
135
|
+
``` text
|
136
|
+
lib
|
137
|
+
└── rcee
|
138
|
+
├── precompiled
|
139
|
+
│ ├── 3.0
|
140
|
+
│ │ └── precompiled.so
|
141
|
+
│ ├── 3.1
|
142
|
+
│ │ └── precompiled.so
|
143
|
+
│ ├── 3.2
|
144
|
+
│ │ └── precompiled.so
|
145
|
+
│ ├── 3.3
|
146
|
+
│ │ └── precompiled.so
|
147
|
+
│ └── version.rb
|
148
|
+
└── precompiled.rb
|
149
|
+
```
|
150
|
+
|
151
|
+
You can see that we have FOUR c extensions in this gem, one for each minor version of Ruby that we support. Remember that a C extension is specific to an architecture and a version of Ruby. For example, if we're running Ruby 3.0.1, then we need to load the extension in the 3.0 directory. Let's make sure we do that.
|
152
|
+
|
153
|
+
In `lib/rcee/precompiled.rb`, we'll replace the normal `require` with:
|
154
|
+
|
155
|
+
``` ruby
|
156
|
+
begin
|
157
|
+
# load the precompiled extension file
|
158
|
+
ruby_version = /(\d+\.\d+)/.match(::RUBY_VERSION)
|
159
|
+
require_relative "precompiled/#{ruby_version}/precompiled"
|
160
|
+
rescue LoadError
|
161
|
+
# fall back to the extension compiled upon installation.
|
162
|
+
require "rcee/precompiled/precompiled"
|
163
|
+
end
|
164
|
+
```
|
165
|
+
|
166
|
+
Go ahead and try it! `gem install rcee_precompiled`. If you're on windows, linux, or macos you should get a precompiled version that installs in under a second. Everyone else (hello FreeBSD people!) it'll take a few more seconds to build the vanilla gem's packaged tarball.
|
167
|
+
|
168
|
+
|
169
|
+
### Windows notes
|
170
|
+
|
171
|
+
You may have noticed that the gem for `x64-mingw32` only contains `.../3.0/precompiled.so` and not a shared library for 3.1, 3.2, or 3.3. Conversely, the gem for `x64-mingw-ucrt` does *not* contain 3.0 (but contains 3.1..3.3 inclusive).
|
172
|
+
|
173
|
+
This is because the Windows installer for Ruby switched from `msvcrt` to `ucrt` for the C standard library. Rubies 3.0 and earlier use `msvcrt` but later Rubies use `ucrt`. So if you're on Ruby 3.0 on Windows, bundler will resolve your platform as `x64-mingw32`; but if you're on Ruby 3.1 or later, bundler will resolve your platform as `x64-mingw-ucrt`. See [the rubyinstaller release notes](https://rubyinstaller.org/2021/12/31/rubyinstaller-3.1.0-1-released.html) for more information.
|
174
|
+
|
175
|
+
This is all taken care of for you by `rake-compiler-dock` and there's no additional work necessary to create those specialized native gems. However, you'll see this libc transition in the CI testing matrix in `.github/workflows/precompiled.yml`.
|
176
|
+
|
177
|
+
|
178
|
+
### Linux notes
|
179
|
+
|
180
|
+
On Linux, the default C library for a long time was GNU libc, and so when you see native gem platforms like `x86_64-linux` the _implied_ libc is `gnu`. However, in recent years the `musl` libc project has gotten off the ground in distributions like Alpine. Often, `musl` systems are able to run code compiled on (and for) `gnu` systems; but not always. And in those incompatible cases, users had to work around it or avoid Alpine.
|
181
|
+
|
182
|
+
As of Rubygems 3.3.22, the `gem` and `bundle` tools are able to distinguish platforms by their libc type (e.g., `x86_64-linux-gnu` versus `x86_64-linux-musl`); and `rake-compiler-dock` started to be able to build `musl` native gems as of v1.5.0.
|
183
|
+
|
184
|
+
|
185
|
+
## Testing
|
186
|
+
|
187
|
+
See [.github/workflows/precompiled.yml](../.github/workflows/precompiled.yml)
|
188
|
+
|
189
|
+
Key things to note:
|
190
|
+
|
191
|
+
- matrix across all supported Rubies and platforms (for compile-from-source installation testing)
|
192
|
+
- test native gems for a variety of platforms
|
193
|
+
- use rake-compiler-dock images to build the gems
|
194
|
+
- then install on native platforms and verify that it passes tests
|
195
|
+
|
196
|
+
Note that there's additional complexity because of how we test:
|
197
|
+
|
198
|
+
- see new script bin/test-gem-build which artificially bumps the VERSION string to double-check we're testing the packaged version of the gem (which the tests output)
|
199
|
+
- see new script bin/test-gem-install which installs the gem, deletes the local source code, and runs the tests against the installed gem
|
200
|
+
- the gemspec handles a missing version file (because we delete the local source code during testing)
|
201
|
+
|
202
|
+
|
203
|
+
## What Can Go Wrong
|
204
|
+
|
205
|
+
This strategy isn't perfect. Remember what I said earlier, that a compiled C extension is specific to
|
206
|
+
|
207
|
+
- the minor version of ruby (e.g., 3.0)
|
208
|
+
- the machine architecture (e.g., x86_64)
|
209
|
+
- the system libraries
|
210
|
+
|
211
|
+
The precompiled strategy mostly takes care of the first two, but there are still edge cases for system libraries. The big gotcha is that linux libc is not the same as linux musl, and we've had to work around this a few times in Nokogiri.
|
212
|
+
|
213
|
+
I'm positive that there are more edge cases that will be found as users add more platforms and as more gems start precompiling. I'm willing to bet money that you can break this by setting some Ruby compile-time flags on your system. I'm honestly surprised it works as well as it has. (Worth noting: the `sassc` gem stopped shipping native gems for linux because of the musl incompatibilities.)
|
214
|
+
|
215
|
+
So the lesson here is: make sure you have an automated test pipeline that will build a gem and test it on the target platform! This takes time to set up, but it will save you time and effort in the long run.
|
data/Rakefile
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/gem_tasks"
|
4
|
+
require "rubygems/package_task"
|
5
|
+
require "rake/testtask"
|
6
|
+
require "rake/extensiontask"
|
7
|
+
require "rake_compiler_dock"
|
8
|
+
|
9
|
+
cross_rubies = ["3.3.0", "3.2.0", "3.1.0", "3.0.0"]
|
10
|
+
cross_platforms = [
|
11
|
+
"aarch64-linux-gnu",
|
12
|
+
"aarch64-linux-musl",
|
13
|
+
"arm-linux-gnu",
|
14
|
+
"arm-linux-musl",
|
15
|
+
"arm64-darwin",
|
16
|
+
"x64-mingw-ucrt",
|
17
|
+
"x64-mingw32",
|
18
|
+
"x86-linux-gnu",
|
19
|
+
"x86-linux-musl",
|
20
|
+
"x86_64-darwin",
|
21
|
+
"x86_64-linux-gnu",
|
22
|
+
"x86_64-linux-musl",
|
23
|
+
]
|
24
|
+
ENV["RUBY_CC_VERSION"] = cross_rubies.join(":")
|
25
|
+
|
26
|
+
rcee_precompiled_spec = Bundler.load_gemspec("rcee_precompiled.gemspec")
|
27
|
+
Gem::PackageTask.new(rcee_precompiled_spec).define #packaged_tarball version of the gem for platform=ruby
|
28
|
+
task "package" => "gem:all"
|
29
|
+
|
30
|
+
Rake::TestTask.new(:test) do |t|
|
31
|
+
t.libs << "test"
|
32
|
+
t.libs << "lib"
|
33
|
+
t.test_files = FileList["test/**/*_test.rb"]
|
34
|
+
end
|
35
|
+
|
36
|
+
Rake::ExtensionTask.new("precompiled", rcee_precompiled_spec) do |ext|
|
37
|
+
ext.lib_dir = "lib/rcee/precompiled"
|
38
|
+
ext.cross_compile = true
|
39
|
+
ext.cross_platform = cross_platforms
|
40
|
+
ext.cross_config_options << "--enable-cross-build" # so extconf.rb knows we're cross-compiling
|
41
|
+
ext.cross_compiling do |spec|
|
42
|
+
# remove things not needed for precompiled gems
|
43
|
+
spec.dependencies.reject! { |dep| dep.name == "mini_portile2" }
|
44
|
+
spec.files.reject! { |file| File.fnmatch?("*.tar.gz", file) }
|
45
|
+
|
46
|
+
if spec.platform.os == "linux"
|
47
|
+
# the `-gnu` suffix is not recognized in earlier versions of rubygems
|
48
|
+
spec.required_rubygems_version.concat([">= 3.3.22"])
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
namespace "gem" do
|
54
|
+
cross_platforms.each do |platform|
|
55
|
+
desc "build native gem for #{platform}"
|
56
|
+
task platform do
|
57
|
+
RakeCompilerDock.sh(<<~EOF, platform: platform)
|
58
|
+
gem install bundler --no-document &&
|
59
|
+
bundle &&
|
60
|
+
bundle exec rake gem:#{platform}:buildit
|
61
|
+
EOF
|
62
|
+
end
|
63
|
+
|
64
|
+
namespace platform do
|
65
|
+
# this runs in the rake-compiler-dock docker container
|
66
|
+
task "buildit" do
|
67
|
+
# use Task#invoke because the pkg/*gem task is defined at runtime
|
68
|
+
Rake::Task["native:#{platform}"].invoke
|
69
|
+
Rake::Task["pkg/#{rcee_precompiled_spec.full_name}-#{Gem::Platform.new(platform)}.gem"].invoke
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
desc "build native gem for all platforms"
|
75
|
+
multitask "all" => [cross_platforms, "gem"].flatten
|
76
|
+
end
|
77
|
+
|
78
|
+
desc "Temporarily set VERSION to a unique timestamp"
|
79
|
+
task "set-version-to-timestamp" do
|
80
|
+
# this task is used by bin/test-gem-build
|
81
|
+
# to test building, packaging, and installing a precompiled gem
|
82
|
+
version_constant_re = /^\s*VERSION\s*=\s*["'](.*)["']$/
|
83
|
+
|
84
|
+
version_file_path = File.join(__dir__, "lib/rcee/precompiled/version.rb")
|
85
|
+
version_file_contents = File.read(version_file_path)
|
86
|
+
|
87
|
+
current_version_string = version_constant_re.match(version_file_contents)[1]
|
88
|
+
current_version = Gem::Version.new(current_version_string)
|
89
|
+
|
90
|
+
fake_version = Gem::Version.new(format("%s.test.%s", current_version.bump, Time.now.strftime("%Y.%m%d.%H%M")))
|
91
|
+
|
92
|
+
unless version_file_contents.gsub!(version_constant_re, " VERSION = \"#{fake_version}\"")
|
93
|
+
raise("Could not hack the VERSION constant")
|
94
|
+
end
|
95
|
+
|
96
|
+
File.open(version_file_path, "w") { |f| f.write(version_file_contents) }
|
97
|
+
|
98
|
+
puts "NOTE: wrote version as \"#{fake_version}\""
|
99
|
+
end
|
100
|
+
|
101
|
+
task default: [:clobber, :compile, :test]
|
102
|
+
|
103
|
+
CLEAN.add("{ext,lib}/**/*.{o,so}", "pkg")
|
104
|
+
CLOBBER.add("ports")
|
105
|
+
|
106
|
+
# when packaging the gem, if the tarball isn't cached, we need to fetch it. the easiest thing to do
|
107
|
+
# is to run the compile phase to invoke the extconf and have mini_portile download the file for us.
|
108
|
+
# this is wasteful and in the future I would prefer to separate mini_portile from the extconf to
|
109
|
+
# allow us to download without compiling.
|
110
|
+
Rake::Task["package"].prerequisites.prepend("compile")
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require "mkmf"
|
2
|
+
require "mini_portile2"
|
3
|
+
|
4
|
+
module RCEE
|
5
|
+
module Precompiled
|
6
|
+
module ExtConf
|
7
|
+
PACKAGE_ROOT_DIR = File.expand_path(File.join(File.dirname(__FILE__), "..", ".."))
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def configure
|
11
|
+
configure_cross_compilers
|
12
|
+
configure_packaged_libraries
|
13
|
+
create_makefile("rcee/precompiled/precompiled")
|
14
|
+
end
|
15
|
+
|
16
|
+
def configure_cross_compilers
|
17
|
+
RbConfig::CONFIG["CC"] = RbConfig::MAKEFILE_CONFIG["CC"] = ENV["CC"] if ENV["CC"]
|
18
|
+
ENV["CC"] = RbConfig::CONFIG["CC"]
|
19
|
+
end
|
20
|
+
|
21
|
+
def configure_packaged_libraries
|
22
|
+
recipe = libyaml_recipe
|
23
|
+
|
24
|
+
# pass some environment variables to the libyaml configuration for cross-compilation
|
25
|
+
if cross_build?
|
26
|
+
ENV.to_h.tap do |env|
|
27
|
+
# -fPIC is necessary for linking into a shared library
|
28
|
+
env["CFLAGS"] = [env["CFLAGS"], "-fPIC"].join(" ")
|
29
|
+
env["SUBDIRS"] = "include src" # libyaml: skip tests
|
30
|
+
|
31
|
+
recipe.configure_options += env.map { |key, value| "#{key}=#{value.strip}" }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# ensure libyaml has already been unpacked, configured, and compiled
|
36
|
+
unless File.exist?(File.join(recipe.target, recipe.host, recipe.name, recipe.version))
|
37
|
+
recipe.cook
|
38
|
+
end
|
39
|
+
|
40
|
+
# use the packaged libyaml
|
41
|
+
recipe.activate
|
42
|
+
pkg_config(File.join(recipe.path, "lib", "pkgconfig", "yaml-0.1.pc"))
|
43
|
+
|
44
|
+
# assert that we can build against the packaged libyaml
|
45
|
+
unless have_library("yaml", "yaml_get_version", "yaml.h")
|
46
|
+
abort("\nERROR: *** could not find libyaml development environment ***\n\n")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def cross_build?
|
51
|
+
enable_config("cross-build")
|
52
|
+
end
|
53
|
+
|
54
|
+
def download
|
55
|
+
libyaml_recipe.download
|
56
|
+
end
|
57
|
+
|
58
|
+
def libyaml_recipe
|
59
|
+
MiniPortile.new("yaml", "0.2.5").tap do |recipe|
|
60
|
+
recipe.files = [{
|
61
|
+
url: "https://github.com/yaml/libyaml/releases/download/0.2.5/yaml-0.2.5.tar.gz",
|
62
|
+
sha256: "c642ae9b75fee120b2d96c712538bd2cf283228d2337df2cf2988e3c02678ef4"
|
63
|
+
}]
|
64
|
+
recipe.target = File.join(PACKAGE_ROOT_DIR, "ports")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# run "ruby ./ext/precompiled/extconf.rb -- --download-dependencies" to download the tarball
|
73
|
+
if arg_config("--download-dependencies")
|
74
|
+
RCEE::Precompiled::ExtConf.download
|
75
|
+
exit!(0)
|
76
|
+
end
|
77
|
+
|
78
|
+
RCEE::Precompiled::ExtConf.configure
|
@@ -0,0 +1,25 @@
|
|
1
|
+
#include "precompiled.h"
|
2
|
+
|
3
|
+
VALUE rb_mRCEE;
|
4
|
+
VALUE rb_mPrecompiled;
|
5
|
+
VALUE rb_cPrecompiledExtension;
|
6
|
+
|
7
|
+
static VALUE
|
8
|
+
rb_precompiled_extension_class_do_something(VALUE self)
|
9
|
+
{
|
10
|
+
int major, minor, patch;
|
11
|
+
|
12
|
+
yaml_get_version(&major, &minor, &patch);
|
13
|
+
|
14
|
+
return rb_sprintf("libyaml version %d.%d.%d", major, minor, patch);
|
15
|
+
}
|
16
|
+
|
17
|
+
void
|
18
|
+
Init_precompiled(void)
|
19
|
+
{
|
20
|
+
rb_mRCEE = rb_define_module("RCEE");
|
21
|
+
rb_mPrecompiled = rb_define_module_under(rb_mRCEE, "Precompiled");
|
22
|
+
rb_cPrecompiledExtension = rb_define_class_under(rb_mPrecompiled, "Extension", rb_cObject);
|
23
|
+
rb_define_singleton_method(rb_cPrecompiledExtension, "do_something",
|
24
|
+
rb_precompiled_extension_class_do_something, 0);
|
25
|
+
}
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "precompiled/version"
|
4
|
+
|
5
|
+
begin
|
6
|
+
# load the precompiled extension file
|
7
|
+
ruby_version = /(\d+\.\d+)/.match(::RUBY_VERSION)
|
8
|
+
require_relative "precompiled/#{ruby_version}/precompiled"
|
9
|
+
rescue LoadError
|
10
|
+
# fall back to the extension compiled upon installation.
|
11
|
+
# use "require" instead of "require_relative" because non-native gems will place C extension files
|
12
|
+
# in Gem::BasicSpecification#extension_dir after compilation (during normal installation), which
|
13
|
+
# is in $LOAD_PATH but not necessarily relative to this file
|
14
|
+
# (see https://github.com/sparklemotion/nokogiri/issues/2300 for more)
|
15
|
+
require "rcee/precompiled/precompiled"
|
16
|
+
end
|
17
|
+
|
18
|
+
module RCEE
|
19
|
+
module Precompiled
|
20
|
+
class Error < StandardError; end
|
21
|
+
# Your code goes here...
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
begin
|
4
|
+
require_relative "lib/rcee/precompiled/version"
|
5
|
+
rescue LoadError
|
6
|
+
puts "WARNING: Could not load RCEE::Precompiled::VERSION"
|
7
|
+
end
|
8
|
+
|
9
|
+
Gem::Specification.new do |spec|
|
10
|
+
spec.name = "rcee_precompiled"
|
11
|
+
spec.version = defined?(RCEE::Precompiled::VERSION) ? RCEE::Precompiled::VERSION : "0.0.0"
|
12
|
+
spec.authors = ["Mike Dalessio"]
|
13
|
+
spec.email = ["mike.dalessio@gmail.com"]
|
14
|
+
|
15
|
+
spec.summary = "Example gem demonstrating a basic C extension."
|
16
|
+
spec.description = "Part of a project to explain how Ruby C extensions work."
|
17
|
+
spec.homepage = "https://github.com/flavorjones/ruby-c-extensions-explained"
|
18
|
+
spec.required_ruby_version = ">= 3.0.0"
|
19
|
+
spec.license = "MIT"
|
20
|
+
|
21
|
+
# Specify which files should be added to the gem when it is released.
|
22
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
23
|
+
spec.files = [
|
24
|
+
".gitignore",
|
25
|
+
"Gemfile",
|
26
|
+
"README.md",
|
27
|
+
"Rakefile",
|
28
|
+
"ext/precompiled/extconf.rb",
|
29
|
+
"ext/precompiled/precompiled.c",
|
30
|
+
"ext/precompiled/precompiled.h",
|
31
|
+
"lib/rcee/precompiled.rb",
|
32
|
+
"lib/rcee/precompiled/version.rb",
|
33
|
+
"ports/archives/yaml-0.2.5.tar.gz",
|
34
|
+
"rcee_precompiled.gemspec",
|
35
|
+
]
|
36
|
+
|
37
|
+
spec.bindir = "exe"
|
38
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
39
|
+
spec.require_paths = ["lib"]
|
40
|
+
spec.extensions = ["ext/precompiled/extconf.rb"]
|
41
|
+
|
42
|
+
spec.add_dependency "mini_portile2"
|
43
|
+
|
44
|
+
# For more information and examples about making a new gem, checkout our
|
45
|
+
# guide at: https://bundler.io/guides/creating_gem.html
|
46
|
+
end
|
metadata
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rcee_precompiled
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.5.1
|
5
|
+
platform: x86_64-linux-gnu
|
6
|
+
authors:
|
7
|
+
- Mike Dalessio
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-01-28 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Part of a project to explain how Ruby C extensions work.
|
14
|
+
email:
|
15
|
+
- mike.dalessio@gmail.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- ".gitignore"
|
21
|
+
- Gemfile
|
22
|
+
- README.md
|
23
|
+
- Rakefile
|
24
|
+
- ext/precompiled/extconf.rb
|
25
|
+
- ext/precompiled/precompiled.c
|
26
|
+
- ext/precompiled/precompiled.h
|
27
|
+
- lib/rcee/precompiled.rb
|
28
|
+
- lib/rcee/precompiled/3.0/precompiled.so
|
29
|
+
- lib/rcee/precompiled/3.1/precompiled.so
|
30
|
+
- lib/rcee/precompiled/3.2/precompiled.so
|
31
|
+
- lib/rcee/precompiled/3.3/precompiled.so
|
32
|
+
- lib/rcee/precompiled/version.rb
|
33
|
+
- rcee_precompiled.gemspec
|
34
|
+
homepage: https://github.com/flavorjones/ruby-c-extensions-explained
|
35
|
+
licenses:
|
36
|
+
- MIT
|
37
|
+
metadata: {}
|
38
|
+
post_install_message:
|
39
|
+
rdoc_options: []
|
40
|
+
require_paths:
|
41
|
+
- lib
|
42
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '3.0'
|
47
|
+
- - "<"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: 3.4.dev
|
50
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: 3.3.22
|
58
|
+
requirements: []
|
59
|
+
rubygems_version: 3.3.26
|
60
|
+
signing_key:
|
61
|
+
specification_version: 4
|
62
|
+
summary: Example gem demonstrating a basic C extension.
|
63
|
+
test_files: []
|