irpack 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/irpack +56 -0
- data/lib/irpack.rb +504 -0
- data/test/test_cscompiler.rb +48 -0
- data/test/test_packager.rb +56 -0
- metadata +70 -0
data/bin/irpack
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
#!/usr/bin/env ir
|
2
|
+
|
3
|
+
=begin
|
4
|
+
Copyright (c) 2010 Ryuichi Sakamoto.
|
5
|
+
|
6
|
+
This software is provided 'as-is', without any express or implied
|
7
|
+
warranty. In no event will the authors be held liable for any damages
|
8
|
+
arising from the use of this software.
|
9
|
+
|
10
|
+
Permission is granted to anyone to use this software for any purpose,
|
11
|
+
including commercial applications, and to alter it and redistribute it
|
12
|
+
freely, subject to the following restrictions:
|
13
|
+
|
14
|
+
1. The origin of this software must not be misrepresented; you must not
|
15
|
+
claim that you wrote the original software. If you use this software
|
16
|
+
in a product, an acknowledgment in the product documentation would be
|
17
|
+
appreciated but is not required.
|
18
|
+
|
19
|
+
2. Altered source versions must be plainly marked as such, and must not be
|
20
|
+
misrepresented as being the original software.
|
21
|
+
|
22
|
+
3. This notice may not be removed or altered from any source
|
23
|
+
distribution.
|
24
|
+
=end
|
25
|
+
|
26
|
+
require 'irpack'
|
27
|
+
require 'optparse'
|
28
|
+
|
29
|
+
packdir = nil
|
30
|
+
output_file = nil
|
31
|
+
target = :exe
|
32
|
+
compress = false
|
33
|
+
stdlib = true
|
34
|
+
opt = OptionParser.new
|
35
|
+
opt.on('-d SOURCEDIR', 'Specify pack directory. [base of ENTRYFILE]') {|v| packdir = v }
|
36
|
+
opt.on('-o OUTPUTFILE', 'Specify output file name.') {|v| output_file = v }
|
37
|
+
opt.on('-w', 'Generate window app.') { target = :winexe }
|
38
|
+
opt.on('-W', 'Generate console app.[default]') { target = :exe }
|
39
|
+
opt.on('--compress', 'Compress package.') { compress = true }
|
40
|
+
opt.on('--no-stdlib', 'Do not include IronRuby assemblies.') {|v| stdlib = v }
|
41
|
+
opt.banner = "Usage: #{$0} [options] ENTRYFILE"
|
42
|
+
opt.parse!(ARGV)
|
43
|
+
|
44
|
+
if ARGV.size<1 then
|
45
|
+
$stderr.puts opt.help
|
46
|
+
exit 1
|
47
|
+
end
|
48
|
+
|
49
|
+
entry_file = ARGV[0]
|
50
|
+
packdir ||= File.dirname(entry_file)
|
51
|
+
output_file ||= File.join(File.dirname(entry_file), File.basename(entry_file, '.*')+'.exe')
|
52
|
+
IRPack.pack_dir(packdir, entry_file, output_file,
|
53
|
+
:target => target,
|
54
|
+
:compress => compress,
|
55
|
+
:stdlib => stdlib)
|
56
|
+
|
data/lib/irpack.rb
ADDED
@@ -0,0 +1,504 @@
|
|
1
|
+
=begin
|
2
|
+
Copyright (c) 2010 Ryuichi Sakamoto.
|
3
|
+
|
4
|
+
This software is provided 'as-is', without any express or implied
|
5
|
+
warranty. In no event will the authors be held liable for any damages
|
6
|
+
arising from the use of this software.
|
7
|
+
|
8
|
+
Permission is granted to anyone to use this software for any purpose,
|
9
|
+
including commercial applications, and to alter it and redistribute it
|
10
|
+
freely, subject to the following restrictions:
|
11
|
+
|
12
|
+
1. The origin of this software must not be misrepresented; you must not
|
13
|
+
claim that you wrote the original software. If you use this software
|
14
|
+
in a product, an acknowledgment in the product documentation would be
|
15
|
+
appreciated but is not required.
|
16
|
+
|
17
|
+
2. Altered source versions must be plainly marked as such, and must not be
|
18
|
+
misrepresented as being the original software.
|
19
|
+
|
20
|
+
3. This notice may not be removed or altered from any source
|
21
|
+
distribution.
|
22
|
+
=end
|
23
|
+
|
24
|
+
require 'erb'
|
25
|
+
require 'fileutils'
|
26
|
+
require 'tmpdir'
|
27
|
+
require 'pathname'
|
28
|
+
require 'WindowsBase'
|
29
|
+
|
30
|
+
unless Dir.respond_to?(:mktmpdir) then
|
31
|
+
def Dir.mktmpdir(prefix_suffix=['d',''], tmpdir=Dir.tmpdir, &block)
|
32
|
+
if prefix_suffix.kind_of?(String) then
|
33
|
+
prefix = prefix_suffix
|
34
|
+
suffix = ''
|
35
|
+
else
|
36
|
+
prefix = prefix_suffix[0]
|
37
|
+
suffix = prefix_suffix[1]
|
38
|
+
end
|
39
|
+
n = 0
|
40
|
+
begin
|
41
|
+
path = File.join(tmpdir, "#{prefix}-#{Time.now.to_i}-#{$$}-#{rand(0x100000000).to_s(36)}-#{suffix}-#{n}")
|
42
|
+
Dir.mkdir(path, 0700)
|
43
|
+
rescue Errno::EEXIST
|
44
|
+
n += 1
|
45
|
+
retry
|
46
|
+
end
|
47
|
+
|
48
|
+
if block then
|
49
|
+
begin
|
50
|
+
block.call(path)
|
51
|
+
ensure
|
52
|
+
FileUtils.remove_entry_secure(path)
|
53
|
+
end
|
54
|
+
else
|
55
|
+
path
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
module IRPack
|
61
|
+
include System
|
62
|
+
include System::Reflection
|
63
|
+
|
64
|
+
module CSCompiler
|
65
|
+
include Microsoft::CSharp
|
66
|
+
include System::CodeDom::Compiler
|
67
|
+
include System::Reflection
|
68
|
+
|
69
|
+
module_function
|
70
|
+
def compiler_version
|
71
|
+
case System::Environment.version.major
|
72
|
+
when 4
|
73
|
+
'v4.0'
|
74
|
+
when 2
|
75
|
+
'v3.5'
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def system_assemblies
|
80
|
+
case compiler_version
|
81
|
+
when 'v4.0'
|
82
|
+
[
|
83
|
+
'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089',
|
84
|
+
'WindowsBase, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35',
|
85
|
+
'System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089',
|
86
|
+
]
|
87
|
+
when 'v3.5'
|
88
|
+
[
|
89
|
+
'System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089',
|
90
|
+
'WindowsBase, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35',
|
91
|
+
'System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089',
|
92
|
+
]
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def system_assembly_files
|
97
|
+
system_assemblies.collect {|name|
|
98
|
+
Assembly.reflection_only_load(name.to_clr_string).location
|
99
|
+
}
|
100
|
+
end
|
101
|
+
|
102
|
+
def find_assembly(paths, file)
|
103
|
+
path = paths.find {|path| File.exist?(File.join(path, file)) }
|
104
|
+
if path then
|
105
|
+
File.join(path, file)
|
106
|
+
else
|
107
|
+
file
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
class CompileError < RuntimeError; end
|
112
|
+
def compile(target, srcs, references, resources, output_name)
|
113
|
+
opts = System::Collections::Generic::Dictionary[System::String,System::String].new
|
114
|
+
opts['CompilerVersion'] = compiler_version
|
115
|
+
@compiler = CSharpCodeProvider.new(opts)
|
116
|
+
srcs = srcs.kind_of?(Array) ? srcs : [srcs]
|
117
|
+
refs = system_assembly_files + references
|
118
|
+
refs = System::Array[System::String].new(refs.size) {|i| refs[i] }
|
119
|
+
icon = resources.find {|rc| File.extname(rc)=='.ico' }
|
120
|
+
|
121
|
+
params = CompilerParameters.new(refs, output_name, false)
|
122
|
+
params.generate_in_memory = false
|
123
|
+
compiler_options = ['/optimize+']
|
124
|
+
case target
|
125
|
+
when :exe, 'exe'
|
126
|
+
params.generate_executable = true
|
127
|
+
compiler_options << '/target:exe'
|
128
|
+
compiler_options << "/win32icon:#{icon}" if icon
|
129
|
+
when :winexe, 'winexe'
|
130
|
+
params.generate_executable = true
|
131
|
+
compiler_options << '/target:winexe'
|
132
|
+
compiler_options << "/win32icon:#{icon}" if icon
|
133
|
+
else
|
134
|
+
params.generate_executable = false
|
135
|
+
compiler_options << '/target:library'
|
136
|
+
end
|
137
|
+
params.compiler_options = compiler_options.join(' ')
|
138
|
+
resources.each do |rc|
|
139
|
+
params.embedded_resources.add(rc)
|
140
|
+
end
|
141
|
+
srcs = System::Array[System::String].new(srcs.size) {|i| srcs[i] }
|
142
|
+
result = @compiler.compile_assembly_from_source(params, srcs)
|
143
|
+
result.errors.each do |err|
|
144
|
+
if err.is_warning then
|
145
|
+
$stderr.puts(err.to_s)
|
146
|
+
else
|
147
|
+
raise CompileError, err.to_s
|
148
|
+
end
|
149
|
+
end
|
150
|
+
result.path_to_assembly
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
module IRPack
|
156
|
+
BootLoaderSource = <<CS
|
157
|
+
using System;
|
158
|
+
using System.IO;
|
159
|
+
using System.IO.Packaging;
|
160
|
+
using System.Reflection;
|
161
|
+
|
162
|
+
namespace <%= module_name %> {
|
163
|
+
public class BootLoader
|
164
|
+
{
|
165
|
+
private static Assembly LoadAssemblyFromPackage(AppDomain domain, Package package, string file)
|
166
|
+
{
|
167
|
+
var uri = PackUriHelper.CreatePartUri(new Uri(file, UriKind.Relative));
|
168
|
+
if (package.PartExists(uri)) {
|
169
|
+
var stream = package.GetPart(uri).GetStream(FileMode.Open, FileAccess.Read);
|
170
|
+
var raw = new byte[stream.Length];
|
171
|
+
stream.Read(raw, 0, (int)stream.Length);
|
172
|
+
stream.Close();
|
173
|
+
return domain.Load(raw);
|
174
|
+
}
|
175
|
+
else {
|
176
|
+
return null;
|
177
|
+
}
|
178
|
+
}
|
179
|
+
|
180
|
+
private static Assembly LoadAssembly(AppDomain domain, Package package, string file)
|
181
|
+
{
|
182
|
+
try {
|
183
|
+
return domain.Load(file);
|
184
|
+
}
|
185
|
+
catch (FileNotFoundException)
|
186
|
+
{
|
187
|
+
return LoadAssemblyFromPackage(domain, package, file);
|
188
|
+
}
|
189
|
+
}
|
190
|
+
|
191
|
+
public static int Main(string[] args)
|
192
|
+
{
|
193
|
+
AppDomain domain = AppDomain.CurrentDomain;
|
194
|
+
domain.AssemblyResolve += new ResolveEventHandler(delegate (object sender, ResolveEventArgs e) {
|
195
|
+
foreach (var asm in domain.GetAssemblies()) {
|
196
|
+
if (e.Name==asm.FullName) {
|
197
|
+
return asm;
|
198
|
+
}
|
199
|
+
}
|
200
|
+
throw new FileNotFoundException(e.Name);
|
201
|
+
});
|
202
|
+
var stream = Assembly.GetEntryAssembly().GetManifestResourceStream(@"<%= package_file %>");
|
203
|
+
var package = Package.Open(stream, FileMode.Open, FileAccess.Read);
|
204
|
+
<% preload_assemblies.each do |asm| %>
|
205
|
+
LoadAssembly(domain, package, @"<%= asm %>");
|
206
|
+
<% end %>
|
207
|
+
var entry_point = LoadAssemblyFromPackage(domain, package, @"<%= module_name %>.EntryPoint.dll");
|
208
|
+
var main = entry_point.GetType(@"<%= module_name %>.EntryPoint").GetMethod("Main");
|
209
|
+
int result = (int)(main.Invoke(null, new object[] { package, args }));
|
210
|
+
package.Close();
|
211
|
+
return result;
|
212
|
+
}
|
213
|
+
}
|
214
|
+
}
|
215
|
+
CS
|
216
|
+
|
217
|
+
EntryPointSource = <<CS
|
218
|
+
using System;
|
219
|
+
using System.IO;
|
220
|
+
using System.IO.Packaging;
|
221
|
+
using System.Reflection;
|
222
|
+
using Microsoft.Scripting;
|
223
|
+
using Microsoft.Scripting.Hosting;
|
224
|
+
|
225
|
+
namespace <%= module_name %> {
|
226
|
+
public class EntryPoint
|
227
|
+
{
|
228
|
+
public class PackagePAL : PlatformAdaptationLayer
|
229
|
+
{
|
230
|
+
public Package CurrentPackage { get; set; }
|
231
|
+
public PackagePAL(Package pkg)
|
232
|
+
{
|
233
|
+
CurrentPackage = pkg;
|
234
|
+
}
|
235
|
+
|
236
|
+
private Uri ToPackageLoadPath(string path)
|
237
|
+
{
|
238
|
+
var domain = AppDomain.CurrentDomain;
|
239
|
+
var fullpath = Path.GetFullPath(path);
|
240
|
+
var searchpath = Path.GetFullPath(
|
241
|
+
domain.RelativeSearchPath!=null ?
|
242
|
+
Path.Combine(domain.BaseDirectory, domain.RelativeSearchPath) :
|
243
|
+
domain.BaseDirectory);
|
244
|
+
if (fullpath.StartsWith(searchpath)) {
|
245
|
+
var relpath = fullpath.Substring(searchpath.Length, fullpath.Length-searchpath.Length);
|
246
|
+
return PackUriHelper.CreatePartUri(new Uri(relpath, UriKind.Relative));
|
247
|
+
}
|
248
|
+
else {
|
249
|
+
return PackUriHelper.CreatePartUri(new Uri(path, UriKind.Relative));
|
250
|
+
}
|
251
|
+
}
|
252
|
+
|
253
|
+
private Uri ToPackagePath(string path)
|
254
|
+
{
|
255
|
+
var fullpath = Path.GetFullPath(path);
|
256
|
+
var searchpath = Path.GetDirectoryName(Path.GetFullPath(Assembly.GetEntryAssembly().Location));
|
257
|
+
if (fullpath.StartsWith(searchpath)) {
|
258
|
+
var relpath = fullpath.Substring(searchpath.Length, fullpath.Length-searchpath.Length);
|
259
|
+
return PackUriHelper.CreatePartUri(new Uri(relpath, UriKind.Relative));
|
260
|
+
}
|
261
|
+
else {
|
262
|
+
return PackUriHelper.CreatePartUri(new Uri(path, UriKind.Relative));
|
263
|
+
}
|
264
|
+
}
|
265
|
+
|
266
|
+
public override Assembly LoadAssembly(string name)
|
267
|
+
{
|
268
|
+
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) {
|
269
|
+
if (asm.FullName==name) {
|
270
|
+
return asm;
|
271
|
+
}
|
272
|
+
}
|
273
|
+
return Assembly.Load(name);
|
274
|
+
}
|
275
|
+
|
276
|
+
public override Assembly LoadAssemblyFromPath(string path)
|
277
|
+
{
|
278
|
+
try {
|
279
|
+
return Assembly.LoadFile(path);
|
280
|
+
}
|
281
|
+
catch (FileNotFoundException e) {
|
282
|
+
var uri = ToPackageLoadPath(path);
|
283
|
+
if (CurrentPackage.PartExists(uri)) {
|
284
|
+
var stream = CurrentPackage.GetPart(uri).GetStream(FileMode.Open, FileAccess.Read);
|
285
|
+
var raw = new byte[stream.Length];
|
286
|
+
stream.Read(raw, 0, (int)stream.Length);
|
287
|
+
stream.Close();
|
288
|
+
return Assembly.Load(raw);
|
289
|
+
}
|
290
|
+
else {
|
291
|
+
throw e;
|
292
|
+
}
|
293
|
+
}
|
294
|
+
}
|
295
|
+
|
296
|
+
public override bool FileExists(string path)
|
297
|
+
{
|
298
|
+
if (File.Exists(path)) {
|
299
|
+
return true;
|
300
|
+
}
|
301
|
+
else {
|
302
|
+
var uri = ToPackagePath(path);
|
303
|
+
return CurrentPackage.PartExists(uri);
|
304
|
+
}
|
305
|
+
}
|
306
|
+
|
307
|
+
public override Stream OpenInputFileStream(string path, FileMode mode, FileAccess access, FileShare share)
|
308
|
+
{
|
309
|
+
if (mode==FileMode.Open && access==FileAccess.Read) {
|
310
|
+
var uri = ToPackagePath(path);
|
311
|
+
if (CurrentPackage.PartExists(uri)) {
|
312
|
+
return CurrentPackage.GetPart(uri).GetStream(mode, access);
|
313
|
+
}
|
314
|
+
else {
|
315
|
+
return new FileStream(path, mode, access, share);
|
316
|
+
}
|
317
|
+
}
|
318
|
+
else {
|
319
|
+
return new FileStream(path, mode, access, share);
|
320
|
+
}
|
321
|
+
}
|
322
|
+
|
323
|
+
public override Stream OpenInputFileStream(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize)
|
324
|
+
{
|
325
|
+
if (mode==FileMode.Open && access==FileAccess.Read) {
|
326
|
+
var uri = ToPackagePath(path);
|
327
|
+
if (CurrentPackage.PartExists(uri)) {
|
328
|
+
return CurrentPackage.GetPart(uri).GetStream(mode, access);
|
329
|
+
}
|
330
|
+
else {
|
331
|
+
return new FileStream(path, mode, access, share, bufferSize);
|
332
|
+
}
|
333
|
+
}
|
334
|
+
else {
|
335
|
+
return new FileStream(path, mode, access, share, bufferSize);
|
336
|
+
}
|
337
|
+
}
|
338
|
+
|
339
|
+
public override Stream OpenInputFileStream(string path)
|
340
|
+
{
|
341
|
+
var uri = ToPackagePath(path);
|
342
|
+
if (CurrentPackage.PartExists(uri)) {
|
343
|
+
return CurrentPackage.GetPart(uri).GetStream(FileMode.Open, FileAccess.Read);
|
344
|
+
}
|
345
|
+
else {
|
346
|
+
return new FileStream(path, FileMode.Open, FileAccess.Read);
|
347
|
+
}
|
348
|
+
}
|
349
|
+
}
|
350
|
+
|
351
|
+
public class IRHost : ScriptHost
|
352
|
+
{
|
353
|
+
private PlatformAdaptationLayer PAL_;
|
354
|
+
public override PlatformAdaptationLayer PlatformAdaptationLayer { get { return PAL_; } }
|
355
|
+
public IRHost(Package pkg)
|
356
|
+
{
|
357
|
+
PAL_ = new PackagePAL(pkg);
|
358
|
+
}
|
359
|
+
}
|
360
|
+
|
361
|
+
public static int Main(Package package, string[] args)
|
362
|
+
{
|
363
|
+
var runtime_setup = new ScriptRuntimeSetup();
|
364
|
+
runtime_setup.LanguageSetups.Add(IronRuby.Ruby.CreateRubySetup());
|
365
|
+
runtime_setup.Options["MainFile"] = "<%= entry_file %>";
|
366
|
+
runtime_setup.Options["Arguments"] = args;
|
367
|
+
runtime_setup.HostType = typeof(IRHost);
|
368
|
+
runtime_setup.HostArguments = new object[] { package };
|
369
|
+
var engine = IronRuby.Ruby.GetEngine(IronRuby.Ruby.CreateRuntime(runtime_setup));
|
370
|
+
try {
|
371
|
+
engine.ExecuteFile("<%= entry_file %>");
|
372
|
+
return 0;
|
373
|
+
}
|
374
|
+
catch (IronRuby.Builtins.SystemExit e) {
|
375
|
+
return e.Status;
|
376
|
+
}
|
377
|
+
}
|
378
|
+
}
|
379
|
+
}
|
380
|
+
CS
|
381
|
+
module_function
|
382
|
+
def bootloader_source(module_name, package_file, preload_assemblies)
|
383
|
+
ERB.new(BootLoaderSource).result(binding)
|
384
|
+
end
|
385
|
+
|
386
|
+
def entrypoint_source(module_name, entry_file)
|
387
|
+
ERB.new(EntryPointSource).result(binding)
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
module IRPack
|
392
|
+
module Packager
|
393
|
+
include System
|
394
|
+
include System::IO::Packaging
|
395
|
+
|
396
|
+
RelType = 'http://schemas.openxmlformats.org/package/2006/relationships/meta data/core-properties'
|
397
|
+
module_function
|
398
|
+
def pack(files, package_file, compress=false)
|
399
|
+
compress_option = compress ? CompressionOption.normal : CompressionOption.not_compressed
|
400
|
+
package = Package.open(package_file, System::IO::FileMode.create)
|
401
|
+
files.each do |src, dest|
|
402
|
+
uri = PackUriHelper.create_part_uri(Uri.new(dest, UriKind.relative))
|
403
|
+
part = package.create_part(uri, 'application/octet-stream', compress_option)
|
404
|
+
stream = part.get_stream
|
405
|
+
File.open(src, 'rb') do |f|
|
406
|
+
data = f.read
|
407
|
+
stream.write(data, 0, data.size)
|
408
|
+
end
|
409
|
+
stream.close
|
410
|
+
package.create_relationship(uri, TargetMode.internal, RelType)
|
411
|
+
end
|
412
|
+
package.close
|
413
|
+
end
|
414
|
+
|
415
|
+
def pack_dir(dir_name, package_file)
|
416
|
+
files = {}
|
417
|
+
base = Pathname.new(dir_name)
|
418
|
+
Dir.glob(base.join('**', '*')) do |fn|
|
419
|
+
files[fn] = Pathname.new(fn).relative_path_from(base)
|
420
|
+
end
|
421
|
+
pack(files, package_file)
|
422
|
+
end
|
423
|
+
end
|
424
|
+
|
425
|
+
AssemblyPath = ::File.dirname(Assembly.get_entry_assembly.location.to_s)
|
426
|
+
PreloadAssemblies = %w[
|
427
|
+
Microsoft.Dynamic.dll
|
428
|
+
Microsoft.Scripting.dll
|
429
|
+
Microsoft.Scripting.Core.dll
|
430
|
+
IronRuby.dll
|
431
|
+
IronRuby.Libraries.dll
|
432
|
+
IronRuby.Libraries.Yaml.dll
|
433
|
+
]
|
434
|
+
|
435
|
+
module_function
|
436
|
+
def path_to_module_name(filename)
|
437
|
+
name = File.basename(filename, '.*')
|
438
|
+
name.gsub!(/[^A-Za-z0-9_]/, '_')
|
439
|
+
/^[A-Za-z]/=~name ? name : ('M'+name)
|
440
|
+
end
|
441
|
+
|
442
|
+
def pack(files, entry_file, output_file, options={})
|
443
|
+
preload_assemblies = PreloadAssemblies.collect {|fn|
|
444
|
+
File.join(AssemblyPath, fn)
|
445
|
+
}.select {|fn|
|
446
|
+
File.exist?(fn)
|
447
|
+
}
|
448
|
+
basename = File.basename(output_file, '.*')
|
449
|
+
module_name = path_to_module_name(output_file)
|
450
|
+
resources = options[:resources] || []
|
451
|
+
target = options[:target] || :exe
|
452
|
+
stdlib = options.include?(:stdlib) ? options[:stdlib] : true
|
453
|
+
compress = options.include?(:compress) ? options[:compress] : false
|
454
|
+
pack_files = files.dup
|
455
|
+
|
456
|
+
Dir.mktmpdir(File.basename($0,'.*')) do |tmp_path|
|
457
|
+
entry_src = entrypoint_source(module_name, entry_file)
|
458
|
+
entry_dll = File.join(tmp_path, module_name+'.EntryPoint.dll')
|
459
|
+
CSCompiler.compile(:dll, entry_src, preload_assemblies, [], entry_dll)
|
460
|
+
pack_files[entry_dll] = File.basename(entry_dll)
|
461
|
+
if stdlib then
|
462
|
+
preload_assemblies.each do |asm|
|
463
|
+
pack_files[asm] = File.basename(asm)
|
464
|
+
end
|
465
|
+
end
|
466
|
+
package_file = File.join(tmp_path, basename+'.pkg')
|
467
|
+
Packager.pack(pack_files, package_file, compress)
|
468
|
+
|
469
|
+
target_src = bootloader_source(
|
470
|
+
module_name,
|
471
|
+
File.basename(package_file),
|
472
|
+
preload_assemblies.collect {|fn| File.basename(fn) }
|
473
|
+
)
|
474
|
+
Dir.chdir(tmp_path) do
|
475
|
+
CSCompiler.compile(target, target_src, [], [File.basename(package_file)], output_file)
|
476
|
+
end
|
477
|
+
end
|
478
|
+
end
|
479
|
+
|
480
|
+
def pack_dir(pack_dir, entry_file, output_file, options={})
|
481
|
+
output_file = File.expand_path(output_file)
|
482
|
+
entry_packed = nil
|
483
|
+
pack_files = {}
|
484
|
+
resources = []
|
485
|
+
base = Pathname.new(pack_dir).expand_path
|
486
|
+
Dir.glob(base.join('**', '*')) do |fn|
|
487
|
+
path = Pathname.new(File.expand_path(fn))
|
488
|
+
next if path==output_file
|
489
|
+
relpath = path.relative_path_from(base)
|
490
|
+
pack_files[path] = relpath
|
491
|
+
if not entry_packed and
|
492
|
+
(path.to_s==File.expand_path(entry_file) or
|
493
|
+
path.basename.to_s==entry_file or
|
494
|
+
relpath.to_s==entry_file) then
|
495
|
+
entry_packed = relpath
|
496
|
+
end
|
497
|
+
resources << path.to_s if path.extname=='.ico'
|
498
|
+
end
|
499
|
+
raise ArgumentError, "Entry file `#{entry_file}' is not in packed directory."unless entry_packed
|
500
|
+
options = options.merge(:resources => resources)
|
501
|
+
pack(pack_files, entry_packed, output_file, options)
|
502
|
+
end
|
503
|
+
end
|
504
|
+
|
@@ -0,0 +1,48 @@
|
|
1
|
+
|
2
|
+
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
3
|
+
require 'test/unit'
|
4
|
+
require 'tempfile'
|
5
|
+
require 'tmpdir'
|
6
|
+
require 'fileutils'
|
7
|
+
require 'irpack'
|
8
|
+
|
9
|
+
require 'WindowsBase'
|
10
|
+
include System
|
11
|
+
include System::IO
|
12
|
+
include System::IO::Packaging
|
13
|
+
|
14
|
+
class TC_CSCompiler < Test::Unit::TestCase
|
15
|
+
def test_compile_dll
|
16
|
+
src = <<-CS
|
17
|
+
using System;
|
18
|
+
namespace hoge {
|
19
|
+
class Hoge {
|
20
|
+
public static int Main(string[] args) {
|
21
|
+
System.Console.WriteLine("hoge");
|
22
|
+
return 0;
|
23
|
+
}
|
24
|
+
}
|
25
|
+
}
|
26
|
+
CS
|
27
|
+
references = []
|
28
|
+
resources = []
|
29
|
+
output_file = Tempfile.new(File.basename(__FILE__))
|
30
|
+
output_file.close
|
31
|
+
result = IRPack::CSCompiler.compile(
|
32
|
+
:dll,
|
33
|
+
src,
|
34
|
+
references,
|
35
|
+
resources,
|
36
|
+
output_file.path
|
37
|
+
)
|
38
|
+
assert_equal(output_file.path, result)
|
39
|
+
asm = nil
|
40
|
+
assert_nothing_raised do
|
41
|
+
asm = System::Reflection::Assembly.load_from(output_file.path)
|
42
|
+
end
|
43
|
+
assert(asm.get_type('hoge.Hoge'))
|
44
|
+
assert_nil(asm.entry_point)
|
45
|
+
assert_equal(System::Reflection::Assembly.get_entry_assembly.image_runtime_version, asm.image_runtime_version)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
@@ -0,0 +1,56 @@
|
|
1
|
+
|
2
|
+
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
3
|
+
require 'test/unit'
|
4
|
+
require 'tempfile'
|
5
|
+
require 'tmpdir'
|
6
|
+
require 'fileutils'
|
7
|
+
require 'irpack'
|
8
|
+
|
9
|
+
require 'WindowsBase'
|
10
|
+
include System
|
11
|
+
include System::IO
|
12
|
+
include System::IO::Packaging
|
13
|
+
|
14
|
+
class TC_Packager < Test::Unit::TestCase
|
15
|
+
SrcFiles = {
|
16
|
+
File.join(File.dirname(__FILE__), 'test_packager.rb') => 'foo.rb',
|
17
|
+
File.join(File.dirname(__FILE__), 'test_cscompiler.rb') => 'bar.rb',
|
18
|
+
}
|
19
|
+
|
20
|
+
def test_pack
|
21
|
+
target = Tempfile.new(File.basename(__FILE__))
|
22
|
+
target.close
|
23
|
+
IRPack::Packager.pack(SrcFiles, target.path)
|
24
|
+
package = Package.open(target.path, FileMode.open)
|
25
|
+
SrcFiles.each do |src, dest|
|
26
|
+
uri = Uri.new(File.join('/', dest), UriKind.relative)
|
27
|
+
assert(package.part_exists(uri))
|
28
|
+
stream = package.get_part(uri).get_stream
|
29
|
+
bytes = System::Array[System::Byte].new(stream.length)
|
30
|
+
stream.read(bytes, 0, stream.length)
|
31
|
+
assert_equal(File.open(src, 'rb'){|f|f.read}, bytes.to_a.pack('C*'))
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_pack_dir
|
36
|
+
Dir.mktmpdir do |src_path|
|
37
|
+
SrcFiles.each do |src, dest|
|
38
|
+
FileUtils.mkdir_p(File.join(src_path, File.dirname(dest)))
|
39
|
+
FileUtils.copy(src, File.join(src_path, dest))
|
40
|
+
end
|
41
|
+
target = Tempfile.new(File.basename(__FILE__))
|
42
|
+
target.close
|
43
|
+
IRPack::Packager.pack_dir(src_path, target.path)
|
44
|
+
package = Package.open(target.path, FileMode.open)
|
45
|
+
SrcFiles.each do |src, dest|
|
46
|
+
uri = Uri.new(File.join('/', dest), UriKind.relative)
|
47
|
+
assert(package.part_exists(uri))
|
48
|
+
stream = package.get_part(uri).get_stream
|
49
|
+
bytes = System::Array[System::Byte].new(stream.length)
|
50
|
+
stream.read(bytes, 0, stream.length)
|
51
|
+
assert_equal(File.open(src, 'rb'){|f|f.read}, bytes.to_a.pack('C*'))
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
metadata
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: irpack
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
version: 0.1.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- kumaryu
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-09-11 00:00:00 +09:00
|
18
|
+
default_executable:
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description: |
|
22
|
+
IRPack converts your IronRuby scripts to a standalone .exe file.
|
23
|
+
Generated executable does not require IronRuby, but only .NET Framework or mono.
|
24
|
+
|
25
|
+
email: kumaryu@kumayu.net
|
26
|
+
executables:
|
27
|
+
- irpack
|
28
|
+
extensions: []
|
29
|
+
|
30
|
+
extra_rdoc_files: []
|
31
|
+
|
32
|
+
files:
|
33
|
+
- bin/irpack
|
34
|
+
- lib/irpack.rb
|
35
|
+
- test/test_cscompiler.rb
|
36
|
+
- test/test_packager.rb
|
37
|
+
has_rdoc: true
|
38
|
+
homepage: http://github.com/kumaryu/irpack
|
39
|
+
licenses: []
|
40
|
+
|
41
|
+
post_install_message:
|
42
|
+
rdoc_options: []
|
43
|
+
|
44
|
+
require_paths:
|
45
|
+
- lib
|
46
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
47
|
+
none: false
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
segments:
|
52
|
+
- 0
|
53
|
+
version: "0"
|
54
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
segments:
|
60
|
+
- 0
|
61
|
+
version: "0"
|
62
|
+
requirements:
|
63
|
+
- none
|
64
|
+
rubyforge_project:
|
65
|
+
rubygems_version: 1.3.7
|
66
|
+
signing_key:
|
67
|
+
specification_version: 3
|
68
|
+
summary: Generate a standalone executable file from IronRuby scripts.
|
69
|
+
test_files: []
|
70
|
+
|