cibuildgem 0.2.2 โ 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +13 -43
- data/lib/cibuildgem/cli.rb +52 -10
- data/lib/cibuildgem/compilation_tasks.rb +31 -13
- data/lib/cibuildgem/extension_patch.rb +7 -1
- data/lib/cibuildgem/tasks/wrapper.rake +2 -4
- data/lib/cibuildgem/templates/github/workflows/cibuildgem.yaml.tt +2 -0
- data/lib/cibuildgem/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2d98ae7e4d9c1c2bd075ee978c39d292fa995d5162d018f399e217e58ac90501
|
|
4
|
+
data.tar.gz: e497b8a81dc7b395b20f7c9f94db94a937b4c55de4e331fbccd7e172d3cf3807
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5255e73551d7a8237dce25300b64f00845f196348443684c7c4fc9fc42e3b57818d3bf30eee5989cd84fac6e610f96dfdf75db4353b0ed4d54c141f3eb124abc
|
|
7
|
+
data.tar.gz: f15c1eab3cbc400375a9e561a452f5ad70f10e09b068433a4eb4589a10dac3cedf37b6e20f6b49b38ab286a65847f8b1371c853b78a483ce4e19abca7568368e
|
data/README.md
CHANGED
|
@@ -22,49 +22,22 @@ As noted by [@flavorjones](https://github.com/flavorjones), this toolchain works
|
|
|
22
22
|
|
|
23
23
|
## ๐ป cibuildgem
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
> cibuildgem is for now not able to compile projects that needs to link on external libraries. Unless the project vendors those libraries or uses [mini_portile](https://github.com/flavorjones/mini_portile).
|
|
27
|
-
|
|
28
|
-
### How to use it
|
|
29
|
-
|
|
30
|
-
While cibuildgem is generally **not** meant to be used locally, it provides a command to generate the right GitHub workflow for your project:
|
|
31
|
-
|
|
32
|
-
1. Install cibuildgem: `gem install cibuildgem`
|
|
33
|
-
2. Generate the workflow: `cd` in your gem's folder and run `cibuildgem ci_template`
|
|
34
|
-
3. Commit the `.github/workflows/cibuildgem.yaml` file.
|
|
35
|
-
|
|
36
|
-
### Triggering the workflow
|
|
37
|
-
|
|
38
|
-
Once pushed in your repository **default** branch, the workflow that we just generated is actionable manually on the GitHub action page. It will run in sequence:
|
|
39
|
-
|
|
40
|
-
1. Compile the gem on the target platform (defaults to MacOS ARM, MacOS Intel, Windows, Ubuntu 24)
|
|
41
|
-
2. Once the compilation succeeds on all platform, it proceeds to run the test suite on the target platform. This will trigger many CI steps as the testing matrix is big.
|
|
42
|
-
3. Once the test suite passes for all platforms and all Ruby versions the gem is compatible with, the action proceeds to installing the gem we just packaged. This step ensure that the gem is actually installable.
|
|
43
|
-
4. [OPTIONAL] When trigering the workflow manually, you can tick the box to automatically release the gems that were packaged. This works using the RubyGems trusted publisher feature (documentation to write later). If you do no want the tool to make the release, you can download all the GitHub artifacts that were uploaded. It will contain all the gems with precompiled binaries in the `pkg` folder. You are free to download them locally and release them yourself from your machine.
|
|
25
|
+
Head to the [documentation Wiki](https://github.com/Shopify/cibuildgem/wiki) to setup and configure cibuildgem for your gem.
|
|
44
26
|
|
|
27
|
+
## Working examples
|
|
45
28
|
|
|
46
|
-
|
|
29
|
+
Here are some working examples on gem that have setup cibuildgem
|
|
47
30
|
|
|
48
|
-
|
|
49
|
-
|
|
31
|
+
| Name | Example Run | Published Gem |
|
|
32
|
+
|-----------|-------------|---------------|
|
|
33
|
+
| [Rubydex](https://github.com/shopify/rubydex) | [CI Run](https://github.com/Shopify/rubydex/actions/runs/21880161517) | [Gem](https://rubygems.org/gems/rubydex/versions/0.1.0.beta4-arm64-darwin) |
|
|
34
|
+
| [Heap Profiler](https://github.com/shopify/heap-profiler) | [CI Run](https://github.com/Shopify/heap-profiler/actions/runs/20996043558) | [Gem](https://rubygems.org/gems/heap-profiler/versions/0.8.0.rc1-x86_64-linux) |
|
|
35
|
+
| [djb2](https://github.com/Shopify/djb2) | [CI Run](https://github.com/Shopify/djb2/actions/runs/22188688549) | [Gem](https://rubygems.org/gems/djb2/versions/0.1.1-x86_64-linux) |
|
|
36
|
+
| [Blake3](https://github.com/Shopify/blake3-rb) | [CI Run](https://github.com/Shopify/blake3-rb/actions/runs/21253662535) | [Gem](https://rubygems.org/gems/blake3-rb/versions/1.5.6.rc1-x86_64-linux) |
|
|
37
|
+
| [Raindrops (fork)](https://github.com/Edouard-chin/raindrops) | [CI Run](https://github.com/Edouard-chin/raindrops/actions/runs/22045845221) | [Gem](https://rubygems.org/gems/precompiled-raindrops) |
|
|
38
|
+
| [Stack Frames](https://github.com/Shopify/stack_frames) | [CI Run](https://github.com/Shopify/stack_frames/actions/runs/19969899178) | [Gem](https://rubygems.org/gems/stack_frames/versions/0.1.4-x86_64-linux) |
|
|
50
39
|
|
|
51
|
-
|
|
52
|
-
# Before
|
|
53
|
-
|
|
54
|
-
require 'date_core.so'
|
|
55
|
-
|
|
56
|
-
# After
|
|
57
|
-
|
|
58
|
-
begin
|
|
59
|
-
ruby_version = /(\d+\.\d+)/.match(::RUBY_VERSION)
|
|
60
|
-
require "#{ruby_version}/date_core"
|
|
61
|
-
rescue LoadError
|
|
62
|
-
# It's important to leave for users that can not or don't want to use the gem with precompiled binaries.
|
|
63
|
-
require "date_core"
|
|
64
|
-
end
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
### Supported platforms/Ruby versions
|
|
40
|
+
## Supported platforms/Ruby versions
|
|
68
41
|
|
|
69
42
|
| | MacOS Intel | MacOS ARM | Windows x64 UCRT | Linux GNU x86_64|Linux AARCH64 |
|
|
70
43
|
|---------|------------- | --------- | ------------|-----------------|-----------------|
|
|
@@ -72,7 +45,4 @@ end
|
|
|
72
45
|
| Ruby 3.2| ๐ข | ๐ข | ๐ข | ๐ข | ๐ข |
|
|
73
46
|
| Ruby 3.3| ๐ข | ๐ข | ๐ข | ๐ข | ๐ข |
|
|
74
47
|
| Ruby 3.4| ๐ข | ๐ข | ๐ข | ๐ข | ๐ข |
|
|
75
|
-
|
|
76
|
-
## ๐งช Development
|
|
77
|
-
|
|
78
|
-
If you'd like to run a end-to-end test, the `date` gem is vendored in this project. You can trigger a manual run to do the whole compile, test, install dance from the GitHub action menu.
|
|
48
|
+
| Ruby 4.0| ๐ข | ๐ข | ๐ (not tested)| ๐ข | ๐ข |
|
data/lib/cibuildgem/cli.rb
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require "thor"
|
|
4
4
|
require "rake/extensiontask"
|
|
5
5
|
require "prism"
|
|
6
|
+
require "open3"
|
|
6
7
|
|
|
7
8
|
module Cibuildgem
|
|
8
9
|
class CLI < Thor
|
|
@@ -10,6 +11,10 @@ module Cibuildgem
|
|
|
10
11
|
|
|
11
12
|
source_root(File.expand_path("templates", __dir__))
|
|
12
13
|
|
|
14
|
+
# RubyGems already restricts a gem's name, version and platform to these characters, so every filename
|
|
15
|
+
# `cibuildgem package` can legitimately produce matches. Anything else was not produced by the package task.
|
|
16
|
+
RELEASABLE_GEM_FILENAME = /\A[A-Za-z0-9._-]+\.gem\z/
|
|
17
|
+
|
|
13
18
|
class << self
|
|
14
19
|
def exit_on_failure?
|
|
15
20
|
true
|
|
@@ -31,7 +36,7 @@ module Cibuildgem
|
|
|
31
36
|
run_rake_tasks!("cibuildgem:setup", :compile)
|
|
32
37
|
end
|
|
33
38
|
|
|
34
|
-
desc "package", "Compile and package a '
|
|
39
|
+
desc "package", "Compile and package a 'multi-ABI gem'.", hide: true
|
|
35
40
|
long_desc <<~MSG
|
|
36
41
|
This command should normally run on CI, using the cibuildgem workflow. It will not work locally unless
|
|
37
42
|
the environment is properly setup.
|
|
@@ -41,13 +46,20 @@ module Cibuildgem
|
|
|
41
46
|
- A gem without precompiled binary (Ruby platform).
|
|
42
47
|
|
|
43
48
|
The gem with precompiled binaries will be packaged with multiple binaries compatible for different
|
|
44
|
-
Ruby ABI (depending on what Ruby version the gem supports).
|
|
49
|
+
Ruby ABI (depending on what Ruby version the gem supports). If `--include-single-abi` is passed,
|
|
50
|
+
cibuildgem will also compile a set of single-ABI gems per Ruby version supported by the gem.
|
|
45
51
|
MSG
|
|
46
52
|
method_option "gemspec", type: "string", required: false, desc: "The gemspec to use. Defaults to the gemspec from the current working directory."
|
|
53
|
+
method_option "include-single-abi", type: :boolean, required: false, default: false, desc: "Whether to also compile a set of single-ABI gems. Defaults to false."
|
|
47
54
|
def package
|
|
48
55
|
ENV["RUBY_CC_VERSION"] ||= compilation_task.ruby_cc_version
|
|
49
|
-
|
|
50
|
-
|
|
56
|
+
run_rake_tasks!(
|
|
57
|
+
"cibuildgem:setup",
|
|
58
|
+
:cross,
|
|
59
|
+
:native,
|
|
60
|
+
:gem,
|
|
61
|
+
env: { "CIBUILDGEM_CONTENT_ADDRESSABLE" => options["include-single-abi"] == true ? "true" : "false" },
|
|
62
|
+
)
|
|
51
63
|
end
|
|
52
64
|
|
|
53
65
|
desc "test", "Run the test suites of the target gem"
|
|
@@ -112,14 +124,25 @@ module Cibuildgem
|
|
|
112
124
|
pathname = Pathname(file)
|
|
113
125
|
next if pathname.directory? || pathname.extname != ".gem"
|
|
114
126
|
|
|
115
|
-
|
|
127
|
+
verify_releasable_filename!(pathname)
|
|
128
|
+
|
|
129
|
+
out, status = Open3.capture2e("gem", "push", file)
|
|
130
|
+
next if status.success?
|
|
131
|
+
|
|
132
|
+
if out =~ /Repushing of gem versions is not allowed/
|
|
133
|
+
puts "Gem #{file} already exists on RubyGems.org, skipping..."
|
|
134
|
+
|
|
135
|
+
next
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
raise out
|
|
116
139
|
end
|
|
117
140
|
end
|
|
118
141
|
|
|
119
142
|
desc "print_ruby_cc_version", "Output the cross compile ruby version needed for the gem. For internal usage", hide: true
|
|
120
143
|
method_option "gemspec", type: "string", required: false, desc: "The gemspec to use. If the option is not passed, a gemspec file from the current working directory will be used."
|
|
121
144
|
def print_ruby_cc_version
|
|
122
|
-
print(compilation_task.ruby_cc_version)
|
|
145
|
+
print(ENV["RUBY_CC_VERSION"] || compilation_task.ruby_cc_version)
|
|
123
146
|
end
|
|
124
147
|
|
|
125
148
|
desc "normalized_platform", "The platform name for compilation purposes", hide: true
|
|
@@ -129,8 +152,20 @@ module Cibuildgem
|
|
|
129
152
|
|
|
130
153
|
private
|
|
131
154
|
|
|
132
|
-
def
|
|
133
|
-
|
|
155
|
+
def verify_releasable_filename!(pathname)
|
|
156
|
+
basename = pathname.basename.to_s
|
|
157
|
+
return if RELEASABLE_GEM_FILENAME.match?(basename)
|
|
158
|
+
|
|
159
|
+
raise(<<~MSG)
|
|
160
|
+
Refusing to publish #{basename.inspect}.
|
|
161
|
+
|
|
162
|
+
A gem filename may only contain letters, digits, dots, dashes and underscores, so this file was not
|
|
163
|
+
produced by `cibuildgem package`. Artifacts reach the release job from the compile job, which runs
|
|
164
|
+
without publishing credentials, so an unexpected filename is treated as tampering rather than a gem.
|
|
165
|
+
MSG
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def run_rake_tasks!(*tasks, env: {})
|
|
134
169
|
rakelibdir = [File.expand_path("tasks", __dir__), "rakelib"].join(File::PATH_SEPARATOR)
|
|
135
170
|
rake_compiler_path = Gem.loaded_specs["rake-compiler"].full_require_paths
|
|
136
171
|
rake_specs = Gem.loaded_specs["rake"]
|
|
@@ -141,8 +176,15 @@ module Cibuildgem
|
|
|
141
176
|
patch = File.expand_path("../extension_patch.rb", __FILE__)
|
|
142
177
|
|
|
143
178
|
system(
|
|
144
|
-
{ "RUBYLIB" => load_paths },
|
|
145
|
-
"bundle
|
|
179
|
+
{ "RUBYLIB" => load_paths }.merge(env),
|
|
180
|
+
"bundle",
|
|
181
|
+
"exec",
|
|
182
|
+
RbConfig.ruby,
|
|
183
|
+
rake_executable,
|
|
184
|
+
*tasks.map(&:to_s),
|
|
185
|
+
"-R#{rakelibdir}",
|
|
186
|
+
"-r",
|
|
187
|
+
patch,
|
|
146
188
|
exception: true,
|
|
147
189
|
)
|
|
148
190
|
end
|
|
@@ -7,18 +7,21 @@ require_relative "create_makefile_finder"
|
|
|
7
7
|
|
|
8
8
|
module Cibuildgem
|
|
9
9
|
class CompilationTasks
|
|
10
|
-
attr_reader :gemspec, :native, :create_packaging_task, :extension_task
|
|
10
|
+
attr_reader :gemspec, :native, :create_packaging_task, :extension_task, :content_addressable
|
|
11
11
|
|
|
12
|
-
def initialize(
|
|
12
|
+
def initialize(
|
|
13
|
+
create_packaging_task = false,
|
|
14
|
+
gemspec = nil,
|
|
15
|
+
content_addressable: ENV["CIBUILDGEM_CONTENT_ADDRESSABLE"] == "true"
|
|
16
|
+
)
|
|
13
17
|
@gemspec = Bundler.load_gemspec(gemspec || find_gemspec)
|
|
14
18
|
verify_gemspec!
|
|
15
19
|
|
|
16
20
|
@create_packaging_task = create_packaging_task
|
|
21
|
+
@content_addressable = content_addressable
|
|
17
22
|
end
|
|
18
23
|
|
|
19
24
|
def setup
|
|
20
|
-
Rake::ExtensionTask.enable!
|
|
21
|
-
|
|
22
25
|
gemspec.extensions.each do |path|
|
|
23
26
|
binary_name = parse_extconf(path)
|
|
24
27
|
define_task(path, binary_name)
|
|
@@ -54,20 +57,35 @@ module Cibuildgem
|
|
|
54
57
|
end
|
|
55
58
|
|
|
56
59
|
def define_task(path, binary_name)
|
|
57
|
-
@extension_task = Rake::ExtensionTask.
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
60
|
+
@extension_task = Rake::ExtensionTask.current || Rake::ExtensionTask.new
|
|
61
|
+
|
|
62
|
+
@extension_task.name = File.basename(binary_name)
|
|
63
|
+
@extension_task.config_script = File.basename(path)
|
|
64
|
+
@extension_task.ext_dir = File.dirname(path)
|
|
65
|
+
@extension_task.lib_dir = binary_lib_dir(binary_name) if binary_lib_dir(binary_name)
|
|
66
|
+
@extension_task.gem_spec = gemspec
|
|
67
|
+
@extension_task.cross_platform = normalized_platform
|
|
68
|
+
@extension_task.cross_compile = true
|
|
69
|
+
@extension_task.no_native = true
|
|
70
|
+
if content_addressable
|
|
71
|
+
if @extension_task.respond_to?(:content_addressable=)
|
|
72
|
+
@extension_task.content_addressable = true
|
|
73
|
+
else
|
|
74
|
+
warn("WARNING: content-addressable packaging was requested, but rake-compiler #{rake_compiler_version} " \
|
|
75
|
+
"does not support it. Upgrade rake-compiler to >= 1.3.2 to build single-ABI gems.")
|
|
76
|
+
end
|
|
66
77
|
end
|
|
67
78
|
|
|
79
|
+
Rake::ExtensionTask.enable!
|
|
80
|
+
@extension_task.define
|
|
81
|
+
|
|
68
82
|
disable_shared unless Gem.win_platform?
|
|
69
83
|
end
|
|
70
84
|
|
|
85
|
+
def rake_compiler_version
|
|
86
|
+
Gem.loaded_specs["rake-compiler"]&.version&.to_s || "unknown"
|
|
87
|
+
end
|
|
88
|
+
|
|
71
89
|
def binary_lib_dir(binary_name)
|
|
72
90
|
dir = File.dirname(binary_name)
|
|
73
91
|
return if dir == "."
|
|
@@ -7,7 +7,7 @@ module Cibuildgem
|
|
|
7
7
|
class << self
|
|
8
8
|
def prepended(mod)
|
|
9
9
|
class << mod
|
|
10
|
-
attr_accessor :enabled
|
|
10
|
+
attr_accessor :enabled, :current
|
|
11
11
|
|
|
12
12
|
def enable!
|
|
13
13
|
@enabled = true
|
|
@@ -16,6 +16,12 @@ module Cibuildgem
|
|
|
16
16
|
end
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
+
def initialize(*)
|
|
20
|
+
super
|
|
21
|
+
|
|
22
|
+
self.class.current = self
|
|
23
|
+
end
|
|
24
|
+
|
|
19
25
|
def define
|
|
20
26
|
super if self.class.enabled
|
|
21
27
|
end
|
|
@@ -12,11 +12,9 @@ task "cibuildgem:setup" do
|
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
task "copy:stage:lib" do
|
|
15
|
-
|
|
16
|
-
dest = File.join(task.extension_task.lib_dir, version)
|
|
17
|
-
src = File.join("tmp", task.extension_task.cross_platform, "stage", dest)
|
|
15
|
+
src = File.join("tmp", task.extension_task.cross_platform, "stage")
|
|
18
16
|
|
|
19
|
-
cp_r(src,
|
|
17
|
+
cp_r(Dir.glob("#{src}/*"), ".", remove_destination: true)
|
|
20
18
|
end
|
|
21
19
|
|
|
22
20
|
unless Rake::Task.task_defined?(:test)
|
data/lib/cibuildgem/version.rb
CHANGED