Class: RakeOE::Toolchain

Inherits:
Object
  • Object
show all
Defined in:
lib/rakeoe/toolchain.rb

Overview

Toolchain specific key value reader

Author:

  • Daniel Schnell

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config) ⇒ Toolchain

Initializes object

Parameters:



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

def initialize(config)
  raise 'Configuration failure' unless config.checks_pass?

  @config = config

  begin
    @kvr = KeyValueReader.new(config.platform)
  rescue Exception => e
    puts e.message
    raise
  end

  @settings = @kvr.env
  fixup_env

  # save target platform of our compiler (gcc specific)
  if RbConfig::CONFIG["host_os"] != "mingw32"
    @target=`export PATH=#{@settings['PATH']} && #{@settings['CC']} -dumpmachine`.chop
  else
    @target=`PATH = #{@settings['PATH']} & #{@settings['CC']} -dumpmachine`.chop
  end

  @settings['TOUCH'] = 'touch'
  # XXX DS: we should only instantiate @qt if we have any qt settings
  @qt = QtSettings.new(self)
  set_build_vars()

  init_test_frameworks
  sanity
end

Instance Attribute Details

#configObject (readonly)

Returns the value of attribute config.



15
16
17
# File 'lib/rakeoe/toolchain.rb', line 15

def config
  @config
end

#qtObject (readonly)

Returns the value of attribute qt.



15
16
17
# File 'lib/rakeoe/toolchain.rb', line 15

def qt
  @qt
end

#settingsObject (readonly)

Returns the value of attribute settings.



15
16
17
# File 'lib/rakeoe/toolchain.rb', line 15

def settings
  @settings
end

#targetObject (readonly)

Returns the value of attribute target.



15
16
17
# File 'lib/rakeoe/toolchain.rb', line 15

def target
  @target
end

Instance Method Details

#app(params = {}) ⇒ Object

Creates application

Parameters:

  • params (Hash) (defaults to: {})

Options Hash (params):

  • :objects (Array)

    array of object file paths

  • :libs (Array)

    array of libraries that should be linked against

  • :app (String)

    application filename path

  • :settings (Hash)

    project specific settings

  • :includes (Array)

    include paths used



447
448
449
450
451
452
453
454
455
456
# File 'lib/rakeoe/toolchain.rb', line 447

def app(params = {})
  incs    = compiler_incs_for(params[:includes])
  ldflags = params[:settings]['ADD_LDFLAGS'] + ' ' + @settings['LDFLAGS']
  objs    = params[:objects].join(' ')
  libs    = linker_line_for(params[:libs])

  sh "#{@settings['SIZE']} #{objs} >#{params[:app]}.size" if @settings['SIZE']
  sh "#{@settings['CXX']} #{incs} #{objs} #{ldflags} #{libs} -o #{params[:app]} -Wl,-Map,#{params[:app]}.map"
  sh "#{@settings['OBJCOPY']} -O binary #{params[:app]} #{params[:app]}.bin"
end

#app_setting(name, setting) ⇒ Object

returns app project setting



125
126
127
# File 'lib/rakeoe/toolchain.rb', line 125

def app_setting(name, setting)
  @apps.get(name, setting)
end

#as_source_extensionsObject

returns assembler source extensions



140
141
142
# File 'lib/rakeoe/toolchain.rb', line 140

def as_source_extensions
  @config.suffixes[:as_sources].uniq
end

#build_dirObject

returns the build directory



70
71
72
# File 'lib/rakeoe/toolchain.rb', line 70

def build_dir
  "#{@config.directories[:build]}/#{@target}/#{@config.release}"
end

#c_header_extensionsObject

returns c header extensions



155
156
157
# File 'lib/rakeoe/toolchain.rb', line 155

def c_header_extensions
  @config.suffixes[:c_headers].uniq
end

#c_source_extensionsObject

returns c source extensions



135
136
137
# File 'lib/rakeoe/toolchain.rb', line 135

def c_source_extensions
  @config.suffixes[:c_sources].uniq
end

#compiler_incs_for(paths) ⇒ String

Generates compiler include line from given include path list

Parameters:

  • paths (Array)

    Paths to be used for include file search

Returns:

  • (String)

    Compiler include line



287
288
289
# File 'lib/rakeoe/toolchain.rb', line 287

def compiler_incs_for(paths)
  paths.each_with_object('') {|path, str| str << " -I#{path}"}
end

#config_empty_test_frameworkObject

Configures empty test framework



95
96
97
98
99
100
101
# File 'lib/rakeoe/toolchain.rb', line 95

def config_empty_test_framework
  @@test_framework[''] = TestFramework.new(:name         => '',
                                           :binary_path  => '',
                                           :include_dir  => '',
                                           :cflags       => '')

end

#cpp_header_extensionsObject

returns c++ header extensions



150
151
152
# File 'lib/rakeoe/toolchain.rb', line 150

def cpp_header_extensions
  (@config.suffixes[:cplus_headers] + [@config.suffixes[:moc_header]]).uniq
end

#cpp_source_extensionsObject

returns c++ source extensions



130
131
132
# File 'lib/rakeoe/toolchain.rb', line 130

def cpp_source_extensions
  (@config.suffixes[:cplus_sources] + [@config.suffixes[:moc_source]]).uniq
end

#current_platform_any?(platforms) ⇒ Boolean

Tests given list of platforms if any of those matches the current platform

Returns:

  • (Boolean)


277
278
279
# File 'lib/rakeoe/toolchain.rb', line 277

def current_platform_any?(platforms)
  ([@target] & platforms).any?
end

#default_test_frameworkObject

Returns default test framework or nil if none defined



104
105
106
# File 'lib/rakeoe/toolchain.rb', line 104

def default_test_framework
  test_framework(@config.test_fw) || test_framework('')
end

#dep(params = {}) ⇒ Object

Creates dependency

Parameters:

  • params (Hash) (defaults to: {})

Options Hash (params):

  • :source (String)

    source filename with path

  • :dep (String)

    dependency filename path

  • :settings (Hash)

    project specific settings

  • :includes (Array)

    include paths used



376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
# File 'lib/rakeoe/toolchain.rb', line 376

def dep(params = {})
  extension = File.extname(params[:source])
  dep       = params[:dep]
  source    = params[:source]
  incs      = compiler_incs_for(params[:includes]) + " #{@settings['LIB_INC']}"
  case
    when cpp_source_extensions.include?(extension)
      flags = @settings['CXXFLAGS'] + ' ' + params[:settings]['ADD_CXXFLAGS']
      compiler = "#{@settings['CXX']} -x c++ "
    when c_source_extensions.include?(extension)
      flags  = @settings['CFLAGS'] + ' ' + params[:settings]['ADD_CFLAGS']
      compiler = "#{@settings['CC']} -x c "
    when as_source_extensions.include?(extension)
      flags = ''
      compiler = "#{@settings['AS']}"
    else
      raise "unsupported source file extension (#{extension}) for creating dependency!"
  end
  sh "#{compiler} -MM #{flags} #{incs} -c #{source} -MT #{dep.ext('.o')} -MF #{dep}", silent: true
end

#dumpObject



478
479
480
481
# File 'lib/rakeoe/toolchain.rb', line 478

def dump
  print "Platform configuration: "
  @kvr.dump
end

#fixup_envObject

Specific fixups for toolchain



170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/rakeoe/toolchain.rb', line 170

def fixup_env
  # set system PATH if no PATH defined
  @settings['PATH'] ||= ENV['PATH']

  # replace $PATH
  @settings['PATH'] = @settings['PATH'].gsub('$PATH', ENV['PATH'])

  # create ARCH
  @settings['ARCH'] = "#{@settings['TARGET_PREFIX']}".chop

  # remove optimizations, we set these explicitly
  @settings['CXXFLAGS'] = "#{@settings['CXXFLAGS']} -DPROGRAM_VERSION=\\\"#{@config.sw_version}\\\"".gsub('-O2', '')
  @settings['CFLAGS'] = "#{@settings['CFLAGS']} -DPROGRAM_VERSION=\\\"#{@config.sw_version}\\\"".gsub('-O2', '')
  KeyValueReader.substitute_dollar_symbols!(@settings)
end

#init_test_frameworksObject

Initializes definitions for test framework TODO: Add possibility to configure test framework specific CFLAGS/CXXFLAGS



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/rakeoe/toolchain.rb', line 77

def init_test_frameworks()
  @@test_framework ||= Hash.new

  config_empty_test_framework

  if @config.test_fw.size > 0
    if PrjFileCache.contain?('LIB', @config.test_fw)
      @@test_framework[@config.test_fw] = TestFramework.new(:name         => @config.test_fw,
                                                            :binary_path  => "#{@settings['LIB_OUT']}/lib#{@config.test_fw}.a",
                                                            :include_dir  => PrjFileCache.exported_lib_incs(@config.test_fw),
                                                            :cflags       => '')
    else
        puts "WARNING: Configured test framework (#{@config.test_fw}) does not exist in project!"
    end
  end
end

#lib(params = {}) ⇒ Object

Creates library

Parameters:

  • params (Hash) (defaults to: {})

Options Hash (params):

  • :objects (Array)

    object filename paths

  • :lib (String)

    library filename path

  • :settings (Hash)

    project specific settings



419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
# File 'lib/rakeoe/toolchain.rb', line 419

def lib(params = {})
  ldflags   = params[:settings]['ADD_LDFLAGS'] + ' ' + @settings['LDFLAGS']
  objs      = params[:objects].join(' ')
  libs      = linker_line_for(params[:libs])
  extension = File.extname(params[:lib])

  case extension
    when ('.a')
      # need to use 'touch' for correct timestamp, ar doesn't update the timestamp
      # if archive hasn't changed
      sh "#{@settings['AR']} curv #{params[:lib]} #{objs} && #{@settings['TOUCH']} #{params[:lib]}"
    when '.so'
      sh "#{@settings['CXX']} -shared  #{ldflags} #{libs} #{objs} -o #{params[:lib]}"
    else
      raise "unsupported library extension (#{extension})!"
  end
end

#lib_setting(name, setting) ⇒ Object

returns library project setting



120
121
122
# File 'lib/rakeoe/toolchain.rb', line 120

def lib_setting(name, setting)
  @libs.get(name, setting)
end

#linker_line_for(libs) ⇒ String

Generates linker line from given library list.

Parameters:

  • libs (Array)

    Libraries to be used for linker line

Returns:

  • (String)

    Linker line



297
298
299
300
301
302
303
304
305
306
307
308
309
# File 'lib/rakeoe/toolchain.rb', line 297

def linker_line_for(libs)
  return '' if (libs.nil? || libs.empty?)
  libs.map do |lib|
    settings = platform_settings_for(lib)
    if settings[:LDFLAGS].nil?
      # automatic linker line if no platform specific LDFLAGS exist
      "-l#{lib}"
    else
      # only matches -l<libname> settings
      /(\s|^)+-l\S+/.match(settings[:LDFLAGS]).to_s
    end
  end.join(' ').strip
end

#moc(params = {}) ⇒ Object

Creates moc_ source file

Parameters:

  • params (Hash) (defaults to: {})

Options Hash (params):

  • :source (String)

    source filename with path

  • :moc (String)

    moc_XXX filename path

  • :settings (Hash)

    project specific settings



405
406
407
408
409
# File 'lib/rakeoe/toolchain.rb', line 405

def moc(params = {})
  moc_compiler = @settings['OE_QMAKE_MOC']
  raise 'No Qt Toolchain set' if moc_compiler.empty?
  sh "#{moc_compiler} -i -f#{File.basename(params[:source])} #{params[:source]} >#{params[:moc]}"
end

#moc_header_extensionObject

returns moc header extensions



160
161
162
# File 'lib/rakeoe/toolchain.rb', line 160

def moc_header_extension
  @config.suffixes[:moc_header]
end

#moc_sourceObject

returns c++ header extensions



165
166
167
# File 'lib/rakeoe/toolchain.rb', line 165

def moc_source
  @config.suffixes[:moc_source]
end

#obj(params = {}) ⇒ Object

Creates compilation object

Parameters:

  • params (Hash) (defaults to: {})

Options Hash (params):

  • :source (String)

    source filename with path

  • :object (String)

    object filename path

  • :settings (Hash)

    project specific settings

  • :includes (Array)

    include paths used



345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
# File 'lib/rakeoe/toolchain.rb', line 345

def obj(params = {})
  extension = File.extname(params[:source])
  object    = params[:object]
  source    = params[:source]
  incs      = compiler_incs_for(params[:includes]) + " #{@settings['LIB_INC']}"

  case
    when cpp_source_extensions.include?(extension)
      flags = @settings['CXXFLAGS'] + ' ' + params[:settings]['ADD_CXXFLAGS']
      compiler = "#{@settings['CXX']} -x c++ "
    when c_source_extensions.include?(extension)
      flags = @settings['CFLAGS'] + ' ' + params[:settings]['ADD_CFLAGS']
      compiler = "#{@settings['CC']} -x c "
    when as_source_extensions.include?(extension)
      flags = ''
      compiler = "#{@settings['AS']}"
    else
      raise "unsupported source file extension (#{extension}) for creating object!"
  end
  sh "#{compiler} #{flags} #{incs} -c #{source} -o #{object}"
end

#platform_settings_for(resource_name) ⇒ Hash

Returns platform specific settings of a resource (APP/LIB/SOLIB or external resource like e.g. an external library) as a hash with the keys CFLAGS, CXXFLAGS and LDFLAGS. The values are empty if no such resource settings exist inside the platform file. The resulting hash values can be used for platform specific compilation/linkage against the the resource.

Parameters:

  • resource_name (String)

    name of resource

Returns:

  • (Hash)

    Hash of compilation/linkage flags or empty hash if no settings are defined The returned hash has the following format: { :CFLAGS => ‘…’, :CXXFLAGS => ‘…’, :LDFLAGS => ‘…’}



326
327
328
329
330
331
332
333
334
335
# File 'lib/rakeoe/toolchain.rb', line 326

def platform_settings_for(resource_name)
  return {} if resource_name.empty?

  rv = Hash.new
  rv[:CFLAGS]  = @settings["#{resource_name}_CFLAGS"]
  rv[:CXXFLAGS]= @settings["#{resource_name}_CXXFLAGS"]
  rv[:LDFLAGS] = @settings["#{resource_name}_LDFLAGS"]
  rv = {} if rv.values.empty?
  rv
end

#rm(files) ⇒ Object

Removes list of given files

Parameters:

  • files (String)

    List of files to be deleted



243
244
245
246
247
# File 'lib/rakeoe/toolchain.rb', line 243

def rm(files)
  if files
    Rake::sh "rm -f #{files}" unless files.empty?
  end
end

#run(binary) ⇒ Object

Executes a given binary

Parameters:

  • binary (String)

    Absolute path of the binary to be executed



254
255
256
257
258
259
260
261
# File 'lib/rakeoe/toolchain.rb', line 254

def run(binary)
  # compare ruby platform config and our target setting
  if @target[RbConfig::CONFIG["target_cpu"]]
    system "export LD_LIBRARY_PATH=#{@settings['LD_LIBRARY_PATH']} && #{binary}"
  else
    puts "Warning: Can't execute on this platform: #{binary}"
  end
end

#run_junit_test(binary) ⇒ Object

Executes a given test binary with test runner specific parameter(s)

Parameters:

  • binary (String)

    Absolute path of the binary to be executed



267
268
269
270
271
272
273
274
# File 'lib/rakeoe/toolchain.rb', line 267

def run_junit_test(binary)
  # compare ruby platform config and our target setting
  if @target[RbConfig::CONFIG["target_cpu"]]
    system "export LD_LIBRARY_PATH=#{@settings['LD_LIBRARY_PATH']} && #{binary} -o junit"
  else
    puts "Warning: Can't execute test on this platform: #{binary}"
  end
end

#sanityObject

Do some sanity checks



54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/rakeoe/toolchain.rb', line 54

def sanity
  # TODO DS: check if libs and apps directories exist
  # TODO DS: check if test frameworks exist
  # check if target is valid

  if @settings['CC'].empty?
    raise "No Compiler specified. Either add platform configuration via RakeOE::Config object in Rakefile or use TOOLCHAIN_ENV environment variable"
  end

  if @target.nil? || @target.empty?
    raise "Compiler #{@settings['CC']} does not work. Fix platform settings or use TOOLCHAIN_ENV environment variable "
  end

end

#set_build_varsObject

Set common build variables

Parameters:

  • release_mode (String)

    Release mode used for the build, either ‘release’ or ‘dbg’



190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# File 'lib/rakeoe/toolchain.rb', line 190

def set_build_vars()
  warning_flags = ' -W -Wall'
  if 'release' == @config.release
    optimization_flags = " #{@config.optimization_release} -DRELEASE"
  else
    optimization_flags = " #{@config.optimization_dbg} -g"
  end

  # we could make these also arrays of source directories ...
  @settings['APP_SRC_DIR'] = 'src/app'
  @settings['LIB_SRC_DIR'] = 'src/lib'

  # derived settings
  @settings['BUILD_DIR'] = "#{build_dir}"
  @settings['LIB_OUT'] = "#{@settings['BUILD_DIR']}/libs"
  @settings['APP_OUT'] = "#{@settings['BUILD_DIR']}/apps"
  unless @settings['OECORE_TARGET_SYSROOT'].nil? || @settings['OECORE_TARGET_SYSROOT'].empty?
    @settings['SYS_LFLAGS'] = "-L#{@settings['OECORE_TARGET_SYSROOT']}/lib -L#{@settings['OECORE_TARGET_SYSROOT']}/usr/lib"
  end

  # set LD_LIBRARY_PATH
  @settings['LD_LIBRARY_PATH'] = @settings['LIB_OUT']

  # standard settings
  @settings['CXXFLAGS'] += warning_flags + optimization_flags + " #{@config.language_std_cpp}"
  @settings['CFLAGS'] += warning_flags + optimization_flags + " #{@config.language_std_c}"
  if @settings['PRJ_TYPE'] == 'SOLIB'
    @settings['CXXFLAGS'] += ' -fPIC'
    @settings['CFLAGS'] += ' -fPIC'
  end
  # !! don't change order of the following string components without care !!
  @settings['LDFLAGS'] = @settings['LDFLAGS'] + " -L #{@settings['LIB_OUT']} #{@settings['SYS_LFLAGS']} -Wl,--no-as-needed -Wl,--start-group"
end

#sh(cmd, silent = false) ⇒ Object

Executes the command



225
226
227
228
229
230
231
232
233
234
235
236
237
238
# File 'lib/rakeoe/toolchain.rb', line 225

def sh(cmd, silent = false)

  if RbConfig::CONFIG["host_os"] != "mingw32"
    full_cmd = "export PATH=#{@settings['PATH']} && #{cmd}"
  else
    full_cmd = "PATH = #{@settings['PATH']} & #{cmd}"
  end

  if silent
    system full_cmd
  else
    Rake::sh full_cmd
  end
end

#source_extensionsObject

returns all source extensions



145
146
147
# File 'lib/rakeoe/toolchain.rb', line 145

def source_extensions
  cpp_source_extensions + c_source_extensions + as_source_extensions
end

#test(params = {}) ⇒ Object

Creates test

Parameters:

  • params (Hash) (defaults to: {})

Options Hash (params):

  • :objects (Array)

    array of object file paths

  • :libs (Array)

    array of libraries that should be linked against

  • :framework (String)

    test framework name

  • :test (String)

    test filename path

  • :settings (Hash)

    project specific settings

  • :includes (Array)

    include paths used



468
469
470
471
472
473
474
475
476
# File 'lib/rakeoe/toolchain.rb', line 468

def test(params = {})
  incs    = compiler_incs_for(params[:includes])
  ldflags = params[:settings]['ADD_LDFLAGS'] + ' ' +  @settings['LDFLAGS']
  objs    = params[:objects].join(' ')
  test_fw = linker_line_for([params[:framework]])
  libs    = linker_line_for(params[:libs])

  sh "#{@settings['CXX']} #{incs} #{objs} #{test_fw} #{ldflags} #{libs} -o #{params[:test]}"
end

#test_framework(name) ⇒ Object

Returns definitions of specific test framework or none if specified test framework doesn’t exist



110
111
112
# File 'lib/rakeoe/toolchain.rb', line 110

def test_framework(name)
  @@test_framework[name]
end

#test_frameworksObject

Returns list of all registered test framework names



115
116
117
# File 'lib/rakeoe/toolchain.rb', line 115

def test_frameworks
  @@test_framework.keys
end

#touch(file) ⇒ Object

Touches a file



312
313
314
# File 'lib/rakeoe/toolchain.rb', line 312

def touch(file)
  sh "#{@settings['TOUCH']} #{file}"
end