Class: Magica::Build

Inherits:
Object show all
Includes:
Rake::DSL
Defined in:
lib/magica/build.rb

Overview

:nodoc:

Direct Known Subclasses

Target

Defined Under Namespace

Classes: Exts

Constant Summary collapse

COMPILERS =
%w[cc cxx].freeze
COMMANDS =
COMPILERS + %w[linker git]

Class Attribute Summary collapse

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name = 'host', options = { dest: 'build' }, &block) ⇒ Build

rubocop:disable Metrics/AbcSize



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
# File 'lib/magica/build.rb', line 26

def initialize(name = 'host', options = { dest: 'build' }, &block)
  @name = name.to_s
  @dest = (options[:dest] || 'build').to_s
  @sources = FileList['src/**/*.cpp']
  @options = OpenStruct.new(options.merge(Rake.application.options.to_h))
  @default_target = nil
  @config_block = block
  @targets = {}

  @exe_name = @name
  @exe_path = 'bin'

  @exts = Exts.new('.o', '', '.a')

  @cc = Command::Compiler.new(self, %w[.c])
  @cxx = Command::Compiler.new(self, %w[.cpp])
  @linker = Command::Linker.new(self)

  @compiler = @cc

  @git = Command::Git.new(self)

  @defines = %w[]
  @include_paths = %w[]
  @libraries = %w[]
  @library_paths = %w[]
  @flags = %w[]

  @dependencies = []
  @static_libraries = []

  Magica.builds[@name] = self
  Magica.builds[@name].instance_eval(&block) unless block.nil?
  Magica.builds[@name].instance_exec(@options, &Magica.default_compile_task)

  Magica.default_toolchain.setup(self, Magica.toolchain_params) if Magica.default_toolchain
end

Class Attribute Details

.currentObject

Returns the value of attribute current.



12
13
14
# File 'lib/magica/build.rb', line 12

def current
  @current
end

Instance Attribute Details

#definesObject (readonly)

Returns the value of attribute defines.



20
21
22
# File 'lib/magica/build.rb', line 20

def defines
  @defines
end

#flagsObject (readonly)

Returns the value of attribute flags.



20
21
22
# File 'lib/magica/build.rb', line 20

def flags
  @flags
end

#include_pathsObject (readonly)

Returns the value of attribute include_paths.



20
21
22
# File 'lib/magica/build.rb', line 20

def include_paths
  @include_paths
end

#optionsObject (readonly)

Returns the value of attribute options.



20
21
22
# File 'lib/magica/build.rb', line 20

def options
  @options
end

#sourcesObject (readonly)

Returns the value of attribute sources.



20
21
22
# File 'lib/magica/build.rb', line 20

def sources
  @sources
end

Instance Method Details

#add(source) ⇒ Object



206
207
208
209
210
211
# File 'lib/magica/build.rb', line 206

def add(source)
  FileUtils.cp(
    source,
    File.join(*[Magica.root, @dest].flatten.reject(&:empty?))
  )
end

#build_task(&block) ⇒ Object



257
258
259
# File 'lib/magica/build.rb', line 257

def build_task(&block)
  Magica.builds[@name].instance_eval(@options, &block)
end

#cleanObject



201
202
203
204
# File 'lib/magica/build.rb', line 201

def clean
  clear_dest
  clear_exe
end

#clear_destObject



191
192
193
194
# File 'lib/magica/build.rb', line 191

def clear_dest
  path = File.join(*[Magica.root, @dest].flatten.reject(&:empty?))
  FileUtils.rm_r(path, force: true)
end

#clear_exeObject



196
197
198
199
# File 'lib/magica/build.rb', line 196

def clear_exe
  path = File.join(*[Magica.root, @exe_path].flatten.reject(&:empty?))
  FileUtils.rm_r(path, force: true)
end

#compile(source) ⇒ Object



219
220
221
222
223
224
225
226
227
228
229
230
# File 'lib/magica/build.rb', line 219

def compile(source)
  return if Rake::Task.task_defined?(objfile(source))
  file objfile(source) => source do |t|
    @compiler.run(
      t.name,
      t.prerequisites.first,
      Build.current.defines,
      Build.current.include_paths,
      Build.current.flags
    )
  end
end

#define(name, value = nil) ⇒ Object



73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/magica/build.rb', line 73

def define(name, value = nil)
  if name.is_a?(Array)
    name.flatten.map { |n| define(n, value) }
  else
    define_name = name.to_s.upcase
    unless value.nil? || value.is_a?(Numeric)
      value = format('\"%s\"', value)
    end
    define_name << "=#{value}" unless value.nil?
    @defines.push(define_name)
  end
  @defines.uniq!
end

#dependency(name, options = {}, &block) ⇒ Object



141
142
143
144
145
146
147
148
149
# File 'lib/magica/build.rb', line 141

def dependency(name, options = {}, &block)
  Dependency.new(self, name, options, &block)
  desc "The targets #{@name}'s dependency project : #{name}"
  task "#{@name}:dependency:#{name}" do
    Dependency[name].build
  end
  @dependencies << "#{@name}:dependency:#{name}"
  @static_libraries.push(*Dependency[name].static_libraries)
end

#dest(path) ⇒ Object



137
138
139
# File 'lib/magica/build.rb', line 137

def dest(path)
  @dest = path.to_s
end

#do_target(name = nil) ⇒ Object



248
249
250
251
252
253
254
255
# File 'lib/magica/build.rb', line 248

def do_target(name = nil)
  name ||= @default_target
  return if name.nil?
  target = @targets[name.to_sym]
  @sources.clear_exclude # Reset exclude files
  @exe_name = name.to_s.capitalize
  Magica.builds[@name].instance_eval(&target) unless target.nil?
end

#dynamic_library(name) ⇒ Object



114
115
116
117
118
119
120
121
122
# File 'lib/magica/build.rb', line 114

def dynamic_library(name)
  config = PackageConfig[name]
  @libraries.push(*config.libraries).uniq!
  @library_paths.push(*config.library_paths).uniq!

  include_path(config.include_paths)
  define(config.defines)
  flag(config.flags)
end

#exclude(*patterns) ⇒ Object



129
130
131
# File 'lib/magica/build.rb', line 129

def exclude(*patterns)
  @sources = @sources.exclude(*patterns)
end

#exe_name(name) ⇒ Object



164
165
166
# File 'lib/magica/build.rb', line 164

def exe_name(name)
  @exe_name = name.to_s
end

#exe_path(path) ⇒ Object



160
161
162
# File 'lib/magica/build.rb', line 160

def exe_path(path)
  @exe_path = path.to_s
end

#exefile(name = nil) ⇒ Object



168
169
170
171
172
173
174
175
176
177
178
# File 'lib/magica/build.rb', line 168

def exefile(name = nil)
  return exefile("#{@exe_name}#{@exts.executable}") if name.nil?
  if name.is_a?(Array)
    name.flatten.map { |n| exefile(n) }
  else
    File.join(
      *[Magica.root, @exe_path, "#{name}#{@exts.executable}"]
      .flatten.reject(&:empty?)
    )
  end
end

#filename(name) ⇒ Object



156
157
158
# File 'lib/magica/build.rb', line 156

def filename(name)
  format('"%s"', name)
end

#flag(flag) ⇒ Object



96
97
98
99
100
101
102
103
# File 'lib/magica/build.rb', line 96

def flag(flag)
  if flag.is_a?(Array)
    flag.flatten.map { |f| flag(f) }
  else
    @flags.push(flag.to_s)
  end
  @flags
end

#include(*patterns) ⇒ Object



133
134
135
# File 'lib/magica/build.rb', line 133

def include(*patterns)
  @sources = @sources.include(*patterns)
end

#include_path(path) ⇒ Object



87
88
89
90
91
92
93
94
# File 'lib/magica/build.rb', line 87

def include_path(path)
  if path.is_a?(Array)
    path.flatten.map { |p| include_path(p) }
  else
    @include_paths.push(path.to_s)
  end
  @include_paths
end

#library(name, path = nil) ⇒ Object



105
106
107
108
# File 'lib/magica/build.rb', line 105

def library(name, path = nil)
  @libraries.push(name.to_s).uniq!
  @library_paths.push(path.to_s).uniq! if path
end

#library_path(path) ⇒ Object



110
111
112
# File 'lib/magica/build.rb', line 110

def library_path(path)
  @library_paths.push(path.to_s).uniq!
end


232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
# File 'lib/magica/build.rb', line 232

def link(exec, objects)
  desc "Build #{@name}'s executable file"
  task @name.to_s do
    Build.current = Magica.builds[@name]
    task "#{@name}:build" => @dependencies + objects do
      @linker.run(
        exec.to_s,
        objects + @static_libraries,
        @libraries,
        @library_paths,
        @flags
      )
    end.invoke
  end
end

#objfile(name) ⇒ Object



180
181
182
183
184
185
186
187
188
189
# File 'lib/magica/build.rb', line 180

def objfile(name)
  if name.is_a?(Array)
    name.flatten.map { |n| objfile(n) }
  else
    File.join(
      *[Magica.root, @dest, "#{name}#{@exts.object}"]
      .flatten.reject(&:empty?)
    )
  end
end

#source(*paths, **options) ⇒ Object



124
125
126
127
# File 'lib/magica/build.rb', line 124

def source(*paths, **options)
  @sources = FileList.new(*paths)
  @sources = @sources.exclude(options[:exclude]) if options[:exclude]
end

#target(name, **options, &block) ⇒ Object

rubocop:enable Metrics/AbcSize



65
66
67
68
69
70
71
# File 'lib/magica/build.rb', line 65

def target(name, **options, &block)
  return if block.nil?
  name = name.to_sym
  @targets[name] = block
  @default_target = name if options[:default]
  Target.new("#{@name}:#{name}", @options.to_h.merge(target: name), &@config_block) if Magica.const_defined?('Target')
end

#toolchain(name, params = {}) ⇒ Object



213
214
215
216
217
# File 'lib/magica/build.rb', line 213

def toolchain(name, params = {})
  toolchain = Toolchain.toolchains[name]
  raise I18n.t('magica.unknow_toolchain', toolchain: name) unless toolchain
  toolchain.setup(self, params)
end

#use(compiler) ⇒ Object



151
152
153
154
# File 'lib/magica/build.rb', line 151

def use(compiler)
  return @compiler = send(compiler.to_s) if COMPILERS.include?(compiler.to_s)
  @compiler = @cc
end