aibika 1.3.12
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 +7 -0
- data/Gemfile +11 -0
- data/History.txt +214 -0
- data/LICENSE.md +30 -0
- data/Manifest.txt +11 -0
- data/README.adoc +564 -0
- data/Rakefile +30 -0
- data/aibika.gemspec +50 -0
- data/bin/aibika +25 -0
- data/lib/aibika/aibika_builder.rb +191 -0
- data/lib/aibika/cli.rb +181 -0
- data/lib/aibika/host.rb +40 -0
- data/lib/aibika/library_detector.rb +88 -0
- data/lib/aibika/pathname.rb +158 -0
- data/lib/aibika/version.rb +5 -0
- data/lib/aibika.rb +675 -0
- data/samples/activerecord_sample.rb +6 -0
- data/samples/bundler_git/Gemfile +3 -0
- data/samples/bundler_git/bundler_git.rb +5 -0
- data/samples/mech.rb +8 -0
- data/samples/mime-types_sample.rb +4 -0
- data/samples/pg_sample.rb +4 -0
- data/samples/prawn_sample.rb +9 -0
- data/samples/readchar.rb +4 -0
- data/samples/sysproctable.rb +12 -0
- data/samples/tk.rb +13 -0
- data/samples/tkextlib.rb +4 -0
- data/samples/watir_sample.rb +31 -0
- data/samples/win32_api_sample.rb +5 -0
- data/samples/win32ole.rb +4 -0
- data/samples/wxruby_sample.rbw +29 -0
- data/share/aibika/lzma.exe +0 -0
- data/src/Makefile +37 -0
- data/src/edicon.c +146 -0
- data/src/lzma/LzmaDec.c +1007 -0
- data/src/lzma/LzmaDec.h +223 -0
- data/src/lzma/Types.h +208 -0
- data/src/seb.exe +0 -0
- data/src/stub.c +703 -0
- data/src/stub.rc +1 -0
- data/src/vit-ruby.ico +0 -0
- metadata +109 -0
data/lib/aibika.rb
ADDED
@@ -0,0 +1,675 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'aibika/aibika_builder'
|
4
|
+
require_relative 'aibika/cli'
|
5
|
+
require_relative 'aibika/host'
|
6
|
+
require_relative 'aibika/library_detector'
|
7
|
+
require_relative 'aibika/pathname'
|
8
|
+
require_relative 'aibika/version'
|
9
|
+
|
10
|
+
module Aibika
|
11
|
+
# Fence against packaging of self (aibika gem) unless implicitly requestd
|
12
|
+
# String, NilClass and arrays of any of these.
|
13
|
+
def self.fence_self?(name)
|
14
|
+
!Aibika.allow_self && name == 'aibika'
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.fence_self_dir?(dir)
|
18
|
+
!Aibika.allow_self && dir.start_with?(__dir__)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Type conversion for the Pathname class. Works with Pathname,
|
22
|
+
# String, NilClass and arrays of any of these.
|
23
|
+
def self.Pathname(obj)
|
24
|
+
case obj
|
25
|
+
when Pathname
|
26
|
+
obj
|
27
|
+
when Array
|
28
|
+
obj.map { |x| Pathname(x) }
|
29
|
+
when String
|
30
|
+
Pathname.new(obj)
|
31
|
+
when NilClass
|
32
|
+
nil
|
33
|
+
else
|
34
|
+
raise ArgumentError, obj
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Sorts and returns an array without duplicates. Works with complex
|
39
|
+
# objects (such as Pathname), in contrast to Array#uniq.
|
40
|
+
def self.sort_uniq(arr)
|
41
|
+
arr.sort.inject([]) { |r, e| r.last == e ? r : r << e }
|
42
|
+
end
|
43
|
+
|
44
|
+
IGNORE_MODULE_NAMES = %r{/(enumerator.so|rational.so|complex.so|fiber.so|thread.rb|ruby2_keywords.rb)$}.freeze
|
45
|
+
|
46
|
+
GEM_SCRIPT_RE = /\.rbw?$/.freeze
|
47
|
+
GEM_EXTRA_RE = %r{(
|
48
|
+
# Auxiliary files in the root of the gem
|
49
|
+
^(\./)?(History|Install|Manifest|README|CHANGES|Licen[sc]e|Contributors|ChangeLog|BSD|GPL).*$ |
|
50
|
+
# Installation files in the root of the gem
|
51
|
+
^(\./)?(Rakefile|setup.rb|extconf.rb)$ |
|
52
|
+
# Documentation/test directories in the root of the gem
|
53
|
+
^(\./)?(doc|ext|examples|test|tests|benchmarks|spec)/ |
|
54
|
+
# Directories anywhere
|
55
|
+
(^|/)(\.autotest|\.svn|\.cvs|\.git)(/|$) |
|
56
|
+
# Unlikely extensions
|
57
|
+
\.(rdoc|c|cpp|c\+\+|cxx|h|hxx|hpp|obj|o|a)$/
|
58
|
+
)}xi.freeze
|
59
|
+
|
60
|
+
GEM_NON_FILE_RE = /(#{GEM_EXTRA_RE}|#{GEM_SCRIPT_RE})/.freeze
|
61
|
+
|
62
|
+
# Alias for the temporary directory where files are extracted.
|
63
|
+
TEMPDIR_ROOT = Pathname.new('|')
|
64
|
+
# Directory for source files in temporary directory.
|
65
|
+
SRCDIR = Pathname.new('src')
|
66
|
+
# Directory for Ruby binaries in temporary directory.
|
67
|
+
BINDIR = Pathname.new('bin')
|
68
|
+
# Directory for GEMHOME files in temporary directory.
|
69
|
+
GEMHOMEDIR = Pathname.new('gemhome')
|
70
|
+
|
71
|
+
@ignore_modules = []
|
72
|
+
|
73
|
+
@options = {
|
74
|
+
lzma_mode: true,
|
75
|
+
extra_dlls: [],
|
76
|
+
files: [],
|
77
|
+
run_script: true,
|
78
|
+
add_all_core: false,
|
79
|
+
output_override: nil,
|
80
|
+
load_autoload: true,
|
81
|
+
chdir_first: false,
|
82
|
+
force_windows: false,
|
83
|
+
force_console: false,
|
84
|
+
icon_filename: nil,
|
85
|
+
gemfile: nil,
|
86
|
+
inno_script: nil,
|
87
|
+
quiet: false,
|
88
|
+
verbose: false,
|
89
|
+
autodll: true,
|
90
|
+
show_warnings: true,
|
91
|
+
debug: false,
|
92
|
+
debug_extract: false,
|
93
|
+
arg: [],
|
94
|
+
enc: true,
|
95
|
+
allow_self: false,
|
96
|
+
gem: []
|
97
|
+
}
|
98
|
+
|
99
|
+
@options.each_key { |opt| eval("def self.#{opt}; @options[:#{opt}]; end") }
|
100
|
+
|
101
|
+
class << self
|
102
|
+
attr_reader :lzmapath, :ediconpath, :stubimage, :stubwimage
|
103
|
+
end
|
104
|
+
|
105
|
+
# Returns a binary blob store embedded in the current Ruby script.
|
106
|
+
def self.get_next_embedded_image
|
107
|
+
DATA.read(DATA.readline.to_i).unpack1('m')
|
108
|
+
end
|
109
|
+
|
110
|
+
def self.save_environment
|
111
|
+
@load_path_before = $LOAD_PATH.dup
|
112
|
+
@pwd_before = Dir.pwd
|
113
|
+
@env_before = {}
|
114
|
+
ENV.each { |key, value| @env_before[key] = value }
|
115
|
+
end
|
116
|
+
|
117
|
+
def self.restore_environment
|
118
|
+
@env_before.each { |key, value| ENV[key] = value }
|
119
|
+
ENV.each_key { |key| ENV.delete(key) unless @env_before.key?(key) }
|
120
|
+
Dir.chdir @pwd_before
|
121
|
+
end
|
122
|
+
|
123
|
+
def self.find_stubs
|
124
|
+
if defined?(DATA)
|
125
|
+
@stubimage = get_next_embedded_image
|
126
|
+
@stubwimage = get_next_embedded_image
|
127
|
+
lzmaimage = get_next_embedded_image
|
128
|
+
@lzmapath = Host.tempdir / 'lzma.exe'
|
129
|
+
File.open(@lzmapath, 'wb') { |file| file << lzmaimage }
|
130
|
+
ediconimage = get_next_embedded_image
|
131
|
+
@ediconpath = Host.tempdir / 'edicon.exe'
|
132
|
+
File.open(@ediconpath, 'wb') { |file| file << ediconimage }
|
133
|
+
else
|
134
|
+
aibikapath = Pathname(File.dirname(__FILE__))
|
135
|
+
@stubimage = File.open(aibikapath / '../share/aibika/stub.exe', 'rb', &:read)
|
136
|
+
@stubwimage = File.open(aibikapath / '../share/aibika/stubw.exe', 'rb', &:read)
|
137
|
+
@lzmapath = (aibikapath / '../share/aibika/lzma.exe').expand
|
138
|
+
@ediconpath = (aibikapath / '../share/aibika/edicon.exe').expand
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def self.init(argv)
|
143
|
+
save_environment
|
144
|
+
parseargs(argv)
|
145
|
+
find_stubs
|
146
|
+
@ignore_modules.push(*ObjectSpace.each_object(Module).to_a)
|
147
|
+
end
|
148
|
+
|
149
|
+
# Force loading autoloaded constants. Searches through all modules
|
150
|
+
# (and hence classes), and checks their constants for autoloaded
|
151
|
+
# ones, then attempts to load them.
|
152
|
+
def self.attempt_load_autoload
|
153
|
+
modules_checked = {}
|
154
|
+
@ignore_modules.each { |m| modules_checked[m] = true }
|
155
|
+
loop do
|
156
|
+
modules_to_check = []
|
157
|
+
ObjectSpace.each_object(Module) do |mod|
|
158
|
+
modules_to_check << mod unless modules_checked.include?(mod)
|
159
|
+
end
|
160
|
+
break if modules_to_check.empty?
|
161
|
+
|
162
|
+
modules_to_check.each do |mod|
|
163
|
+
modules_checked[mod] = true
|
164
|
+
mod.constants.each do |const|
|
165
|
+
# Module::Config causes warning on Ruby 1.9.3 - prevent autoloading
|
166
|
+
next if mod.is_a?(Module) && const == :Config
|
167
|
+
|
168
|
+
next unless mod.autoload?(const)
|
169
|
+
|
170
|
+
Aibika.msg "Attempting to trigger autoload of #{mod}::#{const}"
|
171
|
+
begin
|
172
|
+
mod.const_get(const)
|
173
|
+
rescue NameError
|
174
|
+
Aibika.warn "#{mod}::#{const} was defined autoloadable, but caused NameError"
|
175
|
+
rescue LoadError
|
176
|
+
Aibika.warn "#{mod}::#{const} was not loadable"
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
# Guess the load path (from 'paths') that was used to load
|
184
|
+
# 'path'. This is primarily relevant on Ruby 1.8 which stores
|
185
|
+
# "unqualified" paths in $LOADED_FEATURES.
|
186
|
+
def self.find_load_path(loadpaths, feature)
|
187
|
+
if feature.absolute?
|
188
|
+
# Choose those loadpaths which contain the feature
|
189
|
+
candidate_loadpaths = loadpaths.select { |loadpath| feature.subpath?(loadpath.expand) }
|
190
|
+
# Guess the require'd feature
|
191
|
+
feature_pairs = candidate_loadpaths.map { |loadpath| [loadpath, feature.relative_path_from(loadpath.expand)] }
|
192
|
+
# Select the shortest possible require-path (longest load-path)
|
193
|
+
if feature_pairs.empty?
|
194
|
+
nil
|
195
|
+
else
|
196
|
+
feature_pairs.min_by { |_loadpath, feature| feature.path.size }[0]
|
197
|
+
end
|
198
|
+
else
|
199
|
+
# Select the loadpaths that contain 'feature' and select the shortest
|
200
|
+
candidates = loadpaths.select { |loadpath| feature.expand(loadpath).exist? }
|
201
|
+
candidates.max_by { |loadpath| loadpath.path.size }
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
# Find the root of all files specified on the command line and use
|
206
|
+
# it as the "src" of the output.
|
207
|
+
def self.find_src_root(files)
|
208
|
+
src_files = files.map(&:expand)
|
209
|
+
src_prefix = src_files.inject(src_files.first.dirname) do |srcroot, path|
|
210
|
+
unless path.subpath?(Host.exec_prefix)
|
211
|
+
loop do
|
212
|
+
relpath = path.relative_path_from(srcroot)
|
213
|
+
Aibika.fatal_error 'No common directory contains all specified files' if relpath.absolute?
|
214
|
+
break unless relpath.to_s =~ %r{^\.\./}
|
215
|
+
|
216
|
+
srcroot = srcroot.dirname
|
217
|
+
if srcroot == srcroot.dirname
|
218
|
+
Aibika.fatal_error "Endless loop detected in find_src_root method. Reducing srcroot --> #{srcroot.dirname}"
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
srcroot
|
223
|
+
end
|
224
|
+
src_files = src_files.map do |file|
|
225
|
+
if file.subpath?(src_prefix)
|
226
|
+
file.relative_path_from(src_prefix)
|
227
|
+
else
|
228
|
+
file
|
229
|
+
end
|
230
|
+
end
|
231
|
+
[src_prefix, src_files]
|
232
|
+
end
|
233
|
+
|
234
|
+
# Searches for features that are loaded from gems, then produces a
|
235
|
+
# list of files included in those gems' manifests. Also returns a
|
236
|
+
# list of original features that are caused gems to be
|
237
|
+
# included. Ruby 1.8 provides Gem.loaded_specs to detect gems, but
|
238
|
+
# this is empty with Ruby 1.9. So instead, we look for any loaded
|
239
|
+
# file from a gem path.
|
240
|
+
def self.find_gem_files(features)
|
241
|
+
features_from_gems = []
|
242
|
+
gems = {}
|
243
|
+
|
244
|
+
# If a Bundler Gemfile was provided, add all gems it specifies
|
245
|
+
if Aibika.gemfile
|
246
|
+
Aibika.msg 'Scanning Gemfile'
|
247
|
+
# Load Rubygems and Bundler so we can scan the Gemfile
|
248
|
+
%w[rubygems bundler].each do |lib|
|
249
|
+
require lib
|
250
|
+
rescue LoadError
|
251
|
+
Aibika.fatal_error "Couldn't scan Gemfile, unable to load #{lib}"
|
252
|
+
end
|
253
|
+
|
254
|
+
ENV['BUNDLE_GEMFILE'] = Aibika.gemfile
|
255
|
+
Bundler.load.specs.each do |spec|
|
256
|
+
Aibika.verbose_msg "From Gemfile, adding gem #{spec.full_name}"
|
257
|
+
gems[spec.name] ||= spec unless fence_self?(spec.name)
|
258
|
+
end
|
259
|
+
|
260
|
+
unless gems.any? { |name, _spec| name == 'bundler' }
|
261
|
+
# Bundler itself wasn't added for some reason, let's put it in directly
|
262
|
+
Aibika.verbose_msg 'From Gemfile, forcing inclusion of bundler gem itself'
|
263
|
+
bundler_spec = Gem.loaded_specs['bundler']
|
264
|
+
bundler_spec or Aibika.fatal_error 'Unable to locate bundler gem'
|
265
|
+
gems['bundler'] ||= spec
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
if defined?(Gem)
|
270
|
+
# Include Gems that are loaded
|
271
|
+
Gem.loaded_specs.each { |gemname, spec| gems[gemname] ||= spec unless fence_self?(gemname) }
|
272
|
+
# Fall back to gem detection (loaded_specs are not population on
|
273
|
+
# all Ruby versions)
|
274
|
+
features.each do |feature|
|
275
|
+
# Detect load path unless absolute
|
276
|
+
unless feature.absolute?
|
277
|
+
feature = find_load_path(Pathname($LOAD_PATH), feature)
|
278
|
+
next if feature.nil? # Could be enumerator.so
|
279
|
+
end
|
280
|
+
# Skip if found in known Gem dir
|
281
|
+
if gems.find { |_gem, spec| feature.subpath?(spec.gem_dir) }
|
282
|
+
features_from_gems << feature
|
283
|
+
next
|
284
|
+
end
|
285
|
+
gempaths = Pathname(Gem.path)
|
286
|
+
gempaths.each do |gempath|
|
287
|
+
geminstallpath = Pathname(gempath) / 'gems'
|
288
|
+
next unless feature.subpath?(geminstallpath)
|
289
|
+
|
290
|
+
gemlocalpath = feature.relative_path_from(geminstallpath)
|
291
|
+
fullgemname = gemlocalpath.path.split('/').first
|
292
|
+
gemspecpath = gempath / 'specifications' / "#{fullgemname}.gemspec"
|
293
|
+
if (spec = Gem::Specification.load(gemspecpath))
|
294
|
+
gems[spec.name] ||= spec
|
295
|
+
features_from_gems << feature
|
296
|
+
else
|
297
|
+
Aibika.warn "Failed to load gemspec for '#{fullgemname}'"
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
gem_files = []
|
303
|
+
|
304
|
+
gems.each do |gemname, spec|
|
305
|
+
next if fence_self?(gemname)
|
306
|
+
|
307
|
+
if File.exist?(spec.spec_file)
|
308
|
+
@gemspecs << Pathname(spec.spec_file)
|
309
|
+
else
|
310
|
+
spec_name = File.basename(spec.spec_file)
|
311
|
+
spec_path = File.dirname(spec.spec_file)
|
312
|
+
default_spec_file = "#{spec_path}/default/#{spec_name}"
|
313
|
+
if File.exist?(default_spec_file)
|
314
|
+
@gemspecs << Pathname(default_spec_file)
|
315
|
+
Aibika.msg "Using default specification #{default_spec_file} for gem #{spec.full_name}"
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
# Determine which set of files to include for this particular gem
|
320
|
+
include = %i[loaded files]
|
321
|
+
Aibika.gem.each do |negate, option, list|
|
322
|
+
next unless list.nil? || list.include?(spec.name)
|
323
|
+
|
324
|
+
case option
|
325
|
+
when :minimal
|
326
|
+
include = [:loaded]
|
327
|
+
when :guess
|
328
|
+
include = %i[loaded files]
|
329
|
+
when :all
|
330
|
+
include = %i[scripts files]
|
331
|
+
when :full
|
332
|
+
include = %i[scripts files extras]
|
333
|
+
when :spec
|
334
|
+
include = [:spec]
|
335
|
+
when :scripts
|
336
|
+
if negate
|
337
|
+
include.delete(:scripts)
|
338
|
+
else
|
339
|
+
include.push(:scripts)
|
340
|
+
end
|
341
|
+
when :files
|
342
|
+
if negate
|
343
|
+
include.delete(:files)
|
344
|
+
else
|
345
|
+
include.push(:files)
|
346
|
+
end
|
347
|
+
when :extras
|
348
|
+
if negate
|
349
|
+
include.delete(:extras)
|
350
|
+
else
|
351
|
+
include.push(:extras)
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
Aibika.msg "Detected gem #{spec.full_name} (#{include.join(', ')})"
|
357
|
+
|
358
|
+
gem_root = Pathname(spec.gem_dir)
|
359
|
+
gem_extension = (gem_root / '..' / '..' / 'extensions').expand
|
360
|
+
build_complete = if gem_extension.exist?
|
361
|
+
gem_extension.find_all_files(/gem.build_complete/).select do |p|
|
362
|
+
p.dirname.basename.to_s == spec.full_name
|
363
|
+
end
|
364
|
+
end
|
365
|
+
gem_root_files = nil
|
366
|
+
files = []
|
367
|
+
|
368
|
+
unless gem_root.directory?
|
369
|
+
Aibika.warn "Gem #{spec.full_name} root folder was not found, skipping"
|
370
|
+
next
|
371
|
+
end
|
372
|
+
|
373
|
+
# Find the selected files
|
374
|
+
include.each do |set|
|
375
|
+
case set
|
376
|
+
when :spec
|
377
|
+
files << Pathname(spec.files)
|
378
|
+
when :loaded
|
379
|
+
files << features_from_gems.select { |feature| feature.subpath?(gem_root) }
|
380
|
+
when :files
|
381
|
+
gem_root_files ||= gem_root.find_all_files(//)
|
382
|
+
files << gem_root_files.reject { |path| path.relative_path_from(gem_root) =~ GEM_NON_FILE_RE }
|
383
|
+
files << build_complete if build_complete
|
384
|
+
when :extras
|
385
|
+
gem_root_files ||= gem_root.find_all_files(//)
|
386
|
+
files << gem_root_files.select { |path| path.relative_path_from(gem_root) =~ GEM_EXTRA_RE }
|
387
|
+
when :scripts
|
388
|
+
gem_root_files ||= gem_root.find_all_files(//)
|
389
|
+
files << gem_root_files.select { |path| path.relative_path_from(gem_root) =~ GEM_SCRIPT_RE }
|
390
|
+
end
|
391
|
+
end
|
392
|
+
|
393
|
+
files.flatten!
|
394
|
+
actual_files = files.select(&:file?)
|
395
|
+
|
396
|
+
(files - actual_files).each do |missing_file|
|
397
|
+
Aibika.warn "#{missing_file} was not found"
|
398
|
+
end
|
399
|
+
|
400
|
+
total_size = actual_files.inject(0) { |size, path| size + path.size }
|
401
|
+
Aibika.msg "\t#{actual_files.size} files, #{total_size} bytes"
|
402
|
+
|
403
|
+
gem_files += actual_files
|
404
|
+
end
|
405
|
+
gem_files = sort_uniq(gem_files)
|
406
|
+
else
|
407
|
+
gem_files = []
|
408
|
+
end
|
409
|
+
features_from_gems -= gem_files
|
410
|
+
[gem_files, features_from_gems]
|
411
|
+
end
|
412
|
+
|
413
|
+
def self.build_exe
|
414
|
+
all_load_paths = $LOAD_PATH.map { |loadpath| Pathname(loadpath).expand }
|
415
|
+
@added_load_paths = ($LOAD_PATH - @load_path_before).map { |loadpath| Pathname(loadpath).expand }
|
416
|
+
working_directory = Pathname.pwd.expand
|
417
|
+
|
418
|
+
restore_environment
|
419
|
+
|
420
|
+
# If the script was run, then detect the features it used
|
421
|
+
if Aibika.run_script && Aibika.load_autoload
|
422
|
+
# Attempt to autoload libraries before doing anything else.
|
423
|
+
attempt_load_autoload
|
424
|
+
end
|
425
|
+
|
426
|
+
# Reject own aibika itself, store the currently loaded files (before we require rbconfig for
|
427
|
+
# our own use).
|
428
|
+
features = $LOADED_FEATURES.reject { |feature| fence_self_dir?(feature) }
|
429
|
+
features.map! { |feature| Pathname(feature) }
|
430
|
+
|
431
|
+
# Since https://github.com/rubygems/rubygems/commit/cad4cf16cf8fcc637d9da643ef97cf0be2ed63cb
|
432
|
+
# rubygems/core_ext/kernel_require.rb is evaled and thus missing in $LOADED_FEATURES,
|
433
|
+
# so we can't find it and need to add it manually
|
434
|
+
features.push(Pathname('rubygems/core_ext/kernel_require.rb'))
|
435
|
+
|
436
|
+
# Find gemspecs to include
|
437
|
+
if defined?(Gem)
|
438
|
+
loaded_specs = Gem.loaded_specs.reject { |name, _info| fence_self?(name) }
|
439
|
+
@gemspecs = loaded_specs.map { |_name, info| Pathname(info.loaded_from) }
|
440
|
+
else
|
441
|
+
@gemspecs = []
|
442
|
+
end
|
443
|
+
|
444
|
+
require 'rbconfig'
|
445
|
+
instsitelibdir = Host.sitelibdir.relative_path_from(Host.exec_prefix)
|
446
|
+
|
447
|
+
load_path = []
|
448
|
+
src_load_path = []
|
449
|
+
|
450
|
+
# Find gems files and remove them from features
|
451
|
+
gem_files, features_from_gems = find_gem_files(features)
|
452
|
+
features -= features_from_gems
|
453
|
+
|
454
|
+
# Find the source root and adjust paths
|
455
|
+
src_prefix, = find_src_root(Aibika.files)
|
456
|
+
# Include encoding support files
|
457
|
+
if Aibika.enc
|
458
|
+
all_load_paths.each do |path|
|
459
|
+
next unless path.subpath?(Host.exec_prefix)
|
460
|
+
|
461
|
+
encpath = path / 'enc'
|
462
|
+
next unless encpath.exist?
|
463
|
+
|
464
|
+
encfiles = encpath.find_all_files(/\.so$/)
|
465
|
+
size = encfiles.inject(0) { |sum, pn| sum + pn.size }
|
466
|
+
Aibika.msg "Including #{encfiles.size} encoding support files (#{size} bytes, use --no-enc to exclude)"
|
467
|
+
features.push(*encfiles)
|
468
|
+
end
|
469
|
+
else
|
470
|
+
Aibika.msg 'Not including encoding support files'
|
471
|
+
end
|
472
|
+
|
473
|
+
# Find features and decide where to put them in the temporary
|
474
|
+
# directory layout.
|
475
|
+
libs = []
|
476
|
+
features.each do |feature|
|
477
|
+
path = find_load_path(all_load_paths, feature)
|
478
|
+
if path.nil? || path.expand == Pathname.pwd
|
479
|
+
Aibika.files << feature
|
480
|
+
else
|
481
|
+
feature = feature.relative_path_from(path.expand) if feature.absolute?
|
482
|
+
fullpath = feature.expand(path)
|
483
|
+
|
484
|
+
if fullpath.subpath?(Host.exec_prefix)
|
485
|
+
# Features found in the Ruby installation are put in the
|
486
|
+
# temporary Ruby installation.
|
487
|
+
libs << [fullpath, fullpath.relative_path_from(Host.exec_prefix)]
|
488
|
+
elsif defined?(Gem) && ((gemhome = Gem.path.find { |pth| fullpath.subpath?(pth) }))
|
489
|
+
# Features found in any other Gem path (e.g. ~/.gems) is put
|
490
|
+
# in a special 'gemhome' folder.
|
491
|
+
targetpath = GEMHOMEDIR / fullpath.relative_path_from(Pathname(gemhome))
|
492
|
+
libs << [fullpath, targetpath]
|
493
|
+
elsif fullpath.subpath?(src_prefix) || path == working_directory
|
494
|
+
# Any feature found inside the src_prefix automatically gets
|
495
|
+
# added as a source file (to go in 'src').
|
496
|
+
Aibika.files << fullpath
|
497
|
+
# Add the load path unless it was added by the script while
|
498
|
+
# running (or we assume that the script can also set it up
|
499
|
+
# correctly when running from the resulting executable).
|
500
|
+
src_load_path << path unless @added_load_paths.include?(path)
|
501
|
+
elsif @added_load_paths.include?(path)
|
502
|
+
# Any feature that exist in a load path added by the script
|
503
|
+
# itself is added as a file to go into the 'src' (src_prefix
|
504
|
+
# will be adjusted below to point to the common parent).
|
505
|
+
Aibika.files << fullpath
|
506
|
+
else
|
507
|
+
# All other feature that can not be resolved go in the the
|
508
|
+
# Ruby sitelibdir. This is automatically in the load path
|
509
|
+
# when Ruby starts.
|
510
|
+
libs << [fullpath, instsitelibdir / feature]
|
511
|
+
end
|
512
|
+
end
|
513
|
+
end
|
514
|
+
|
515
|
+
# Recompute the src_prefix. Files may have been added implicitly
|
516
|
+
# while scanning through features.
|
517
|
+
src_prefix, src_files = find_src_root(Aibika.files)
|
518
|
+
Aibika.files.replace(src_files)
|
519
|
+
|
520
|
+
# Add the load path that are required with the correct path after
|
521
|
+
# src_prefix was adjusted.
|
522
|
+
load_path += src_load_path.map { |loadpath| TEMPDIR_ROOT / SRCDIR / loadpath.relative_path_from(src_prefix) }
|
523
|
+
|
524
|
+
# Decide where to put gem files, either the system gem folder, or
|
525
|
+
# GEMHOME.
|
526
|
+
gem_files.each do |gemfile|
|
527
|
+
if gemfile.subpath?(Host.exec_prefix)
|
528
|
+
libs << [gemfile, gemfile.relative_path_from(Host.exec_prefix)]
|
529
|
+
elsif defined?(Gem) && ((gemhome = Gem.path.find { |pth| gemfile.subpath?(pth) }))
|
530
|
+
targetpath = GEMHOMEDIR / gemfile.relative_path_from(Pathname(gemhome))
|
531
|
+
libs << [gemfile, targetpath]
|
532
|
+
else
|
533
|
+
Aibika.msg "Processing #{gemfile}"
|
534
|
+
Aibika.msg "Host.exec_prefix #{Host.exec_prefix}"
|
535
|
+
Aibika.msg "Gem: #{Gem}" if defined?(Gem)
|
536
|
+
Aibika.fatal_error "Don't know where to put gem file #{gemfile}"
|
537
|
+
end
|
538
|
+
end
|
539
|
+
|
540
|
+
# If requested, add all ruby standard libraries
|
541
|
+
if Aibika.add_all_core
|
542
|
+
Aibika.msg 'Will include all ruby core libraries'
|
543
|
+
@load_path_before.each do |lp|
|
544
|
+
path = Pathname.new(lp)
|
545
|
+
next unless path.to_posix =~
|
546
|
+
%r{/(ruby/(?:site_ruby/|vendor_ruby/)?[0-9.]+)/?$}i
|
547
|
+
|
548
|
+
subdir = ::Regexp.last_match(1)
|
549
|
+
Dir["#{lp}/**/*"].each do |f|
|
550
|
+
fpath = Pathname.new(f)
|
551
|
+
next if fpath.directory?
|
552
|
+
|
553
|
+
tgt = "lib/#{subdir}/#{fpath.relative_path_from(path).to_posix}"
|
554
|
+
libs << [f, tgt]
|
555
|
+
end
|
556
|
+
end
|
557
|
+
end
|
558
|
+
|
559
|
+
# Detect additional DLLs
|
560
|
+
dlls = Aibika.autodll ? LibraryDetector.detect_dlls : []
|
561
|
+
|
562
|
+
# Detect external manifests
|
563
|
+
manifests = Host.exec_prefix.find_all_files(/\.manifest$/)
|
564
|
+
|
565
|
+
executable = nil
|
566
|
+
if Aibika.output_override
|
567
|
+
executable = Aibika.output_override
|
568
|
+
else
|
569
|
+
executable = Aibika.files.first.basename.ext('.exe')
|
570
|
+
executable.append_to_filename!('-debug') if Aibika.debug
|
571
|
+
end
|
572
|
+
|
573
|
+
windowed = (Aibika.files.first.ext?('.rbw') || Aibika.force_windows) && !Aibika.force_console
|
574
|
+
|
575
|
+
Aibika.msg "Building #{executable}"
|
576
|
+
target_script = nil
|
577
|
+
AibikaBuilder.new(executable, windowed) do |sb|
|
578
|
+
# Add explicitly mentioned files
|
579
|
+
Aibika.msg 'Adding user-supplied source files'
|
580
|
+
Aibika.files.each do |file|
|
581
|
+
file = src_prefix / file
|
582
|
+
target = if file.subpath?(Host.exec_prefix)
|
583
|
+
file.relative_path_from(Host.exec_prefix)
|
584
|
+
elsif file.subpath?(src_prefix)
|
585
|
+
SRCDIR / file.relative_path_from(src_prefix)
|
586
|
+
else
|
587
|
+
SRCDIR / file.basename
|
588
|
+
end
|
589
|
+
|
590
|
+
target_script ||= target
|
591
|
+
|
592
|
+
if file.directory?
|
593
|
+
sb.ensuremkdir(target)
|
594
|
+
else
|
595
|
+
begin
|
596
|
+
sb.createfile(file, target)
|
597
|
+
rescue Errno::ENOENT
|
598
|
+
raise unless file =~ IGNORE_MODULE_NAMES
|
599
|
+
end
|
600
|
+
end
|
601
|
+
end
|
602
|
+
|
603
|
+
# Add the ruby executable and DLL
|
604
|
+
rubyexe = if windowed
|
605
|
+
Host.rubyw_exe
|
606
|
+
else
|
607
|
+
Host.ruby_exe
|
608
|
+
end
|
609
|
+
Aibika.msg "Adding ruby executable #{rubyexe}"
|
610
|
+
sb.createfile(Host.bindir / rubyexe, BINDIR / rubyexe)
|
611
|
+
sb.createfile(Host.bindir / Host.libruby_so, BINDIR / Host.libruby_so) if Host.libruby_so
|
612
|
+
|
613
|
+
# Add detected DLLs
|
614
|
+
dlls.each do |dll|
|
615
|
+
Aibika.msg "Adding detected DLL #{dll}"
|
616
|
+
target = if dll.subpath?(Host.exec_prefix)
|
617
|
+
dll.relative_path_from(Host.exec_prefix)
|
618
|
+
else
|
619
|
+
BINDIR / File.basename(dll)
|
620
|
+
end
|
621
|
+
sb.createfile(dll, target)
|
622
|
+
end
|
623
|
+
|
624
|
+
# Add external manifest files
|
625
|
+
manifests.each do |manifest|
|
626
|
+
Aibika.msg "Adding external manifest #{manifest}"
|
627
|
+
target = manifest.relative_path_from(Host.exec_prefix)
|
628
|
+
sb.createfile(manifest, target)
|
629
|
+
end
|
630
|
+
|
631
|
+
# Add extra DLLs specified on the command line
|
632
|
+
Aibika.extra_dlls.each do |dll|
|
633
|
+
Aibika.msg "Adding supplied DLL #{dll}"
|
634
|
+
sb.createfile(Host.bindir / dll, BINDIR / dll)
|
635
|
+
end
|
636
|
+
|
637
|
+
# Add gemspec files
|
638
|
+
@gemspecs = sort_uniq(@gemspecs)
|
639
|
+
@gemspecs.each do |gemspec|
|
640
|
+
if gemspec.subpath?(Host.exec_prefix)
|
641
|
+
path = gemspec.relative_path_from(Host.exec_prefix)
|
642
|
+
sb.createfile(gemspec, path)
|
643
|
+
elsif defined?(Gem) && ((gemhome = Pathname(Gem.path.find { |pth| gemspec.subpath?(pth) })))
|
644
|
+
path = GEMHOMEDIR / gemspec.relative_path_from(gemhome)
|
645
|
+
sb.createfile(gemspec, path)
|
646
|
+
else
|
647
|
+
Aibika.fatal_error "Gem spec #{gemspec} does not exist in the Ruby installation. Don't know where to put it."
|
648
|
+
end
|
649
|
+
end
|
650
|
+
|
651
|
+
# Add loaded libraries (features, gems)
|
652
|
+
Aibika.msg 'Adding library files'
|
653
|
+
libs.each do |path, target|
|
654
|
+
sb.createfile(path, target)
|
655
|
+
end
|
656
|
+
|
657
|
+
# Set environment variable
|
658
|
+
sb.setenv('RUBYOPT', ENV['RUBYOPT'] || '')
|
659
|
+
sb.setenv('RUBYLIB', load_path.map(&:to_native).uniq.join(';'))
|
660
|
+
|
661
|
+
sb.setenv('GEM_PATH', (TEMPDIR_ROOT / GEMHOMEDIR).to_native)
|
662
|
+
|
663
|
+
# Add the opcode to launch the script
|
664
|
+
extra_arg = Aibika.arg.map { |arg| " \"#{arg.gsub('"', '\"')}\"" }.join
|
665
|
+
installed_ruby_exe = TEMPDIR_ROOT / BINDIR / rubyexe
|
666
|
+
launch_script = (TEMPDIR_ROOT / target_script).to_native
|
667
|
+
sb.postcreateprocess(installed_ruby_exe,
|
668
|
+
"#{rubyexe} \"#{launch_script}\"#{extra_arg}")
|
669
|
+
end
|
670
|
+
|
671
|
+
return if Aibika.inno_script
|
672
|
+
|
673
|
+
Aibika.msg "Finished building #{executable} (#{File.size(executable)} bytes)"
|
674
|
+
end
|
675
|
+
end
|