Class: BaseProject

Inherits:
Object
  • Object
show all
Defined in:
lib/makeconf/baseproject.rb

Overview

A project contains all of the information about the build. This is the base class from which all other Project subclasses are built

Direct Known Subclasses

AndroidProject

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options) {|_self| ... } ⇒ BaseProject

Called by the object constructor

Yields:

  • (_self)

Yield Parameters:

  • _self (BaseProject)

    the object that the method was called on

Raises:

  • (ArgumentError)


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
# File 'lib/makeconf/baseproject.rb', line 21

def initialize(options)
  raise ArgumentError unless options.kind_of?(Hash)
  @id = 'myproject'
  @version = '0.1'
  @summary = 'Undefined project summary'
  @description = 'Undefined project description'
  @license = 'Unknown license'
  @license_file = nil
  @author = 'Unknown author'
  @config_h = 'config.h'
  @config_h_rules = [] # Makefile rules to generate config.h
  @header = {}        # Hash of system header availablity
  @build = []         # List of items to build
  @distribute = []    # List of items to distribute
  @install = []       # List of items to install
  @target = []        # List of additional Makefile targets
  @decls = {}         # List of declarations discovered via check_decl()
  @funcs = {}         # List of functions discovered via check_func()
  @defs = {}          # Custom preprocessor macro definitions
  @packager = Packager.new(self)
  @cc = nil

  # Provided by the parent Makeconf object
  @installer = nil
  @makefile = nil

#    # Initialize missing variables to be empty Arrays 
#    [:manpages, :headers, :libraries, :tests, :check_decls, :check_funcs,
#     :extra_dist, :targets, :binaries].each do |k|
#       h[k] = [] unless h.has_key? k
#       h[k] = [ h[k] ] if h[k].kind_of?(String)
#    end
#    h[:scripts] = {} unless h.has_key?(:scripts)

   # Generate a hash containing all the different element types
   #items = {}
   #%w{manpage header library binary test check_decl check_func extra_dist targets}.each do |k|
   #  items[k] = xml.elements[k] || []
   #end

   options.each do |key,val|
      #p "key=#{key} val=#{val}"
     case key
     when :id
       @id = val
     when :version
       @version = val.to_s
     when :cc
       @cc = val
     when :license_file
       @license_file = val
     when 'library', 'libraries'
       val.each do |id, e|
         build SharedLibrary.new(id, @cc.clone).parse(e)
         build StaticLibrary.new(id, @cc.clone).parse(e)
       end
     when 'manpage'
        manpage(val)  
     when 'header'
        header(val)  
     when 'extra_dist'
        distribute val 
     when 'targets'
        target val
     when 'script', 'check_decl', 'check_func'
        throw 'FIXME'
          #items['script'].each { |k,v| script(k,v) }
          #items['check_decl'].each { |id,decl| check_decl(id,decl) }
#items['check_func'].each { |f| check_func(f) }
     else
        throw "Unknown option -- #{key}: #{val}"
     end
   end

  # Determine the path to the license file
  if @license_file.nil?
    %w{COPYING LICENSE}.each do |p|
      if File.exists?(p)
          @license_file = p
          break
      end
    end
  end

  @cc ||= CCompiler.new 


  yield self if block_given?
end

Instance Attribute Details

#authorObject

Returns the value of attribute author.



8
9
10
# File 'lib/makeconf/baseproject.rb', line 8

def author
  @author
end

#ccObject (readonly)

Returns the value of attribute cc.



11
12
13
# File 'lib/makeconf/baseproject.rb', line 11

def cc
  @cc
end

#config_hObject

Returns the value of attribute config_h.



8
9
10
# File 'lib/makeconf/baseproject.rb', line 8

def config_h
  @config_h
end

#descriptionObject

Returns the value of attribute description.



8
9
10
# File 'lib/makeconf/baseproject.rb', line 8

def description
  @description
end

#idObject

Returns the value of attribute id.



8
9
10
# File 'lib/makeconf/baseproject.rb', line 8

def id
  @id
end

#installerObject

KLUDGE: remove these if possible



14
15
16
# File 'lib/makeconf/baseproject.rb', line 14

def installer
  @installer
end

#licenseObject

Returns the value of attribute license.



8
9
10
# File 'lib/makeconf/baseproject.rb', line 8

def license
  @license
end

#license_fileObject

Returns the value of attribute license_file.



8
9
10
# File 'lib/makeconf/baseproject.rb', line 8

def license_file
  @license_file
end

#makefileObject

KLUDGE: remove these if possible



14
15
16
# File 'lib/makeconf/baseproject.rb', line 14

def makefile
  @makefile
end

#packagerObject

KLUDGE: remove these if possible



14
15
16
# File 'lib/makeconf/baseproject.rb', line 14

def packager
  @packager
end

#summaryObject

Returns the value of attribute summary.



8
9
10
# File 'lib/makeconf/baseproject.rb', line 8

def summary
  @summary
end

#versionObject

Returns the value of attribute version.



8
9
10
# File 'lib/makeconf/baseproject.rb', line 8

def version
  @version
end

Instance Method Details

#add(*objs) ⇒ Object



270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/makeconf/baseproject.rb', line 270

def add(*objs)
  objs.each do |obj|
    if obj.kind_of?(Library)
      obj.buildable.each do |e|
         add(e)
      end
    else
      obj.project = self if obj.kind_of?(Buildable)
      build(obj)
    end
  end
end

#add_binary(options) ⇒ Object



264
265
266
267
268
# File 'lib/makeconf/baseproject.rb', line 264

def add_binary(options)
  options[:cc] ||= @cc
  id = options[:id] + Platform.executable_extension
  build Binary.new(options)
end

#build(*arg) ⇒ Object

Add item(s) to build FIXME: this violates OOP encapsulation



285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
# File 'lib/makeconf/baseproject.rb', line 285

def build(*arg)
  arg.each do |x|

    # Add a custom Makefile target
    if x.kind_of? Target
        @target.push x
        next
    end

    unless x.respond_to?(:build)
      pp x
      throw ArgumentError.new('Invalid argument') 
    end

    if x.kind_of?(SharedLibrary) or x.kind_of?(StaticLibrary)
      dest = '$(LIBDIR)'
    else
      dest = '$(BINDIR)'
    end
    sources = x.output
    mode = '0755'

    @build.push x

    next if x.kind_of?(Header) #ugly

    @install.push({ 
      :sources => sources,
      :dest => dest,
      :mode => mode,
      }) if x.installable
  end
end

#check_decl(decl, opt = { :include => 'stdlib.h' }) ⇒ Object

Check if a system header declares a macro or symbol



212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
# File 'lib/makeconf/baseproject.rb', line 212

def check_decl(decl, opt = { :include => 'stdlib.h' })
    decl = [ decl ] if decl.kind_of? String
    throw ArgumentError unless decl.kind_of? Array
    rc = true

    decl.each do |x|
      next if @decls.has_key? x
      printf "checking whether #{x} is declared... "
      source = [
       "#define _GNU_SOURCE",
       "#include <#{opt[:include]}>",
       "int main() { #{x}; }"
       ].join("\n")
      @decls[x] = @cc.test_compile(source)
      if @decls[x]
        puts 'yes'
      else
        puts 'no'
        rc = false
      end
    end

    rc
end

#check_function(func, *arg) ⇒ Object

Check if a function is available in the standard C library TODO: probably should add :ldadd when checking..



239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
# File 'lib/makeconf/baseproject.rb', line 239

def check_function(func, *arg)
    func = [ func ] if func.kind_of? String
    throw ArgumentError unless func.kind_of? Array
    rc = true

    func.each do |x|
      next if @funcs.has_key? x
      printf "checking for #{x}... "
      @funcs[x] = @cc.test_link "void *#{x}();\nint main() { void *p;\np = &#{x}; }"
      if @funcs[x] 
        puts 'yes'
      else
        puts 'no'
        rc = false
      end
    end

    rc
end

#check_header(headers) ⇒ Object

Check if a system header file is available



192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/makeconf/baseproject.rb', line 192

def check_header(headers)
    headers = [ headers ] if headers.kind_of? String
    throw ArgumentError unless headers.kind_of? Array
    rc = true

    headers.each do |header|
      printf "checking for #{header}... "
      @header[header] = @cc.check_header(header)
      if @header[header]
        puts 'yes'
      else
        puts 'no'
        rc = false
      end
    end

    rc
end

#compiler(language = 'C') ⇒ Object

Return the compiler associated with the project



367
368
369
370
371
# File 'lib/makeconf/baseproject.rb', line 367

def compiler(language = 'C')
  throw 'Not implemented' if language != 'C'
  throw 'Undefined compiler' if @cc.nil?
  @cc
end

#configureObject

Examine the operating environment and set configuration options



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
149
150
151
# File 'lib/makeconf/baseproject.rb', line 120

def configure

  preconfigure if respond_to? 'preconfigure'

  # Run each buildable object's preconfigure() method
  @build.each { |x| x.preconfigure if x.respond_to? 'preconfigure' }

  # Run each buildable object's configure() method
  @build.each { |x| x.configure if x.respond_to? 'configure' }

  postconfigure if respond_to? 'postconfigure'

  # Run each buildable object's postconfigure() method
  @build.each { |x| x.postconfigure if x.respond_to? 'postconfigure' }

  # Build a list of local headers
  local_headers = []
  @build.each do |x| 
    local_headers.concat x.makedepends
  end
  local_headers.sort!.uniq!

  # Test for the existence of each referenced system header
  sysdeps.each do |header|
    printf "checking for #{header}... "
    @header[header] = @cc.check_header(header)
    puts @header[header] ? 'yes' : 'no'
  end

#    make_installable(@ast['data'], '$(PKGDATADIR)')
#    make_installable(@ast['manpages'], '$(MANDIR)') #FIXME: Needs a subdir
end

#define(id, value) ⇒ Object

Define a C preprocessor symbol



260
261
262
# File 'lib/makeconf/baseproject.rb', line 260

def define(id,value)
  @defs[id] = value
end

#distfileObject

Returns the filename of the source code distribution archive



389
390
391
# File 'lib/makeconf/baseproject.rb', line 389

def distfile
  @id + '-' + @version.to_s + '.tar.gz'
end

#distribute(*arg) ⇒ Object

Add item(s) to distribute in the source tarball



328
329
330
331
332
# File 'lib/makeconf/baseproject.rb', line 328

def distribute(*arg)
  arg.each do |x|
    @distribute.push Dir.glob(x)
  end
end

#finalizeObject



185
186
187
188
189
# File 'lib/makeconf/baseproject.rb', line 185

def finalize
  @packager.finalize
  @build.each { |x| x.finalize }
  @install.each { |x| @installer.install x }
end

#header(path, opt = {}) ⇒ Object

Add a C/C++ header file to be installed



335
336
337
338
339
340
341
342
# File 'lib/makeconf/baseproject.rb', line 335

def header(path, opt = {})
  throw ArgumentError, 'bad options' unless opt.kind_of? Hash
  @install.push({ 
      :sources => path,
      :dest => (opt[:dest].nil? ? '$(INCLUDEDIR)' : opt[:dest]),
      :mode => '0644',
      })
end

#install(*arg) ⇒ Object

Add item(s) to install



320
321
322
323
324
325
# File 'lib/makeconf/baseproject.rb', line 320

def install(*arg)
  arg.each do |x|
    # FIXME: shouldn't something be installed now?
    @distribute.push Dir.glob(x)
  end
end

#library(id) ⇒ Object

Return a library definition



374
375
376
# File 'lib/makeconf/baseproject.rb', line 374

def library(id)
  @ast['libraries'][id]
end

#logObject



16
17
18
# File 'lib/makeconf/baseproject.rb', line 16

def log
  Makeconf.logger
end

#manpage(path, opt = {}) ⇒ Object

Add a manpage file to be installed



345
346
347
348
349
350
351
352
353
# File 'lib/makeconf/baseproject.rb', line 345

def manpage(path, opt = {})
  throw ArgumentError, 'bad options' unless opt.kind_of? Hash
  section = path.gsub(/.*\./, '')
  @install.push({ 
      :sources => path,
      :dest => (opt[:dest].nil? ? "$(MANDIR)/man#{section}" : opt[:dest]),
      :mode => '0644',
      })
end

#mount(uri, subdir) ⇒ Object

XXX fixme – testing



425
426
427
428
# File 'lib/makeconf/baseproject.rb', line 425

def mount(uri,subdir)
  x = Net::HTTP.get(URI(uri))
  puts x.length
end

#parse_options(opts) ⇒ Object

Parse ARGV options Should only be called from Makeconf.parse_options()



113
114
115
116
117
# File 'lib/makeconf/baseproject.rb', line 113

def parse_options(opts)
  opts.separator ""
  opts.separator "Project options:"
#none yet
end

#provides?(path) ⇒ Boolean

Test if the project will build a library with a given pathname. This is used for inter-dependency analysis

Returns:

  • (Boolean)


432
433
434
435
436
437
438
439
440
# File 'lib/makeconf/baseproject.rb', line 432

def provides?(path)
  fn = File.basename(path)
  @build.each do |obj|
     if obj.respond_to?(:output)
       return true if obj.output == fn
     end
  end
  return false
end

#script(id, opt = {}) ⇒ Object

Add a script to be installed



356
357
358
359
360
361
362
363
364
# File 'lib/makeconf/baseproject.rb', line 356

def script(id, opt = {})
  throw ArgumentError, 'bad options' unless opt.kind_of? Hash
  @install.push({ 
      :sources => opt[:sources],
      :dest => (opt[:dest].nil? ? "$(BINDIR)" : opt[:dest]),
      :rename => opt[:rename],
      :mode => '0755',
      })
end

#sysdepsObject

Return a list of all system header dependencies for all Buildable objects in the project.



380
381
382
383
384
385
386
# File 'lib/makeconf/baseproject.rb', line 380

def sysdeps
  res = []
  @build.each do |x|
    x.sysdep.each { |k,v| res.concat v }
  end
  res.sort.uniq
end

#target(t) ⇒ Object

Add an additional Makefile target



419
420
421
422
# File 'lib/makeconf/baseproject.rb', line 419

def target(t)
  throw ArgumentError.new('Invalid data type') unless t.kind_of?(Target) 
  @target.push t
end

#to_makeObject

Return the Makefile for the project This should only be done after finalize() has been called.



155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/makeconf/baseproject.rb', line 155

def to_make
  makefile = Makefile.new

  makefile.add_dependency('dist', distfile)
  makefile.distclean(distfile)
  makefile.distclean(@config_h)
  makefile.merge!(@cc.makefile)
  makefile.merge!(@packager.makefile)
  makefile.make_dist(@id, @version)
  @distribute.each { |f| @makefile.distribute f }
  @build.each { |x| makefile.merge!(x.build) if x.enable }
  makefile.merge! @installer.to_make

  # Add custom targets
  @target.each { |t| makefile.add_target t }

  # Add the config.h target
  @config_h_rules.unshift \
      '@echo "/* AUTOMATICALLY GENERATED -- DO NOT EDIT */" > config.h.tmp',
      '@date > config.log'
  @config_h_rules.push \
      '@rm -f conftest.c conftest.o',
      '@mv config.h.tmp ' + @config_h
  makefile.add_target Target.new('config.h', [], @config_h_rules) 

  makefile.distribute 'Makefile'

  makefile
end

#write_config_hObject

Generate the config.h header file



394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
# File 'lib/makeconf/baseproject.rb', line 394

def write_config_h
  ofile = @config_h
  buf = {}

  @header.keys.sort.each { |k| buf["HAVE_#{k}".upcase] = @header[k] }
  @decls.keys.sort.each { |x| buf["HAVE_DECL_#{x}".upcase] = @decls[x] }
  @funcs.keys.sort.each { |x| buf["HAVE_#{x}".upcase] = @funcs[x] }
  @defs.keys.sort.each { |x| buf[x] = @defs[x] }

  puts 'creating ' + ofile
  f = File.open(ofile, 'w')
  f.print "/* AUTOMATICALLY GENERATED -- DO NOT EDIT */\n"
  buf.keys.sort.each do |k|
    v = buf[k]
    id = k.upcase.gsub(%r{[/.-]}, '_')
    if v == true
      f.printf "#define #{id} 1\n"
    else
      f.printf "/* #undef  #{id} */\n" 
    end
  end
  f.close
end