Class: Gem::Compiler

Inherits:
Object
  • Object
show all
Extended by:
UserInteraction
Defined in:
lib/rubygems/compiler.rb

Class Method Summary collapse

Class Method Details

.compile(gem, platform = Gem::Platform::CURRENT, fat_commands = {}) ⇒ Object



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/rubygems/compiler.rb', line 13

def self.compile(gem, platform = Gem::Platform::CURRENT, fat_commands = {})
	gem_dir = "#{File.basename(gem)}.build"
	gem_dir = File.expand_path(gem_dir)

	format = Gem::Format.from_file_by_path(gem)

	spec = format.spec

	if spec.extensions.empty?
		raise Gem::Exception, "There are no extensions to build."
	end

	if spec.platform != Gem::Platform::RUBY
		raise Gem::Exception, "The package seems to be built already."
	end

	dest_path = File.join(gem_dir, spec.require_paths.first)
	FileUtils.rm_rf(dest_path) if File.exists?(dest_path)

	format.file_entries.each do |entry, file_data|
		path = entry['path'].untaint
		path = File.expand_path File.join(gem_dir, path)

		FileUtils.rm_rf(path) if File.exists?(path)
		FileUtils.mkdir_p File.dirname(path)

		File.open(path, "wb") do |out|
			out.write file_data
		end

		FileUtils.chmod entry['mode'], path

		say path if Gem.configuration.really_verbose
	end

	ran_rake = false
	start_dir = Dir.pwd

	spec.extensions.each do |extension|
		break if ran_rake
		results = []

		builder = case extension
							when /extconf/ then
								Gem::Ext::ExtConfBuilder
							when /configure/ then
								Gem::Ext::ConfigureBuilder
							when /rakefile/i, /mkrf_conf/i then
								ran_rake = true
								Gem::Ext::RakeBuilder
							else
								results = ["No builder for extension '#{extension}'"]
								raise results.last
							end

		begin
			build_dir = File.join(gem_dir, File.dirname(extension))
			extension = File.expand_path(extension)
			Dir.chdir build_dir

			if fat_commands.empty?
				results = builder.build(extension, gem_dir, dest_path, results)

			else
				ext_files = []

				fat_commands.each_pair do |version, command|
					dest_version_path = File.join(dest_path, version)

					script = %'require "rubygems/ext"; puts #{builder}.build(#{extension.dump},#{gem_dir.dump},#{dest_version_path.dump}, [])'

					result = `#{command} -e '#{script}'`
					results << result
					raise result if $? != 0

					FileUtils.rm Dir.glob("**/*.o")    # FIXME
				end
			end

			say results.join("\n") if Gem.configuration.really_verbose

		rescue => ex
			results = results.join "\n"

			File.open('gem_make.out', 'wb') {|f| f.puts results }

			message = <<-EOF
ERROR: Failed to build gem native extension.

			#{results}

Results logged to #{File.join(Dir.pwd, 'gem_make.out')}
			EOF

			raise Gem::Exception, message

		ensure
			Dir.chdir start_dir
		end
	end

	spec.extensions = []

	unless fat_commands.empty?
		fat_ext_files = fat_commands.keys.uniq.map do |version|
			dest_version_path = File.join(dest_path, version)
			fat_ext_paths = Dir.glob("#{dest_version_path}/**/*")
			fat_ext_paths.map {|path| path[File.join(dest_version_path,'').length..-1] }
		end.flatten.uniq

		fat_ext_files.uniq.each do |ext_file|
			ext_name = ext_file.sub(/\.[^\.]*$/, '')
			rb_path = File.join(dest_path, "#{ext_name}.rb")
			File.open(rb_path, "w") do |f|
				f.write <<-EOF
require File.join File.dirname(__FILE__), RUBY_VERSION.match(/\\d+\\.\\d+/)[0], #{ext_name.dump}
				EOF
			end
		end
	end

	built_paths = Dir.glob("#{dest_path}/**/*")
	built_files = built_paths.map {|path| path[File.join(gem_dir,'').length..-1] }
	built_files.reject! {|path| path =~ /\.o$/ }  # FIXME

	spec.files = (spec.files + built_files).sort.uniq
	spec.platform = platform if platform

	Dir.chdir gem_dir
	begin
		out_fname = Gem::Builder.new(spec).build
		FileUtils.mv(out_fname, start_dir)
	ensure
		Dir.chdir start_dir
	end
end