makeconf 0.1.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.
- data/lib/makeconf/androidproject.rb +310 -0
- data/lib/makeconf/baseproject.rb +386 -0
- data/lib/makeconf/binary.rb +30 -0
- data/lib/makeconf/buildable.rb +270 -0
- data/lib/makeconf/compiler.rb +332 -0
- data/lib/makeconf/externalproject.rb +108 -0
- data/lib/makeconf/gui.rb +239 -0
- data/lib/makeconf/header.rb +37 -0
- data/lib/makeconf/installer.rb +205 -0
- data/lib/makeconf/library.rb +72 -0
- data/lib/makeconf/linker.rb +171 -0
- data/lib/makeconf/makefile.rb +126 -0
- data/lib/makeconf/packager.rb +90 -0
- data/lib/makeconf/platform.rb +213 -0
- data/lib/makeconf/project.rb +19 -0
- data/lib/makeconf/systemtype.rb +35 -0
- data/lib/makeconf/target.rb +73 -0
- data/lib/makeconf/test.rb +28 -0
- data/lib/makeconf/wxapp.rb +22 -0
- data/lib/makeconf.rb +213 -0
- metadata +64 -0
@@ -0,0 +1,108 @@
|
|
1
|
+
# An external project is typically a third-party library dependency
|
2
|
+
# that does not use makeconf for it's build system.
|
3
|
+
#
|
4
|
+
class ExternalProject < Buildable
|
5
|
+
|
6
|
+
require 'net/http'
|
7
|
+
require 'uri'
|
8
|
+
|
9
|
+
attr_accessor :uri, :patch
|
10
|
+
|
11
|
+
def initialize(options)
|
12
|
+
# KLUDGE - parent constructor will barf unless we delete our
|
13
|
+
# custom options
|
14
|
+
@uri = options[:uri]
|
15
|
+
options.delete :uri
|
16
|
+
@configure = options[:configure] # options passed to ./configure
|
17
|
+
options.delete :configure
|
18
|
+
@configure = './configure' if @configure.nil?
|
19
|
+
@patch = options[:patch]
|
20
|
+
options.delete :patch
|
21
|
+
@patch = [] if @patch.nil?
|
22
|
+
|
23
|
+
super(options)
|
24
|
+
|
25
|
+
@installable = false
|
26
|
+
@distributable = false
|
27
|
+
end
|
28
|
+
|
29
|
+
# Examine the operating environment and set configuration options
|
30
|
+
def configure
|
31
|
+
printf "checking for external project #{@id}... "
|
32
|
+
if File.exists?(@id)
|
33
|
+
puts "yes"
|
34
|
+
else
|
35
|
+
puts "no"
|
36
|
+
download
|
37
|
+
|
38
|
+
# Apply patches
|
39
|
+
@patch.each do |p|
|
40
|
+
system "cd #{@id} && patch -p0 -N < ../#{p}" \
|
41
|
+
or throw "failed to apply patch: ../#{p}"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# KLUDGE: passthrough certain options
|
46
|
+
passthru = []
|
47
|
+
Makeconf.original_argv.each do |x|
|
48
|
+
passthru.push x if x =~ /^--(host|with-ndk|with-sdk)/
|
49
|
+
end
|
50
|
+
@configure += ' ' + passthru.join(' ') unless passthru.empty?
|
51
|
+
|
52
|
+
# FIXME: this works, but autotools differ widely across host systems.
|
53
|
+
# make this an optional step that can be done
|
54
|
+
#
|
55
|
+
# Regenerate the Autotools files
|
56
|
+
#if File.exists?(@id + '/configure.ac')
|
57
|
+
# system "cd #{@id} && autoreconf -fvi" \
|
58
|
+
# or throw "autoreconf failed"
|
59
|
+
# end
|
60
|
+
|
61
|
+
# Run the autoconf-style ./configure script
|
62
|
+
puts "*** Configuring #{@id} using #{@configure}"
|
63
|
+
system "cd #{@id} && #{@configure}" \
|
64
|
+
or throw "Unable to configure #{@id}"
|
65
|
+
puts "*** Done"
|
66
|
+
end
|
67
|
+
|
68
|
+
def build
|
69
|
+
makefile = Makefile.new
|
70
|
+
return makefile unless @buildable
|
71
|
+
makefile.add_dependency('all', "#{@id}-build-stamp")
|
72
|
+
makefile.add_target("#{@id}-build-stamp", [],
|
73
|
+
[
|
74
|
+
"cd #{@id} && make",
|
75
|
+
"touch #{@id}-build-stamp",
|
76
|
+
])
|
77
|
+
makefile.add_rule('check', [ "cd #{@id} && make check" ])
|
78
|
+
makefile.add_rule('clean', Platform.rm("#{@id}-build-stamp"))
|
79
|
+
makefile
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
# Download the project from an external source
|
86
|
+
def download
|
87
|
+
|
88
|
+
#example for tarball
|
89
|
+
# x = Net::HTTP.get(URI(uri))
|
90
|
+
# end
|
91
|
+
uri = URI(@uri)
|
92
|
+
|
93
|
+
case uri.scheme
|
94
|
+
when 'svn', 'svn+ssh'
|
95
|
+
puts "downloading #{@uri}.. "
|
96
|
+
system "svn co #{@uri} #{@id}" or throw "Unable to checkout working copy"
|
97
|
+
when 'file'
|
98
|
+
puts "unpacking #{uri.host}.. "
|
99
|
+
system "tar zxf #{uri.host}" or throw "Unable to unpack #{uri.host}"
|
100
|
+
else
|
101
|
+
throw "Unsupported URI scheme #{@uri}"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def log
|
106
|
+
Makeconf.logger
|
107
|
+
end
|
108
|
+
end
|
data/lib/makeconf/gui.rb
ADDED
@@ -0,0 +1,239 @@
|
|
1
|
+
class Makeconf::GUI
|
2
|
+
|
3
|
+
def initialize(project)
|
4
|
+
require 'tk'
|
5
|
+
|
6
|
+
@project = project
|
7
|
+
@page = [ 'intro_page',
|
8
|
+
'license_page',
|
9
|
+
# TODO:'install_prefix_page',
|
10
|
+
'build_page',
|
11
|
+
'outro_page',
|
12
|
+
]
|
13
|
+
@pageIndex = 0
|
14
|
+
|
15
|
+
@mainTitle = TkVariable.new
|
16
|
+
@mainMessage = TkVariable.new
|
17
|
+
|
18
|
+
@root = TkRoot.new() {
|
19
|
+
title "Installation"
|
20
|
+
}
|
21
|
+
|
22
|
+
@mainTitleWidget = TkLabel.new(@root) {
|
23
|
+
pack('side' => 'top')
|
24
|
+
}
|
25
|
+
@mainTitleWidget.configure('textvariable', @mainTitle)
|
26
|
+
|
27
|
+
@mainFrame = TkFrame.new(@root) {
|
28
|
+
height 600
|
29
|
+
width 600
|
30
|
+
background 'white'
|
31
|
+
borderwidth 5
|
32
|
+
relief 'groove'
|
33
|
+
padx 10
|
34
|
+
pady 10
|
35
|
+
pack('side' => 'top')
|
36
|
+
}
|
37
|
+
|
38
|
+
@mainLabel = TkLabel.new(@mainFrame) {
|
39
|
+
background 'white'
|
40
|
+
}
|
41
|
+
@mainLabel.configure('textvariable', @mainMessage)
|
42
|
+
|
43
|
+
@mainText = TkText.new(@mainFrame) {
|
44
|
+
background 'white'
|
45
|
+
}
|
46
|
+
|
47
|
+
@cancelButton = TkButton.new(@root) {
|
48
|
+
text "Cancel"
|
49
|
+
command proc {
|
50
|
+
exit 1
|
51
|
+
}
|
52
|
+
pack('side' => 'left')
|
53
|
+
}
|
54
|
+
|
55
|
+
@nextButton = TkButton.new(@root) {
|
56
|
+
text "Next"
|
57
|
+
pack('side' => 'right')
|
58
|
+
}
|
59
|
+
@nextButton.configure('command', method(:next_page))
|
60
|
+
#nextButton.configure('command', proc { mainMessage.set_value 'You click it' })
|
61
|
+
@nextButtonEnable = true
|
62
|
+
|
63
|
+
@backButton = TkButton.new(@root) {
|
64
|
+
text "Back"
|
65
|
+
command proc { prev_page }
|
66
|
+
state 'disabled'
|
67
|
+
pack('side' => 'right')
|
68
|
+
}
|
69
|
+
@backButton.configure('command', method(:prev_page))
|
70
|
+
@backButtonEnable = true
|
71
|
+
|
72
|
+
update_buttons
|
73
|
+
end
|
74
|
+
|
75
|
+
def next_page
|
76
|
+
eval "#{@page[@pageIndex]}(false)"
|
77
|
+
@pageIndex = @pageIndex + 1
|
78
|
+
eval "#{@page[@pageIndex]}(true)"
|
79
|
+
update_buttons
|
80
|
+
end
|
81
|
+
|
82
|
+
def prev_page
|
83
|
+
eval "#{@page[@pageIndex]}(false)"
|
84
|
+
@pageIndex = @pageIndex - 1
|
85
|
+
eval "#{@page[@pageIndex]}(true)"
|
86
|
+
update_buttons
|
87
|
+
end
|
88
|
+
|
89
|
+
# Update the Back and Next buttons based on the position in the pagelist
|
90
|
+
def update_buttons
|
91
|
+
if @pageIndex == 0
|
92
|
+
@backButton.configure('state', 'disabled')
|
93
|
+
@nextButton.configure('state', 'normal')
|
94
|
+
@nextButton.configure('text', 'Next')
|
95
|
+
elsif @pageIndex == @page.length - 1
|
96
|
+
@nextButton.configure('text', 'Finish')
|
97
|
+
@nextButton.configure('command', proc { exit 0 })
|
98
|
+
@backButton.configure('state', 'disabled')
|
99
|
+
@cancelButton.configure('state', 'disabled')
|
100
|
+
else
|
101
|
+
@nextButton.configure('text', 'Next')
|
102
|
+
@nextButton.configure('state', @nextButtonEnable ? 'normal' : 'disabled')
|
103
|
+
@backButton.configure('state', @backButtonEnable ? 'normal' : 'disabled')
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def main_loop
|
108
|
+
eval "#{@page[0]}(true)"
|
109
|
+
Tk.mainloop()
|
110
|
+
end
|
111
|
+
|
112
|
+
def intro_page(display)
|
113
|
+
if display
|
114
|
+
@mainTitle.set_value 'Welcome'
|
115
|
+
@mainLabel.place('relx'=>0.0, 'rely' => 0.0)
|
116
|
+
@mainMessage.set_value "This will install #{@project.id} on your computer"
|
117
|
+
else
|
118
|
+
TkPlace.forget(@mainLabel)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def license_page(display)
|
123
|
+
if display
|
124
|
+
@mainTitle.set_value 'License Agreement'
|
125
|
+
@mainText.insert('end', File.read(@project.license_file))
|
126
|
+
@mainText.place('relx'=>0.0, 'rely' => 0.0)
|
127
|
+
else
|
128
|
+
TkPlace.forget(@mainText)
|
129
|
+
@mainText.delete(1.0, 'end')
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def install_prefix_page(display)
|
134
|
+
if display
|
135
|
+
@mainTitle.set_value 'Installation Path'
|
136
|
+
@mainText.insert('end', "choose an installation path")
|
137
|
+
@mainText.place('relx'=>0.0, 'rely' => 0.0)
|
138
|
+
Tk.getOpenFile
|
139
|
+
else
|
140
|
+
TkPlace.forget(@mainText)
|
141
|
+
@mainText.delete(1.0, 'end')
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def build_page(display)
|
146
|
+
if display
|
147
|
+
@nextButtonEnable = false
|
148
|
+
update_buttons
|
149
|
+
@mainTitle.set_value 'Checking Configuration'
|
150
|
+
@mainText.delete(1.0, 'end')
|
151
|
+
@mainText.place('relx'=>0.0, 'rely' => 0.0)
|
152
|
+
Thread.new {
|
153
|
+
@mainText.insert('end', "Configuring.. ")
|
154
|
+
Makeconf.configure_project @project
|
155
|
+
@mainText.insert('end', "done\n")
|
156
|
+
|
157
|
+
make = Platform.is_windows? ? 'nmake' : 'make'
|
158
|
+
|
159
|
+
@mainText.insert('end', "Building.. ")
|
160
|
+
system "#{make}"
|
161
|
+
@mainText.insert('end', "done\n")
|
162
|
+
|
163
|
+
@mainText.insert('end', "Installing.. ")
|
164
|
+
system "#{make} install"
|
165
|
+
@mainText.insert('end', "done\n")
|
166
|
+
|
167
|
+
@mainText.insert('end', "\nAll tasks completed.")
|
168
|
+
|
169
|
+
@nextButtonEnable = true
|
170
|
+
update_buttons
|
171
|
+
}
|
172
|
+
else
|
173
|
+
TkPlace.forget(@mainText)
|
174
|
+
@mainText.delete(1.0, 'end')
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
def outro_page(display)
|
179
|
+
if display
|
180
|
+
@mainTitle.set_value 'Installation Complete'
|
181
|
+
@mainLabel.place('relx'=>0.0, 'rely' => 0.0)
|
182
|
+
@mainMessage.set_value "Installation is complete."
|
183
|
+
else
|
184
|
+
TkPlace.forget(@mainLabel)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
end
|
189
|
+
|
190
|
+
__END__
|
191
|
+
# UNUSED: might use for showing error messages if "require 'tk'" fails
|
192
|
+
#
|
193
|
+
class Makeconf::GUI::Minimal
|
194
|
+
|
195
|
+
if Platform.is_windows?
|
196
|
+
require 'dl'
|
197
|
+
end
|
198
|
+
|
199
|
+
def initialize
|
200
|
+
end
|
201
|
+
|
202
|
+
# Display a graphical message box
|
203
|
+
def message_box(txt, title, buttons=0)
|
204
|
+
if Platform.is_windows?
|
205
|
+
|
206
|
+
# FIXME: add conditional
|
207
|
+
|
208
|
+
#Ruby 1.8:
|
209
|
+
# user32 = DL.dlopen('user32')
|
210
|
+
# msgbox = user32['MessageBoxA', 'ILSSI']
|
211
|
+
# r, rs = msgbox.call(0, txt, title, buttons)
|
212
|
+
# return r
|
213
|
+
|
214
|
+
#Ruby 1.9:
|
215
|
+
user32 = DL.dlopen('user32')
|
216
|
+
msgbox = DL::CFunc.new(user32['MessageBoxA'], DL::TYPE_LONG, 'MessageBox')
|
217
|
+
r, rs = msgbox.call([0, txt, title, buttons].pack('L!ppL!').unpack('L!*'))
|
218
|
+
return r
|
219
|
+
elsif Platform.is_linux?
|
220
|
+
#XXX-scrub txt to eliminate "'" character
|
221
|
+
cmd = "zenity --text='#{txt}' " + (buttons > 0 ? '--question' : '--info')
|
222
|
+
rv = system cmd
|
223
|
+
return rv == true ? 1 : 0
|
224
|
+
else
|
225
|
+
throw 'STUB'
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
# Display an informational message with a single 'OK' button
|
230
|
+
def notice(txt, title)
|
231
|
+
message_box(txt, title, 0)
|
232
|
+
end
|
233
|
+
|
234
|
+
# Display an confirmation message with an OK button and CANCEL button
|
235
|
+
def confirm(txt, title)
|
236
|
+
return (message_box(txt, title, 1) == 1) ? true : false
|
237
|
+
end
|
238
|
+
|
239
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# A generic Header class that installs header files into $(PKGINCLUDEDIR)
|
2
|
+
|
3
|
+
class Header < Buildable
|
4
|
+
|
5
|
+
def initialize(options)
|
6
|
+
raise ArgumentError unless options.kind_of?(Hash)
|
7
|
+
|
8
|
+
# KLUDGE - parent constructor will barf unless we delete our
|
9
|
+
# custom options
|
10
|
+
@namespace = options[:namespace]
|
11
|
+
options.delete :namespace
|
12
|
+
|
13
|
+
super(options)
|
14
|
+
end
|
15
|
+
|
16
|
+
def build
|
17
|
+
mk = Makefile.new
|
18
|
+
|
19
|
+
mk.distribute(@sources)
|
20
|
+
|
21
|
+
dest = '$(INCLUDEDIR)'
|
22
|
+
dest += '/' + @namespace unless @namespace.nil?
|
23
|
+
|
24
|
+
@project.installer.install(
|
25
|
+
:sources => @sources,
|
26
|
+
:dest => dest,
|
27
|
+
:mode => '644'
|
28
|
+
)
|
29
|
+
|
30
|
+
return mk
|
31
|
+
end
|
32
|
+
|
33
|
+
def makedepends
|
34
|
+
[]
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,205 @@
|
|
1
|
+
# An installer copies files from the current directory to an OS-wide location
|
2
|
+
class Installer
|
3
|
+
|
4
|
+
attr_reader :dir
|
5
|
+
attr_accessor :package
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@items = [] # Items to be installed
|
9
|
+
@project = nil
|
10
|
+
@path = nil
|
11
|
+
|
12
|
+
# Set default installation paths
|
13
|
+
@dir = {
|
14
|
+
:prefix => Platform.is_superuser? ? '/usr' : '/usr/local',
|
15
|
+
:eprefix => '$(PREFIX)', # this is --exec-prefix
|
16
|
+
:bindir => '$(EPREFIX)/bin',
|
17
|
+
:datarootdir => '$(PREFIX)/share',
|
18
|
+
:datadir => '$(DATAROOTDIR)',
|
19
|
+
:docdir => '$(DATAROOTDIR)/doc/$(PACKAGE)',
|
20
|
+
:includedir => '$(PREFIX)/include',
|
21
|
+
:infodir => '$(DATAROOTDIR)/info',
|
22
|
+
:libdir => '$(EPREFIX)/lib',
|
23
|
+
:libexecdir => '$(EPREFIX)/libexec',
|
24
|
+
:localedir => '$(DATAROOTDIR)/locale',
|
25
|
+
:localstatedir => '$(PREFIX)/var',
|
26
|
+
:mandir => '$(DATAROOTDIR)/man',
|
27
|
+
:oldincludedir => '/usr/include',
|
28
|
+
:sbindir => '$(EPREFIX)/sbin',
|
29
|
+
:sysconfdir => '$(PREFIX)/etc',
|
30
|
+
:sharedstatedir => '$(PREFIX)/com',
|
31
|
+
|
32
|
+
# Package-specific directories
|
33
|
+
:pkgincludedir => '$(INCLUDEDIR)/$(PACKAGE)',
|
34
|
+
:pkgdatadir => '$(DATADIR)/$(PACKAGE)',
|
35
|
+
:pkglibdir => '$(LIBDIR)/$(PACKAGE)',
|
36
|
+
|
37
|
+
#TODO: document this
|
38
|
+
#DEPRECATED: htmldir, dvidir, pdfdir, psdir
|
39
|
+
}
|
40
|
+
|
41
|
+
@dir[:prefix] = ENV['SystemDrive'] + @dir[:prefix] if Platform.is_windows?
|
42
|
+
end
|
43
|
+
|
44
|
+
# Examine the operating environment and set configuration options
|
45
|
+
def configure(project)
|
46
|
+
@project = project
|
47
|
+
printf 'checking for a BSD-compatible install.. '
|
48
|
+
if Platform.is_windows?
|
49
|
+
puts 'not found'
|
50
|
+
else
|
51
|
+
@path = search() or throw 'No installer found'
|
52
|
+
printf @path + "\n"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Parse command line options.
|
57
|
+
# Should only be called from Makeconf.parse_options()
|
58
|
+
def parse_options(opts)
|
59
|
+
opts.separator ""
|
60
|
+
opts.separator "Installation options:"
|
61
|
+
|
62
|
+
# Convert symbols to strings
|
63
|
+
tmp = {}
|
64
|
+
@dir.each { |k,v| tmp[k.to_s] = v }
|
65
|
+
|
66
|
+
tmp.sort.each do |k, v|
|
67
|
+
opts.on('--' + k + ' [DIRECTORY]', "TODO describe this [#{v}]") do |arg|
|
68
|
+
@dir[k.to_sym] = arg
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
# Register a file to be copied during the 'make install' phase.
|
75
|
+
def install(src)
|
76
|
+
buf = {
|
77
|
+
:sources => nil,
|
78
|
+
:dest => nil,
|
79
|
+
:rename => nil,
|
80
|
+
:directory? => false,
|
81
|
+
:group => nil,
|
82
|
+
:user => nil,
|
83
|
+
:mode => '0755',
|
84
|
+
}
|
85
|
+
#TODO: check for leading '/': raise ArgumentError, 'absolute path is required' unless src[:dest].index(0) == '/'
|
86
|
+
raise ArgumentError, ':dest is require' if src[:dest].nil?
|
87
|
+
raise ArgumentError, 'Cannot specify both directory and sources' \
|
88
|
+
if buf[:directory] == true and not buf[:sources].nil
|
89
|
+
@items.push buf.merge(src)
|
90
|
+
end
|
91
|
+
|
92
|
+
def to_make
|
93
|
+
mkdir_list = [] # all directories that have been created so far
|
94
|
+
|
95
|
+
m = Makefile.new
|
96
|
+
m.define_variable('INSTALL', '?=', @path) unless @path.nil?
|
97
|
+
|
98
|
+
# Add 'make install' rules
|
99
|
+
@items.each do |i|
|
100
|
+
# Automatically create the destination directory, if needed
|
101
|
+
destdir = expand_dir(i[:dest])
|
102
|
+
unless mkdir_list.include?(destdir)
|
103
|
+
m.add_rule('install', Platform.is_windows? ?
|
104
|
+
"dir $(DESTDIR)#{destdir} >NUL 2>NUL || mkdir $(DESTDIR)#{destdir}" :
|
105
|
+
"/usr/bin/test -e $(DESTDIR)#{destdir} || $(INSTALL) -d -m 755 $(DESTDIR)#{destdir}")
|
106
|
+
mkdir_list.push(destdir)
|
107
|
+
end
|
108
|
+
|
109
|
+
m.add_rule('install', install_command(i))
|
110
|
+
m.add_rule('uninstall', uninstall_command(i))
|
111
|
+
end
|
112
|
+
|
113
|
+
return m
|
114
|
+
end
|
115
|
+
|
116
|
+
private
|
117
|
+
|
118
|
+
# Expand makefile variables related to installation directories
|
119
|
+
def expand_dir(s)
|
120
|
+
buf = s
|
121
|
+
|
122
|
+
throw 'FIXME -- handle $(PACKAGE)' if buf =~ /\$\(PACKAGE\)/
|
123
|
+
while buf =~ /\$/
|
124
|
+
old = buf.dup
|
125
|
+
@dir.each do |k,v|
|
126
|
+
buf.gsub!(/\$\(#{k.to_s.upcase}\)/, v)
|
127
|
+
end
|
128
|
+
# Crude way of bailing out when there are undefined variables
|
129
|
+
# like $(DESTDIR)
|
130
|
+
break if old == buf and buf =~ /\$\(/
|
131
|
+
end
|
132
|
+
|
133
|
+
Platform.pathspec(buf)
|
134
|
+
end
|
135
|
+
|
136
|
+
# Translate an @item into the equivalent shell command(s)
|
137
|
+
def install_command(h)
|
138
|
+
res = []
|
139
|
+
h[:sources] = [ h[:sources] ] if h[:sources].kind_of? String
|
140
|
+
|
141
|
+
# TODO: more sanity checks (e.g. !h[:directory] && h[:sources])
|
142
|
+
|
143
|
+
if Platform.is_windows?
|
144
|
+
# XXX-this is not fully implemented, need mode/owner/group
|
145
|
+
if h[:directory]
|
146
|
+
res.push 'mkdir $(DESTDIR)' + expand_dir(h[:dest])
|
147
|
+
else
|
148
|
+
res.push "copy"
|
149
|
+
h[:sources].each do |src|
|
150
|
+
res.push Platform.pathspec(src)
|
151
|
+
end
|
152
|
+
res.push '$(DESTDIR)' + expand_dir(h[:dest])
|
153
|
+
end
|
154
|
+
else
|
155
|
+
res.push '$(INSTALL)'
|
156
|
+
res.push '-d' if h[:directory]
|
157
|
+
res.push('-m', h[:mode]) if h[:mode]
|
158
|
+
res.push('-o', h[:owner]) if h[:owner]
|
159
|
+
res.push('-g', h[:group]) if h[:group]
|
160
|
+
h[:sources].each do |src|
|
161
|
+
res.push Platform.pathspec(src)
|
162
|
+
end
|
163
|
+
dst = '$(DESTDIR)' + expand_dir(h[:dest])
|
164
|
+
dst += '/' + h[:rename] unless h[:rename].nil?
|
165
|
+
res.push dst
|
166
|
+
end
|
167
|
+
|
168
|
+
res.join(' ')
|
169
|
+
end
|
170
|
+
|
171
|
+
# Translate an @item into the equivalent uninstallation shell command(s)
|
172
|
+
def uninstall_command(h)
|
173
|
+
res = []
|
174
|
+
|
175
|
+
h[:sources] = [ h[:sources] ] if h[:sources].kind_of?(String)
|
176
|
+
|
177
|
+
# TODO: use Platform abstractions instead of duplicate logic
|
178
|
+
if Platform.is_windows?
|
179
|
+
unless h[:sources]
|
180
|
+
res.push 'del', Platform.pathspec('$(DESTDIR)' + h[:dest])
|
181
|
+
else
|
182
|
+
h[:sources].each do |src|
|
183
|
+
res.push 'del', Platform.pathspec('$(DESTDIR)' + h[:dest] + '/' + File.basename(src) )
|
184
|
+
end
|
185
|
+
end
|
186
|
+
else
|
187
|
+
unless h[:sources]
|
188
|
+
res.push 'rmdir', '$(DESTDIR)' + h[:dest]
|
189
|
+
else
|
190
|
+
res.push 'rm', '-f', h[:sources].map { |x| '$(DESTDIR)' + h[:dest] + '/' + x }
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
res.join(' ')
|
195
|
+
end
|
196
|
+
|
197
|
+
def search()
|
198
|
+
[ ENV['INSTALL'], '/usr/ucb/install', '/usr/bin/install' ].each do |x|
|
199
|
+
if !x.nil? and File.exists?(x)
|
200
|
+
return x
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# A generic Library class that builds both shared and static
|
2
|
+
|
3
|
+
class Library < Buildable
|
4
|
+
|
5
|
+
attr_reader :buildable
|
6
|
+
|
7
|
+
def initialize(options)
|
8
|
+
raise ArgumentError unless options.kind_of?(Hash)
|
9
|
+
@buildable = [SharedLibrary.new(options), StaticLibrary.new(options)]
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
class SharedLibrary < Buildable
|
15
|
+
|
16
|
+
def initialize(options)
|
17
|
+
raise ArgumentError unless options.kind_of?(Hash)
|
18
|
+
id = options[:id]
|
19
|
+
|
20
|
+
super(options)
|
21
|
+
@abi_major = 0
|
22
|
+
@abi_minor = 0
|
23
|
+
@output = id + Platform.shared_library_extension
|
24
|
+
@output_type = 'shared library'
|
25
|
+
#FIXME: @cc.ld.flags.push('-export-dynamic') unless Platform.is_solaris?
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
class StaticLibrary < Buildable
|
31
|
+
|
32
|
+
def initialize(options)
|
33
|
+
raise ArgumentError unless options.kind_of?(Hash)
|
34
|
+
id = options[:id]
|
35
|
+
super(options)
|
36
|
+
@output = id + Platform.static_library_extension
|
37
|
+
@output_type = 'static library'
|
38
|
+
|
39
|
+
# FIXME: clashes with shared objects
|
40
|
+
# src = d.sub(/-static#{Platform.object_extension}$/, '.c')
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
#
|
46
|
+
# UnionLibrary - combine multiple static libraries into a single library.
|
47
|
+
#
|
48
|
+
# The :sources for this library should be an array of Library objects
|
49
|
+
#
|
50
|
+
class UnionLibrary < Library
|
51
|
+
|
52
|
+
def initialize(options)
|
53
|
+
raise ArgumentError unless options.kind_of?(Hash)
|
54
|
+
@buildable = []
|
55
|
+
options[:sources].each do |x|
|
56
|
+
x.buildable.each do |y|
|
57
|
+
@buildable.push y if y.kind_of?(StaticLibrary)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
@buildable.flatten!
|
61
|
+
|
62
|
+
# Build a list of all source files within each component library
|
63
|
+
sources = []
|
64
|
+
@buildable.each { |x| sources.push x.sources }
|
65
|
+
sources.flatten!
|
66
|
+
|
67
|
+
@buildable.push StaticLibrary.new(
|
68
|
+
:id => options[:id],
|
69
|
+
:sources => sources
|
70
|
+
)
|
71
|
+
end
|
72
|
+
end
|