Class: Buildable

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

Overview

A buildable object like a library or executable

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options) ⇒ Buildable

Returns a new instance of Buildable.

Raises:

  • (ArgumentError)


10
11
12
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
# File 'lib/makeconf/buildable.rb', line 10

def initialize(options)
  raise ArgumentError unless options.kind_of?(Hash)
  default = {
      :id => options[:id],
      :enable => true,
      :buildable => true,
      :distributable => true,
      :installable => true,
      :extension => '',
      :cflags => [],
      :ldflags => [],
      :ldadd => [],
      :rpath => '',
      :topdir => '',
      :depends => [],
  }
  default.each do |k,v| 
    instance_variable_set('@' + k.to_s, v)
  end
  @output = id
  @output_type = nil      # filled in by the derived class

  # Local and system header dependencies for each @sources file
  # These are filled in by Compiler.makedepends()
  @localdep = {}
  @sysdep = {}

  # Filled in by sources=()
  @sources = []
  @source_code = {}

  # Parse options

  # FIXME- consider adding support for:
  #%w{name enable distributable installable extension
#   topdir rpath}

  log.debug "Buildable options: " + options.pretty_inspect
    
  options.each do |k,v|
    log.debug "k=#{k} v=#{v.to_s}"
    case k
    when :id
      @id = v
    when :cc
      @cc = v.clone
    when :cflags
      @cflags = v
      @cflags = [ @cflags ] if @cflags.kind_of?(String)
    when :ldflags
      @ldflags = v
    when :ldadd
      @ldadd.push(v).flatten!
    when :project
      @project = v
    when :buildable
      @buildable = v
    when :sources
      v = [ v ] if v.kind_of?(String)
      @sources = v
    else
      throw "Unrecognized option -- #{k}: #{v}"
    end
  end
  log.debug "Buildable parsed as: " + self.pretty_inspect

#FIXME: move some of these to the switch statement
#    # Parse simple textual child elements
#    %w{cflags ldflags ldadd depends sources}.each do |k|
#      instance_variable_set('@' + k, yaml[k]) if yaml.has_key? k
#    end

end

Instance Attribute Details

#buildableObject

Returns the value of attribute buildable.



4
5
6
# File 'lib/makeconf/buildable.rb', line 4

def buildable
  @buildable
end

#cflagsObject

Returns the value of attribute cflags.



4
5
6
# File 'lib/makeconf/buildable.rb', line 4

def cflags
  @cflags
end

#distributableObject

Returns the value of attribute distributable.



4
5
6
# File 'lib/makeconf/buildable.rb', line 4

def distributable
  @distributable
end

#enableObject

Returns the value of attribute enable.



4
5
6
# File 'lib/makeconf/buildable.rb', line 4

def enable
  @enable
end

#idObject

Returns the value of attribute id.



4
5
6
# File 'lib/makeconf/buildable.rb', line 4

def id
  @id
end

#installableObject

Returns the value of attribute installable.



4
5
6
# File 'lib/makeconf/buildable.rb', line 4

def installable
  @installable
end

#ldaddObject

Returns the value of attribute ldadd.



4
5
6
# File 'lib/makeconf/buildable.rb', line 4

def ldadd
  @ldadd
end

#localdepObject

Returns the value of attribute localdep.



4
5
6
# File 'lib/makeconf/buildable.rb', line 4

def localdep
  @localdep
end

#outputObject

Returns the value of attribute output.



4
5
6
# File 'lib/makeconf/buildable.rb', line 4

def output
  @output
end

#output_typeObject

Returns the value of attribute output_type.



4
5
6
# File 'lib/makeconf/buildable.rb', line 4

def output_type
  @output_type
end

#projectObject

Returns the value of attribute project.



4
5
6
# File 'lib/makeconf/buildable.rb', line 4

def project
  @project
end

#rpathObject

Returns the value of attribute rpath.



4
5
6
# File 'lib/makeconf/buildable.rb', line 4

def rpath
  @rpath
end

#sourcesObject

Returns the value of attribute sources.



4
5
6
# File 'lib/makeconf/buildable.rb', line 4

def sources
  @sources
end

#sysdepObject

Returns the value of attribute sysdep.



4
5
6
# File 'lib/makeconf/buildable.rb', line 4

def sysdep
  @sysdep
end

#topdirObject

Returns the value of attribute topdir.



4
5
6
# File 'lib/makeconf/buildable.rb', line 4

def topdir
  @topdir
end

Instance Method Details

#binary?Boolean

Returns:

  • (Boolean)


132
133
134
# File 'lib/makeconf/buildable.rb', line 132

def binary?
  @output_type =~ /binary/
end

#buildObject

Return a hash containing Makefile rules and targets needed to build the object.



142
143
144
145
146
147
148
149
150
151
152
153
154
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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/makeconf/buildable.rb', line 142

def build
  makefile = Makefile.new
  objs = []
  sources = expand_sources(@sources)

  # Don't do anything if we aren't going to be built
  return makefile unless @buildable

  # Allow ndk-build to create the object, for Android
  return makefile if SystemType.host =~ /-androideabi$/

  log.debug 'buildable = ' + self.pretty_inspect

  if sources.empty?
    pp self
    raise 'One or more source files are required' if sources.empty?
  end

  # Generate the targets and rules for each translation unit
  sources.each do |src|
    object_suffix = ''
    if library? 
      if library_type == :shared
#DEADWOOD:cflags.push '-fpic'
      else
        object_suffix = '-static'
      end
    end
    obj = src.sub(/.c$/, object_suffix + Platform.object_extension)
    cc = @project.cc.clone
    cc.shared_library = library? and library_type == :shared
    cc.flags = @cflags
    cc.output = obj
    cc.sources = src
    #TODO: cc.topdir = @topdir

    ld = cc.ld
    ld.flags = @ldflags
    @ldadd = [ @ldadd ] if @ldadd.kind_of?(String)
    @ldadd.each { |lib| ld.library lib }

    makefile.add_target(obj, [@project.config_h, src, localdep[src]].flatten, cc.rule)
    makefile.clean(obj)
    objs.push obj
  end

  # Generate the targets and rules for the link stage
  if library? and library_type == :static
     cmd = Platform.archiver(output, objs)
  else
    cc = @project.cc.clone
    cc.shared_library = library? and library_type == :shared
    cc.flags = @cflags
    cc.sources = sources
    cc.ld.flags = @ldflags
    @ldadd = [ @ldadd ] if @ldadd.kind_of?(String)
    @ldadd.each { |lib| cc.ld.library lib }
    cc.ld.output = @output
    cmd = cc.ld.rule 
  end
  makefile.add_target(output, objs, cmd)
  makefile.add_dependency('all', output)
  makefile.clean(output)
  makefile.distribute(sources) if distributable

  return makefile
end

#expand_sources(x) ⇒ Object



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

def expand_sources(x)
  log.info "expanding [#{x.to_s}] to source file list"
  raise ArgumentError('Wrong type') unless x.is_a? Array

  # Use glob(3) to expand the list of sources
  buf = []
  x.each do |src| 
    if src =~ /\*/
      buf << Dir.glob(src)
    else
      buf.push src
    end
  end
  buf.flatten

# TODO: elsewhere
  # Ensure that all source files exist
#@sources.each do |src|
#      throw ArgumentError("#{src} does not exist") unless File.exist? src
#    end

#XXX-lame
#    # Read all source code into a single array
#    @source_code = {}
#    @sources.each { |x| @source_code[x] = File.readlines(x) }

end

#finalizeObject



136
137
# File 'lib/makeconf/buildable.rb', line 136

def finalize
end

#library?Boolean

Returns:

  • (Boolean)


117
118
119
# File 'lib/makeconf/buildable.rb', line 117

def library?
  @output_type == 'shared library' or @output_type == 'static library'
end

#library_typeObject



121
122
123
124
125
126
127
128
129
130
# File 'lib/makeconf/buildable.rb', line 121

def library_type
  case @output_type
  when 'shared library'
  return :shared
  when 'static library'
  return :static
  else
  throw 'Not a library'
  end
end

#makedependsObject

Return a hash containing Makefile dependencies



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
# File 'lib/makeconf/buildable.rb', line 211

def makedepends
  res = []

  if @sources.nil?
     log.error self.to_s
     raise 'Missing sources'
  end

  # Generate the targets and rules for each translation unit
  expand_sources(@sources).each do |src|
    next if src =~ /\.o$/
    cc = @project.cc.clone
    cc.flags = [ @cflags, '-E' ]
    cc.output = '-'
    cc.sources = src
    #TODO: topdir
    cmd = cc.command + Platform.dev_null_stderr

    # TODO: do @sysdep also
    @localdep[src] = []
    IO.popen(cmd).each do |x|
      if x =~ /^# \d+ "([^\/<].*\.h)"/
        @localdep[src].push $1
      end
    end
    @localdep[src].sort!.uniq!
    res.concat @localdep[src]

    # Generate a list of system header dependencies
    # FIXME: does a lot of duplicate work reading files in..
    buf = []
    @sysdep[src] = []
    buf.concat File.readlines(src)
    @localdep[src].each do |x|
      if File.exist? x
        buf.concat File.readlines(x)
      end
    end
    buf.each do |x|
      begin
        if x =~ /^#\s*include\s+<(.*?)>/
          @sysdep[src].push $1
        end
      rescue ArgumentError
        # FIXME: should give more info about which file and line
        warn "** WARNING: invalid multibyte sequence encountered in one of the source code files:"
      end
    end
    @sysdep[src].sort!.uniq!

  end
  res
end

#objectsObject

Return the list of intermediate object files



113
114
115
# File 'lib/makeconf/buildable.rb', line 113

def objects
   expand_sources(@sources).map { |x| x.gsub(/\.c$/, '.o') }
end