bake 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|