Module: Cxxproject::HasSources

Included in:
Linkable, SingleSource, StaticLibrary
Defined in:
lib/cxxproject/buildingblocks/has_sources_mixin.rb

Overview

users of this module can implement no_sources_found() to handle cases where no sources are given

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#file_dependenciesObject



14
15
16
# File 'lib/cxxproject/buildingblocks/has_sources_mixin.rb', line 14

def file_dependencies
  @file_dependencies ||= []
end

#incArrayObject (readonly)

Returns the value of attribute incArray.



12
13
14
# File 'lib/cxxproject/buildingblocks/has_sources_mixin.rb', line 12

def incArray
  @incArray
end

Instance Method Details

#add_to_sources_to_build(sources_to_build, excluded_files, sources, alternative_toolchain = nil) ⇒ Object



183
184
185
186
187
188
189
190
# File 'lib/cxxproject/buildingblocks/has_sources_mixin.rb', line 183

def add_to_sources_to_build(sources_to_build, excluded_files, sources, alternative_toolchain=nil)
  sources.each do |f|
    next if excluded_files.include?(f)
    next if sources_to_build.has_key?(f)
    t = tcs4source(f) || alternative_toolchain
    sources_to_build[f] = t
  end
end

#additional_object_file_flagsObject



304
305
306
# File 'lib/cxxproject/buildingblocks/has_sources_mixin.rb', line 304

def additional_object_file_flags
  []
end

#apply_depfile(depfile, outfileTask) ⇒ Object



165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/cxxproject/buildingblocks/has_sources_mixin.rb', line 165

def apply_depfile(depfile,outfileTask)
  deps = nil
  begin
    deps = YAML.load_file(depfile)
    deps.each do |d|
      deps_in_depFiles << d
      f = file d
      f.ignore_missing_file
    end
    outfileTask.enhance(deps)
  rescue
    # may happen if depfile was not converted the last time
    def outfileTask.needed?
      true
    end
  end
end

#calc_command_line_for_source(source, toolchain) ⇒ Object



255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
# File 'lib/cxxproject/buildingblocks/has_sources_mixin.rb', line 255

def calc_command_line_for_source(source, toolchain)
  if !File.exists?(source)
    raise "File '#{source}' not found"
  end
  if File.is_absolute?(source)
    source = File.rel_from_to_project(@project_dir, source, false)
  end

  type = get_source_type(source)
  raise "Unknown filetype for #{source}" unless type

  object = get_object_file(source)
  object_path = File.expand_path(object)
  source_path = File.expand_path(source)

  @objects << object

  depStr = ""
  dep_file = nil
  if type != :ASM
    dep_file = get_dep_file(object)
    dep_file = "\""+dep_file+"\"" if dep_file.include?(" ")
    depStr = toolchain[:COMPILER][type][:DEP_FLAGS]
  end

  compiler = toolchain[:COMPILER][type]
  i_array = toolchain == @tcs ? @include_string[type] : get_include_string(toolchain, type)
  d_array = toolchain == @tcs ? @define_string[type] : get_define_string(toolchain, type)

  cmd = [compiler[:COMMAND]].flatten
  cmd += compiler[:COMPILE_FLAGS].split(" ")
  if dep_file
    cmd += depStr.split(" ")
    if toolchain[:COMPILER][type][:DEP_FLAGS_SPACE]
      cmd << dep_file
    else
      cmd[cmd.length-1] << dep_file
    end
  end
  cmd += compiler[:FLAGS]
  cmd += additional_object_file_flags
  cmd += i_array
  cmd += d_array
  cmd += (compiler[:OBJECT_FILE_FLAG] + object).split(" ")
  cmd += compiler[:PREPRO_FLAGS].split(" ") if Rake::application.preproFlags
  cmd << source
  return [cmd, source_path, object, object_path, compiler, type]
end

#calc_compiler_stringsObject



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
# File 'lib/cxxproject/buildingblocks/has_sources_mixin.rb', line 74

def calc_compiler_strings()
  @include_string = {}
  @define_string = {}

  @incArray = local_includes.dup
  @incArray.concat(includes)

  if Rake::application.deriveIncludes
    all_dependencies.each_with_index do |d,i|
      next if not HasIncludes === d
      next if i == 0
      if BinaryLibrary === d
        @incArray.concat(d.includes)
      else
        prefix = File.rel_from_to_project(@project_dir, d.project_dir)
        next if not prefix
        @incArray.concat(d.includes.map {|inc| File.add_prefix(prefix,inc)})
      end
    end
    @incArray.uniq!
  end

  [:CPP, :C, :ASM].each do |type|
    @include_string[type] = get_include_string(@tcs, type)
    @define_string[type] = get_define_string(@tcs, type)
  end
end

#calc_dirs_with_files(sources) ⇒ Object

calcs a map from unique directories to array of sources within this dir



225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/cxxproject/buildingblocks/has_sources_mixin.rb', line 225

def calc_dirs_with_files(sources)
  filemap = {}
  sources.keys.sort.reverse.each do |o|
    d = File.dirname(o)
    if filemap.include?(d)
      filemap[d] << o
    else
      filemap[d] = [o]
    end
  end
  return filemap
end

#collect_sources_and_toolchainsObject

returns a hash from all sources to the toolchain that should be used for a source



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/cxxproject/buildingblocks/has_sources_mixin.rb', line 193

def collect_sources_and_toolchains
  sources_to_build = {}

  exclude_files = Set.new
  exclude_sources.each do |p|
    if p.include?("..")
      Printer.printError "Error: Exclude source file pattern '#{p}' must not include '..'"
      return nil
    end

    Dir.glob(p).each {|f| exclude_files << f}
  end
  files = Set.new  # do not build the same file twice

  add_to_sources_to_build(sources_to_build, exclude_files, sources)

  source_patterns.each do |p|
    if p.include?("..")
      Printer.printError "Error: Source file pattern '#{p}' must not include '..'"
      return nil
    end

    globRes = Dir.glob(p)
    if (globRes.length == 0)
      Printer.printWarning "Warning: Source file pattern '#{p}' did not match to any file"
    end
    add_to_sources_to_build(sources_to_build, exclude_files, globRes, tcs4source(p))
  end
  return sources_to_build
end

#convert_depfile(depfile) ⇒ Object



147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/cxxproject/buildingblocks/has_sources_mixin.rb', line 147

def convert_depfile(depfile)
  deps_string = read_file_or_empty_string(depfile)
  deps = parse_includes(deps_string)
  if deps.nil?
    return # ok, because next run the source will be recompiled due to invalid depfile
  end
  expanded_deps = deps.map do |d|
    tmp = d.gsub(/[\\]/,'/')
    deps_in_depFiles << tmp
    tmp
  end

  FileUtils.mkpath File.dirname(depfile)
  File.open(depfile, 'wb') do |f|
    f.write(expanded_deps.to_yaml)
  end
end

#create_object_file_task(sourceRel, the_tcs) ⇒ Object



308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
# File 'lib/cxxproject/buildingblocks/has_sources_mixin.rb', line 308

def create_object_file_task(sourceRel, the_tcs)
  cmd, source, object, object_path, compiler, type = calc_command_line_for_source(sourceRel, the_tcs)
  depStr = ""
  dep_file = nil
  if type != :ASM
    dep_file = get_dep_file(object)
    dep_file = "\""+dep_file+"\"" if dep_file.include?(" ")
    depStr = compiler[:DEP_FLAGS]
  end
  res = typed_file_task Rake::Task::OBJECT, object_path=> source do
    rd, wr = IO.pipe
    cmd << {
      :err=>wr,
      :out=>wr
    }
    sp = spawn(*cmd)
    cmd.pop
    consoleOutput = ProcessHelper.readOutput(sp, rd, wr)

    process_result(cmd, consoleOutput, compiler[:ERROR_PARSER], "Compiling #{sourceRel}")

    convert_depfile(dep_file) if dep_file

    check_config_file()
  end
  enhance_with_additional_files(res)
  add_output_dir_dependency(object, res, false)
  apply_depfile(dep_file, res) if depStr != ""
  res
end

#create_object_file_tasksObject



238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
# File 'lib/cxxproject/buildingblocks/has_sources_mixin.rb', line 238

def create_object_file_tasks()
  sources_to_build = collect_sources_and_toolchains()
  no_sources_found() if sources_to_build.empty?

  dirs_with_files = calc_dirs_with_files(sources_to_build)

  obj_tasks = []
  @objects = []
  dirs_with_files.each do |dir, files|
    files.reverse.each do |f|
      obj_task = create_object_file_task(f, sources_to_build[f])
      obj_tasks << obj_task unless obj_task.nil?
    end
  end
  obj_tasks
end

#define_string(type) ⇒ Object



70
71
72
# File 'lib/cxxproject/buildingblocks/has_sources_mixin.rb', line 70

def define_string(type)
  @define_string[type] ||= ""
end

#deps_in_depFilesObject



30
31
32
# File 'lib/cxxproject/buildingblocks/has_sources_mixin.rb', line 30

def deps_in_depFiles
  @deps_in_depFiles ||= Set.new
end

#enhance_with_additional_files(task) ⇒ Object



339
340
341
342
# File 'lib/cxxproject/buildingblocks/has_sources_mixin.rb', line 339

def enhance_with_additional_files(task)
  task.enhance(file_dependencies)
  task.enhance(@config_files)
end

#exclude_sourcesObject



42
43
44
# File 'lib/cxxproject/buildingblocks/has_sources_mixin.rb', line 42

def exclude_sources
  @exclude_sources ||= []
end

#get_define_string(tcs, type) ⇒ Object



106
107
108
109
110
111
112
# File 'lib/cxxproject/buildingblocks/has_sources_mixin.rb', line 106

def get_define_string(tcs, type)
  if (has_tcs?)
    return tcs[:COMPILER][type][:DEFINES].map {|k| "#{tcs[:COMPILER][type][:DEFINE_FLAG]}#{k}"}
  else
    return 'only needed for spec'
  end
end

#get_dep_file(object) ⇒ Object



126
127
128
# File 'lib/cxxproject/buildingblocks/has_sources_mixin.rb', line 126

def get_dep_file(object)
  object[0..-3] + ".o.d"
end

#get_include_string(tcs, type) ⇒ Object



102
103
104
# File 'lib/cxxproject/buildingblocks/has_sources_mixin.rb', line 102

def get_include_string(tcs, type)
  @incArray.map {|k| "#{tcs[:COMPILER][type][:INCLUDE_PATH_FLAG]}#{k}"}
end

#get_object_file(sourceRel) ⇒ Object



114
115
116
117
118
119
120
121
122
123
124
# File 'lib/cxxproject/buildingblocks/has_sources_mixin.rb', line 114

def get_object_file(sourceRel)
  parts = [@output_dir]
  if @output_dir_abs
    parts = [@output_dir_relPath] if @output_dir_relPath
    parts << 'objects'
    parts << @name
  end

  parts << sourceRel.chomp(File.extname(sourceRel)).gsub('..', '_')
  res = File.join(parts) + (Rake::application.preproFlags ? ".i" : ".o")
end

#get_source_type(source) ⇒ Object



130
131
132
133
134
135
136
# File 'lib/cxxproject/buildingblocks/has_sources_mixin.rb', line 130

def get_source_type(source)
  ex = File.extname(source)
  [:CPP, :C, :ASM].each do |t|
    return t if tcs[:COMPILER][t][:SOURCE_FILE_ENDINGS].include?(ex)
  end
  nil
end

#get_sources_task_nameObject



138
139
140
# File 'lib/cxxproject/buildingblocks/has_sources_mixin.rb', line 138

def get_sources_task_name
  "Objects of #{name}"
end

#include_string(type) ⇒ Object



66
67
68
# File 'lib/cxxproject/buildingblocks/has_sources_mixin.rb', line 66

def include_string(type)
  @include_string[type] ||= ""
end

#no_sources_foundObject



387
388
389
# File 'lib/cxxproject/buildingblocks/has_sources_mixin.rb', line 387

def no_sources_found()
  raise "No Sources found for '#{self.class} #{name}'"
end

#parse_includes(deps) ⇒ Object



142
143
144
145
# File 'lib/cxxproject/buildingblocks/has_sources_mixin.rb', line 142

def parse_includes(deps)
  #deps look like "test.o: test.cpp test.h" -> remove .o and .cpp from list
  return deps.gsub(/\\\n/,'').split()[2..-1]
end

#prepare_tasks_for_objectsObject



374
375
376
377
378
379
380
381
382
383
384
385
# File 'lib/cxxproject/buildingblocks/has_sources_mixin.rb', line 374

def prepare_tasks_for_objects
  if (@output_dir_abs)
    CLEAN.include(@output_dir + "/objects/" + @name)
  end

  @objects = []
  t = multitask get_sources_task_name
  t.type = Rake::Task::SOURCEMULTI
  t.transparent_timestamp = true
  t.set_building_block(self)
  t
end

#process_console_output(console_output, error_parser) ⇒ Object



344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
# File 'lib/cxxproject/buildingblocks/has_sources_mixin.rb', line 344

def process_console_output(console_output, error_parser)
  ret = false
  if not console_output.empty?
    if error_parser
      begin
        error_descs, console_output_full = error_parser.scan_lines(console_output, @project_dir)

        console_output = console_output_full if Rake::application.consoleOutput_fullnames

        ret = error_descs.any? { |e| e.severity == ErrorParser::SEVERITY_ERROR }

        console_output.gsub!(/[\r]/, "")
        highlighter = @tcs[:CONSOLE_HIGHLIGHTER]
        if (highlighter and highlighter.enabled?)
          puts highlighter.format(console_output, error_descs, error_parser)
        else
          puts console_output
        end

        Rake.application.idei.set_errors(error_descs)
      rescue Exception => e
        Printer.printWarning "Parsing output failed (maybe language not set to English?): " + e.message
        puts "Original output:"
        puts console_output
      end
    end
  end
  ret
end

#set_exclude_sources(x) ⇒ Object



45
46
47
48
# File 'lib/cxxproject/buildingblocks/has_sources_mixin.rb', line 45

def set_exclude_sources(x)
  @exclude_sources = x
  self
end

#set_source_patterns(x) ⇒ Object



37
38
39
40
# File 'lib/cxxproject/buildingblocks/has_sources_mixin.rb', line 37

def set_source_patterns(x)
  @source_patterns = x
  self
end

#set_sources(x) ⇒ Object



21
22
23
24
25
26
27
28
# File 'lib/cxxproject/buildingblocks/has_sources_mixin.rb', line 21

def set_sources(x)
  if x.class == Rake::FileList
    raise "specifying sources but FileList is empty!" if x.empty?
  end
  x.each {|f| raise "File #{f} does not exist!" unless File.exists?(f)}
  @sources = x
  self
end

#set_tcs4source(x) ⇒ Object



61
62
63
64
# File 'lib/cxxproject/buildingblocks/has_sources_mixin.rb', line 61

def set_tcs4source(x)
  @tcs4source = x
  self
end

#source_patternsObject



34
35
36
# File 'lib/cxxproject/buildingblocks/has_sources_mixin.rb', line 34

def source_patterns
  @source_patterns ||= []
end

#sourcesObject



18
19
20
# File 'lib/cxxproject/buildingblocks/has_sources_mixin.rb', line 18

def sources
  @sources ||= []
end

#tcs4source(source) ⇒ Object

used when a source file shall have different tcs than the project default



51
52
53
54
55
56
57
58
59
# File 'lib/cxxproject/buildingblocks/has_sources_mixin.rb', line 51

def tcs4source(source)
  @tcs4source ||= {}

  if @tcs4source.include?(source)
    @tcs4source[source]
  else
    @tcs
  end
end