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.
- data/CHANGELOG +16 -0
- data/CONCEPTS +52 -0
- data/TUTORIAL +12 -23
- data/lib/bake.rb +7 -34
- data/lib/bake/addon.rb +20 -0
- data/lib/bake/context.rb +40 -60
- data/lib/bake/file_target.rb +14 -0
- data/lib/bake/plugin.rb +72 -0
- data/lib/bake/plugins/cpp.rb +122 -0
- data/lib/bake/plugins/cpp/darwin.rb +27 -0
- data/lib/bake/plugins/cpp/gcc.rb +9 -0
- data/lib/bake/plugins/cpp/gcc_toolset_base.rb +118 -0
- data/lib/bake/plugins/cpp/msvc.rb +124 -0
- data/lib/bake/plugins/cpp/qt.rb +50 -0
- data/lib/bake/plugins/cpp/toolset_base.rb +98 -0
- data/lib/bake/plugins/macro.rb +18 -0
- data/lib/bake/plugins/system.rb +46 -0
- data/lib/bake/project.rb +50 -0
- data/lib/bake/project_loader.rb +11 -15
- data/lib/bake/string_utils.rb +4 -0
- data/lib/bake/target.rb +43 -80
- data/lib/bake/toolset.rb +13 -6
- data/lib/bake_version.rb +1 -1
- metadata +19 -7
- data/lib/bake/common_scheme.rb +0 -42
- data/lib/bake/cpp_scheme.rb +0 -460
- data/lib/bake/qt_scheme.rb +0 -62
- data/lib/bake/scheme.rb +0 -104
- data/lib/bake/scheme_loader.rb +0 -28
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'bake/target'
|
2
|
+
|
3
|
+
module Bake
|
4
|
+
module Plugins
|
5
|
+
module Cpp
|
6
|
+
class SystemLibrary < Target
|
7
|
+
attr_reader :file
|
8
|
+
|
9
|
+
def initialize(parent, toolset, name, file)
|
10
|
+
super(parent, toolset)
|
11
|
+
@built = true
|
12
|
+
@name = name
|
13
|
+
@file = file
|
14
|
+
opt(:built? => true)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class Library < Target
|
19
|
+
def initialize(parent, toolset, name)
|
20
|
+
super(parent, toolset)
|
21
|
+
@name = name
|
22
|
+
default(:libtype => 'static')
|
23
|
+
default(:debug_symbols? => false)
|
24
|
+
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
|
+
end
|
31
|
+
|
32
|
+
class Executable < Target
|
33
|
+
def initialize(parent, toolset, name)
|
34
|
+
super(parent, toolset)
|
35
|
+
@name = name
|
36
|
+
default(:debug_symbols? => false)
|
37
|
+
end
|
38
|
+
|
39
|
+
def add_dep(target)
|
40
|
+
return super if !target.is_a?(FileTarget)
|
41
|
+
deps << Cpp::Object.new(self, toolset, target)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
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)
|
53
|
+
end
|
54
|
+
|
55
|
+
def src
|
56
|
+
return deps.first.path
|
57
|
+
end
|
58
|
+
|
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
|
67
|
+
end
|
68
|
+
return @includes
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
def load_includes(incfile)
|
73
|
+
includes = Set.new
|
74
|
+
file = File.open(incfile)
|
75
|
+
while line = file.gets
|
76
|
+
line.chomp!
|
77
|
+
includes << line if !line.empty?
|
78
|
+
end
|
79
|
+
file.close
|
80
|
+
return includes
|
81
|
+
end
|
82
|
+
|
83
|
+
def calc_includes(filename, include_fns)
|
84
|
+
new_include_fns = Set.new
|
85
|
+
File.open(filename) do |file|
|
86
|
+
incdirs = get(:incdirs)
|
87
|
+
while line = file.gets
|
88
|
+
if line =~ /\s*#\s*include\s+("|<)([^"]+)("|>)/
|
89
|
+
inc = $2
|
90
|
+
incdirs.each do |include_dir|
|
91
|
+
fn = File.join(include_dir, inc)
|
92
|
+
break if include_fns.include?(fn)
|
93
|
+
if File.exists?(fn)
|
94
|
+
new_include_fns << fn
|
95
|
+
include_fns << fn
|
96
|
+
break
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
new_include_fns.each do |inc|
|
104
|
+
calc_includes(inc, include_fns)
|
105
|
+
end
|
106
|
+
return include_fns
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
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
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Bake
|
2
|
+
module Plugins
|
3
|
+
module Cpp
|
4
|
+
class Darwin < GccToolsetBase
|
5
|
+
def ar(lib)
|
6
|
+
obj_str, lib_str, flags = process_inputs(lib)
|
7
|
+
|
8
|
+
output = lib_fn(lib)
|
9
|
+
if lib[:libtype] == 'dynamic'
|
10
|
+
sh("g++ #{flags} -dynamiclib -o #{output} #{obj_str} #{lib_str}")
|
11
|
+
else
|
12
|
+
sh("ar rcs #{output} #{obj_str}")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
def lib_fn(lib)
|
18
|
+
if lib[:libtype] == 'dynamic'
|
19
|
+
return File.join(lib[:outdir], "#{lib.name}.dylib")
|
20
|
+
end
|
21
|
+
return File.join(lib[:outdir], "lib#{lib.name}.a")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module Bake
|
4
|
+
module Plugins
|
5
|
+
module Cpp
|
6
|
+
class GccToolsetBase < ToolsetBase
|
7
|
+
def output(target)
|
8
|
+
if target.is_a?(Cpp::Object)
|
9
|
+
return obj_fn(target)
|
10
|
+
elsif target.is_a?(Cpp::Library)
|
11
|
+
return lib_fn(target)
|
12
|
+
elsif target.is_a?(Cpp::Executable)
|
13
|
+
return exe_fn(target)
|
14
|
+
elsif target.is_a?(Cpp::Runner)
|
15
|
+
return runner_fn(target)
|
16
|
+
end
|
17
|
+
return nil
|
18
|
+
end
|
19
|
+
|
20
|
+
def compile(obj)
|
21
|
+
src = obj.src
|
22
|
+
output = obj_fn(obj)
|
23
|
+
flags = build_flags('-I', obj[:incdirs] + obj[:sysincdirs]) +
|
24
|
+
build_flags('-D', obj[:defines])
|
25
|
+
flags += obj[:cflags].join(' ')
|
26
|
+
flags += ' -fno-rtti' if !obj[:rtti?]
|
27
|
+
flags += ' -O3' if obj[:optimizations?]
|
28
|
+
flags += ' -g' if obj[:debug_symbols?]
|
29
|
+
sh("g++ -c -o #{output} #{flags} #{src}")
|
30
|
+
end
|
31
|
+
|
32
|
+
def ar(lib)
|
33
|
+
obj_str, lib_str, flags = process_inputs(lib)
|
34
|
+
|
35
|
+
output = lib_fn(lib)
|
36
|
+
if lib[:libtype] == 'dynamic'
|
37
|
+
sh("g++ #{flags} -shared -Wl,-soname,#{output} -o #{output} #{obj_str} #{lib_str}")
|
38
|
+
if lib.has_prop?(:gcc_lib_path)
|
39
|
+
fn = File.join(lib[:gcc_lib_path], output.basename)
|
40
|
+
File.symlink(output, fn) if !File.exists?(fn)
|
41
|
+
end
|
42
|
+
else
|
43
|
+
sh("ar rcs #{output} #{obj_str}")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def link(exe)
|
48
|
+
obj_str, lib_str, flags = process_inputs(exe)
|
49
|
+
|
50
|
+
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} " }
|
62
|
+
end
|
63
|
+
|
64
|
+
def obj_fn(obj)
|
65
|
+
src = obj.src
|
66
|
+
basename = File.basename(src, File.extname(src)) + '.o'
|
67
|
+
return File.join(obj[:outdir], basename)
|
68
|
+
end
|
69
|
+
|
70
|
+
def lib_fn(lib)
|
71
|
+
if lib[:libtype] == 'dynamic'
|
72
|
+
return File.join(lib[:outdir], "lib#{lib.name}.so")
|
73
|
+
end
|
74
|
+
return File.join(lib[:outdir], "lib#{lib.name}.a")
|
75
|
+
end
|
76
|
+
|
77
|
+
def exe_fn(exe)
|
78
|
+
return File.join(exe[:outdir], exe.name)
|
79
|
+
end
|
80
|
+
|
81
|
+
def runner_fn(runner)
|
82
|
+
return "#{exe_fn(runner.deps.first)}.success"
|
83
|
+
end
|
84
|
+
|
85
|
+
def process_inputs(target)
|
86
|
+
output = output(target)
|
87
|
+
obj_str = ''
|
88
|
+
lib_str = ''
|
89
|
+
libdirs = []
|
90
|
+
rtdirs = []
|
91
|
+
target.deps.each do |input|
|
92
|
+
if input.is_a?(Cpp::Object)
|
93
|
+
fn = obj_fn(input)
|
94
|
+
obj_str += fn + ' '
|
95
|
+
elsif input.is_a?(Cpp::SystemLibrary)
|
96
|
+
lib_str += '-l' + input.file + ' '
|
97
|
+
elsif input.is_a?(Cpp::Library)
|
98
|
+
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
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
libdirs.concat(target[:libdirs])
|
111
|
+
flags = build_flags('-L', libdirs)
|
112
|
+
return [ obj_str, lib_str, flags ]
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module Bake
|
4
|
+
module Plugins
|
5
|
+
module Cpp
|
6
|
+
class Msvc < ToolsetBase
|
7
|
+
def output(target)
|
8
|
+
if target.is_a?(Object)
|
9
|
+
return obj_fn(target)
|
10
|
+
elsif target.is_a?(Library)
|
11
|
+
return lib_fn(target)
|
12
|
+
elsif target.is_a?(Executable)
|
13
|
+
return exe_fn(target)
|
14
|
+
end
|
15
|
+
return nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def compile(obj)
|
19
|
+
src = obj.src
|
20
|
+
output = obj_fn(obj)
|
21
|
+
flags = build_flags('/I', obj[:incdirs] + obj[:sysincdirs]) +
|
22
|
+
build_flags('/D', obj[:defines])
|
23
|
+
flags += obj[:cflags].join(' ')
|
24
|
+
flags += ' /MD'
|
25
|
+
flags += ' /EHsc' if obj[:exceptions?]
|
26
|
+
flags += ' /GR' if obj[:rtti?]
|
27
|
+
flags += obj[:optimizations?] ? ' /O2' : ' /Od'
|
28
|
+
flags += ' /Z7' if obj[:debug_symbols?]
|
29
|
+
sh("cl /nologo #{flags} /c /Fo#{output} /Tp#{src}")
|
30
|
+
end
|
31
|
+
|
32
|
+
def ar(lib)
|
33
|
+
obj_str, flags = process_inputs(lib)
|
34
|
+
|
35
|
+
output = lib_fn(lib)
|
36
|
+
if lib[:libtype] == 'dynamic'
|
37
|
+
flags += ' /debug' if lib[:debug_symbols?]
|
38
|
+
sh("link /nologo /dll #{flags} /out:#{output[1]} #{obj_str}")
|
39
|
+
else
|
40
|
+
sh("lib /nologo /out:#{output} #{obj_str}")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def link(exe)
|
45
|
+
obj_str, flags = process_inputs(exe)
|
46
|
+
|
47
|
+
output = exe_fn(exe)
|
48
|
+
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} " }
|
60
|
+
end
|
61
|
+
|
62
|
+
def obj_fn(obj)
|
63
|
+
src = obj.src
|
64
|
+
basename = File.basename(src, File.extname(src)) + '.obj'
|
65
|
+
return File.join(obj[:outdir], basename)
|
66
|
+
end
|
67
|
+
|
68
|
+
def lib_fn(lib)
|
69
|
+
if lib[:libtype] == 'dynamic'
|
70
|
+
return [File.join(lib[:outdir], "#{lib.name}.lib"),
|
71
|
+
File.join(lib[:outdir], "#{lib.name}.dll"),
|
72
|
+
File.join(lib[:outdir], "#{lib.name}.exp")]
|
73
|
+
end
|
74
|
+
return File.join(lib[:outdir], "#{lib.name}.lib")
|
75
|
+
end
|
76
|
+
|
77
|
+
def exe_fn(exe)
|
78
|
+
return File.join(exe[:outdir], exe.name + '.exe')
|
79
|
+
end
|
80
|
+
|
81
|
+
def runner_fn(runner)
|
82
|
+
return "#{exe_fn(runner.deps.first)}.success"
|
83
|
+
end
|
84
|
+
|
85
|
+
def process_inputs(target)
|
86
|
+
output = output(target)
|
87
|
+
obj_str = ''
|
88
|
+
libdirs = []
|
89
|
+
static_lib = target.is_a?(Library) && target[:libtype] == 'static'
|
90
|
+
target.deps.each do |input|
|
91
|
+
if input.is_a?(Object)
|
92
|
+
fn = obj_fn(input)
|
93
|
+
obj_str += fn + ' '
|
94
|
+
elsif input.is_a?(SystemLibrary)
|
95
|
+
if !static_lib
|
96
|
+
obj_str += input.file + '.lib '
|
97
|
+
end
|
98
|
+
elsif input.is_a?(Library)
|
99
|
+
if !static_lib
|
100
|
+
if input[:libtype] == 'dynamic'
|
101
|
+
fn = lib_fn(input)[0]
|
102
|
+
else
|
103
|
+
fn = lib_fn(input)
|
104
|
+
end
|
105
|
+
libdir = File.dirname(fn)
|
106
|
+
libdirs << libdir if !libdirs.include?(libdir)
|
107
|
+
obj_str += File.basename(fn) + ' '
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
if !static_lib
|
113
|
+
target[:libs].each { |lib| obj_str += lib + '.lib ' }
|
114
|
+
end
|
115
|
+
libdirs.concat(target[:libdirs])
|
116
|
+
flags = build_flags('/LIBPATH:', libdirs)
|
117
|
+
|
118
|
+
return [ obj_str, flags ]
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'bake/toolset'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
module Bake
|
5
|
+
module Plugins
|
6
|
+
module Cpp
|
7
|
+
module Qt
|
8
|
+
class Moc
|
9
|
+
include Toolset
|
10
|
+
|
11
|
+
def build(target)
|
12
|
+
raise "unknown target '#{target}'" if !target.is_a?(MocFile)
|
13
|
+
return if !stale?(target)
|
14
|
+
src = target.src
|
15
|
+
sh("moc -o #{target.output} #{target.src}")
|
16
|
+
end
|
17
|
+
|
18
|
+
def clean(target)
|
19
|
+
FileUtils.rm_f(target.output)
|
20
|
+
end
|
21
|
+
|
22
|
+
def stale?(target)
|
23
|
+
return true if !File.exists?(target.output)
|
24
|
+
return File.mtime(target.src) > File.mtime(target.output)
|
25
|
+
end
|
26
|
+
|
27
|
+
def sh(*args)
|
28
|
+
cmd = args.join(' ')
|
29
|
+
puts cmd
|
30
|
+
system(*args)
|
31
|
+
raise "error: #{cmd}" if !$? || !$?.success?
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class MocFile < Bake::Target
|
36
|
+
attr_reader :output
|
37
|
+
attr_accessor :src
|
38
|
+
|
39
|
+
def initialize(parent, src)
|
40
|
+
super(parent)
|
41
|
+
ext = File.extname(src)
|
42
|
+
@output = File.basename(src, ext) + '.moc' + ext
|
43
|
+
@src = src
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|