rcee_system 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a7c664ec9bf7164bf409808c01388459d95b09eb9612b71c68297d930ea9d350
4
- data.tar.gz: 3a8f12c1501e564f82d9c263cf4945c8bb689c8955b09b5dd9b1ead95358cf45
3
+ metadata.gz: ff7148e3553b2213be8a833e3beeae61df65c8f8a11be133b30377d1152d8c17
4
+ data.tar.gz: c9247be0c803ca52871abec835d0a13bcdb8ff46bc8fc9656dfcae948bc210a6
5
5
  SHA512:
6
- metadata.gz: a68f4616208fb9d39417fc8bca4568fd15b39e6b809756c21be58dc127e4109b48a7377b9f64b8a5e149fdc47df0712f4b03ab508c3d4f8e0fa94f0c33ac08b2
7
- data.tar.gz: 38b2296af87d4182f66a2926191c1858fcb5c0c95cb9521f15f7845c69b2a2c3fc79fe8356e8e399e6ce7be23aa88fc8e226a0a72d1b089a58f0354681c6f3fa
6
+ metadata.gz: a5346e5943f665665b4837a0602e55064e21fcb0d21bc47f808e9b5099cb94f1549e9a81ba8434242486b0666287f1f3da73dd94458e7708e37a94e2fb2788a9
7
+ data.tar.gz: 119bc1e5b65c1d07296e386ece1e3361f5b25827adb14d43ac693e23f319293191d0b7ce1ed567fdab5215c288af2c50e97dc6c5c5af7651df1f1ed2270d59ab
data/README.md CHANGED
@@ -1,2 +1,91 @@
1
+ # RCEE::System
1
2
 
2
3
  This gem is part of the Ruby C Extensions Explained project at https://github.com/flavorjones/ruby-c-extensions-explained
4
+
5
+ ## Context
6
+
7
+ In the `isolated` gem, I mentioned that one goal of a C extension might be to optimize performance. This is the case for BCrypt.
8
+
9
+ But there's another, more common, reason to write a C extension, which is to talk to a third-party library. Many Ruby gems use C extensions solely to integrate with a third-party library. Some examples:
10
+
11
+ - nokogiri → libxml2, libxslt, libgumbo
12
+ - psych → libyaml
13
+ - sqlite3 → libsqlite3
14
+ - rmagick → libMagick
15
+ - grpc → libgrpc
16
+
17
+ These gems have a thin-ish wrapper of Ruby and C that work together to make the library's features available as idiomatic Ruby.
18
+
19
+
20
+ ## Summary
21
+
22
+ This gem, as well as all the following gems, will call `libyaml` as an example third-party integration, and will require that `libyaml` be installed ahead of time on the target system.
23
+
24
+ Some real-world gems that use this "system" strategy are ruby-sqlite3 and rmagick.
25
+
26
+
27
+ ## Details
28
+
29
+ This gem's C code is located in `ext/system/system.c`:
30
+
31
+ ``` C
32
+ static VALUE
33
+ rb_system_extension_class_do_something(VALUE self)
34
+ {
35
+ int major, minor, patch;
36
+
37
+ yaml_get_version(&major, &minor, &patch);
38
+
39
+ return rb_sprintf("libyaml version %d.%d.%d", major, minor, patch);
40
+ }
41
+ ```
42
+
43
+ That's pretty simple, but is enough to demonstrate the integration with `libyaml` works.
44
+
45
+ The `extconf.rb` is still simple (and similar to `isolated/ext/isolated/extconf.rb` but contains this additional block:
46
+
47
+ ``` ruby
48
+ unless find_header("yaml.h") && find_library("yaml", "yaml_get_version")
49
+ abort("\nERROR: *** could not find libyaml development environment ***\n\n")
50
+ end
51
+ ```
52
+
53
+ `find_header` and `find_library` are `MakeMakefile` helper methods which will search your system's standard directories looking for files. If it finds them, it makes sure the compile step will be able to find `yaml.h`, and the link step will be able to find the `libyaml` library file.
54
+
55
+ We ask `find_header` to look for the `yaml.h` header file because that's what our C code needs (see `ext/system/system.h`). We ask `find_library` to look for a library named `libyaml` and check that it has the function `yaml_get_version()` defined in it.
56
+
57
+ (We don't need to call `find_library` for every function we intend to use; we just need to provide one function from the library so that `MakeMakefile` can verify that linking will succeed.)
58
+
59
+ If these methods succeed, the `Makefile` recipe looks something like this. Note the include directory is added for the compile step, and the library directory and name are added to the link step.
60
+
61
+ ``` sh
62
+ # `create_makefile` recipe is something like this
63
+
64
+ # compile phase:
65
+ gcc -c -I/path/to/ruby/include -I/path/to/libyaml/include system.c -o system.o
66
+
67
+ # link phase:
68
+ gcc -shared \
69
+ -L/path/to/ruby/lib -lruby \
70
+ -L/path/to/libyaml/lib -lyaml \
71
+ -lc -lm \
72
+ system.o -o system.so
73
+ ```
74
+
75
+ If you run `ldd` on the generated `system.so` you should see `libyaml` listed, something like:
76
+
77
+ ``` text
78
+ libyaml-0.so.2 => /usr/lib/x86_64-linux-gnu/libyaml-0.so.2 (0x00007f345a3dc000)
79
+ ```
80
+
81
+ ## What Can Go Wrong
82
+
83
+ In addition to what's enumerated in `isolated`'s README ...
84
+
85
+ If `MakeMakefile` methods fail to find the third-party library (or fail to compile and link against it), then the user will see an error message, and have to go figure out how to install `libyaml` on their system.
86
+
87
+ If the third-party library is installed into non-standard directories by the package manager, your `extconf.rb` may need special logic. `rmagick` needs to do a lot of this.
88
+
89
+ If the third-party library has compile-time flags to control whether features are turned on or off, then your `extconf.rb` may need to test for that with `have_func` and your C code will need to handle the case where those methods aren't implemented.
90
+
91
+ The version of the third-party library may be older or newer than you expected, and either contain bugs or be missing new features, which also require additional code complexity.
data/Rakefile CHANGED
@@ -1,8 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "bundler/gem_tasks"
4
- require "rake/testtask"
5
4
  require "rubygems/package_task"
5
+ require "rake/testtask"
6
+ require "rake/extensiontask"
6
7
 
7
8
  rcee_system_spec = Bundler.load_gemspec("rcee_system.gemspec")
8
9
  Gem::PackageTask.new(rcee_system_spec).define
@@ -13,14 +14,10 @@ Rake::TestTask.new(:test) do |t|
13
14
  t.test_files = FileList["test/**/*_test.rb"]
14
15
  end
15
16
 
16
- require "rake/extensiontask"
17
-
18
- task build: :compile
19
-
20
17
  Rake::ExtensionTask.new("system") do |ext|
21
18
  ext.lib_dir = "lib/rcee/system"
22
19
  end
23
20
 
24
- task default: %i[clobber compile test]
21
+ task default: [:clobber, :compile, :test]
25
22
 
26
- CLEAN.add("{ext,lib}/**/*.{o,so}")
23
+ CLEAN.add("{ext,lib}/**/*.{o,so}", "pkg")
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RCEE
4
4
  module System
5
- VERSION = "0.1.0"
5
+ VERSION = "0.2.0"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rcee_system
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Dalessio
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-09-02 00:00:00.000000000 Z
11
+ date: 2021-09-10 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Part of a project to explain how Ruby C extensions work.
14
14
  email:
@@ -47,7 +47,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
47
47
  - !ruby/object:Gem::Version
48
48
  version: '0'
49
49
  requirements: []
50
- rubygems_version: 3.2.15
50
+ rubygems_version: 3.2.22
51
51
  signing_key:
52
52
  specification_version: 4
53
53
  summary: Example gem demonstrating a basic C extension.