rub 0.4.0
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.
- checksums.yaml +7 -0
- data/lib/rub/c.rb +276 -0
- data/lib/rub/d.rb +252 -0
- data/lib/rub/dirs.rb +30 -0
- data/lib/rub/help.rb +178 -0
- data/lib/rub/init.rb +91 -0
- data/lib/rub/l.rb +40 -0
- data/lib/rub/l/c.rb +476 -0
- data/lib/rub/l/c/compiler/clang.rb +94 -0
- data/lib/rub/l/c/compiler/gcc.rb +94 -0
- data/lib/rub/l/ld.rb +254 -0
- data/lib/rub/l/ld/linker/clang.rb +89 -0
- data/lib/rub/l/ld/linker/gcc.rb +89 -0
- data/lib/rub/l/ld/linker/ld.rb +91 -0
- data/lib/rub/l/template.rb +92 -0
- data/lib/rub/l/test.rb +256 -0
- data/lib/rub/l/util.rb +163 -0
- data/lib/rub/r.rb +42 -0
- data/lib/rub/r/command.rb +293 -0
- data/lib/rub/r/env.rb +71 -0
- data/lib/rub/r/i/commandline.rb +192 -0
- data/lib/rub/r/i/runner.rb +78 -0
- data/lib/rub/r/persist.rb +71 -0
- data/lib/rub/r/target.rb +250 -0
- data/lib/rub/r/targetgenerator.rb +80 -0
- data/lib/rub/r/tool.rb +159 -0
- data/lib/rub/r/version-git.rb +62 -0
- data/lib/rub/r/version.rb +145 -0
- metadata +127 -0
data/lib/rub/dirs.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# Copyright 2013 Kevin Cox
|
2
|
+
|
3
|
+
################################################################################
|
4
|
+
# #
|
5
|
+
# This software is provided 'as-is', without any express or implied #
|
6
|
+
# warranty. In no event will the authors be held liable for any damages #
|
7
|
+
# arising from the use of this software. #
|
8
|
+
# #
|
9
|
+
# Permission is granted to anyone to use this software for any purpose, #
|
10
|
+
# including commercial applications, and to alter it and redistribute it #
|
11
|
+
# freely, subject to the following restrictions: #
|
12
|
+
# #
|
13
|
+
# 1. The origin of this software must not be misrepresented; you must not #
|
14
|
+
# claim that you wrote the original software. If you use this software in #
|
15
|
+
# a product, an acknowledgment in the product documentation would be #
|
16
|
+
# appreciated but is not required. #
|
17
|
+
# #
|
18
|
+
# 2. Altered source versions must be plainly marked as such, and must not be #
|
19
|
+
# misrepresented as being the original software. #
|
20
|
+
# #
|
21
|
+
# 3. This notice may not be removed or altered from any source distribution. #
|
22
|
+
# #
|
23
|
+
################################################################################
|
24
|
+
|
25
|
+
[
|
26
|
+
R::Env.src_dir,
|
27
|
+
R::Env.out_dir,
|
28
|
+
R::Env.global_cache,
|
29
|
+
R::Env.project_cache,
|
30
|
+
].each{|d| d.mkpath }
|
data/lib/rub/help.rb
ADDED
@@ -0,0 +1,178 @@
|
|
1
|
+
# Copyright 2013 Kevin Cox
|
2
|
+
|
3
|
+
################################################################################
|
4
|
+
# #
|
5
|
+
# This software is provided 'as-is', without any express or implied #
|
6
|
+
# warranty. In no event will the authors be held liable for any damages #
|
7
|
+
# arising from the use of this software. #
|
8
|
+
# #
|
9
|
+
# Permission is granted to anyone to use this software for any purpose, #
|
10
|
+
# including commercial applications, and to alter it and redistribute it #
|
11
|
+
# freely, subject to the following restrictions: #
|
12
|
+
# #
|
13
|
+
# 1. The origin of this software must not be misrepresented; you must not #
|
14
|
+
# claim that you wrote the original software. If you use this software in #
|
15
|
+
# a product, an acknowledgment in the product documentation would be #
|
16
|
+
# appreciated but is not required. #
|
17
|
+
# #
|
18
|
+
# 2. Altered source versions must be plainly marked as such, and must not be #
|
19
|
+
# misrepresented as being the original software. #
|
20
|
+
# #
|
21
|
+
# 3. This notice may not be removed or altered from any source distribution. #
|
22
|
+
# #
|
23
|
+
################################################################################
|
24
|
+
|
25
|
+
require 'pathname'
|
26
|
+
require 'singleton'
|
27
|
+
|
28
|
+
module R
|
29
|
+
class TargetHelp < C::TargetTag
|
30
|
+
@@tag = nil
|
31
|
+
def gen_help
|
32
|
+
@@tag and return
|
33
|
+
|
34
|
+
@@tag = Set.new
|
35
|
+
@@bld = Set.new
|
36
|
+
@@ins = Set.new
|
37
|
+
@@src = Set.new
|
38
|
+
|
39
|
+
R.targets.each do |p, t|
|
40
|
+
if p.is_a? Symbol
|
41
|
+
@@tag << [p, t]
|
42
|
+
elsif p.to_s.start_with?(R::Env.out_dir.to_s)
|
43
|
+
@@bld << [p, t]
|
44
|
+
elsif (
|
45
|
+
p.to_s.start_with?(D[:prefix].to_s+'/') ||
|
46
|
+
!p.to_s.start_with?(R::Env.src_dir.to_s)
|
47
|
+
)
|
48
|
+
@@ins << [p, t]
|
49
|
+
else
|
50
|
+
@@src << [p, t]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def initialize(t)
|
56
|
+
super t.to_sym
|
57
|
+
|
58
|
+
register
|
59
|
+
end
|
60
|
+
|
61
|
+
def print_target(ta)
|
62
|
+
p, t = ta
|
63
|
+
ps = if p.is_a? Symbol
|
64
|
+
#p.inspect
|
65
|
+
":#{p}"
|
66
|
+
else
|
67
|
+
p.to_s
|
68
|
+
end
|
69
|
+
|
70
|
+
if t.description
|
71
|
+
printf " %-20s - %s\n", ps, t.description
|
72
|
+
else
|
73
|
+
printf " %s\n", ps
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def print_targets(tm)
|
78
|
+
tm.each do |t|
|
79
|
+
print_target t
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def build
|
84
|
+
gen_help
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
class TargetHelpHelp < TargetHelp
|
89
|
+
include Singleton
|
90
|
+
|
91
|
+
def initialize
|
92
|
+
super :help
|
93
|
+
end
|
94
|
+
|
95
|
+
def build
|
96
|
+
super
|
97
|
+
|
98
|
+
puts <<'EOS'
|
99
|
+
Help:
|
100
|
+
Just displaying tags. If you want to see more see:
|
101
|
+
:help-tag
|
102
|
+
:help-installed
|
103
|
+
:help-built
|
104
|
+
:help-all
|
105
|
+
EOS
|
106
|
+
R.get_target('help-tag'.to_sym).build
|
107
|
+
end
|
108
|
+
end
|
109
|
+
TargetHelpHelp.instance
|
110
|
+
|
111
|
+
class TargetHelpTag < TargetHelp
|
112
|
+
include Singleton
|
113
|
+
|
114
|
+
def initialize
|
115
|
+
super 'help-tag'
|
116
|
+
end
|
117
|
+
|
118
|
+
def build
|
119
|
+
super
|
120
|
+
|
121
|
+
puts 'Tags:'
|
122
|
+
print_targets @@tag
|
123
|
+
end
|
124
|
+
end
|
125
|
+
TargetHelpTag.instance
|
126
|
+
|
127
|
+
class TargetHelpInstalled < TargetHelp
|
128
|
+
include Singleton
|
129
|
+
|
130
|
+
def initialize
|
131
|
+
super 'help-installed'
|
132
|
+
end
|
133
|
+
|
134
|
+
def build
|
135
|
+
super
|
136
|
+
|
137
|
+
puts 'Installed:'
|
138
|
+
print_targets @@ins
|
139
|
+
end
|
140
|
+
end
|
141
|
+
TargetHelpInstalled.instance
|
142
|
+
|
143
|
+
class TargetHelpBuilt < TargetHelp
|
144
|
+
include Singleton
|
145
|
+
|
146
|
+
def initialize
|
147
|
+
super 'help-built'
|
148
|
+
end
|
149
|
+
|
150
|
+
def build
|
151
|
+
super
|
152
|
+
|
153
|
+
puts 'Build Targets:'
|
154
|
+
print_targets @@bld
|
155
|
+
end
|
156
|
+
end
|
157
|
+
TargetHelpBuilt.instance
|
158
|
+
|
159
|
+
class TargetHelpAll < TargetHelp
|
160
|
+
include Singleton
|
161
|
+
|
162
|
+
def initialize
|
163
|
+
super 'help-all'
|
164
|
+
end
|
165
|
+
|
166
|
+
def build
|
167
|
+
super
|
168
|
+
|
169
|
+
[
|
170
|
+
'help-tag',
|
171
|
+
'help-installed',
|
172
|
+
'help-built',
|
173
|
+
].each{|t| R.get_target(t.to_sym).build }
|
174
|
+
end
|
175
|
+
end
|
176
|
+
TargetHelpAll.instance
|
177
|
+
|
178
|
+
end
|
data/lib/rub/init.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
|
3
|
+
# Copyright 2013 Kevin Cox
|
4
|
+
|
5
|
+
################################################################################
|
6
|
+
# #
|
7
|
+
# This software is provided 'as-is', without any express or implied #
|
8
|
+
# warranty. In no event will the authors be held liable for any damages #
|
9
|
+
# arising from the use of this software. #
|
10
|
+
# #
|
11
|
+
# Permission is granted to anyone to use this software for any purpose, #
|
12
|
+
# including commercial applications, and to alter it and redistribute it #
|
13
|
+
# freely, subject to the following restrictions: #
|
14
|
+
# #
|
15
|
+
# 1. The origin of this software must not be misrepresented; you must not #
|
16
|
+
# claim that you wrote the original software. If you use this software in #
|
17
|
+
# a product, an acknowledgment in the product documentation would be #
|
18
|
+
# appreciated but is not required. #
|
19
|
+
# #
|
20
|
+
# 2. Altered source versions must be plainly marked as such, and must not be #
|
21
|
+
# misrepresented as being the original software. #
|
22
|
+
# #
|
23
|
+
# 3. This notice may not be removed or altered from any source distribution. #
|
24
|
+
# #
|
25
|
+
################################################################################
|
26
|
+
|
27
|
+
##### These libraries are guaranteed to be loaded.
|
28
|
+
require 'pathname'
|
29
|
+
require 'set'
|
30
|
+
require 'pp'
|
31
|
+
require 'digest/sha1'
|
32
|
+
|
33
|
+
require 'sysexits'
|
34
|
+
require 'xdg'
|
35
|
+
|
36
|
+
# This is first so we modify all of our classes.
|
37
|
+
'
|
38
|
+
class Object
|
39
|
+
def self.method_added name
|
40
|
+
return if name == :initialize
|
41
|
+
return if @__last_methods_added && @__last_methods_added.include?(name)
|
42
|
+
|
43
|
+
with = :"#{name}_with_before_each_method"
|
44
|
+
without = :"#{name}_without_before_each_method"
|
45
|
+
|
46
|
+
@__last_methods_added = [name, with, without]
|
47
|
+
define_method with do |*args, &block|
|
48
|
+
puts "#{self.class}##{name}"
|
49
|
+
pp args, &block
|
50
|
+
puts "calling..."
|
51
|
+
|
52
|
+
r = send without, *args, &block
|
53
|
+
|
54
|
+
puts "#{self.class}##{name} returned"
|
55
|
+
|
56
|
+
r
|
57
|
+
end
|
58
|
+
alias_method without, name
|
59
|
+
alias_method name, with
|
60
|
+
@__last_methods_added = nil
|
61
|
+
end
|
62
|
+
end
|
63
|
+
#'
|
64
|
+
|
65
|
+
##### Load the namespaces.
|
66
|
+
require_relative 'd'
|
67
|
+
require_relative 'r'
|
68
|
+
require_relative 'l'
|
69
|
+
require_relative 'c'
|
70
|
+
|
71
|
+
# Odd jobs.
|
72
|
+
require_relative 'dirs'
|
73
|
+
require_relative 'help'
|
74
|
+
|
75
|
+
##### Add the first two scripts.
|
76
|
+
R::I::Runner.do_file(R::Env.src_dir+"root.rub")
|
77
|
+
R::I::Runner.do_file(R::Env.cmd_dir+"dir.rub")
|
78
|
+
|
79
|
+
##### Add default target if necessary.
|
80
|
+
ARGV.empty? and ARGV << ':all'
|
81
|
+
|
82
|
+
##### Build requested targets.
|
83
|
+
ARGV.each do |t|
|
84
|
+
t = if t =~ /^:[^\/]*$/ # Is a tag.
|
85
|
+
t[1..-1].to_sym
|
86
|
+
else
|
87
|
+
C.path(t)
|
88
|
+
end
|
89
|
+
R::get_target(t).build
|
90
|
+
end
|
91
|
+
|
data/lib/rub/l.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
|
3
|
+
# Copyright 2013 Kevin Cox
|
4
|
+
|
5
|
+
################################################################################
|
6
|
+
# #
|
7
|
+
# This software is provided 'as-is', without any express or implied #
|
8
|
+
# warranty. In no event will the authors be held liable for any damages #
|
9
|
+
# arising from the use of this software. #
|
10
|
+
# #
|
11
|
+
# Permission is granted to anyone to use this software for any purpose, #
|
12
|
+
# including commercial applications, and to alter it and redistribute it #
|
13
|
+
# freely, subject to the following restrictions: #
|
14
|
+
# #
|
15
|
+
# 1. The origin of this software must not be misrepresented; you must not #
|
16
|
+
# claim that you wrote the original software. If you use this software in #
|
17
|
+
# a product, an acknowledgment in the product documentation would be #
|
18
|
+
# appreciated but is not required. #
|
19
|
+
# #
|
20
|
+
# 2. Altered source versions must be plainly marked as such, and must not be #
|
21
|
+
# misrepresented as being the original software. #
|
22
|
+
# #
|
23
|
+
# 3. This notice may not be removed or altered from any source distribution. #
|
24
|
+
# #
|
25
|
+
################################################################################
|
26
|
+
|
27
|
+
# Library Module
|
28
|
+
#
|
29
|
+
# Loaded libraries become available here.
|
30
|
+
module L
|
31
|
+
# Auto-load libraries.
|
32
|
+
def self.const_missing(n)
|
33
|
+
#pp n
|
34
|
+
p = "l/#{n.to_s.downcase}"
|
35
|
+
|
36
|
+
require_relative p
|
37
|
+
const_defined?(n, false) or raise "Library #{p} malformed, was expected to load into L::#{n}."
|
38
|
+
const_get(n, false)
|
39
|
+
end
|
40
|
+
end
|
data/lib/rub/l/c.rb
ADDED
@@ -0,0 +1,476 @@
|
|
1
|
+
# Copyright 2013 Kevin Cox
|
2
|
+
|
3
|
+
################################################################################
|
4
|
+
# #
|
5
|
+
# This software is provided 'as-is', without any express or implied #
|
6
|
+
# warranty. In no event will the authors be held liable for any damages #
|
7
|
+
# arising from the use of this software. #
|
8
|
+
# #
|
9
|
+
# Permission is granted to anyone to use this software for any purpose, #
|
10
|
+
# including commercial applications, and to alter it and redistribute it #
|
11
|
+
# freely, subject to the following restrictions: #
|
12
|
+
# #
|
13
|
+
# 1. The origin of this software must not be misrepresented; you must not #
|
14
|
+
# claim that you wrote the original software. If you use this software in #
|
15
|
+
# a product, an acknowledgment in the product documentation would be #
|
16
|
+
# appreciated but is not required. #
|
17
|
+
# #
|
18
|
+
# 2. Altered source versions must be plainly marked as such, and must not be #
|
19
|
+
# misrepresented as being the original software. #
|
20
|
+
# #
|
21
|
+
# 3. This notice may not be removed or altered from any source distribution. #
|
22
|
+
# #
|
23
|
+
################################################################################
|
24
|
+
|
25
|
+
require 'tempfile'
|
26
|
+
|
27
|
+
# C Library
|
28
|
+
module L::C
|
29
|
+
# @!scope class
|
30
|
+
# All available compilers.
|
31
|
+
# @return [Hash{Symbol=>Compiler}]
|
32
|
+
cattr_accessor :compilers
|
33
|
+
@compilers = {}
|
34
|
+
|
35
|
+
# Compiler
|
36
|
+
#
|
37
|
+
# The compiler to use.
|
38
|
+
#
|
39
|
+
# @return (see compiler)
|
40
|
+
# @see compiler
|
41
|
+
cattr_reader :compiler
|
42
|
+
def self.compiler=(name)
|
43
|
+
@compiler = get_compiler name
|
44
|
+
end
|
45
|
+
|
46
|
+
# @!scope class
|
47
|
+
# Default optimization level.
|
48
|
+
#
|
49
|
+
# This takes one of four optimization levels. The actual optimization
|
50
|
+
# done is linker dependant. For example, some linker may not have
|
51
|
+
# any optimization so all levels will be equivalent.
|
52
|
+
#
|
53
|
+
# One of the following:
|
54
|
+
# [+:none+] Perform no optimization. This should be fast and debuggable.
|
55
|
+
# [+:some+] Perform light optimization that is pretty fast.
|
56
|
+
# [+:full+] Perform a high level of optimization producing a fast binary.
|
57
|
+
# this may considerably slow down compilation.
|
58
|
+
# [+:max+] Perform all available optimizations. These may be
|
59
|
+
# experimental and very slow.
|
60
|
+
#
|
61
|
+
# This value defaults to +:full+ if +D:debug+ is set, otherwise +:none+.
|
62
|
+
#
|
63
|
+
# @return [Symbol]
|
64
|
+
cattr_accessor :optimize
|
65
|
+
|
66
|
+
# @!scope class
|
67
|
+
# Default optimization goal.
|
68
|
+
#
|
69
|
+
# This determines what the compiler should optimize for if it has the
|
70
|
+
# option.
|
71
|
+
#
|
72
|
+
# One of the following:
|
73
|
+
# [+:size+] The compiler should focus on creating a small binary.
|
74
|
+
# [+:speed+] The compiler should focus on creating a fast binary.
|
75
|
+
#
|
76
|
+
# @return [Symbol]
|
77
|
+
cattr_accessor :optimize_for
|
78
|
+
|
79
|
+
# @!scope class
|
80
|
+
# Default debug symbols setting.
|
81
|
+
#
|
82
|
+
# This determines if the compiler should produce debugging symbols.
|
83
|
+
#
|
84
|
+
# @return [true,false]
|
85
|
+
cattr_accessor :debug
|
86
|
+
|
87
|
+
# @!scope class
|
88
|
+
# Default profile symbols setting.
|
89
|
+
#
|
90
|
+
# This determines if the compiler should produce code suitable for
|
91
|
+
# profiling.
|
92
|
+
#
|
93
|
+
# @return [true,false]
|
94
|
+
cattr_accessor :profile
|
95
|
+
|
96
|
+
# @!scope class
|
97
|
+
# A list of directories to search for header files.
|
98
|
+
#
|
99
|
+
# These paths are searched in order.
|
100
|
+
#
|
101
|
+
# @return [Array<Pathname>]
|
102
|
+
cattr_accessor :include_dirs
|
103
|
+
|
104
|
+
# @!scope class
|
105
|
+
# A list of libraries to link.
|
106
|
+
#
|
107
|
+
# @return [Array<String,Pathname>]
|
108
|
+
cattr_accessor :libs
|
109
|
+
|
110
|
+
# @!scope class
|
111
|
+
# A list of macros to define. `nil` can be used to undefine a macro.
|
112
|
+
#
|
113
|
+
# @return [Hash{String=>String,true,nil}]
|
114
|
+
cattr_accessor :define
|
115
|
+
|
116
|
+
@debug = @profile = !!D[:debug]
|
117
|
+
@optimize = @debug ? :none : :full
|
118
|
+
|
119
|
+
@include_dirs = R::Tool::PathArray.new
|
120
|
+
@libs = L::LD::LibraryArray.new
|
121
|
+
@define = {
|
122
|
+
@debug ? 'DEBUG' : 'NDEBUG' => true,
|
123
|
+
}
|
124
|
+
|
125
|
+
# An Abstraction over different compilers.
|
126
|
+
module Compiler
|
127
|
+
# The name of the compiler.
|
128
|
+
#
|
129
|
+
# @return [Symbol]
|
130
|
+
def self.name
|
131
|
+
:default
|
132
|
+
end
|
133
|
+
|
134
|
+
# If the compiler is available on the current system.
|
135
|
+
#
|
136
|
+
# @return [true,false]
|
137
|
+
def self.available?
|
138
|
+
false
|
139
|
+
end
|
140
|
+
|
141
|
+
# Return the preferred linker.
|
142
|
+
#
|
143
|
+
# Some compilers create objects that need to be linked with their
|
144
|
+
# linker. This allows the compiler to specify the linker is wishes to
|
145
|
+
# be used.
|
146
|
+
def self.linker
|
147
|
+
nil
|
148
|
+
end
|
149
|
+
|
150
|
+
# Compile source files.
|
151
|
+
#
|
152
|
+
# @param src [Set<Pathname>] The source files to link and generated headers.
|
153
|
+
# @param obj [Pathname] The path of the output file.
|
154
|
+
# @param opt [Options] An options object.
|
155
|
+
# @return [Pathname] The output file.
|
156
|
+
def self.compile_command(opt, src, obj)
|
157
|
+
raise "Not implemented!"
|
158
|
+
end
|
159
|
+
|
160
|
+
# Compile a file.
|
161
|
+
#
|
162
|
+
# @param (see compile_command)
|
163
|
+
# @return [R::Command] the process that compiled the file.
|
164
|
+
def self.do_compile_file(opt, f, obj)
|
165
|
+
c = R::Command.new(compile_command(opt, f, obj))
|
166
|
+
c.run
|
167
|
+
c
|
168
|
+
end
|
169
|
+
|
170
|
+
# Compile a string.
|
171
|
+
#
|
172
|
+
# @param str [String] A string containing the complete source to compile.
|
173
|
+
# @param obj [Pathname] The path of the output file.
|
174
|
+
# @param opt [Options] An options object.
|
175
|
+
# @return [R::Command] the process that compiled the string.
|
176
|
+
def self.do_compile_string(opt, str, obj)
|
177
|
+
f = Tempfile.new(['rub.l.c.testcompile', '.c'])
|
178
|
+
f.write(str)
|
179
|
+
f.close
|
180
|
+
c = do_compile_file(opt, f.path, obj)
|
181
|
+
f.unlink
|
182
|
+
c
|
183
|
+
end
|
184
|
+
|
185
|
+
# Peform a test compile.
|
186
|
+
#
|
187
|
+
# @param (see do_compile_file)
|
188
|
+
# @return [true,false] true if the compilation succeeded.
|
189
|
+
def self.test_compile(opt, src)
|
190
|
+
c = do_compile_file(opt, src, File::NULL)
|
191
|
+
#p c.success?, c.stdin, c.stdout, c.stderr
|
192
|
+
c.success?
|
193
|
+
end
|
194
|
+
|
195
|
+
# Peform a test compile.
|
196
|
+
#
|
197
|
+
# @param (see do_compile_string)
|
198
|
+
# @return [true,false] true if the compilation succeeded.
|
199
|
+
def self.test_compile_string(opt, src)
|
200
|
+
c = do_compile_string(opt, src, File::NULL)
|
201
|
+
#p c.success?, c.stdin, c.stdout, c.stderr
|
202
|
+
c.success?
|
203
|
+
end
|
204
|
+
|
205
|
+
# Check to see if a macro is defined.
|
206
|
+
#
|
207
|
+
# @param name [String] macro identifier.
|
208
|
+
# @return [true,false] true if the macro is defined.
|
209
|
+
def self.test_macro(opt, name)
|
210
|
+
test_compile_string opt, <<EOF
|
211
|
+
#ifndef #{name}
|
212
|
+
#error "#{name}Not Defined"
|
213
|
+
#endif
|
214
|
+
EOF
|
215
|
+
end
|
216
|
+
|
217
|
+
def self.include_directories(opt)
|
218
|
+
@include_directories and return @include_directories.dup
|
219
|
+
|
220
|
+
cmd = [C.find_command('cpp'), '-v', '-o', File::NULL, File::NULL]
|
221
|
+
c = R::Command.new cmd
|
222
|
+
c.run
|
223
|
+
|
224
|
+
l = c.stderr.lines.map &:chomp
|
225
|
+
|
226
|
+
#qb = l.find_index('#include "..." search starts here:') + 1
|
227
|
+
sb = l.find_index('#include <...> search starts here:') + 1
|
228
|
+
se = l.find_index 'End of search list.'
|
229
|
+
|
230
|
+
@include_directories = l[sb...se].map{|d| Pathname.new d[1..-1] }
|
231
|
+
|
232
|
+
@include_directories.dup
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
def self.get_compiler(name)
|
237
|
+
if name.is_a? Symbol
|
238
|
+
compilers[name]
|
239
|
+
else
|
240
|
+
name
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
R::Tool.load_dir(Pathname.new(__FILE__).realpath.dirname+"c/compiler/")
|
245
|
+
|
246
|
+
tdir = Pathname.new(__FILE__).realpath.dirname + "c/test/"
|
247
|
+
|
248
|
+
@compilers.keep_if do |n, c|
|
249
|
+
c.available? or next false
|
250
|
+
|
251
|
+
r = (
|
252
|
+
c.test_compile(self, tdir+'basic.c') and
|
253
|
+
not c.test_compile(self, tdir+'undefined.c') and
|
254
|
+
c.test_macro(self, '__LINE__')
|
255
|
+
)
|
256
|
+
|
257
|
+
r or $stderr.puts "Ignoring compiler #{n} because it failed the tests."
|
258
|
+
|
259
|
+
r
|
260
|
+
end
|
261
|
+
|
262
|
+
D[:l_c_compiler].map! {|c| c.to_sym}
|
263
|
+
@compiler = compilers[ D[:l_c_compiler].find{|c| compilers.has_key? c} ]
|
264
|
+
|
265
|
+
# Compile source files.
|
266
|
+
#
|
267
|
+
# @param src [Set<Pathname,String>,Array<Pathname,String>,Pathname,String]
|
268
|
+
# The source files to compile and generated headers.
|
269
|
+
# @param opt [Options] An options object.
|
270
|
+
# @return [Set<Pathname>] The resulting object files.
|
271
|
+
def self.compile(src)
|
272
|
+
src = R::Tool.make_set_paths src
|
273
|
+
|
274
|
+
headers = Set.new
|
275
|
+
src.keep_if do |s|
|
276
|
+
if s.extname.match /[H]/i
|
277
|
+
headers << s
|
278
|
+
false
|
279
|
+
else
|
280
|
+
true
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
src.map! do |s|
|
285
|
+
out = R::Env.out_dir + 'l/c/' + C.unique_segment(self) + "#{s.basename}.o"
|
286
|
+
|
287
|
+
R.find_target(s) or TargetCSource.new(self, s, headers)
|
288
|
+
::C.generator(s, compiler.compile_command(self, s, out), out, desc:"Compiling")
|
289
|
+
end
|
290
|
+
src.flatten!
|
291
|
+
src
|
292
|
+
end
|
293
|
+
|
294
|
+
# A C source file.
|
295
|
+
class TargetCSource < R::Target
|
296
|
+
def initialize(opt, f, input = [])
|
297
|
+
#TargetC.initialize
|
298
|
+
|
299
|
+
@f = C.path(f)
|
300
|
+
@opt = opt
|
301
|
+
@input = input
|
302
|
+
|
303
|
+
register
|
304
|
+
end
|
305
|
+
|
306
|
+
def included_files(opt, set=Set.new)
|
307
|
+
set.include?(@f) and return
|
308
|
+
|
309
|
+
set << @f
|
310
|
+
@incs ||= @f.readlines.map do |l|
|
311
|
+
l =~ /\s*#\s*include\s*("(.*)"|<(.*)>)/ or next
|
312
|
+
if $3 and !D[:l_c_system_headers]
|
313
|
+
next
|
314
|
+
end
|
315
|
+
|
316
|
+
p = Pathname.new( $2 || $3 )
|
317
|
+
ip = opt.compiler.include_directories(opt)
|
318
|
+
|
319
|
+
if $2
|
320
|
+
ip << @f.dirname
|
321
|
+
end
|
322
|
+
|
323
|
+
h = nil
|
324
|
+
ip.each do |d|
|
325
|
+
hg = d.join(p)
|
326
|
+
|
327
|
+
if hg.exist?
|
328
|
+
h = hg
|
329
|
+
break
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
h # Ignoring missing headers for now.
|
334
|
+
end.compact
|
335
|
+
|
336
|
+
@incs.each do |h|
|
337
|
+
icd = R::find_target(h) || TargetCSource.new(opt, h, @input)
|
338
|
+
|
339
|
+
if icd.respond_to? :included_files
|
340
|
+
icd.included_files opt, set
|
341
|
+
else
|
342
|
+
set << h
|
343
|
+
end
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
def input
|
348
|
+
@input + included_files(@opt)
|
349
|
+
end
|
350
|
+
|
351
|
+
def output
|
352
|
+
Set[@f]
|
353
|
+
end
|
354
|
+
|
355
|
+
def build
|
356
|
+
@depsbuilt and return
|
357
|
+
|
358
|
+
@depsbuilt = true
|
359
|
+
build_dependancies
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
def self.to_c_identifier(s)
|
364
|
+
s.delete('`!@#$%^&*()+=[]{};"\'<>?')
|
365
|
+
.gsub(/[\~\-\\\|\:\,\.\/]/, '_')
|
366
|
+
.gsub(/^[0-9]/, '_\0')
|
367
|
+
end
|
368
|
+
|
369
|
+
class TargetGeneratedHeader < R::TargetSmart
|
370
|
+
def initialize(opt, name, h, c, values)
|
371
|
+
super()
|
372
|
+
|
373
|
+
@n = name
|
374
|
+
@h = h
|
375
|
+
@c = c
|
376
|
+
|
377
|
+
@val = values
|
378
|
+
|
379
|
+
output << @h << @c
|
380
|
+
end
|
381
|
+
|
382
|
+
def hash_input
|
383
|
+
Digest::SHA1.digest(@val.inspect)
|
384
|
+
end
|
385
|
+
|
386
|
+
def hash_output(t)
|
387
|
+
Digest::SHA1.digest(t.readlines.drop(2).join('\n'))
|
388
|
+
end
|
389
|
+
|
390
|
+
def build_self
|
391
|
+
@h.dirname.mkpath
|
392
|
+
@c.dirname.mkpath
|
393
|
+
|
394
|
+
h = @h.open('w')
|
395
|
+
c = @c.open('w')
|
396
|
+
|
397
|
+
notice = <<"EOS"
|
398
|
+
/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT EDIT! */
|
399
|
+
/* This file was generated by Rub on #{DateTime.now.iso8601} */
|
400
|
+
|
401
|
+
EOS
|
402
|
+
h.print notice
|
403
|
+
c.print notice
|
404
|
+
|
405
|
+
hname = L::C.to_c_identifier(@h.basename.to_s).upcase
|
406
|
+
h.puts "#ifndef RUB_L_C_GENERATE_HEADER___#{hname}"
|
407
|
+
h.puts "#define RUB_L_C_GENERATE_HEADER___#{hname}"
|
408
|
+
h.puts ''
|
409
|
+
|
410
|
+
c.puts %|#include "#{@n}.h"|
|
411
|
+
c.puts ''
|
412
|
+
|
413
|
+
@val.each do |k, v|
|
414
|
+
type, v = if v.is_a?(Array)
|
415
|
+
[v[0], v[1]]
|
416
|
+
elsif v.is_a? Numeric
|
417
|
+
['int', v.to_s]
|
418
|
+
elsif v.equal?(true) || v.equal?(false)
|
419
|
+
['short unsigned int', v ? 1 : 0]
|
420
|
+
elsif v.respond_to? :to_s
|
421
|
+
['const char *', v.to_s.inspect] # @TODO: make this quote for C rather then ruby.
|
422
|
+
end
|
423
|
+
|
424
|
+
h.puts "extern #{type} #{k};"
|
425
|
+
c.puts "#{type} #{k} = #{v};"
|
426
|
+
end
|
427
|
+
|
428
|
+
h.puts ''
|
429
|
+
h.puts "#endif /* RUB_L_C_GENERATE_HEADER___#{hname} */"
|
430
|
+
|
431
|
+
h.close
|
432
|
+
c.close
|
433
|
+
|
434
|
+
bs = R::BuildStep.new
|
435
|
+
bs.desc = "Generating #{@h} and #{@c}"
|
436
|
+
bs.print
|
437
|
+
end
|
438
|
+
end
|
439
|
+
|
440
|
+
# Generate a header
|
441
|
+
#
|
442
|
+
# Generates a header with information in it.
|
443
|
+
def self.generate_header(name, vals)
|
444
|
+
h = C.unique_path("#{name}.h", vals)
|
445
|
+
c = C.unique_path("#{name}.c", vals)
|
446
|
+
|
447
|
+
t = TargetGeneratedHeader.new(self, name, h, c, vals)
|
448
|
+
t.register
|
449
|
+
|
450
|
+
include_dirs << h.dirname
|
451
|
+
|
452
|
+
t.output
|
453
|
+
end
|
454
|
+
|
455
|
+
# Compile and link an executable.
|
456
|
+
#
|
457
|
+
# @param src [Set<Pathname,String>,Array<Pathname,String>,Pathname,String]
|
458
|
+
# The source files to compile and generated headers.
|
459
|
+
# @param name [Pathname,String] The basename of the output file.
|
460
|
+
# @return [Pathname] The resulting executable.
|
461
|
+
def self.program(src, name)
|
462
|
+
obj = compile(src)
|
463
|
+
linker = L::LD.clone
|
464
|
+
|
465
|
+
linker.set_linker compiler.linker
|
466
|
+
linker.link(obj, libs, name, format: :exe)
|
467
|
+
end
|
468
|
+
|
469
|
+
def self.initialize_copy(s)
|
470
|
+
super
|
471
|
+
|
472
|
+
self.include_dirs = s.include_dirs.dup
|
473
|
+
self.libs = s.libs.dup
|
474
|
+
self.define = s.define.dup
|
475
|
+
end
|
476
|
+
end
|