bake 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,111 @@
1
+ require 'bake/target'
2
+
3
+ module Bake
4
+ class ProjectLoader
5
+ attr_reader :invok_project
6
+
7
+ def initialize(context, invok_dir, props)
8
+ @context = context
9
+ load_root_project(invok_dir, props)
10
+ load_invok_project
11
+ end
12
+
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
25
+ return proj
26
+ end
27
+
28
+ private
29
+ def load_root_project(invok_dir, props)
30
+ project = nil
31
+ dir = invok_dir
32
+ @invok_path = []
33
+ while true
34
+ bakefile = File.join(dir, 'root.bake')
35
+ if File.exists?(bakefile)
36
+ project = Project.new(nil)
37
+ project.loader = self
38
+ project.req(:rootdir => dir)
39
+ project.opt(:projname => 'root')
40
+ project.opt(:cwdir => dir)
41
+ project.opt(:outdir => '${cwdir}')
42
+ props.each_pair { |key, val| project.opt(key => val) }
43
+ break
44
+ end
45
+
46
+ parent_dir = File.dirname(dir)
47
+ raise 'root.bake not found' if parent_dir == dir
48
+ @invok_path << File.basename(dir)
49
+ dir = parent_dir
50
+ end
51
+
52
+ @root_project = project
53
+ process(@root_project)
54
+ end
55
+
56
+ def load_invok_project
57
+ project = @root_project
58
+ @invok_path.reverse_each do |name|
59
+ project = load_project(name, project)
60
+ end
61
+ @invok_project = project
62
+ return project
63
+ end
64
+
65
+ def process(proj)
66
+ if proj.parent
67
+ dir = proj[:cwdir]
68
+ bakefile = File.join(dir, 'sub.bake')
69
+ if File.exists?(bakefile)
70
+ Dir.chdir(dir) { eval_bakefile(proj, bakefile) }
71
+ end
72
+ else
73
+ raise 'internal error' if !@root_project.equal?(proj)
74
+ Dir.chdir(@root_project[:cwdir]) do
75
+ if config_bakefile
76
+ eval_bakefile(@root_project, config_bakefile)
77
+ end
78
+ eval_bakefile(@root_project, root_bakefile)
79
+ end
80
+ end
81
+ end
82
+
83
+ def eval_bakefile(project, bakefile)
84
+ @context.context_eval(project, File.read(bakefile), bakefile)
85
+ end
86
+
87
+ def root_bakefile
88
+ return @root_bakefile if @root_bakefile
89
+ @root_bakefile = File.join(@root_project[:cwdir], 'root.bake')
90
+ return @root_bakefile
91
+ end
92
+
93
+ def config_bakefile
94
+ return @config_bakefile if @config_bakefile
95
+ bakefile = File.join(@root_project[:cwdir], 'config.bake')
96
+ if !File.exists?(bakefile)
97
+ home = ENV['HOME']
98
+ if home
99
+ bakefile = File.join(home, 'config.bake')
100
+ if !File.exists?(bakefile)
101
+ bakefile = nil
102
+ end
103
+ else
104
+ bakefile = nil
105
+ end
106
+ end
107
+ return @config_bakefile = bakefile
108
+ end
109
+ end
110
+ end
111
+
@@ -0,0 +1,62 @@
1
+ require 'bake/toolset'
2
+ require 'bake/target'
3
+ require 'bake/cpp_scheme.rb'
4
+ require 'fileutils'
5
+
6
+ module Qt
7
+ class Moc < Bake::Toolset
8
+ def build(target)
9
+ raise "unknown target '#{target}'" if !target.is_a?(MocFile)
10
+ return if !stale?(target)
11
+ src = target.src
12
+ sh("moc -o #{target.output} #{target.src}")
13
+ end
14
+
15
+ def clean(target)
16
+ FileUtils.rm_f(target.output)
17
+ end
18
+
19
+ def stale?(target)
20
+ return true if !File.exists?(target.output)
21
+ return File.mtime(target.src) > File.mtime(target.output)
22
+ end
23
+
24
+ def sh(*args)
25
+ cmd = args.join(' ')
26
+ puts cmd
27
+ system(*args)
28
+ raise "error: #{cmd}" if !$? || !$?.success?
29
+ end
30
+ end
31
+
32
+ class MocFile < Bake::Target
33
+ attr_reader :output
34
+ attr_accessor :src
35
+
36
+ def initialize(parent, src)
37
+ super(parent)
38
+ ext = File.extname(src)
39
+ @output = File.basename(src, ext) + '.moc' + ext
40
+ @src = src
41
+ end
42
+ end
43
+ end
44
+
45
+ module Cpp
46
+ class Library
47
+ def moc(*args)
48
+ return args.flatten.collect do |file|
49
+ Qt::MocFile.new(Cpp::Object.new(self), file)
50
+ end
51
+ end
52
+ end
53
+
54
+ class Executable
55
+ def moc(*args)
56
+ return args.flatten.collect do |file|
57
+ Qt::MocFile.new(Cpp::Object.new(self), file)
58
+ end
59
+ end
60
+ end
61
+ end
62
+
@@ -0,0 +1,104 @@
1
+ require 'bake/target'
2
+ require 'bake/toolset'
3
+
4
+ module Bake
5
+ class Scheme
6
+ attr_reader :name, :targets, :toolsets, :toolset
7
+
8
+ def initialize(mod)
9
+ @name = underscore(mod.name)
10
+ @module = mod
11
+ @targets = []
12
+ @toolsets = []
13
+ populate_targets_and_toolsets
14
+ raise "no toolsets in scheme '#{@name}'" if @toolsets.size == 0
15
+ raise "no targets in scheme '#{@name}'" if @targets.size == 0
16
+ @accessors = {}
17
+ populate_accessors
18
+ end
19
+
20
+ def toolset=(toolset)
21
+ if !toolset.is_a?(Toolset)
22
+ ts = toolset_class(toolset.to_s)
23
+ raise "could not find toolset '#{toolset}'" if !ts
24
+ @toolset = ts.new
25
+ return
26
+ end
27
+ if !@toolsets.include?(toolset.class)
28
+ raise "toolset #{toolset.class.name} is not in scheme #{name}"
29
+ end
30
+ @toolset = toolset
31
+ end
32
+
33
+ def has_constructor?(accessor)
34
+ return accessors.has_key?(accessor)
35
+ end
36
+
37
+ def construct(type, *args)
38
+ if type.instance_of?(Class)
39
+ target_class = type
40
+ raise "#{type} not in #{name}" if !targets.include?(type)
41
+ else
42
+ target_class = accessors[type]
43
+ raise "no such constructor #{type}" if !target_class
44
+ end
45
+ target = target_class.new(*args)
46
+ return target
47
+ end
48
+
49
+ private
50
+ attr_reader :accessors
51
+
52
+ def underscore(str)
53
+ str = str.gsub(/[A-Z][a-z0-9]*/) { |val| val.downcase + '_' }.chop
54
+ return str.gsub('_::', '/')
55
+ end
56
+
57
+ def capitalize(str)
58
+ str = str.gsub(/[a-z0-9]+/) { |val| val.capitalize }
59
+ return str.gsub('_', '')
60
+ end
61
+
62
+ def toolset_class(name)
63
+ name = @module.name + '::' + capitalize(name)
64
+ return @toolsets.find { |t| t.name == name }
65
+ end
66
+
67
+ def populate_targets_and_toolsets
68
+ @module.constants.each do |const|
69
+ klazz = @module.const_get(const.to_sym)
70
+ if klazz.instance_of?(Class)
71
+ sup = klazz.superclass
72
+ while sup
73
+ if sup.equal?(Toolset)
74
+ @toolsets << klazz
75
+ break
76
+ elsif sup.equal?(Target)
77
+ @targets << klazz
78
+ break
79
+ end
80
+ sup = sup.superclass
81
+ end
82
+ end
83
+ end
84
+ end
85
+
86
+ def populate_accessors
87
+ @targets.each do |target|
88
+ if target.const_defined?(:ACCESSORS)
89
+ accessors = target.const_get(:ACCESSORS)
90
+ if accessors.respond_to?(:to_ary)
91
+ accessors = accessors.to_ary
92
+ else
93
+ accessors = [ accessors ]
94
+ end
95
+ accessors.each { |accessor| @accessors[accessor] = target }
96
+ end
97
+ if !target.const_defined?(:SCHEME)
98
+ target.const_set(:SCHEME, self)
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
104
+
@@ -0,0 +1,28 @@
1
+ require 'bake/scheme'
2
+
3
+ module Bake
4
+ class SchemeLoader
5
+ attr_reader :schemes
6
+
7
+ def initialize
8
+ @schemes = {}
9
+ end
10
+
11
+ def scheme(name)
12
+ scheme = @schemes[name]
13
+ return scheme if scheme
14
+ return load_scheme(name)
15
+ end
16
+
17
+ def load_scheme(name)
18
+ file = File.join(File.dirname(__FILE__), "#{name}_scheme.rb")
19
+ raise "unknown scheme '#{name}'" if !File.exists?(file)
20
+ require "bake/#{name}_scheme"
21
+ mod = Bake.const_get(name.capitalize.to_sym)
22
+ scheme = Scheme.new(mod)
23
+ @schemes[scheme.name] = scheme
24
+ return scheme
25
+ end
26
+ end
27
+ end
28
+
@@ -0,0 +1,19 @@
1
+ class String
2
+ def basename(options = {})
3
+ if options[:ext]
4
+ return File.basename(self, extname) + options[:ext]
5
+ elsif options[:noext]
6
+ return File.basename(self, extname)
7
+ end
8
+ return File.basename(self)
9
+ end
10
+
11
+ def dirname
12
+ return File.dirname(self)
13
+ end
14
+
15
+ def extname
16
+ return File.extname(self)
17
+ end
18
+ end
19
+
@@ -0,0 +1,115 @@
1
+ require 'bake/configuration'
2
+
3
+ module Bake
4
+ class Target
5
+ include Configuration
6
+
7
+ attr_reader :parent, :children, :deps
8
+ attr_accessor :name
9
+
10
+ def initialize(parent)
11
+ @parent = parent
12
+ @children = []
13
+ @deps = []
14
+ parent.children << self if parent
15
+ opt(:built? => false)
16
+ end
17
+
18
+ def child(name, klazz = nil)
19
+ if klazz
20
+ return children.find do |child|
21
+ child.name == name && child.is_a?(klazz)
22
+ end
23
+ end
24
+ return children.find { |child| child.name == name }
25
+ end
26
+
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
42
+ end
43
+ deps << target
44
+ ret << target
45
+ end
46
+ return ret
47
+ end
48
+
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
63
+ end
64
+ end
65
+
66
+ class Project < Target
67
+ SCHEME = nil
68
+
69
+ attr_accessor :loader
70
+
71
+ def initialize(parent)
72
+ super(parent)
73
+ @mappings = {}
74
+ end
75
+
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
81
+ end
82
+
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)
92
+ 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
+ end
101
+ 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
112
+ end
113
+ end
114
+ end
115
+
@@ -0,0 +1,11 @@
1
+ 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?
8
+ end
9
+ end
10
+ end
11
+