bake 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,98 @@
1
+ require 'bake/toolset'
2
+ require 'fileutils'
3
+ require 'set'
4
+
5
+ module Bake
6
+ module Plugins
7
+ module Cpp
8
+ class ToolsetBase
9
+ include Toolset
10
+
11
+ def initialize
12
+ constructor :syslib, SystemLibrary
13
+ constructor :lib, Library
14
+ constructor :exe, Executable
15
+ constructor :run, Runner
16
+ end
17
+
18
+ def build(target)
19
+ if stale?(target)
20
+ FileUtils.mkdir_p(target[:outdir])
21
+ if target.is_a?(Cpp::Object)
22
+ compile(target)
23
+ # refresh the .includes file
24
+ includes = target.includes
25
+ filename = "#{target[:outdir]}/#{target.src.basename}.includes"
26
+ File.open(filename, "w") do |file|
27
+ includes.each { |inc| file.puts(inc) }
28
+ end
29
+ elsif target.is_a?(Cpp::Library)
30
+ ar(target)
31
+ elsif target.is_a?(Cpp::Executable)
32
+ link(target)
33
+ elsif target.is_a?(Cpp::Runner)
34
+ run(target)
35
+ else
36
+ raise "unknown Cpp target of class '#{target.class}"
37
+ end
38
+ end
39
+ end
40
+
41
+ def stale?(target)
42
+ t = Time.now
43
+ output_files(target).each do |out|
44
+ return true if !File.exists?(out)
45
+ out_time = File.mtime(out)
46
+ t = out_time if out_time < t
47
+ end
48
+ if target.is_a?(Cpp::Object)
49
+ return true if File.mtime(target.src) > t
50
+ target.includes.each { |file| return true if File.mtime(file) > t }
51
+ elsif target.is_a?(Cpp::Runner)
52
+ return File.mtime(output_files(target.deps[0])[0]) > t
53
+ else
54
+ is_linked = target.is_a?(Cpp::Executable) ||
55
+ (target.is_a?(Cpp::Library) && target[:libtype] == 'dynamic')
56
+ target.children.each do |child|
57
+ output_files(child).each do |file|
58
+ return true if File.mtime(file) > t
59
+ end
60
+ end
61
+ target.deps.each do |dep|
62
+ if is_linked && dep.is_a?(Cpp::Library) &&
63
+ dep[:libtype] != 'dynamic'
64
+ output_files(dep).each do |file|
65
+ return true if File.mtime(file) > t
66
+ end
67
+ end
68
+ end
69
+ end
70
+ return false
71
+ end
72
+
73
+ def clean(target)
74
+ output_files(target).each { |file| FileUtils.rm_f(file) }
75
+ if target.is_a?(Cpp::Object)
76
+ filename = "#{target[:outdir]}/#{target.src.basename}.includes"
77
+ FileUtils.rm_f(filename)
78
+ end
79
+ end
80
+
81
+ def output_files(target)
82
+ out = output(target)
83
+ return [] if !out
84
+ return out.to_a if out.respond_to?(:to_a)
85
+ return [ out ]
86
+ end
87
+
88
+ def sh(*args)
89
+ cmd = args.join(' ')
90
+ puts cmd
91
+ system(*args)
92
+ raise "error: #{cmd}" if !$? || !$?.success?
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
98
+
@@ -0,0 +1,18 @@
1
+ require 'bake/addon'
2
+
3
+ module Bake
4
+ module Plugins
5
+ class Macro
6
+ include Addon
7
+
8
+ def initialize
9
+ command(:macro)
10
+ end
11
+
12
+ def macro(context, name, &block)
13
+ context.register(name, &block)
14
+ end
15
+ end
16
+ end
17
+ end
18
+
@@ -0,0 +1,46 @@
1
+ require 'bake/addon'
2
+
3
+ module Bake
4
+ module Plugins
5
+ class System
6
+ include Addon
7
+
8
+ def initialize
9
+ command(:glob)
10
+ end
11
+
12
+ def glob(context, *args)
13
+ has_options = args.last.respond_to?(:to_hash)
14
+ options = has_options ? args.pop.to_hash : {}
15
+ exclude = array_opt(options, :exclude)
16
+ files = []
17
+ args.each do |pat|
18
+ matches = Dir[pat]
19
+ matches.each do |file|
20
+ if !exclude.find { |exc| File.fnmatch(exc, file) }
21
+ files.push(file)
22
+ end
23
+ end
24
+ end
25
+ if block_given?
26
+ for i in 0...files.size
27
+ yield(files[i])
28
+ end
29
+ end
30
+ return files
31
+ end
32
+
33
+ private
34
+ def array_opt(options, name)
35
+ opt = options[name]
36
+ return [] if !opt
37
+ if opt.respond_to?(:to_ary)
38
+ opt = opt.to_ary
39
+ else
40
+ opt = [ opt ]
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+
@@ -0,0 +1,50 @@
1
+ require 'bake/target'
2
+
3
+ module Bake
4
+ class Project < Target
5
+ attr_accessor :loader
6
+
7
+ def initialize(parent, loader)
8
+ super(parent, nil)
9
+ @loader = loader
10
+ end
11
+
12
+ def current_project
13
+ return self
14
+ end
15
+
16
+ def parent_project
17
+ return parent ? parent.current_project : nil
18
+ end
19
+
20
+ def child_project(name)
21
+ child = children.find do |child|
22
+ child.name == name && child.is_a?(Project)
23
+ end
24
+ return child || loader.load_project(self, name)
25
+ end
26
+
27
+ def resolve(path)
28
+ index = path.index(':')
29
+ raise "invalid path '#{path}'" if !index
30
+ dir = path.slice(0, index)
31
+ name = path.slice(index + 1, path.length - index - 1)
32
+ proj = self
33
+ dir.split('/').each do |el|
34
+ if el == '.'
35
+ next
36
+ elsif el == '..'
37
+ proj = proj.parent_project
38
+ raise "invalid target path '#{path}'" if !proj
39
+ else
40
+ proj = proj.child_project(el)
41
+ raise "invalid target path '#{path}'" if !proj
42
+ end
43
+ end
44
+ target = proj.children.find { |child| child.name == name }
45
+ raise "invalid target path '#{path}'" if !target
46
+ return target
47
+ end
48
+ end
49
+ end
50
+
@@ -1,4 +1,5 @@
1
1
  require 'bake/target'
2
+ require 'bake/project'
2
3
 
3
4
  module Bake
4
5
  class ProjectLoader
@@ -10,18 +11,14 @@ module Bake
10
11
  load_invok_project
11
12
  end
12
13
 
13
- def load_project(name, from_proj)
14
- proj = from_proj.child(name, Project)
15
- if !proj
16
- dir = File.join(from_proj[:cwdir], name)
17
- raise "no such directory #{dir}" if !File.exists?(dir)
18
- proj = Project.new(from_proj)
19
- proj.loader = self
20
- proj.name = name
21
- proj.opt(:projname => name)
22
- proj.opt(:cwdir => dir)
23
- process(proj)
24
- end
14
+ def load_project(parent, name)
15
+ dir = File.join(parent[:cwdir], name)
16
+ raise "no such directory '#{dir}'" if !File.directory?(dir)
17
+ proj = Project.new(parent, self)
18
+ proj.name = name
19
+ proj.opt(:projname => name)
20
+ proj.opt(:cwdir => dir)
21
+ process(proj)
25
22
  return proj
26
23
  end
27
24
 
@@ -33,8 +30,7 @@ module Bake
33
30
  while true
34
31
  bakefile = File.join(dir, 'root.bake')
35
32
  if File.exists?(bakefile)
36
- project = Project.new(nil)
37
- project.loader = self
33
+ project = Project.new(nil, self)
38
34
  project.req(:rootdir => dir)
39
35
  project.opt(:projname => 'root')
40
36
  project.opt(:cwdir => dir)
@@ -56,7 +52,7 @@ module Bake
56
52
  def load_invok_project
57
53
  project = @root_project
58
54
  @invok_path.reverse_each do |name|
59
- project = load_project(name, project)
55
+ project = load_project(project, name)
60
56
  end
61
57
  @invok_project = project
62
58
  return project
@@ -15,5 +15,9 @@ class String
15
15
  def extname
16
16
  return File.extname(self)
17
17
  end
18
+
19
+ def underscore
20
+ return gsub(/([a-z0-9])([A-Z])/) { |val| $1 + '_' + $2 }.downcase
21
+ end
18
22
  end
19
23
 
@@ -1,115 +1,78 @@
1
1
  require 'bake/configuration'
2
+ require 'bake/string_utils'
2
3
 
3
4
  module Bake
4
5
  class Target
5
6
  include Configuration
6
7
 
7
- attr_reader :parent, :children, :deps
8
+ attr_reader :parent, :children, :deps, :toolset
8
9
  attr_accessor :name
9
10
 
10
- def initialize(parent)
11
+ def initialize(parent, toolset)
11
12
  @parent = parent
13
+ @toolset = toolset
12
14
  @children = []
13
15
  @deps = []
14
16
  parent.children << self if parent
15
- opt(:built? => false)
16
- end
17
17
 
18
- def child(name, klazz = nil)
19
- if klazz
20
- return children.find do |child|
21
- child.name == name && child.is_a?(klazz)
18
+ if toolset
19
+ mixin_name = self.class.name.split('::').last
20
+ toolset.class
21
+ if toolset.class.const_defined?(mixin_name)
22
+ extend(toolset.class.const_get(mixin_name))
22
23
  end
23
24
  end
24
- return children.find { |child| child.name == name }
25
+ post_initialize if respond_to?(:post_initialize)
25
26
  end
26
27
 
27
- def find(name)
28
- target = children.find do |child|
29
- !child.is_a?(Project) && child.name == name
30
- end
31
- target ||= parent.find(name) if parent
32
- return target
33
- end
34
-
35
- def dep(*targets)
36
- ret = []
37
- targets.each do |target|
38
- if !target.is_a?(Target)
39
- real_target = parent.find(target) if parent
40
- raise "uknown target '#{target}'" if !real_target
41
- target = real_target
28
+ def build
29
+ return if @built
30
+ deps.each { |dep| dep.build }
31
+ children.each { |child| child.build }
32
+ if toolset
33
+ Dir.chdir(get(:cwdir)) do
34
+ toolset.build(self)
42
35
  end
43
- deps << target
44
- ret << target
45
36
  end
46
- return ret
37
+ @built = true
47
38
  end
48
39
 
49
- def to_s(level = 0)
50
- str = (' ' * level) + (@name || '<empty>') +
51
- ' (' + self.class.name + ')'
52
- if !deps.empty?
53
- str += ' => '
54
- deps.each do |target|
55
- str += target.name + ' (' + target.class.name + ') '
56
- end
57
- end
58
- str += "\n"
59
- if !children.empty?
60
- children.each { |target| str += target.to_s(level + 1) }
61
- end
62
- return str
40
+ def clean
41
+ children.each { |child| child.clean }
42
+ toolset.clean(self) if toolset
63
43
  end
64
- end
65
44
 
66
- class Project < Target
67
- SCHEME = nil
68
-
69
- attr_accessor :loader
45
+ def dep(*targets)
46
+ targets = normalize_targets(*targets)
47
+ targets.each { |target| add_dep(target) }
48
+ end
70
49
 
71
- def initialize(parent)
72
- super(parent)
73
- @mappings = {}
50
+ def add_dep(target)
51
+ deps << target
74
52
  end
75
53
 
76
- def map(mappings)
77
- mappings.each do |name, loc|
78
- raise "target '#{name}' already mapped" if @mappings[name]
79
- @mappings[name] = loc
80
- end
54
+ def current_project
55
+ return parent.current_project
81
56
  end
82
57
 
83
- def mapping(name)
84
- target = nil
85
- mapping = @mappings[name]
86
- if mapping
87
- if mapping.instance_of?(String)
88
- path = @mappings[name].split('/')
89
- proj = self
90
- path.each do |dir|
91
- proj = loader.load_project(dir, proj)
58
+ private
59
+ def normalize_targets(*targets)
60
+ normalized_targets = []
61
+ targets.flatten.each do |target|
62
+ if !target.is_a?(Target)
63
+ if File.exists?(target)
64
+ target = FileTarget.new(self, target)
65
+ else
66
+ target = current_project.resolve(target)
92
67
  end
93
- target = proj.child(name)
94
- @mappings[name] = target
95
- raise "invalid mapping #{@mappings[name]}" if !target
96
- elsif mapping.is_a?(Target)
97
- target = mapping
98
- else
99
- raise "mapping has invalid class '#{mapping.class.name}'"
100
68
  end
69
+ normalized_targets << target
101
70
  end
102
- return target
103
- end
104
-
105
- def find(name)
106
- target = mapping(name)
107
- target ||= children.find do |child|
108
- !child.is_a?(Project) && child.name == name
109
- end
110
- target ||= parent.find(name) if parent
111
- return target
71
+ return normalized_targets
112
72
  end
113
73
  end
114
74
  end
115
75
 
76
+ require 'bake/file_target'
77
+ require 'bake/project'
78
+
@@ -1,10 +1,17 @@
1
+ require 'bake/plugin'
2
+
1
3
  module Bake
2
- class Toolset
3
- def sh(*args)
4
- cmd = args.join(' ')
5
- puts cmd
6
- system(*args)
7
- raise "error: #{cmd}" if !$? || !$?.success?
4
+ module Toolset
5
+ include Addon
6
+
7
+ def constructor(name, target_class)
8
+ toolset = self
9
+ command(name) do |*args|
10
+ block = args.last.is_a?(Proc) ? args.pop : nil
11
+ target = target_class.new(current, toolset, *args)
12
+ context_eval(target, &block) if block
13
+ return target
14
+ end
8
15
  end
9
16
  end
10
17
  end