ocran 1.4.5 → 1.5.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/CHANGELOG.txt +74 -0
- data/README.md +296 -9
- data/ext/extconf.rb +5 -1
- data/lib/ocran/aot_toolchain.rb +154 -0
- data/lib/ocran/command_output.rb +8 -1
- data/lib/ocran/compatibility_scan.rb +414 -0
- data/lib/ocran/cosmo_toolchain.rb +29 -7
- data/lib/ocran/dir_builder.rb +88 -38
- data/lib/ocran/direction.rb +232 -33
- data/lib/ocran/ed_resource.rb +113 -0
- data/lib/ocran/ed_resource_builder.rb +199 -0
- data/lib/ocran/file_path_set.rb +9 -5
- data/lib/ocran/gem_spec_queryable.rb +7 -3
- data/lib/ocran/host_config_helper.rb +11 -1
- data/lib/ocran/inno_setup_script_builder.rb +24 -14
- data/lib/ocran/launcher_batch_builder.rb +8 -11
- data/lib/ocran/npm_package.rb +106 -0
- data/lib/ocran/option.rb +433 -35
- data/lib/ocran/pe_imports.rb +96 -0
- data/lib/ocran/pe_resources.rb +226 -0
- data/lib/ocran/refine_pathname.rb +29 -32
- data/lib/ocran/roundhouse_builder.rb +316 -0
- data/lib/ocran/runner.rb +96 -11
- data/lib/ocran/runtime_environment.rb +14 -6
- data/lib/ocran/runtime_sdk.rb +252 -0
- data/lib/ocran/spinel_builder.rb +183 -0
- data/lib/ocran/spinel_compatibility.rb +149 -0
- data/lib/ocran/static_runtime/boot.rb +443 -0
- data/lib/ocran/static_runtime/build_static_ext.rb +86 -0
- data/lib/ocran/static_runtime_builder.rb +814 -0
- data/lib/ocran/stub_builder.rb +70 -25
- data/lib/ocran/version.rb +1 -1
- data/lib/ocran/wasm_builder.rb +570 -0
- data/lib/ocran/wasm_compatibility.rb +198 -0
- data/lib/ocran/windows_command_escaping.rb +21 -0
- data/lib/ocran/zip_payload_builder.rb +18 -9
- data/lib/ocran/zip_writer.rb +48 -9
- data/src/Makefile +18 -2
- data/src/Makefile.mswin +65 -0
- data/src/inst_dir.c +34 -6
- data/src/path_utils.c +144 -0
- data/src/script_info.c +5 -0
- data/src/stub.c +77 -19
- data/src/stub.rc +1 -1
- data/src/system_utils.c +276 -155
- data/src/system_utils.h +46 -3
- data/src/system_utils_posix.c +243 -148
- data/src/unpack.c +9 -0
- metadata +23 -5
data/lib/ocran/option.rb
CHANGED
|
@@ -6,15 +6,21 @@ module Ocran
|
|
|
6
6
|
load File.expand_path("refine_pathname.rb", __dir__) unless defined? RefinePathname
|
|
7
7
|
using RefinePathname
|
|
8
8
|
|
|
9
|
+
# Valid values for --set-requested-execution-level (manifest UAC levels).
|
|
10
|
+
EXECUTION_LEVELS = %w[asInvoker highestAvailable requireAdministrator].freeze
|
|
11
|
+
|
|
9
12
|
def initialize
|
|
10
13
|
@options = {
|
|
11
14
|
:add_all_core? => false,
|
|
12
15
|
:add_all_encoding? => true,
|
|
16
|
+
:application_manifest => nil,
|
|
13
17
|
:argv => [],
|
|
14
18
|
:auto_detect_dlls? => true,
|
|
15
19
|
:bundle_identifier => nil,
|
|
16
20
|
:macosx_bundle => nil,
|
|
17
21
|
:macosx_bundle? => false,
|
|
22
|
+
:runtime_dlls => [],
|
|
23
|
+
:static_runtime => nil,
|
|
18
24
|
:chdir_before? => false,
|
|
19
25
|
:chdir_exe_dir? => false,
|
|
20
26
|
:cosmo_cc => nil,
|
|
@@ -23,26 +29,44 @@ module Ocran
|
|
|
23
29
|
:enable_compression? => true,
|
|
24
30
|
:enable_debug_extract? => false,
|
|
25
31
|
:enable_debug_mode? => false,
|
|
32
|
+
:execution_level => nil,
|
|
26
33
|
:extra_dlls => [],
|
|
34
|
+
:file_version => nil,
|
|
27
35
|
:force_console? => false,
|
|
28
36
|
:force_windows? => false,
|
|
29
37
|
:gem_options => [],
|
|
30
38
|
:gemfile => nil,
|
|
31
39
|
:icon_filename => nil,
|
|
40
|
+
:inputs => [],
|
|
32
41
|
:inno_setup_script => nil,
|
|
33
42
|
:load_autoload? => true,
|
|
34
43
|
:output_dir => nil,
|
|
35
44
|
:output_override => nil,
|
|
36
45
|
:output_zip => nil,
|
|
46
|
+
:product_version => nil,
|
|
37
47
|
:quiet? => false,
|
|
48
|
+
:resource_strings => {},
|
|
49
|
+
:roundhouse? => false,
|
|
50
|
+
:roundhouse_app => nil,
|
|
51
|
+
:roundhouse_options => [],
|
|
52
|
+
:roundhouse_output => nil,
|
|
38
53
|
:rubyopt => nil,
|
|
39
54
|
:run_script? => true,
|
|
40
55
|
:script => nil,
|
|
41
56
|
:source_files => [],
|
|
57
|
+
:spinel? => false,
|
|
58
|
+
:spinel_options => [],
|
|
42
59
|
:verbose? => false,
|
|
60
|
+
:version_strings => {},
|
|
43
61
|
:warning? => true,
|
|
62
|
+
:wasm_options => [],
|
|
63
|
+
:wasm_output => nil,
|
|
64
|
+
:wasm_ruby => nil,
|
|
65
|
+
:wasm_runtime => nil,
|
|
66
|
+
:wasm_zip? => false,
|
|
44
67
|
:wrapper_exe? => true,
|
|
45
68
|
}
|
|
69
|
+
@warnings = []
|
|
46
70
|
end
|
|
47
71
|
|
|
48
72
|
def usage
|
|
@@ -69,7 +93,7 @@ Gem content detection modes:
|
|
|
69
93
|
--gem-guess=[gem1,...] Include loaded scripts & best guess (DEFAULT)
|
|
70
94
|
--gem-all[=gem1,..] Include all scripts & files
|
|
71
95
|
--gem-full[=gem1,..] Include EVERYTHING
|
|
72
|
-
--gem-spec[=gem1,..] Include files in gemspec
|
|
96
|
+
--gem-spec[=gem1,..] Include the files listed in the gemspec
|
|
73
97
|
|
|
74
98
|
minimal: loaded scripts
|
|
75
99
|
guess: loaded scripts and other files
|
|
@@ -86,7 +110,8 @@ Gem content detection modes:
|
|
|
86
110
|
|
|
87
111
|
Auto-detection options:
|
|
88
112
|
|
|
89
|
-
--no-dep-run Don't run script.rb to check for dependencies
|
|
113
|
+
--no-dep-run Don't run script.rb to check for dependencies (usually
|
|
114
|
+
needs --add-all-core, and --gem-full with --gemfile).
|
|
90
115
|
--no-autoload Don't load/include script.rb's autoloads.
|
|
91
116
|
--no-autodll Disable detection of runtime DLL dependencies.
|
|
92
117
|
|
|
@@ -116,8 +141,38 @@ Executable options:
|
|
|
116
141
|
--debug Executable will be verbose.
|
|
117
142
|
--debug-extract Executable will unpack to local dir and not delete after.
|
|
118
143
|
|
|
144
|
+
PE resource options (Windows, rcedit-compatible):
|
|
145
|
+
|
|
146
|
+
--set-version-string <key> <value> Add a StringFileInfo entry (e.g. CompanyName).
|
|
147
|
+
Alias: --version-string
|
|
148
|
+
--set-file-version <x.y.z.w> Set the file version. Alias: --file-version
|
|
149
|
+
--set-product-version <x.y.z.w> Set the product version. Alias: --product-version
|
|
150
|
+
--set-resource-string <id> <value> Set an RT_STRING table entry by numeric id.
|
|
151
|
+
Alias: --resource-string
|
|
152
|
+
--set-requested-execution-level <level> Set the manifest UAC level (asInvoker,
|
|
153
|
+
highestAvailable, requireAdministrator).
|
|
154
|
+
Alias: --uac-level
|
|
155
|
+
--application-manifest <file> Embed the given file as the application manifest.
|
|
156
|
+
Alias: --manifest
|
|
157
|
+
|
|
119
158
|
Experimental options:
|
|
120
159
|
|
|
160
|
+
--static-runtime <runtime-dir> Build a single executable that runs the
|
|
161
|
+
application without extracting anything: a statically
|
|
162
|
+
linked Ruby (the static runtime in <runtime-dir>, built
|
|
163
|
+
with the scripts in runtime/) with the application as a
|
|
164
|
+
ZIP archive. The runtime decides the target: Windows or
|
|
165
|
+
Linux (archive appended, readable with unzip or 7-Zip)
|
|
166
|
+
or macOS (archive linked in as section __OCRAN,__zip;
|
|
167
|
+
packaging needs a Mac). The runtime's own standard
|
|
168
|
+
library and bundled gems are packed; C extensions must
|
|
169
|
+
be linked into the runtime. The build host's Ruby must
|
|
170
|
+
have the runtime's API version (e.g. 4.0.0).
|
|
171
|
+
--runtime-dll <lib,...> With --static-runtime: link these C libraries of the
|
|
172
|
+
runtime's SDK as DLLs shipped next to the executable
|
|
173
|
+
instead of into it (e.g. iconv,sybdb - the LGPL ones;
|
|
174
|
+
see runtime/LICENSES.md). Their DLL dependencies come
|
|
175
|
+
along.
|
|
121
176
|
--cosmo-ruby <ruby.com> Package the given cosmopolitan-built Ruby (an APE,
|
|
122
177
|
e.g. ruby.com) as the interpreter instead of the host
|
|
123
178
|
Ruby: the result is a single <scriptname>.com that runs
|
|
@@ -144,6 +199,50 @@ Experimental options:
|
|
|
144
199
|
packages the host Ruby behind an APE stub. Console-only;
|
|
145
200
|
output defaults to <scriptname>.com.
|
|
146
201
|
(Alias: --cosmo-toolchain)
|
|
202
|
+
|
|
203
|
+
Native compilation (experimental):
|
|
204
|
+
|
|
205
|
+
--spinel Compile script.rb ahead of time with Spinel
|
|
206
|
+
(https://github.com/matz/spinel) into a native executable
|
|
207
|
+
that needs no Ruby, instead of packaging the interpreter.
|
|
208
|
+
Spinel compiles a subset of Ruby: when the program is
|
|
209
|
+
outside it, OCRAN reports what in your code and in which
|
|
210
|
+
gems stands in the way. The script is not run at build
|
|
211
|
+
time. Requires the spinel command (SPINEL, PATH, or
|
|
212
|
+
~/.local/bin); OCRAN explains how to install it.
|
|
213
|
+
--spinel-opt <arg> Pass <arg> to the spinel compiler (repeatable), e.g.
|
|
214
|
+
--spinel-opt --int-overflow=promote
|
|
215
|
+
--roundhouse Compile a Rails application with Roundhouse
|
|
216
|
+
(https://github.com/rubys/roundhouse) and Spinel into a
|
|
217
|
+
native server binary. Give the application directory
|
|
218
|
+
instead of a script (default: the current directory).
|
|
219
|
+
The output is a directory (default <app>-spinel, or
|
|
220
|
+
--output/--output-dir) with the binary and the files it
|
|
221
|
+
serves. When the app is not covered yet, OCRAN shows
|
|
222
|
+
Roundhouse's analysis, including which gems it does not
|
|
223
|
+
support. Requires roundhouse, spinel and spin.
|
|
224
|
+
--roundhouse-opt <arg> Pass <arg> to roundhouse (repeatable), e.g.
|
|
225
|
+
--roundhouse-opt --survey
|
|
226
|
+
|
|
227
|
+
WebAssembly (experimental):
|
|
228
|
+
|
|
229
|
+
--wasm[=ruby|picoruby] Export the application as a web page that runs it
|
|
230
|
+
in the browser on WebAssembly: a folder (default
|
|
231
|
+
<scriptname>-wasm, or --output-dir) or a zip archive
|
|
232
|
+
(--output-zip, or an --output name ending in .zip) with
|
|
233
|
+
index.html, the runtime and the application.
|
|
234
|
+
ruby: ruby.wasm, CRuby with its standard library; needs
|
|
235
|
+
rbwasm (gem install ruby_wasm). Gems must be listed in
|
|
236
|
+
the application's Gemfile.
|
|
237
|
+
picoruby: PicoRuby, a 2 MB mruby-based runtime with its
|
|
238
|
+
own small library and no gems; needs nothing installed.
|
|
239
|
+
OCRAN reports what in the program and its gems may not
|
|
240
|
+
work there. The script is not run at build time.
|
|
241
|
+
--picoruby Same as --wasm=picoruby.
|
|
242
|
+
--wasm-ruby <x.y> The CRuby version for --wasm (4.0, 3.4, 3.3 or 3.2;
|
|
243
|
+
default: this Ruby's, when ruby.wasm has it).
|
|
244
|
+
--wasm-opt <arg> Pass <arg> to `rbwasm build` (repeatable), used when the
|
|
245
|
+
application has gems.
|
|
147
246
|
EOF
|
|
148
247
|
end
|
|
149
248
|
|
|
@@ -163,6 +262,32 @@ EOF
|
|
|
163
262
|
load File.expand_path("cosmo_toolchain.rb", __dir__) unless defined? CosmoToolchain
|
|
164
263
|
end
|
|
165
264
|
|
|
265
|
+
# The --gem-<group> options GemSpecQueryable.gem_inclusion_set knows,
|
|
266
|
+
# and the file sets among them that --no-gem-<set> can take away.
|
|
267
|
+
GEM_GROUPS = %i[minimal guess all full spec scripts files extras].freeze
|
|
268
|
+
GEM_FILE_SETS = %i[scripts files extras].freeze
|
|
269
|
+
|
|
270
|
+
# Warnings about the command line, for the caller to print once output
|
|
271
|
+
# is set up.
|
|
272
|
+
attr_reader :warnings
|
|
273
|
+
|
|
274
|
+
# The value of an option that takes a path or name: the next argument,
|
|
275
|
+
# which must be there and must not be empty.
|
|
276
|
+
def required_argument(argv, option)
|
|
277
|
+
value = argv.shift
|
|
278
|
+
raise "#{option} requires an argument" if value.nil? || value.empty?
|
|
279
|
+
|
|
280
|
+
value
|
|
281
|
+
end
|
|
282
|
+
private :required_argument
|
|
283
|
+
|
|
284
|
+
# Whether a --gem-* option makes every gem be packed with all of its
|
|
285
|
+
# scripts, which is what a build without the dependency run needs.
|
|
286
|
+
def whole_gems?
|
|
287
|
+
gem_options.any? { |negate, group, list| list.nil? && !negate && %i[all full spec scripts].include?(group) }
|
|
288
|
+
end
|
|
289
|
+
private :whole_gems?
|
|
290
|
+
|
|
166
291
|
def parse(argv)
|
|
167
292
|
while (arg = argv.shift)
|
|
168
293
|
case arg
|
|
@@ -173,23 +298,19 @@ EOF
|
|
|
173
298
|
when "--add-all-core"
|
|
174
299
|
@options[:add_all_core?] = true
|
|
175
300
|
when "--output"
|
|
176
|
-
|
|
177
|
-
@options[:output_override] = Pathname.new(path).expand_path if path
|
|
301
|
+
@options[:output_override] = Pathname.new(required_argument(argv, arg)).expand_path
|
|
178
302
|
when "--output-dir"
|
|
179
|
-
|
|
180
|
-
@options[:output_dir] = Pathname.new(path).expand_path if path
|
|
303
|
+
@options[:output_dir] = Pathname.new(required_argument(argv, arg)).expand_path
|
|
181
304
|
when "--output-zip"
|
|
182
|
-
|
|
183
|
-
@options[:output_zip] = Pathname.new(path).expand_path if path
|
|
305
|
+
@options[:output_zip] = Pathname.new(required_argument(argv, arg)).expand_path
|
|
184
306
|
when "--no-wrapper-exe"
|
|
185
307
|
@options[:wrapper_exe?] = false
|
|
186
308
|
when "--macosx-bundle"
|
|
187
309
|
@options[:macosx_bundle?] = true
|
|
188
310
|
when "--bundle-id"
|
|
189
|
-
@options[:bundle_identifier] = argv
|
|
311
|
+
@options[:bundle_identifier] = required_argument(argv, arg)
|
|
190
312
|
when "--dll"
|
|
191
|
-
|
|
192
|
-
@options[:extra_dlls] << path if path
|
|
313
|
+
@options[:extra_dlls] << required_argument(argv, arg)
|
|
193
314
|
when "--quiet"
|
|
194
315
|
@options[:quiet?] = true
|
|
195
316
|
when "--verbose"
|
|
@@ -205,26 +326,81 @@ EOF
|
|
|
205
326
|
when "--chdir-exe-dir"
|
|
206
327
|
@options[:chdir_exe_dir?] = true
|
|
207
328
|
when "--icon"
|
|
208
|
-
path = argv
|
|
209
|
-
raise "Icon file #{path} not found" unless
|
|
329
|
+
path = required_argument(argv, arg)
|
|
330
|
+
raise "Icon file #{path} not found" unless File.exist?(path)
|
|
210
331
|
@options[:icon_filename] = Pathname.new(path).expand_path
|
|
332
|
+
when "--set-version-string", "--version-string"
|
|
333
|
+
key = argv.shift
|
|
334
|
+
value = argv.shift
|
|
335
|
+
raise "#{arg} requires a key and a value" unless key && value
|
|
336
|
+
@options[:version_strings][key] = value
|
|
337
|
+
when "--set-file-version", "--file-version"
|
|
338
|
+
value = argv.shift
|
|
339
|
+
raise "#{arg} requires a version string" unless value
|
|
340
|
+
@options[:file_version] = value
|
|
341
|
+
when "--set-product-version", "--product-version"
|
|
342
|
+
value = argv.shift
|
|
343
|
+
raise "#{arg} requires a version string" unless value
|
|
344
|
+
@options[:product_version] = value
|
|
345
|
+
when "--set-resource-string", "--resource-string"
|
|
346
|
+
id = argv.shift
|
|
347
|
+
value = argv.shift
|
|
348
|
+
raise "#{arg} requires an id and a value" unless id && value
|
|
349
|
+
@options[:resource_strings][id.to_i] = value
|
|
350
|
+
when "--set-requested-execution-level", "--uac-level"
|
|
351
|
+
level = argv.shift
|
|
352
|
+
unless EXECUTION_LEVELS.include?(level)
|
|
353
|
+
raise "#{arg} must be one of: #{EXECUTION_LEVELS.join(", ")}"
|
|
354
|
+
end
|
|
355
|
+
@options[:execution_level] = level
|
|
356
|
+
when "--application-manifest", "--manifest"
|
|
357
|
+
path = argv.shift
|
|
358
|
+
raise "Manifest file #{path} not found" unless path && File.exist?(path)
|
|
359
|
+
@options[:application_manifest] = Pathname.new(path).expand_path
|
|
211
360
|
when "--rubyopt"
|
|
212
|
-
|
|
361
|
+
# An empty value is meaningful: run with no RUBYOPT at all.
|
|
362
|
+
@options[:rubyopt] = argv.shift or raise "#{arg} requires an argument"
|
|
213
363
|
when "--cosmo", "--cosmo-toolchain"
|
|
214
364
|
# Kept unresolved until validation: resolving here would report
|
|
215
365
|
# "cosmocc ... is not executable" on a Windows build host, ahead of
|
|
216
366
|
# the clearer "not supported when building on Windows" check.
|
|
217
|
-
@options[:cosmo_cc] = argv
|
|
367
|
+
@options[:cosmo_cc] = required_argument(argv, arg)
|
|
368
|
+
when "--spinel"
|
|
369
|
+
@options[:spinel?] = true
|
|
370
|
+
when "--spinel-opt"
|
|
371
|
+
@options[:spinel_options] << required_argument(argv, arg)
|
|
372
|
+
when "--roundhouse"
|
|
373
|
+
@options[:roundhouse?] = true
|
|
374
|
+
when /\A--wasm(?:=(.*))?\z/
|
|
375
|
+
runtime = $1.nil? || $1.empty? ? "ruby" : $1
|
|
376
|
+
@options[:wasm_runtime] =
|
|
377
|
+
case runtime
|
|
378
|
+
when "ruby", "ruby.wasm", "cruby" then :ruby
|
|
379
|
+
when "picoruby" then :picoruby
|
|
380
|
+
else raise "Unknown --wasm runtime #{runtime.inspect} (use --wasm=ruby or --wasm=picoruby)"
|
|
381
|
+
end
|
|
382
|
+
when "--picoruby"
|
|
383
|
+
@options[:wasm_runtime] = :picoruby
|
|
384
|
+
when "--wasm-ruby"
|
|
385
|
+
@options[:wasm_ruby] = required_argument(argv, arg)
|
|
386
|
+
when "--wasm-opt"
|
|
387
|
+
@options[:wasm_options] << required_argument(argv, arg)
|
|
388
|
+
when "--roundhouse-opt"
|
|
389
|
+
@options[:roundhouse_options] << required_argument(argv, arg)
|
|
390
|
+
when "--static-runtime"
|
|
391
|
+
@options[:static_runtime] = Pathname.new(required_argument(argv, arg)).expand_path
|
|
392
|
+
when "--runtime-dll"
|
|
393
|
+
@options[:runtime_dlls] |= required_argument(argv, arg).split(",").map(&:strip).reject(&:empty?)
|
|
218
394
|
when "--cosmo-ruby"
|
|
219
395
|
load_cosmo_toolchain
|
|
220
396
|
@options[:cosmo_ruby] = CosmoToolchain.resolve_ruby(argv.shift)
|
|
221
397
|
when "--gemfile"
|
|
222
|
-
path = argv
|
|
223
|
-
raise "Gemfile #{path} not found" unless
|
|
398
|
+
path = required_argument(argv, arg)
|
|
399
|
+
raise "Gemfile #{path} not found" unless File.exist?(path)
|
|
224
400
|
@options[:gemfile] = Pathname.new(path).expand_path
|
|
225
401
|
when "--innosetup"
|
|
226
|
-
path = argv
|
|
227
|
-
raise "Inno Script #{path} not found" unless
|
|
402
|
+
path = required_argument(argv, arg)
|
|
403
|
+
raise "Inno Script #{path} not found" unless File.exist?(path)
|
|
228
404
|
@options[:inno_setup_script] = Pathname.new(path).expand_path
|
|
229
405
|
when "--no-autodll"
|
|
230
406
|
@options[:auto_detect_dlls?] = false
|
|
@@ -246,25 +422,44 @@ EOF
|
|
|
246
422
|
@options[:add_all_encoding?] = !$1
|
|
247
423
|
when /\A--(no-)?gem-(\w+)(?:=(.*))?$/
|
|
248
424
|
negate, group, list = $1, $2, $3
|
|
249
|
-
|
|
250
|
-
|
|
425
|
+
group = group.to_sym
|
|
426
|
+
if negate ? !GEM_FILE_SETS.include?(group) : !GEM_GROUPS.include?(group)
|
|
427
|
+
raise "Invalid gem content detection option #{arg}: use " \
|
|
428
|
+
"#{GEM_GROUPS.map { |g| "--gem-#{g}" }.join(", ")} or " \
|
|
429
|
+
"#{GEM_FILE_SETS.map { |g| "--no-gem-#{g}" }.join(", ")}"
|
|
430
|
+
end
|
|
431
|
+
@options[:gem_options] << [negate, group, list&.split(",")]
|
|
432
|
+
when "--help", "-h"
|
|
251
433
|
puts usage
|
|
252
434
|
raise SystemExit
|
|
435
|
+
when /\A--./
|
|
436
|
+
raise "Unknown option #{arg} (see ocran --help)"
|
|
253
437
|
else
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
expanded = [arg]
|
|
258
|
-
end
|
|
438
|
+
@options[:inputs] << arg
|
|
439
|
+
end
|
|
440
|
+
end
|
|
259
441
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
442
|
+
if roundhouse?
|
|
443
|
+
# A Rails application directory rather than a script: none of the
|
|
444
|
+
# packaging below applies, and the application is not loaded.
|
|
445
|
+
parse_roundhouse
|
|
446
|
+
return
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
@options[:inputs].each do |arg|
|
|
450
|
+
expanded = Dir.glob(arg)
|
|
451
|
+
if expanded.empty?
|
|
452
|
+
raise "#{arg} not found!" unless File.exist?(arg)
|
|
453
|
+
expanded = [arg]
|
|
454
|
+
end
|
|
455
|
+
|
|
456
|
+
expanded.each do |f|
|
|
457
|
+
if File.directory?(f)
|
|
458
|
+
raise "#{f} is empty!" if Dir.empty?(f)
|
|
459
|
+
# If a directory is passed, we want all files under that directory
|
|
460
|
+
@options[:source_files] += Pathname.new(f).find.reject(&:directory?).map(&:expand_path)
|
|
461
|
+
else
|
|
462
|
+
@options[:source_files] << Pathname.new(f).expand_path
|
|
268
463
|
end
|
|
269
464
|
end
|
|
270
465
|
end
|
|
@@ -273,11 +468,31 @@ EOF
|
|
|
273
468
|
|
|
274
469
|
@options[:script] = source_files.first
|
|
275
470
|
|
|
471
|
+
if wasm_runtime
|
|
472
|
+
parse_wasm
|
|
473
|
+
end
|
|
474
|
+
|
|
475
|
+
if spinel?
|
|
476
|
+
reject_with_native_compilation("--spinel", output_dir: "--output-dir")
|
|
477
|
+
# Spinel compiles the source; it never needs the program to run, and
|
|
478
|
+
# running it would only pull OCRAN's dependency detection in.
|
|
479
|
+
@options[:run_script?] = false
|
|
480
|
+
end
|
|
481
|
+
|
|
276
482
|
@options[:force_autoload?] = run_script? && load_autoload?
|
|
277
483
|
|
|
278
484
|
@options[:output_executable] =
|
|
279
485
|
if output_override
|
|
280
|
-
|
|
486
|
+
# Windows runs a program only by its extension, so a name given
|
|
487
|
+
# without .exe - `--output myapp`, as a build script shared with
|
|
488
|
+
# Linux and macOS writes it - gets one there. .exe and .com names
|
|
489
|
+
# are used as given.
|
|
490
|
+
windows_target = static_runtime ? static_runtime_os == "windows" : Gem.win_platform?
|
|
491
|
+
if windows_target && !output_override.extname?(".exe") && !output_override.extname?(".com")
|
|
492
|
+
Pathname("#{output_override}.exe")
|
|
493
|
+
else
|
|
494
|
+
output_override
|
|
495
|
+
end
|
|
281
496
|
else
|
|
282
497
|
executable = script
|
|
283
498
|
# If debug mode is enabled, append "-debug" to the filename
|
|
@@ -286,6 +501,8 @@ EOF
|
|
|
286
501
|
# APE binaries built with cosmocc conventionally use .com.
|
|
287
502
|
ext = if cosmo?
|
|
288
503
|
".com"
|
|
504
|
+
elsif static_runtime
|
|
505
|
+
static_runtime_os == "windows" ? ".exe" : ""
|
|
289
506
|
elsif Gem.win_platform?
|
|
290
507
|
".exe"
|
|
291
508
|
else
|
|
@@ -303,6 +520,28 @@ EOF
|
|
|
303
520
|
raise "--chdir-first and --chdir-exe-dir cannot be used together"
|
|
304
521
|
end
|
|
305
522
|
|
|
523
|
+
if force_windows? && force_console?
|
|
524
|
+
raise "--windows and --console cannot be used together"
|
|
525
|
+
end
|
|
526
|
+
|
|
527
|
+
if inno_setup_script && (output_dir || output_zip)
|
|
528
|
+
raise "--innosetup cannot be combined with --output-dir or --output-zip"
|
|
529
|
+
end
|
|
530
|
+
|
|
531
|
+
unless run_script?
|
|
532
|
+
# Without the dependency run nothing the script loads is detected,
|
|
533
|
+
# so the libraries it needs must be named some other way.
|
|
534
|
+
unless add_all_core?
|
|
535
|
+
@warnings << "--no-dep-run without --add-all-core: the script is not run, so none of the " \
|
|
536
|
+
"standard library it requires is detected or packed"
|
|
537
|
+
end
|
|
538
|
+
if gemfile && !whole_gems?
|
|
539
|
+
@warnings << "--no-dep-run with --gemfile but without --gem-all or --gem-full: the script " \
|
|
540
|
+
"is not run, so no gem file it loads is detected, and the gems are packed " \
|
|
541
|
+
"without their scripts"
|
|
542
|
+
end
|
|
543
|
+
end
|
|
544
|
+
|
|
306
545
|
@options[:use_inno_setup?] = !!inno_setup_script
|
|
307
546
|
|
|
308
547
|
@options[:verbose?] &&= !quiet?
|
|
@@ -365,12 +604,112 @@ EOF
|
|
|
365
604
|
if macosx_bundle && (output_dir || output_zip || inno_setup_script)
|
|
366
605
|
raise "--macosx-bundle cannot be combined with --output-dir, --output-zip, or --innosetup"
|
|
367
606
|
end
|
|
607
|
+
|
|
608
|
+
if static_runtime
|
|
609
|
+
reject_with_static_runtime
|
|
610
|
+
raise "#{static_runtime} is not a directory" unless static_runtime.directory?
|
|
611
|
+
end
|
|
612
|
+
raise "--runtime-dll needs --static-runtime" if runtime_dlls.any? && !static_runtime
|
|
368
613
|
end
|
|
369
614
|
|
|
615
|
+
# --static-runtime produces one executable from a prebuilt runtime, so neither
|
|
616
|
+
# the other output formats nor what only the C stub implements apply.
|
|
617
|
+
def reject_with_static_runtime
|
|
618
|
+
conflicts = {
|
|
619
|
+
"--output-dir" => output_dir,
|
|
620
|
+
"--output-zip" => output_zip,
|
|
621
|
+
"--innosetup" => inno_setup_script,
|
|
622
|
+
"--macosx-bundle" => @options[:macosx_bundle?],
|
|
623
|
+
"--cosmo/--cosmo-ruby" => cosmo?,
|
|
624
|
+
"--spinel/--roundhouse" => spinel? || roundhouse?,
|
|
625
|
+
"--wasm" => wasm_runtime,
|
|
626
|
+
"--debug-extract" => enable_debug_extract?,
|
|
627
|
+
}
|
|
628
|
+
conflicts.each do |name, given|
|
|
629
|
+
raise "#{name} cannot be used with --static-runtime" if given
|
|
630
|
+
end
|
|
631
|
+
end
|
|
632
|
+
private :reject_with_static_runtime
|
|
633
|
+
|
|
634
|
+
# Validates --wasm and works out where the site goes: a zip archive for
|
|
635
|
+
# --output-zip or an --output name ending in .zip, a folder otherwise.
|
|
636
|
+
def parse_wasm
|
|
637
|
+
mode = wasm_runtime == :picoruby ? "--wasm=picoruby" : "--wasm"
|
|
638
|
+
reject_with_native_compilation(mode, output_zip: false)
|
|
639
|
+
raise "#{mode} cannot be used with --spinel or --roundhouse" if spinel? || roundhouse?
|
|
640
|
+
raise "--output-dir and --output-zip cannot be used together" if output_dir && output_zip
|
|
641
|
+
|
|
642
|
+
suffix = wasm_runtime == :picoruby ? "-picoruby" : "-wasm"
|
|
643
|
+
if output_zip || output_override&.extname?(".zip")
|
|
644
|
+
@options[:wasm_zip?] = true
|
|
645
|
+
@options[:wasm_output] = output_zip || output_override
|
|
646
|
+
else
|
|
647
|
+
@options[:wasm_output] = output_dir || output_override ||
|
|
648
|
+
Pathname("#{script.basename(".*")}#{suffix}").expand_path
|
|
649
|
+
end
|
|
650
|
+
# Nothing runs at build time: the browser is where the program runs.
|
|
651
|
+
@options[:run_script?] = false
|
|
652
|
+
end
|
|
653
|
+
private :parse_wasm
|
|
654
|
+
|
|
655
|
+
# Validates --roundhouse and works out the application and the output
|
|
656
|
+
# directory.
|
|
657
|
+
def parse_roundhouse
|
|
658
|
+
raise "--static-runtime cannot be used with --roundhouse" if static_runtime
|
|
659
|
+
raise "--roundhouse takes one Rails application directory" if @options[:inputs].size > 1
|
|
660
|
+
reject_with_native_compilation("--roundhouse")
|
|
661
|
+
raise "--spinel and --roundhouse cannot be used together (--roundhouse compiles with Spinel already)" if spinel?
|
|
662
|
+
|
|
663
|
+
input = Pathname(@options[:inputs].first || Dir.pwd).expand_path
|
|
664
|
+
raise "#{input} not found!" unless input.exist?
|
|
665
|
+
|
|
666
|
+
app = rails_root(input.directory? ? input : input.dirname)
|
|
667
|
+
unless app
|
|
668
|
+
raise "#{input} is not a Rails application (no config/application.rb in it or above it); " \
|
|
669
|
+
"--roundhouse compiles a Rails app - use --spinel for a plain script"
|
|
670
|
+
end
|
|
671
|
+
|
|
672
|
+
output = output_dir || output_override || Pathname("#{app.basename}-spinel").expand_path
|
|
673
|
+
raise "The output directory #{output} would overwrite the application itself" if output == app
|
|
674
|
+
|
|
675
|
+
@options[:roundhouse_app] = app
|
|
676
|
+
@options[:roundhouse_output] = output
|
|
677
|
+
@options[:run_script?] = false
|
|
678
|
+
@options[:force_autoload?] = false
|
|
679
|
+
@options[:verbose?] &&= !quiet?
|
|
680
|
+
end
|
|
681
|
+
private :parse_roundhouse
|
|
682
|
+
|
|
683
|
+
# The Rails application root at or above the given directory.
|
|
684
|
+
def rails_root(dir)
|
|
685
|
+
dir.ascend.find { |d| (d + "config" + "application.rb").file? }
|
|
686
|
+
end
|
|
687
|
+
private :rails_root
|
|
688
|
+
|
|
689
|
+
# Native compilation produces a program, not a package of one, so the
|
|
690
|
+
# options that shape a package do not apply to it.
|
|
691
|
+
def reject_with_native_compilation(mode, output_dir: nil, output_zip: true)
|
|
692
|
+
conflicts = {
|
|
693
|
+
"--innosetup" => inno_setup_script,
|
|
694
|
+
"--macosx-bundle" => @options[:macosx_bundle?],
|
|
695
|
+
"--cosmo/--cosmo-ruby" => cosmo?,
|
|
696
|
+
"--windows" => force_windows?,
|
|
697
|
+
"--icon" => icon_filename,
|
|
698
|
+
}
|
|
699
|
+
conflicts[output_dir] = self.output_dir if output_dir
|
|
700
|
+
conflicts["--output-zip"] = self.output_zip if output_zip
|
|
701
|
+
conflicts.each do |name, given|
|
|
702
|
+
raise "#{name} cannot be used with #{mode}" if given
|
|
703
|
+
end
|
|
704
|
+
end
|
|
705
|
+
private :reject_with_native_compilation
|
|
706
|
+
|
|
370
707
|
def add_all_core? = @options[__method__]
|
|
371
708
|
|
|
372
709
|
def add_all_encoding? = @options[__method__]
|
|
373
710
|
|
|
711
|
+
def application_manifest = @options[__method__]
|
|
712
|
+
|
|
374
713
|
def argv = @options[__method__]
|
|
375
714
|
|
|
376
715
|
def bundle_identifier = @options[__method__]
|
|
@@ -386,6 +725,23 @@ EOF
|
|
|
386
725
|
|
|
387
726
|
def cosmo_ruby = @options[__method__]
|
|
388
727
|
|
|
728
|
+
# Directory of the static runtime given with --static-runtime, or nil.
|
|
729
|
+
def static_runtime = @options[__method__]
|
|
730
|
+
|
|
731
|
+
def static_runtime? = !!static_runtime
|
|
732
|
+
|
|
733
|
+
# The operating system the --static-runtime runtime is for, from its
|
|
734
|
+
# runtime.json ("windows" when that cannot be read yet).
|
|
735
|
+
def static_runtime_os
|
|
736
|
+
require "json"
|
|
737
|
+
JSON.parse(File.read(File.join(static_runtime, "runtime.json"))).fetch("os", "windows")
|
|
738
|
+
rescue SystemCallError, JSON::ParserError
|
|
739
|
+
"windows"
|
|
740
|
+
end
|
|
741
|
+
|
|
742
|
+
# C libraries --runtime-dll ships as DLLs next to the executable.
|
|
743
|
+
def runtime_dlls = @options[__method__]
|
|
744
|
+
|
|
389
745
|
# True when the application is packaged by injecting it into the ZIP
|
|
390
746
|
# store of the cosmopolitan Ruby itself: no cosmocc, no launcher stub,
|
|
391
747
|
# and no extraction to a temporary directory at run time.
|
|
@@ -410,8 +766,12 @@ EOF
|
|
|
410
766
|
|
|
411
767
|
def enable_debug_mode? = @options[__method__]
|
|
412
768
|
|
|
769
|
+
def execution_level = @options[__method__]
|
|
770
|
+
|
|
413
771
|
def extra_dlls = @options[__method__]
|
|
414
772
|
|
|
773
|
+
def file_version = @options[__method__]
|
|
774
|
+
|
|
415
775
|
def force_autoload? = @options[__method__]
|
|
416
776
|
|
|
417
777
|
def force_console? = @options[__method__]
|
|
@@ -436,12 +796,42 @@ EOF
|
|
|
436
796
|
|
|
437
797
|
def output_zip = @options[__method__]
|
|
438
798
|
|
|
799
|
+
def product_version = @options[__method__]
|
|
800
|
+
|
|
439
801
|
def quiet? = @options[__method__]
|
|
440
802
|
|
|
803
|
+
def resource_strings = @options[__method__]
|
|
804
|
+
|
|
441
805
|
def wrapper_exe? = @options[__method__]
|
|
442
806
|
|
|
443
807
|
def rubyopt = @options[__method__]
|
|
444
808
|
|
|
809
|
+
def roundhouse? = @options[__method__]
|
|
810
|
+
|
|
811
|
+
# The root directory of the Rails application --roundhouse compiles.
|
|
812
|
+
def roundhouse_app = @options[__method__]
|
|
813
|
+
|
|
814
|
+
def roundhouse_options = @options[__method__]
|
|
815
|
+
|
|
816
|
+
# The directory --roundhouse writes the binary and its files to.
|
|
817
|
+
def roundhouse_output = @options[__method__]
|
|
818
|
+
|
|
819
|
+
def spinel? = @options[__method__]
|
|
820
|
+
|
|
821
|
+
def spinel_options = @options[__method__]
|
|
822
|
+
|
|
823
|
+
# :ruby (ruby.wasm) or :picoruby with --wasm, else nil.
|
|
824
|
+
def wasm_runtime = @options[__method__]
|
|
825
|
+
|
|
826
|
+
def wasm_options = @options[__method__]
|
|
827
|
+
|
|
828
|
+
def wasm_ruby = @options[__method__]
|
|
829
|
+
|
|
830
|
+
# The folder or zip archive --wasm writes.
|
|
831
|
+
def wasm_output = @options[__method__]
|
|
832
|
+
|
|
833
|
+
def wasm_zip? = @options[__method__]
|
|
834
|
+
|
|
445
835
|
def run_script? = @options[__method__]
|
|
446
836
|
|
|
447
837
|
def script = @options[__method__]
|
|
@@ -482,9 +872,17 @@ EOF
|
|
|
482
872
|
|
|
483
873
|
def verbose? = @options[__method__]
|
|
484
874
|
|
|
875
|
+
def version_strings = @options[__method__]
|
|
876
|
+
|
|
485
877
|
def warning? = @options[__method__]
|
|
486
878
|
|
|
487
879
|
def windowed?
|
|
880
|
+
if static_runtime?
|
|
881
|
+
# The runtime decides, not the build host. For a runtime that is
|
|
882
|
+
# not for Windows only an explicit --windows counts, so that the
|
|
883
|
+
# builder can reject it; a .rbw script is just a script there.
|
|
884
|
+
return static_runtime_os == "windows" ? @options[:windowed?] : force_windows?
|
|
885
|
+
end
|
|
488
886
|
return false unless Gem.win_platform?
|
|
489
887
|
@options[:windowed?]
|
|
490
888
|
end
|