polycrystal 0.1.2 → 0.1.3
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/.gitignore +1 -0
- data/README.md +26 -5
- data/lib/polycrystal/compiler.rb +69 -32
- data/lib/polycrystal/loader.rb +3 -8
- data/lib/polycrystal/version.rb +1 -1
- data/lib/polycrystal.rb +15 -1
- data/sample_project/.gitignore +2 -1
- data/sample_project/Gemfile.lock +1 -1
- data/sample_project/crystal/sample.cr +6 -0
- data/sample_project/crystal/shard.lock +14 -0
- data/sample_project/crystal/shard.yml +14 -0
- data/sample_project/sample.rb +1 -5
- metadata +8 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6b792f50cc3fd49e84d1964fb3a494cad847b945685b887774ccb902e5d37092
|
4
|
+
data.tar.gz: b07a7239c6dfa5daeb20cfdf17c9dee8d592183509d7e2c25e16df0cf63582d6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fcc7135cbcadd6ccaa981e71192c3305f08e71c82f08883bb0820c938991fb0db7a39cd4cc06a181aae1df5ea59ecde1bc565252d9086a9bd2e29a017756a37c
|
7
|
+
data.tar.gz: 647f6a42daf887880b76e3a42fc3c9f995734e0a57f69cc18766b2e67780092f16aec941998cadf2f4b4830d5cbc73103db3e9678964da72098c825015b018bc
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -71,21 +71,42 @@ Polycrystal::Registry.register(
|
|
71
71
|
modules: ['CrystalModule']
|
72
72
|
)
|
73
73
|
|
74
|
-
#
|
74
|
+
# cpmpile and load
|
75
|
+
# should be called once, after all Polycrystal::Registry#register calls
|
76
|
+
Polycrystal.load
|
77
|
+
```
|
78
|
+
|
79
|
+
Set custom properties
|
80
|
+
```ruby
|
81
|
+
# directory for crystal entrypoint and compiled library.
|
75
82
|
build_path = File.expand_path("#{__dir__}/build")
|
76
83
|
FileUtils.mkdir_p(build_path)
|
77
84
|
|
78
|
-
|
79
|
-
|
80
|
-
|
85
|
+
|
86
|
+
Polycrystal.load(
|
87
|
+
# directory for crystal entrypoint and compiled library.
|
88
|
+
build_path: build_path,
|
89
|
+
# used to find lib with installed shards. SHARDS_INSTALL_PATH is used if present
|
90
|
+
shardfile: "./crystal/shard.yml",
|
91
|
+
# Polycrystal::NO_PRECOMPILE - compile everytime
|
92
|
+
# Polycrystal::LAZY_COMPILE - compile if not yet compiled
|
93
|
+
# Polycrystal::REQUIRE_AOT - not compile, require to be precompiled
|
94
|
+
precompile: Polycrystal::LAZY_COMPILE, # by default
|
95
|
+
)
|
81
96
|
```
|
82
97
|
|
83
98
|
## TODO
|
84
99
|
|
85
100
|
1. Test suite
|
101
|
+
2. Remove C code from this extension.
|
102
|
+
* C code is not required. Crystal code may be directly compiled to extension and loaded using standard `requre`
|
103
|
+
* To achieve that, anyolite glue files should be compiled to object files and linked to existing ruby correctly. I got segfault when I built glue files outside of ruby extension
|
86
104
|
2. Code should not be recompiled if it was not changed
|
105
|
+
* Rudimentary implementation is present, but more stable is preferrable: `Polycrystal.load(precompile: Polycrystal::LAZY_COMPILE)`
|
87
106
|
3. Ability to precompile all code on demand, e.g. for Docker images
|
88
|
-
|
107
|
+
* It is possible to do that right now by calling `Polycrystal.load(precompile: Polycrystal::LAZY_COMPILE)` in separate command, while loading Crystal module using `Polycrystal.load(precompile: Polycrystal::REQUIRE_AOT)`
|
108
|
+
4. make shards work. DONE, except:
|
109
|
+
* Anyolite can't be loaded from shards, because it's postinstall script downloads and compiles it's own mruby
|
89
110
|
|
90
111
|
## Development
|
91
112
|
|
data/lib/polycrystal/compiler.rb
CHANGED
@@ -1,32 +1,54 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'zlib'
|
4
|
+
|
3
5
|
module Polycrystal
|
4
6
|
class Compiler
|
5
|
-
attr_reader :build_path, :registry
|
7
|
+
attr_reader :build_path, :shardfile, :registry, :precompile
|
6
8
|
|
7
|
-
def initialize(build_path:, registry: Polycrystal::Registry.instance)
|
9
|
+
def initialize(build_path:, shardfile: nil, registry: Polycrystal::Registry.instance, precompile: LAZY_COMPILE)
|
8
10
|
@build_path = build_path
|
9
11
|
@registry = registry
|
10
|
-
|
11
|
-
|
12
|
+
@shardfile = shardfile
|
13
|
+
@precompile = precompile
|
12
14
|
end
|
13
15
|
|
14
16
|
def prepare
|
15
17
|
# load anyolite
|
16
18
|
add_anyolite
|
19
|
+
# add lib with shards
|
20
|
+
use_shards
|
17
21
|
# write crystal entrypoint
|
18
22
|
in_file.write(entrypoint)
|
19
23
|
in_file.close
|
20
24
|
end
|
21
25
|
|
22
26
|
def execute
|
23
|
-
|
24
|
-
|
25
|
-
|
27
|
+
if precompile == NO_PRECOMPILE
|
28
|
+
compile
|
29
|
+
elsif precompile == REQUIRE_AOT
|
30
|
+
raise 'Crystal module should be compiled before run' unless File.exist?(outfile)
|
31
|
+
else
|
32
|
+
compile unless File.exist?(outfile)
|
33
|
+
end
|
26
34
|
|
27
35
|
outfile
|
28
36
|
end
|
29
37
|
|
38
|
+
private
|
39
|
+
|
40
|
+
def use_shards
|
41
|
+
shard_path = ENV.fetch('SHARDS_INSTALL_PATH') do
|
42
|
+
return unless shardfile
|
43
|
+
|
44
|
+
shardfile_path = File.expand_path(shardfile)
|
45
|
+
return unless File.exist?(shardfile_path)
|
46
|
+
|
47
|
+
"#{File.dirname(shardfile_path)}/lib"
|
48
|
+
end
|
49
|
+
registry.register(path: shard_path)
|
50
|
+
end
|
51
|
+
|
30
52
|
def add_anyolite
|
31
53
|
registry.register(
|
32
54
|
path: find_anyolite,
|
@@ -87,16 +109,16 @@ module Polycrystal
|
|
87
109
|
end
|
88
110
|
|
89
111
|
def crystal_link_flags
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
112
|
+
case RUBY_PLATFORM
|
113
|
+
when /darwin/
|
114
|
+
'-dynamic -bundle'
|
115
|
+
when /linux/
|
116
|
+
mapfile = File.expand_path("#{build_path}/version.map")
|
117
|
+
File.write(mapfile, "VERS_1.1 {\tglobal:\t\t*;};")
|
118
|
+
"-shared -Wl,--version-script=#{mapfile}"
|
119
|
+
else
|
120
|
+
raise 'Unknown platform'
|
121
|
+
end
|
100
122
|
end
|
101
123
|
|
102
124
|
def pad_line(line, n)
|
@@ -112,31 +134,31 @@ module Polycrystal
|
|
112
134
|
end
|
113
135
|
|
114
136
|
def outfile
|
115
|
-
File.expand_path("#{build_path}/
|
137
|
+
@outfile ||= File.expand_path("#{build_path}/polycrystal#{compile_hash}_module.#{lib_ext}")
|
116
138
|
end
|
117
139
|
|
118
140
|
def lib_ext
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
141
|
+
case RUBY_PLATFORM
|
142
|
+
when /darwin/
|
143
|
+
'bundle'
|
144
|
+
when /linux/
|
145
|
+
'so'
|
146
|
+
else
|
147
|
+
raise 'Unknown platform'
|
148
|
+
end
|
127
149
|
end
|
128
150
|
|
129
151
|
def include_paths
|
130
|
-
existing = `#{compiler_cmd} env
|
131
|
-
[existing, *crystal_paths].join(':')
|
152
|
+
existing = `#{compiler_cmd} env CRYSTAL_PATH`.strip
|
153
|
+
["CRYSTAL_PATH=#{existing}", *crystal_paths].join(':')
|
132
154
|
end
|
133
155
|
|
134
156
|
def anyolite_glue
|
135
157
|
"-L#{RbConfig::CONFIG['libdir']} #{RbConfig::CONFIG['LIBRUBYARG_SHARED']} " \
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
158
|
+
"#{File.expand_path("#{__dir__}/../../ext/polycrystal/data_helper.o")} " \
|
159
|
+
"#{File.expand_path("#{__dir__}/../../ext/polycrystal/error_helper.o")} " \
|
160
|
+
"#{File.expand_path("#{__dir__}/../../ext/polycrystal/return_functions.o")} " \
|
161
|
+
"#{File.expand_path("#{__dir__}/../../ext/polycrystal/script_helper.o")} "
|
140
162
|
end
|
141
163
|
|
142
164
|
def compiler_cmd
|
@@ -162,5 +184,20 @@ module Polycrystal
|
|
162
184
|
|
163
185
|
local_path
|
164
186
|
end
|
187
|
+
|
188
|
+
def compile
|
189
|
+
# run compiler
|
190
|
+
puts command
|
191
|
+
raise 'Failed to compile crystal module' unless system(command)
|
192
|
+
end
|
193
|
+
|
194
|
+
def compile_hash
|
195
|
+
paths = crystal_paths.sort + [in_file.path]
|
196
|
+
paths.map { |path| path_hash(path) }.reduce(:^).to_s(32)
|
197
|
+
end
|
198
|
+
|
199
|
+
def path_hash(path)
|
200
|
+
Zlib.crc32(`ls -lRF #{path}`)
|
201
|
+
end
|
165
202
|
end
|
166
203
|
end
|
data/lib/polycrystal/loader.rb
CHANGED
@@ -2,18 +2,13 @@
|
|
2
2
|
|
3
3
|
module Polycrystal
|
4
4
|
class Loader
|
5
|
-
attr_reader :
|
5
|
+
attr_reader :compiler
|
6
6
|
|
7
|
-
def initialize(
|
8
|
-
@
|
9
|
-
@registry = registry
|
7
|
+
def initialize(compiler:)
|
8
|
+
@compiler = compiler
|
10
9
|
end
|
11
10
|
|
12
11
|
def load
|
13
|
-
compiler = Polycrystal::Compiler.new(
|
14
|
-
build_path: build_path,
|
15
|
-
registry: registry
|
16
|
-
)
|
17
12
|
compiler.prepare
|
18
13
|
library = compiler.execute
|
19
14
|
load_library(library) # load_library is defined in C file
|
data/lib/polycrystal/version.rb
CHANGED
data/lib/polycrystal.rb
CHANGED
@@ -8,5 +8,19 @@ require 'polycrystal/loader'
|
|
8
8
|
|
9
9
|
module Polycrystal
|
10
10
|
class Error < StandardError; end
|
11
|
-
|
11
|
+
|
12
|
+
PRECOMPILE = [
|
13
|
+
NO_PRECOMPILE = :no_precompile,
|
14
|
+
LAZY_COMPILE = :lazy_compile,
|
15
|
+
REQUIRE_AOT = :require_compiled
|
16
|
+
].freeze
|
17
|
+
|
18
|
+
def self.load(build_path: nil, shardfile: nil, precompile: LAZY_COMPILE)
|
19
|
+
build_path ||= "#{Dir.pwd}/build"
|
20
|
+
shardfile ||= "#{Dir.pwd}/shard.yml" if File.exist?("#{Dir.pwd}/shard.yml")
|
21
|
+
shardfile ||= "#{Dir.pwd}/crystal/shard.yml" if File.exist?("#{Dir.pwd}/crystal/shard.yml")
|
22
|
+
|
23
|
+
compiler = Polycrystal::Compiler.new(build_path: build_path, shardfile: shardfile, precompile: precompile)
|
24
|
+
Polycrystal::Loader.new(compiler: compiler).load
|
25
|
+
end
|
12
26
|
end
|
data/sample_project/.gitignore
CHANGED
@@ -1 +1,2 @@
|
|
1
|
-
/build
|
1
|
+
/build
|
2
|
+
/crystal/lib
|
data/sample_project/Gemfile.lock
CHANGED
@@ -0,0 +1,14 @@
|
|
1
|
+
version: 2.0
|
2
|
+
shards:
|
3
|
+
bindata:
|
4
|
+
git: https://github.com/spider-gazelle/bindata.git
|
5
|
+
version: 1.10.0
|
6
|
+
|
7
|
+
jwt:
|
8
|
+
git: https://github.com/crystal-community/jwt.git
|
9
|
+
version: 1.6.0
|
10
|
+
|
11
|
+
openssl_ext:
|
12
|
+
git: https://github.com/spider-gazelle/openssl_ext.git
|
13
|
+
version: 2.2.0
|
14
|
+
|
data/sample_project/sample.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: polycrystal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrii Hrushetskyi
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-09-
|
11
|
+
date: 2022-09-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -100,6 +100,8 @@ files:
|
|
100
100
|
- sample_project/Gemfile
|
101
101
|
- sample_project/Gemfile.lock
|
102
102
|
- sample_project/crystal/sample.cr
|
103
|
+
- sample_project/crystal/shard.lock
|
104
|
+
- sample_project/crystal/shard.yml
|
103
105
|
- sample_project/sample.rb
|
104
106
|
homepage: https://github.com/ahrushetskyi/polycrystal
|
105
107
|
licenses:
|
@@ -109,7 +111,7 @@ metadata:
|
|
109
111
|
source_code_uri: https://github.com/ahrushetskyi/polycrystal
|
110
112
|
changelog_uri: https://github.com/ahrushetskyi/polycrystal/CHANGELOG.md
|
111
113
|
rubygems_mfa_required: 'true'
|
112
|
-
post_install_message:
|
114
|
+
post_install_message:
|
113
115
|
rdoc_options: []
|
114
116
|
require_paths:
|
115
117
|
- lib
|
@@ -125,8 +127,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
125
127
|
- !ruby/object:Gem::Version
|
126
128
|
version: '0'
|
127
129
|
requirements: []
|
128
|
-
rubygems_version: 3.
|
129
|
-
signing_key:
|
130
|
+
rubygems_version: 3.2.33
|
131
|
+
signing_key:
|
130
132
|
specification_version: 4
|
131
133
|
summary: Integrate Crystal into ruby
|
132
134
|
test_files: []
|