bake 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,44 +1,26 @@
1
- require 'bake/string_utils'
2
-
3
- class Object
4
- def self.const_missing(name)
5
- return Bake::Plugins.const_get(name)
6
- end
7
- end
8
-
9
1
  module Bake
10
- class PluginManager
11
- @@plugins = { }
12
- @@search_dirs = [ File.join(File.dirname(__FILE__), '..') ]
13
-
14
- def self.search_dirs
15
- return @@search_dirs
16
- end
17
-
18
- def self.plugins
19
- return @@plugins
20
- end
21
-
22
- def self.load_plugin(full_name)
23
- parent = Plugins
24
- plugin = nil
2
+ module PluginManager
3
+ def load_plugin(full_name)
4
+ plugin = Object.main_object.class
25
5
  full_name.to_s.split('::').each do |name|
26
- plugin = load_child_plugin(parent, name)
6
+ plugin = load_child_plugin(plugin, name)
27
7
  end
28
8
  return plugin
29
9
  end
30
10
 
31
- def self.load_child_plugin(parent, name)
11
+ def load_child_plugin(parent, name)
32
12
  name = name.to_s
33
- full_name = parent.name + '::' + name
13
+ full_name = parent.equal?(Object.main_object.class) ?
14
+ name : parent.name + '::' + name
34
15
  plugin_file = full_name.underscore.gsub('::', '/')
35
16
 
36
17
  plugin = nil
37
18
  if parent.const_defined?(name)
38
19
  plugin = parent.const_get(name)
20
+ return plugin if plugin.equal?(Bake)
39
21
  end
40
22
 
41
- @@search_dirs.each do |rootdir|
23
+ search_dirs.each do |rootdir|
42
24
  if File.exists?(File.join(rootdir, plugin_file + '.rb'))
43
25
  require plugin_file
44
26
  if !plugin && parent.const_defined?(name)
@@ -51,22 +33,17 @@ module Bake
51
33
  plugin = Module.new
52
34
  parent.const_set(name, plugin)
53
35
  end
54
- def plugin.const_missing(name)
55
- return PluginManager.load_child_plugin(self, name)
36
+ plugin_manager = self
37
+ plugin.metaclass.send(
38
+ :define_method, :const_missing) do |name|
39
+ return plugin_manager.load_child_plugin(self, name)
56
40
  end
57
41
  end
58
42
  end
59
43
 
60
44
  raise "could not find plugin '#{name}'" if !plugin
61
- @@plugins[full_name] = plugin
62
45
  return plugin
63
46
  end
64
47
  end
65
-
66
- module Plugins
67
- def self.const_missing(name)
68
- return PluginManager.load_plugin(name)
69
- end
70
- end
71
48
  end
72
49
 
@@ -6,72 +6,129 @@ module Bake
6
6
  class SystemLibrary < Target
7
7
  attr_reader :file
8
8
 
9
- def initialize(parent, toolset, name, file)
10
- super(parent, toolset)
9
+ def post_initialize(name, file)
11
10
  @built = true
12
11
  @name = name
13
12
  @file = file
14
- opt(:built? => true)
13
+ end
14
+
15
+ def products
16
+ return nil
17
+ end
18
+
19
+ def mtimes
20
+ return [ Time.at(0) ]
21
+ end
22
+ end
23
+
24
+ # +MainTarget+ is a mix-in for the +Library+ and +Executable+
25
+ # classes containing code common to both types of targets.
26
+ module MainTarget
27
+ # A special override of +stale?+ that ignores changes to
28
+ # dlls when determining if this target is stale. The only
29
+ # case in which a lib or exe should have to update when a
30
+ # dll dependency is updated is when the interface changes.
31
+ # Since exes and libs depend on the headers implicitly,
32
+ # they will be updated if the interface changes
33
+ # automatically.
34
+ def stale?
35
+ return @stale if !@stale.nil?
36
+ tmin = mtimes.min
37
+ @stale = deps.any? do |dep|
38
+ is_dll = dep.is_a?(Library) &&
39
+ dep[:libtype] == 'dynamic'
40
+ (dep.stale? || dep.mtimes.max > tmin) && !is_dll
41
+ end
42
+ return @stale
43
+ end
44
+
45
+ def add_dep(target)
46
+ if target.is_a?(FileTarget)
47
+ target = Source.new(self, toolset, target)
48
+ end
49
+ return super if !target.is_a?(Source)
50
+ deps << Cpp::Object.new(self, toolset, target)
51
+ end
52
+
53
+ def build
54
+ toolset.build(self)
15
55
  end
16
56
  end
17
57
 
18
58
  class Library < Target
19
- def initialize(parent, toolset, name)
20
- super(parent, toolset)
59
+ include MainTarget
60
+
61
+ def post_initialize(name)
21
62
  @name = name
22
63
  default(:libtype => 'static')
23
64
  default(:debug_symbols? => false)
24
65
  end
25
-
26
- def add_dep(target)
27
- return super if !target.is_a?(FileTarget)
28
- deps << Cpp::Object.new(self, toolset, target)
29
- end
30
66
  end
31
67
 
32
68
  class Executable < Target
33
- def initialize(parent, toolset, name)
34
- super(parent, toolset)
69
+ include MainTarget
70
+
71
+ def post_initialize(name)
35
72
  @name = name
36
73
  default(:debug_symbols? => false)
37
74
  end
38
75
 
39
- def add_dep(target)
40
- return super if !target.is_a?(FileTarget)
41
- deps << Cpp::Object.new(self, toolset, target)
76
+ # Enables +Executable+ to be run via a +Runner+ target.
77
+ def run_command
78
+ return toolset.exe_fn(self)
42
79
  end
43
80
  end
44
81
 
45
- class Object < Target
46
- def initialize(parent, toolset, file_target)
47
- super(parent, toolset)
48
- deps << file_target
49
- default(:exceptions? => true)
50
- default(:rtti? => true)
51
- default(:optimizations? => false)
52
- default(:multithreaded? => true)
82
+ class Source < Target
83
+ def post_initialize(source)
84
+ @source = source
85
+ @includes = IncludeList.new(self, toolset, source)
86
+ dep(source, @includes)
53
87
  end
54
88
 
55
- def src
56
- return deps.first.path
89
+ def path
90
+ return @source.path
57
91
  end
58
92
 
59
- def includes(recalc = false)
60
- incfile = "#{get(:outdir)}/#{src}.includes"
61
- if !@includes || recalc
62
- if File.exists?(incfile)
63
- @includes = load_includes(incfile)
64
- else
65
- @includes = calc_includes(src, Set.new)
66
- end
93
+ alias :id :path
94
+
95
+ def mtimes
96
+ return @includes.mtimes
97
+ end
98
+ end
99
+
100
+ class IncludeList < Target
101
+ attr_reader :includes
102
+
103
+ def post_initialize(source)
104
+ @src = source.path
105
+ if File.exists?(products)
106
+ @includes = load_includes
107
+ @calculated = false
108
+ else
109
+ @includes = calc_includes(@src)
110
+ @calculated = true
67
111
  end
68
- return @includes
112
+ dep(source, *@includes)
113
+ end
114
+
115
+ def id
116
+ return @src
117
+ end
118
+
119
+ def build
120
+ @includes = calc_includes(@src) if !@calculated
121
+ toolset.sys.fwrite(products, includes.to_a.join("\n"))
122
+ end
123
+
124
+ def products
125
+ return "#{get(:outdir)}/#{@src.basename}.includes"
69
126
  end
70
127
 
71
128
  private
72
- def load_includes(incfile)
129
+ def load_includes
73
130
  includes = Set.new
74
- file = File.open(incfile)
131
+ file = File.open(products)
75
132
  while line = file.gets
76
133
  line.chomp!
77
134
  includes << line if !line.empty?
@@ -80,9 +137,9 @@ module Bake
80
137
  return includes
81
138
  end
82
139
 
83
- def calc_includes(filename, include_fns)
140
+ def calc_includes(src, include_fns = Set.new)
84
141
  new_include_fns = Set.new
85
- File.open(filename) do |file|
142
+ File.open(src) do |file|
86
143
  incdirs = get(:incdirs)
87
144
  while line = file.gets
88
145
  if line =~ /\s*#\s*include\s+("|<)([^"]+)("|>)/
@@ -107,13 +164,22 @@ module Bake
107
164
  end
108
165
  end
109
166
 
110
- class Runner < Target
111
- def initialize(parent, toolset, exe)
112
- super(parent, toolset)
113
- target = dep(exe)[0]
114
- if !target.is_a?(Executable)
115
- raise "target '#{target}' is not an executable"
116
- end
167
+ class Object < Target
168
+ attr_reader :src
169
+
170
+ alias :id :src
171
+
172
+ def post_initialize(source)
173
+ @src = source.path
174
+ dep(source)
175
+ default(:exceptions? => true)
176
+ default(:rtti? => true)
177
+ default(:optimizations? => false)
178
+ default(:multithreaded? => true)
179
+ end
180
+
181
+ def build
182
+ toolset.build(self)
117
183
  end
118
184
  end
119
185
  end
@@ -7,16 +7,15 @@ module Bake
7
7
 
8
8
  output = lib_fn(lib)
9
9
  if lib[:libtype] == 'dynamic'
10
- sh("g++ #{flags} -dynamiclib -o #{output} #{obj_str} #{lib_str}")
10
+ sys.sh("g++ #{flags} -dynamiclib -o #{output} #{obj_str} #{lib_str}")
11
11
  else
12
- sh("ar rcs #{output} #{obj_str}")
12
+ sys.sh("ar rcs #{output} #{obj_str}")
13
13
  end
14
14
  end
15
15
 
16
- private
17
16
  def lib_fn(lib)
18
17
  if lib[:libtype] == 'dynamic'
19
- return File.join(lib[:outdir], "#{lib.name}.dylib")
18
+ return File.join(lib[:outdir], "lib#{lib.name}.dylib")
20
19
  end
21
20
  return File.join(lib[:outdir], "lib#{lib.name}.a")
22
21
  end
@@ -2,6 +2,11 @@ module Bake
2
2
  module Plugins
3
3
  module Cpp
4
4
  class Gcc < GccToolsetBase
5
+ module Library
6
+ def post_initialize
7
+ opt(:cflags => '-fPIC') if get(:libtype) == 'dynamic'
8
+ end
9
+ end
5
10
  end
6
11
  end
7
12
  end
@@ -11,8 +11,6 @@ module Bake
11
11
  return lib_fn(target)
12
12
  elsif target.is_a?(Cpp::Executable)
13
13
  return exe_fn(target)
14
- elsif target.is_a?(Cpp::Runner)
15
- return runner_fn(target)
16
14
  end
17
15
  return nil
18
16
  end
@@ -26,7 +24,7 @@ module Bake
26
24
  flags += ' -fno-rtti' if !obj[:rtti?]
27
25
  flags += ' -O3' if obj[:optimizations?]
28
26
  flags += ' -g' if obj[:debug_symbols?]
29
- sh("g++ -c -o #{output} #{flags} #{src}")
27
+ sys.sh("g++ -c -o #{output} #{flags} #{src}")
30
28
  end
31
29
 
32
30
  def ar(lib)
@@ -34,13 +32,13 @@ module Bake
34
32
 
35
33
  output = lib_fn(lib)
36
34
  if lib[:libtype] == 'dynamic'
37
- sh("g++ #{flags} -shared -Wl,-soname,#{output} -o #{output} #{obj_str} #{lib_str}")
35
+ sys.sh("g++ #{flags} -shared -Wl,-soname,#{output} -o #{output} #{obj_str} #{lib_str}")
38
36
  if lib.has_prop?(:gcc_lib_path)
39
37
  fn = File.join(lib[:gcc_lib_path], output.basename)
40
38
  File.symlink(output, fn) if !File.exists?(fn)
41
39
  end
42
40
  else
43
- sh("ar rcs #{output} #{obj_str}")
41
+ sys.sh("ar rcs #{output} #{obj_str}")
44
42
  end
45
43
  end
46
44
 
@@ -48,17 +46,7 @@ module Bake
48
46
  obj_str, lib_str, flags = process_inputs(exe)
49
47
 
50
48
  output = exe_fn(exe)
51
- sh("g++ #{flags} -o #{output} #{obj_str} #{lib_str}")
52
- end
53
-
54
- def run(runner)
55
- sh(exe_fn(runner.deps.first))
56
- FileUtils.touch(runner_fn(runner))
57
- end
58
-
59
- private
60
- def build_flags(flag, args)
61
- return args.inject('') { |str, arg| str + "#{flag}#{arg} " }
49
+ sys.sh("g++ #{flags} -o #{output} #{obj_str} #{lib_str}")
62
50
  end
63
51
 
64
52
  def obj_fn(obj)
@@ -78,16 +66,16 @@ module Bake
78
66
  return File.join(exe[:outdir], exe.name)
79
67
  end
80
68
 
81
- def runner_fn(runner)
82
- return "#{exe_fn(runner.deps.first)}.success"
69
+ private
70
+ def build_flags(flag, args)
71
+ return args.inject('') { |str, arg| str + "#{flag}#{arg} " }
83
72
  end
84
-
73
+
85
74
  def process_inputs(target)
86
75
  output = output(target)
87
76
  obj_str = ''
88
77
  lib_str = ''
89
78
  libdirs = []
90
- rtdirs = []
91
79
  target.deps.each do |input|
92
80
  if input.is_a?(Cpp::Object)
93
81
  fn = obj_fn(input)
@@ -96,14 +84,9 @@ module Bake
96
84
  lib_str += '-l' + input.file + ' '
97
85
  elsif input.is_a?(Cpp::Library)
98
86
  fn = lib_fn(input)
99
- if input[:libtype] == 'dynamic'
100
- obj_str += fn + ' '
101
- rtdirs << File.dirname(fn)
102
- else
103
- lib_str += '-l' + input.name + ' '
104
- libdir = File.dirname(fn)
105
- libdirs << libdir if !libdirs.include?(libdir)
106
- end
87
+ lib_str += '-l' + input.name + ' '
88
+ libdir = File.dirname(fn)
89
+ libdirs << libdir if !libdirs.include?(libdir)
107
90
  end
108
91
  end
109
92
 
@@ -26,7 +26,7 @@ module Bake
26
26
  flags += ' /GR' if obj[:rtti?]
27
27
  flags += obj[:optimizations?] ? ' /O2' : ' /Od'
28
28
  flags += ' /Z7' if obj[:debug_symbols?]
29
- sh("cl /nologo #{flags} /c /Fo#{output} /Tp#{src}")
29
+ sys.sh("cl /nologo #{flags} /c /Fo#{output} /Tp#{src}")
30
30
  end
31
31
 
32
32
  def ar(lib)
@@ -35,9 +35,12 @@ module Bake
35
35
  output = lib_fn(lib)
36
36
  if lib[:libtype] == 'dynamic'
37
37
  flags += ' /debug' if lib[:debug_symbols?]
38
- sh("link /nologo /dll #{flags} /out:#{output[1]} #{obj_str}")
38
+ sys.sh("link /nologo /dll #{flags} /out:#{output[1]} #{obj_str}")
39
+ # need to touch the .exp file because it sometimes
40
+ # doesn't get updated
41
+ sys.touch(output[2])
39
42
  else
40
- sh("lib /nologo /out:#{output} #{obj_str}")
43
+ sys.sh("lib /nologo /out:#{output} #{obj_str}")
41
44
  end
42
45
  end
43
46
 
@@ -46,17 +49,7 @@ module Bake
46
49
 
47
50
  output = exe_fn(exe)
48
51
  flags += ' /debug' if exe[:debug_symbols?]
49
- sh("link /nologo /subsystem:console #{flags} /out:#{output} #{obj_str}")
50
- end
51
-
52
- def run(runner)
53
- sh(exe_fn(runner.deps.first))
54
- FileUtils.touch(runner_fn(runner))
55
- end
56
-
57
- private
58
- def build_flags(flag, args)
59
- return args.inject('') { |str, arg| str + "#{flag}#{arg} " }
52
+ sys.sh("link /nologo /subsystem:console #{flags} /out:#{output} #{obj_str}")
60
53
  end
61
54
 
62
55
  def obj_fn(obj)
@@ -78,8 +71,9 @@ module Bake
78
71
  return File.join(exe[:outdir], exe.name + '.exe')
79
72
  end
80
73
 
81
- def runner_fn(runner)
82
- return "#{exe_fn(runner.deps.first)}.success"
74
+ private
75
+ def build_flags(flag, args)
76
+ return args.inject('') { |str, arg| str + "#{flag}#{arg} " }
83
77
  end
84
78
 
85
79
  def process_inputs(target)