mxc 0.3.0-aarch64-linux → 0.4.0-aarch64-linux
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/lib/mxc/3.2/mxc.so +0 -0
- data/lib/mxc/3.3/mxc.so +0 -0
- data/lib/mxc/3.4/mxc.so +0 -0
- data/lib/mxc/4.0/mxc.so +0 -0
- data/lib/mxc/libraries.rb +138 -0
- data/lib/mxc/load_commands.rb +50 -0
- data/lib/mxc/sandbox.rb +70 -11
- data/lib/mxc/version.rb +1 -1
- data/lib/mxc.rb +2 -0
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 40697749dc7afb74546b19dee6b7fd8c5d2ff143a5b041b61bdeb09c32f3c575
|
|
4
|
+
data.tar.gz: ec0f98019d301ae75674f09a5e0c0f2d713cfe38e558184116cf14da3e1459e4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3658a7479944d9f1b1527db35cd754c9b8b589f8ec449e307b41df4cdc8ba26b227d4b318c6c63483d16f829ee09be615e50fa82ce7e3537597ef230c437e056
|
|
7
|
+
data.tar.gz: 1932637c3b54ef4653963507e45dd35c8a4a959728a8e7a63738c9b317792c6daee2c6df3419848ed4b47c39fba994f820c28856b2773f41367ccec63bcffb02
|
data/lib/mxc/3.2/mxc.so
CHANGED
|
Binary file
|
data/lib/mxc/3.3/mxc.so
CHANGED
|
Binary file
|
data/lib/mxc/3.4/mxc.so
CHANGED
|
Binary file
|
data/lib/mxc/4.0/mxc.so
CHANGED
|
Binary file
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'open3'
|
|
4
|
+
require 'shellwords'
|
|
5
|
+
|
|
6
|
+
module MXC
|
|
7
|
+
# Finds the shared library files programs load, directly or through
|
|
8
|
+
# other libraries, so a sandbox can read them and nothing beside them. Only macOS needs this: Seatbelt
|
|
9
|
+
# sandboxes read the system's libraries but not those a package manager
|
|
10
|
+
# installs, such as Homebrew's, which a program like Ruby may link. The
|
|
11
|
+
# libraries come from the programs' load commands, read with otool from
|
|
12
|
+
# the Command Line Tools. Without them nothing is found, because
|
|
13
|
+
# /usr/bin/otool would offer to install them instead.
|
|
14
|
+
module Libraries # :nodoc:
|
|
15
|
+
OTOOL = '/usr/bin/otool'
|
|
16
|
+
XCODE_SELECT = '/usr/bin/xcode-select'
|
|
17
|
+
SYSTEM = %w[/usr/lib/ /System/ /Library/].freeze
|
|
18
|
+
TOKEN = %r{\A@(loader_path|executable_path|rpath)/}
|
|
19
|
+
|
|
20
|
+
@links = {}
|
|
21
|
+
@lock = Mutex.new
|
|
22
|
+
|
|
23
|
+
class << self
|
|
24
|
+
# Returns the real paths of the library files +binaries+ load outside
|
|
25
|
+
# the system's own, empty where none are needed or otool is missing.
|
|
26
|
+
# +executable+ is the program that loads them, for libraries named
|
|
27
|
+
# relative to it.
|
|
28
|
+
def files(binaries, executable: nil)
|
|
29
|
+
return [] if binaries.empty? || !available?
|
|
30
|
+
|
|
31
|
+
libraries(binaries, executable)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Returns the path of the program +arguments+ start: the first argument, or the first
|
|
35
|
+
# word of a command for the shell, found on +path+ or under +directory+. Returns nil
|
|
36
|
+
# when there is none.
|
|
37
|
+
def program(arguments, path:, directory:)
|
|
38
|
+
name = program_name(arguments)
|
|
39
|
+
return if name.nil?
|
|
40
|
+
return File.expand_path(name, directory || '/') if name.include?('/')
|
|
41
|
+
|
|
42
|
+
path.to_s.split(File::PATH_SEPARATOR).map { |entry| File.join(entry, name) }
|
|
43
|
+
.find { |candidate| File.file?(candidate) && File.executable?(candidate) }
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Returns true when this host can list a program's libraries.
|
|
47
|
+
def available?
|
|
48
|
+
return @available if defined?(@available)
|
|
49
|
+
|
|
50
|
+
@available = RUBY_PLATFORM.include?('darwin') && File.executable?(OTOOL) && developer_tools?
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
def program_name(arguments)
|
|
56
|
+
arguments.one? ? Shellwords.split(arguments.first).first : arguments.first
|
|
57
|
+
rescue ArgumentError
|
|
58
|
+
nil
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def libraries(binaries, executable)
|
|
62
|
+
roots = binaries.filter_map { |binary| real_path(binary) }
|
|
63
|
+
links_of(roots)
|
|
64
|
+
found = {}
|
|
65
|
+
roots.each { |root| visit(root, executable || root, [], found) }
|
|
66
|
+
found.keys
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def visit(path, executable, inherited, found)
|
|
70
|
+
dependencies(path, links_of([path]).fetch(path), executable, inherited).each do |library, rpaths|
|
|
71
|
+
next if found.key?(library)
|
|
72
|
+
|
|
73
|
+
found[library] = true
|
|
74
|
+
visit(library, executable, rpaths, found)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def developer_tools?
|
|
79
|
+
system(XCODE_SELECT, '-p', out: File::NULL, err: File::NULL) == true
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def dependencies(path, links, executable, inherited)
|
|
83
|
+
rpaths = links[:rpaths].filter_map { |rpath| expand(rpath, path, executable) } + inherited
|
|
84
|
+
links[:libraries].filter_map do |name|
|
|
85
|
+
next if system?(name)
|
|
86
|
+
|
|
87
|
+
library = locate(name, path, executable, rpaths)
|
|
88
|
+
[library, rpaths] if library && !system?(library)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def locate(name, loader, executable, rpaths)
|
|
93
|
+
relative = name.delete_prefix('@rpath/')
|
|
94
|
+
candidates = if relative == name
|
|
95
|
+
[expand(name, loader, executable)]
|
|
96
|
+
else
|
|
97
|
+
rpaths.map { |rpath| File.join(rpath, relative) }
|
|
98
|
+
end
|
|
99
|
+
candidates.compact.lazy.filter_map { |candidate| real_path(candidate) }.first
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def expand(name, loader, executable)
|
|
103
|
+
token = name[TOKEN, 1]
|
|
104
|
+
return name unless token
|
|
105
|
+
return if token == 'rpath'
|
|
106
|
+
|
|
107
|
+
base = token == 'loader_path' ? loader : executable
|
|
108
|
+
File.expand_path(name.sub(TOKEN, ''), File.dirname(base))
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def system?(path)
|
|
112
|
+
path.start_with?(*SYSTEM)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def real_path(path)
|
|
116
|
+
path = File.realpath(path)
|
|
117
|
+
path if File.file?(path)
|
|
118
|
+
rescue SystemCallError
|
|
119
|
+
nil
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def links_of(paths)
|
|
123
|
+
@lock.synchronize do
|
|
124
|
+
missing = paths.reject { |path| @links.key?(path) }
|
|
125
|
+
@links.merge!(LoadCommands.parse(otool(missing), missing)) if missing.any?
|
|
126
|
+
@links.slice(*paths)
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def otool(paths)
|
|
131
|
+
output, = Open3.capture2(OTOOL, '-l', *paths, err: File::NULL)
|
|
132
|
+
output
|
|
133
|
+
rescue SystemCallError
|
|
134
|
+
''
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MXC
|
|
4
|
+
# Reads the libraries and run paths of Mach-O files from the load
|
|
5
|
+
# commands <tt>otool -l</tt> lists, with every architecture of a
|
|
6
|
+
# universal file together.
|
|
7
|
+
module LoadCommands # :nodoc:
|
|
8
|
+
LOAD = /\A\s*cmd LC_(?:LOAD_DYLIB|LOAD_WEAK_DYLIB|REEXPORT_DYLIB|LAZY_LOAD_DYLIB|LOAD_UPWARD_DYLIB)\z/
|
|
9
|
+
RPATH = /\A\s*cmd LC_RPATH\z/
|
|
10
|
+
COMMAND = /\A\s*cmd /
|
|
11
|
+
VALUE = /\A\s*(?:name|path) (.+) \(offset \d+\)\z/
|
|
12
|
+
ARCHITECTURE = / \(architecture [^)]+\)\z/
|
|
13
|
+
|
|
14
|
+
class << self
|
|
15
|
+
# Returns, for each of +paths+, the install names of the libraries it
|
|
16
|
+
# loads and its run paths, as <tt>{ libraries: [...], rpaths: [...] }</tt>.
|
|
17
|
+
def parse(output, paths)
|
|
18
|
+
links = paths.to_h { |path| [path, { libraries: [], rpaths: [] }] }
|
|
19
|
+
current = kind = nil
|
|
20
|
+
output.each_line(chomp: true) do |line|
|
|
21
|
+
if links.key?(header = header_path(line))
|
|
22
|
+
current = links[header]
|
|
23
|
+
kind = nil
|
|
24
|
+
elsif current
|
|
25
|
+
kind = record(current, kind, line)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
links
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def record(links, kind, line)
|
|
34
|
+
return :libraries if line.match?(LOAD)
|
|
35
|
+
return :rpaths if line.match?(RPATH)
|
|
36
|
+
return if line.match?(COMMAND)
|
|
37
|
+
|
|
38
|
+
value = line[VALUE, 1] if kind
|
|
39
|
+
return kind unless value
|
|
40
|
+
|
|
41
|
+
links[kind] << value
|
|
42
|
+
nil
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def header_path(line)
|
|
46
|
+
line.delete_suffix(':').sub(ARCHITECTURE, '') if line.end_with?(':') && !line.start_with?(' ', "\t")
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
data/lib/mxc/sandbox.rb
CHANGED
|
@@ -30,7 +30,8 @@ module MXC
|
|
|
30
30
|
class Sandbox
|
|
31
31
|
BACKENDS = %i[auto bubblewrap landlock seatbelt process_container].freeze # :nodoc:
|
|
32
32
|
LANDLOCK_FALLBACK = /runs on Landlock instead/ # :nodoc:
|
|
33
|
-
OPTIONS = %i[readable writable denied network env directory timeout backend limits
|
|
33
|
+
OPTIONS = %i[readable writable denied libraries libraries_of network env directory timeout backend limits
|
|
34
|
+
priority].freeze # :nodoc:
|
|
34
35
|
HOST_RESOLVER_SOCKETS = %w[/run/systemd/resolve].freeze # :nodoc:
|
|
35
36
|
WINDOWS_ENV = %w[SYSTEMROOT WINDIR SYSTEMDRIVE COMSPEC PATHEXT PATH LOCALAPPDATA TEMP TMP
|
|
36
37
|
PROCESSOR_ARCHITECTURE NUMBER_OF_PROCESSORS OS].freeze # :nodoc:
|
|
@@ -40,8 +41,8 @@ module MXC
|
|
|
40
41
|
PRIORITIES = { normal: nil, low: 'low', lowest: 'idle' }.freeze # :nodoc:
|
|
41
42
|
MEGABYTE = 1024 * 1024 # :nodoc:
|
|
42
43
|
DEFAULTS = {
|
|
43
|
-
readable: [], writable: [], denied: [],
|
|
44
|
-
limits: {}, priority: nil
|
|
44
|
+
readable: [], writable: [], denied: [], libraries: true, libraries_of: [], env: {}, network: false,
|
|
45
|
+
directory: nil, timeout: nil, backend: nil, limits: {}, priority: nil
|
|
45
46
|
}.freeze # :nodoc:
|
|
46
47
|
|
|
47
48
|
class << self
|
|
@@ -54,6 +55,13 @@ module MXC
|
|
|
54
55
|
# Adds paths every instance hides, even inside readable or writable paths.
|
|
55
56
|
def denied(*paths) = configure { |sandbox| sandbox.with_denied(*paths) }
|
|
56
57
|
|
|
58
|
+
# Adds programs and libraries whose shared libraries every instance can load.
|
|
59
|
+
# Takes the same arguments as #with_libraries_of.
|
|
60
|
+
def libraries_of(*paths) = configure { |sandbox| sandbox.with_libraries_of(*paths) }
|
|
61
|
+
|
|
62
|
+
# Sets whether every instance can read the libraries its programs load. See #with_libraries.
|
|
63
|
+
def libraries(enabled) = configure { |sandbox| sandbox.with_libraries(enabled) }
|
|
64
|
+
|
|
57
65
|
# Sets every instance's network access. Takes the same arguments as #with_network.
|
|
58
66
|
def network(...) = configure { |sandbox| sandbox.with_network(...) }
|
|
59
67
|
|
|
@@ -135,6 +143,12 @@ module MXC
|
|
|
135
143
|
# Returns the paths hidden from the command, as given.
|
|
136
144
|
def denied = @settings[:denied].dup.freeze
|
|
137
145
|
|
|
146
|
+
# Returns the programs and libraries whose shared libraries the command can load, as given.
|
|
147
|
+
def libraries_of = @settings[:libraries_of].dup.freeze
|
|
148
|
+
|
|
149
|
+
# Returns true when the command can read the libraries its program loads, the default.
|
|
150
|
+
def libraries = @settings[:libraries]
|
|
151
|
+
|
|
138
152
|
# Returns the environment variables set for the command.
|
|
139
153
|
def env = @settings[:env].dup.freeze
|
|
140
154
|
|
|
@@ -173,6 +187,32 @@ module MXC
|
|
|
173
187
|
add_paths(:denied, paths)
|
|
174
188
|
end
|
|
175
189
|
|
|
190
|
+
# Adds programs and libraries whose shared libraries the command loads, such as the
|
|
191
|
+
# extensions an interpreter opens. On macOS, the command can read those library files,
|
|
192
|
+
# and the libraries they load in turn, when they are not the system's own. The program
|
|
193
|
+
# the command runs needs no entry: #run grants its libraries already. Elsewhere, on a
|
|
194
|
+
# Mac without the Command Line Tools, and with <tt>with_libraries(false)</tt>, this
|
|
195
|
+
# grants nothing.
|
|
196
|
+
#
|
|
197
|
+
# sandbox.with_libraries_of(*Dir[File.join(RbConfig::CONFIG["archdir"], "**", "*.bundle")])
|
|
198
|
+
def with_libraries_of(*paths)
|
|
199
|
+
add_paths(:libraries_of, paths)
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# Sets whether the command can read the shared libraries its program and #libraries_of
|
|
203
|
+
# load, on macOS. +true+ is the default; +false+ grants no library, so the command reads
|
|
204
|
+
# only the system's and those under #readable. +nil+ resets it to +true+.
|
|
205
|
+
#
|
|
206
|
+
# sandbox.with_libraries(false)
|
|
207
|
+
def with_libraries(enabled)
|
|
208
|
+
unless [true, false, nil].include?(enabled)
|
|
209
|
+
raise ArgumentError, "libraries must be true, false or nil, got #{enabled.inspect}"
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
@settings[:libraries] = enabled != false
|
|
213
|
+
self
|
|
214
|
+
end
|
|
215
|
+
|
|
176
216
|
# Sets network access. The default, +false+, gives the command no network at all.
|
|
177
217
|
# +true+ allows any destination. <tt>allow:</tt> takes a list of hosts the command
|
|
178
218
|
# may reach over HTTP and HTTPS: <tt>"pypi.org"</tt>, <tt>"*.pythonhosted.org"</tt>
|
|
@@ -273,6 +313,12 @@ module MXC
|
|
|
273
313
|
#
|
|
274
314
|
# With a block, yields each Chunk of output as it arrives.
|
|
275
315
|
#
|
|
316
|
+
# On macOS, the command can read the shared library files its program links outside
|
|
317
|
+
# the system's own, such as Homebrew's, so programs built against them start. The
|
|
318
|
+
# program is the first argument, or the first word of a command for the shell, found
|
|
319
|
+
# on the +PATH+ of #env. See #with_libraries_of for libraries the program opens later,
|
|
320
|
+
# and #with_libraries to turn this off.
|
|
321
|
+
#
|
|
276
322
|
# sandbox.run("python3 build.py && ls dist")
|
|
277
323
|
# sandbox.run("python3", "convert.py", params[:filename])
|
|
278
324
|
# sandbox.run("python3", "build.py") { |chunk| print chunk.content }
|
|
@@ -283,7 +329,8 @@ module MXC
|
|
|
283
329
|
def run(*command, &)
|
|
284
330
|
return stream(*command, &) if block_given?
|
|
285
331
|
|
|
286
|
-
|
|
332
|
+
arguments = command_arguments(command)
|
|
333
|
+
outcome = StartupFailure.check!(Native.run(command_line(arguments), request(arguments)))
|
|
287
334
|
Result.new(**outcome, backend: resolved_backend(outcome[:warnings]))
|
|
288
335
|
end
|
|
289
336
|
|
|
@@ -292,7 +339,8 @@ module MXC
|
|
|
292
339
|
#
|
|
293
340
|
# sandbox.spawn("python3", "-i", "-q")
|
|
294
341
|
def spawn(*command)
|
|
295
|
-
|
|
342
|
+
arguments = command_arguments(command)
|
|
343
|
+
native = Native.spawn(command_line(arguments), request(arguments))
|
|
296
344
|
Process.new(native, backend: resolved_backend(native.warnings))
|
|
297
345
|
end
|
|
298
346
|
|
|
@@ -315,7 +363,8 @@ module MXC
|
|
|
315
363
|
def inspect # :nodoc:
|
|
316
364
|
resources = " limits=#{limits.inspect} priority=#{priority.inspect}" if self.resources
|
|
317
365
|
"#<#{self.class.name || 'MXC::Sandbox'} backend=#{backend.inspect} network=#{network.inspect} " \
|
|
318
|
-
"readable=#{readable.inspect} writable=#{writable.inspect} timeout=#{timeout.inspect}#{resources}
|
|
366
|
+
"readable=#{readable.inspect} writable=#{writable.inspect} timeout=#{timeout.inspect}#{resources}" \
|
|
367
|
+
"#{libraries_inspect}>"
|
|
319
368
|
end
|
|
320
369
|
|
|
321
370
|
protected
|
|
@@ -330,7 +379,7 @@ module MXC
|
|
|
330
379
|
|
|
331
380
|
def apply(name, value)
|
|
332
381
|
case name
|
|
333
|
-
when :readable, :writable, :denied then public_send(:"with_#{name}", *Array(value))
|
|
382
|
+
when :readable, :writable, :denied, :libraries_of then public_send(:"with_#{name}", *Array(value))
|
|
334
383
|
when :network then value.is_a?(Hash) ? with_network(**value) : with_network(value)
|
|
335
384
|
when :limits then value.nil? ? with_limits(nil) : with_limits(**value)
|
|
336
385
|
else public_send(:"with_#{name}", value)
|
|
@@ -384,8 +433,7 @@ module MXC
|
|
|
384
433
|
process&.kill unless finished
|
|
385
434
|
end
|
|
386
435
|
|
|
387
|
-
def command_line(
|
|
388
|
-
arguments = command_arguments(command)
|
|
436
|
+
def command_line(arguments)
|
|
389
437
|
return command_line_for_windows(arguments) if Preflight.windows?
|
|
390
438
|
|
|
391
439
|
arguments.one? ? arguments.first : Shellwords.join(arguments)
|
|
@@ -420,10 +468,10 @@ module MXC
|
|
|
420
468
|
warnings.any?(LANDLOCK_FALLBACK) ? :landlock : :bubblewrap
|
|
421
469
|
end
|
|
422
470
|
|
|
423
|
-
def request
|
|
471
|
+
def request(arguments)
|
|
424
472
|
Preflight.check!(network:, denied:, resources:, backend:)
|
|
425
473
|
{
|
|
426
|
-
readonly: expand(readable),
|
|
474
|
+
readonly: expand(readable) | library_files(arguments),
|
|
427
475
|
readwrite: expand(writable),
|
|
428
476
|
denied: expand(denied) | hidden_resolver_sockets,
|
|
429
477
|
environment:,
|
|
@@ -474,6 +522,17 @@ module MXC
|
|
|
474
522
|
system.reject { |name, _| env.keys.any? { |own| own.casecmp?(name) } }.merge(env)
|
|
475
523
|
end
|
|
476
524
|
|
|
525
|
+
def libraries_inspect
|
|
526
|
+
libraries ? (" libraries_of=#{libraries_of.inspect}" if libraries_of.any?) : ' libraries=false'
|
|
527
|
+
end
|
|
528
|
+
|
|
529
|
+
def library_files(arguments)
|
|
530
|
+
return [] unless libraries && Libraries.available?
|
|
531
|
+
|
|
532
|
+
program = Libraries.program(arguments, path: env['PATH'], directory: working_directory)
|
|
533
|
+
Libraries.files([*program, *expand(libraries_of)], executable: program)
|
|
534
|
+
end
|
|
535
|
+
|
|
477
536
|
def hidden_resolver_sockets
|
|
478
537
|
return [] if network == true
|
|
479
538
|
|
data/lib/mxc/version.rb
CHANGED
data/lib/mxc.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mxc
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: aarch64-linux
|
|
6
6
|
authors:
|
|
7
7
|
- Carmine Paolino
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-10-
|
|
11
|
+
date: 2026-10-26 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: An unofficial Ruby binding to Microsoft's MXC. Run commands in Bubblewrap,
|
|
14
14
|
Seatbelt or Windows ProcessContainer sandboxes with filesystem, network, environment
|
|
@@ -32,6 +32,8 @@ files:
|
|
|
32
32
|
- lib/mxc/chunk.rb
|
|
33
33
|
- lib/mxc/configuration.rb
|
|
34
34
|
- lib/mxc/error.rb
|
|
35
|
+
- lib/mxc/libraries.rb
|
|
36
|
+
- lib/mxc/load_commands.rb
|
|
35
37
|
- lib/mxc/native.rb
|
|
36
38
|
- lib/mxc/preflight.rb
|
|
37
39
|
- lib/mxc/process.rb
|