bake 0.1.1 → 0.1.2

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.
@@ -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)