jitsu 0.2.1 → 0.3.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.
- data/README.rdoc +3 -3
- data/Rakefile +2 -1
- data/VERSION +1 -1
- data/features/jitsu.feature +48 -0
- data/jitsu.gemspec +1 -1
- data/lib/jitsu.rb +80 -12
- data/spec/jitsu_spec.rb +99 -0
- metadata +2 -2
data/README.rdoc
CHANGED
@@ -4,9 +4,9 @@ Ninja (https://github.com/martine/ninja) is an excellent build system, but
|
|
4
4
|
Ninja files are hard to write, by design. Jitsu is a simple meta build system
|
5
5
|
that writes Ninja files for you from YAML project descriptions.
|
6
6
|
|
7
|
-
For now,
|
8
|
-
|
9
|
-
for docs.
|
7
|
+
For now, C++ is the only supported langugage. Jitsu can build executables and
|
8
|
+
static, dynamic and libtool libraries. See the features dir for examples and
|
9
|
+
http://ilkka.github.com/jitsu for docs.
|
10
10
|
|
11
11
|
== Using Jitsu
|
12
12
|
|
data/Rakefile
CHANGED
@@ -37,12 +37,13 @@ end
|
|
37
37
|
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
38
38
|
spec.pattern = 'spec/**/*_spec.rb'
|
39
39
|
spec.rcov = true
|
40
|
+
spec.rcov_opts = "-x '^[\/]'"
|
40
41
|
end
|
41
42
|
|
42
43
|
require 'cucumber/rake/task'
|
43
44
|
Cucumber::Rake::Task.new(:features)
|
44
45
|
|
45
|
-
task :default => :spec
|
46
|
+
task :default => [:spec, :features]
|
46
47
|
|
47
48
|
require 'yard'
|
48
49
|
yardtask = YARD::Rake::YardocTask.new
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
data/features/jitsu.feature
CHANGED
@@ -113,3 +113,51 @@ Feature: Build C++ programs
|
|
113
113
|
And I run "ninja all"
|
114
114
|
And I run "env LD_PRELOAD=./lib.so ./blah"
|
115
115
|
Then the output should be "Hello World" with a newline
|
116
|
+
|
117
|
+
Scenario: Build an executable using libtool
|
118
|
+
Given a directory
|
119
|
+
And a file "lib.h" with contents
|
120
|
+
"""
|
121
|
+
#include <string>
|
122
|
+
|
123
|
+
std::string greeting();
|
124
|
+
"""
|
125
|
+
And a file "lib.cpp" with contents
|
126
|
+
"""
|
127
|
+
#include "lib.h"
|
128
|
+
|
129
|
+
std::string greeting() {
|
130
|
+
return std::string("Hello World");
|
131
|
+
}
|
132
|
+
"""
|
133
|
+
And a file "main.cpp" with contents
|
134
|
+
"""
|
135
|
+
#include <iostream>
|
136
|
+
|
137
|
+
extern std::string greeting();
|
138
|
+
|
139
|
+
int main(int argc, char* argv[]) {
|
140
|
+
std::cout << greeting() << std::endl;
|
141
|
+
return 0;
|
142
|
+
}
|
143
|
+
"""
|
144
|
+
And a file "build.jitsu" with contents
|
145
|
+
"""
|
146
|
+
---
|
147
|
+
targets:
|
148
|
+
lib.la:
|
149
|
+
type: libtool_library
|
150
|
+
sources:
|
151
|
+
- lib.cpp
|
152
|
+
blah:
|
153
|
+
type: executable
|
154
|
+
sources:
|
155
|
+
- main.cpp
|
156
|
+
dependencies:
|
157
|
+
- lib.la
|
158
|
+
"""
|
159
|
+
When I run jitsu
|
160
|
+
And I run "ninja all"
|
161
|
+
And I run "libtool --mode=execute ./blah"
|
162
|
+
Then the output should be "Hello World" with a newline
|
163
|
+
|
data/jitsu.gemspec
CHANGED
data/lib/jitsu.rb
CHANGED
@@ -35,18 +35,32 @@ module Jitsu
|
|
35
35
|
YAML.load(File.open(jitsufile, 'r').read)
|
36
36
|
end
|
37
37
|
|
38
|
+
# Check if any of the targets needs libtool.
|
39
|
+
#
|
40
|
+
# @param targets [Enum] the targets from a build specification hash.
|
41
|
+
# @return [Boolean] true if libtool required, nil otherwise.
|
42
|
+
def self.libtool_needed_for(targets)
|
43
|
+
not targets.select { |key,val| val['type'] == 'libtool_library' }.empty?
|
44
|
+
end
|
45
|
+
|
38
46
|
# Output jitsu build specification as build.ninja file(s).
|
39
47
|
#
|
40
48
|
# @param data [Hash] a build specification from e.g. Jitsu::read.
|
41
49
|
# @return nil
|
42
50
|
def self.output(data)
|
43
51
|
File.open NINJA_FILE_NAME, 'w' do |f|
|
52
|
+
libtool = libtool_needed_for data['targets']
|
44
53
|
f.write <<-EOS
|
45
54
|
cxxflags =
|
46
55
|
ldflags =
|
47
56
|
cxx = g++
|
48
57
|
ld = g++
|
49
58
|
ar = ar
|
59
|
+
EOS
|
60
|
+
if libtool
|
61
|
+
f.write "libtool = libtool\n"
|
62
|
+
end
|
63
|
+
f.write <<-EOS
|
50
64
|
|
51
65
|
rule cxx
|
52
66
|
description = CC ${in}
|
@@ -61,11 +75,23 @@ rule archive
|
|
61
75
|
description = AR ${out}
|
62
76
|
command = ${ar} rT ${out} ${in}
|
63
77
|
EOS
|
78
|
+
if libtool_needed_for data['targets']
|
79
|
+
f.write <<-EOS
|
80
|
+
|
81
|
+
rule ltcxx
|
82
|
+
description = CC ${in}
|
83
|
+
depfile = ${out}.d
|
84
|
+
command = ${libtool} --quiet --mode=compile ${cxx} -MMD -MF ${out}.d ${cxxflags} -c ${in}
|
85
|
+
|
86
|
+
rule ltlink
|
87
|
+
description = LD ${out}
|
88
|
+
command = ${libtool} --quiet --mode=link ${ld} ${ldflags} -o ${out} ${in}
|
89
|
+
EOS
|
90
|
+
end
|
64
91
|
data['targets'].each do |target,conf|
|
65
92
|
f.write "\n"
|
66
93
|
sources = conf['sources']
|
67
|
-
|
68
|
-
Jitsu.send "handle_#{conf['type']}".to_sym, f, target, sources, objects, conf
|
94
|
+
Jitsu.send "handle_#{conf['type']}".to_sym, f, target, sources, conf, data['targets']
|
69
95
|
end
|
70
96
|
f.write("\nbuild all: phony || #{data['targets'].keys.join(' ')}\n")
|
71
97
|
end
|
@@ -79,8 +105,11 @@ EOS
|
|
79
105
|
# @param conf [Hash] the entire build spec hash for this target.
|
80
106
|
def self.output_sources(out, sources, conf)
|
81
107
|
cxxflags = conf['cxxflags']
|
108
|
+
libtool = conf['type'] == 'libtool_library'
|
109
|
+
rule = (libtool ? "ltcxx" : "cxx")
|
82
110
|
sources.each do |src|
|
83
|
-
|
111
|
+
object = (libtool ? source_to_ltobject(src) : source_to_object(src))
|
112
|
+
out.write "build #{object}: #{rule} #{src}\n"
|
84
113
|
out.write " cxxflags = #{cxxflags}\n" if cxxflags
|
85
114
|
end
|
86
115
|
end
|
@@ -91,11 +120,15 @@ EOS
|
|
91
120
|
# @param target [String] the filename of the target.
|
92
121
|
# @param sources [Enumerable] a list of sourcefile names to output rules
|
93
122
|
# for.
|
94
|
-
# @param objects [Enumerable] a list of all object files for the target.
|
95
123
|
# @param conf [Hash] the entire build spec hash for this target.
|
96
|
-
|
124
|
+
# @param targets [Hash] all targets for the build
|
125
|
+
def self.handle_executable(out, target, sources, conf, targets)
|
97
126
|
output_sources(out, sources, conf)
|
98
|
-
|
127
|
+
libtool = libtool_needed_for targets.select { |key,val|
|
128
|
+
conf['dependencies'] and conf['dependencies'].include? key
|
129
|
+
}
|
130
|
+
rule = libtool ? "ltlink" : "link"
|
131
|
+
out.write "build #{target}: #{rule} #{sources_to_objects(sources).join ' '}"
|
99
132
|
out.write " #{conf['dependencies'].join(' ')}" if conf['dependencies']
|
100
133
|
out.write "\n"
|
101
134
|
out.write " ldflags = #{conf['ldflags']}\n" if conf['ldflags']
|
@@ -107,11 +140,11 @@ EOS
|
|
107
140
|
# @param target [String] the filename of the target.
|
108
141
|
# @param sources [Enumerable] a list of sourcefile names to output rules
|
109
142
|
# for.
|
110
|
-
# @param objects [Enumerable] a list of all object files for the target.
|
111
143
|
# @param conf [Hash] the entire build spec hash for this target.
|
112
|
-
|
144
|
+
# @param targets [Hash] all targets for the build
|
145
|
+
def self.handle_static_library(out, target, sources, conf, targets)
|
113
146
|
output_sources(out, sources, conf)
|
114
|
-
out.write "build #{target}: archive #{
|
147
|
+
out.write "build #{target}: archive #{sources_to_objects(sources).join ' '}"
|
115
148
|
out.write " #{conf['dependencies'].join(' ')}" if conf['dependencies']
|
116
149
|
out.write "\n"
|
117
150
|
end
|
@@ -122,13 +155,13 @@ EOS
|
|
122
155
|
# @param target [String] the filename of the target.
|
123
156
|
# @param sources [Enumerable] a list of sourcefile names to output rules
|
124
157
|
# for.
|
125
|
-
# @param objects [Enumerable] a list of all object files for the target.
|
126
158
|
# @param conf [Hash] the entire build spec hash for this target.
|
127
|
-
|
159
|
+
# @param targets [Hash] all targets for the build
|
160
|
+
def self.handle_dynamic_library(out, target, sources, conf, targets)
|
128
161
|
conf['cxxflags'] ||= '${cxxflags}'
|
129
162
|
conf['cxxflags'] += ' -fPIC'
|
130
163
|
output_sources(out, sources, conf)
|
131
|
-
out.write "build #{target}: link #{
|
164
|
+
out.write "build #{target}: link #{sources_to_objects(sources).join ' '}"
|
132
165
|
out.write " #{conf['dependencies'].join(' ')}" if conf['dependencies']
|
133
166
|
out.write "\n"
|
134
167
|
conf['ldflags'] ||= '${ldflags}'
|
@@ -136,6 +169,24 @@ EOS
|
|
136
169
|
out.write " ldflags = #{conf['ldflags']}\n"
|
137
170
|
end
|
138
171
|
|
172
|
+
# Output build rules for one libtool library target.
|
173
|
+
#
|
174
|
+
# @param out [IO] the output stream where output is written.
|
175
|
+
# @param target [String] the filename of the target.
|
176
|
+
# @param sources [Enumerable] a list of sourcefile names to output rules
|
177
|
+
# for.
|
178
|
+
# @param conf [Hash] the entire build spec hash for this target.
|
179
|
+
# @param targets [Hash] all targets for the build
|
180
|
+
def self.handle_libtool_library(out, target, sources, conf, targets)
|
181
|
+
output_sources(out, sources, conf)
|
182
|
+
out.write "build #{target}: ltlink #{sources_to_ltobjects(sources).join ' '}"
|
183
|
+
out.write " #{conf['dependencies'].join(' ')}" if conf['dependencies']
|
184
|
+
out.write "\n"
|
185
|
+
conf['ldflags'] ||= '${ldflags}'
|
186
|
+
conf['ldflags'] += " -rpath /usr/local/lib"
|
187
|
+
out.write " ldflags = #{conf['ldflags']}\n"
|
188
|
+
end
|
189
|
+
|
139
190
|
# Convert sourcefile name to corresponding object file name.
|
140
191
|
#
|
141
192
|
# @param src [String] source file path.
|
@@ -151,4 +202,21 @@ EOS
|
|
151
202
|
def self.sources_to_objects(srcs)
|
152
203
|
srcs.map { |src| source_to_object src }
|
153
204
|
end
|
205
|
+
|
206
|
+
# Convert sourcefile name to corresponding libtool object file name.
|
207
|
+
#
|
208
|
+
# @param src [String] source file path.
|
209
|
+
# @return [String] libtool object file path.
|
210
|
+
def self.source_to_ltobject(src)
|
211
|
+
src.gsub /\.[Cc]\w+$/, '.lo'
|
212
|
+
end
|
213
|
+
|
214
|
+
# Convert a list of sourcefile names to corresponding libtool object file
|
215
|
+
# names.
|
216
|
+
#
|
217
|
+
# @param srcs [Enumerable] source file paths.
|
218
|
+
# @return [Enumerable] libtool object file paths.
|
219
|
+
def self.sources_to_ltobjects(srcs)
|
220
|
+
srcs.map { |src| source_to_ltobject src }
|
221
|
+
end
|
154
222
|
end
|
data/spec/jitsu_spec.rb
CHANGED
@@ -180,6 +180,105 @@ build aaa3.so: link aaa3.o
|
|
180
180
|
ldflags = ${ldflags} -shared -Wl,-soname,aaa3.so
|
181
181
|
|
182
182
|
build all: phony || aaa1 aaa2.a aaa3.so
|
183
|
+
EOS
|
184
|
+
end
|
185
|
+
File.open('build.ninja', 'r').read.should == ninjafile
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
it "outputs a build.jitsu file with libtool" do
|
191
|
+
Dir.mktmpdir do |dir|
|
192
|
+
Dir.chdir dir do |dir|
|
193
|
+
File.open 'build.jitsu', 'w' do |f|
|
194
|
+
f.write <<-EOS
|
195
|
+
---
|
196
|
+
targets:
|
197
|
+
aaa1:
|
198
|
+
type: executable
|
199
|
+
sources:
|
200
|
+
- aaa1a.cpp
|
201
|
+
- aaa1b.cpp
|
202
|
+
dependencies:
|
203
|
+
- aaa2.a
|
204
|
+
- aaa3.la
|
205
|
+
aaa2.a:
|
206
|
+
type: static_library
|
207
|
+
sources:
|
208
|
+
- aaa2.cpp
|
209
|
+
cxxflags: -ansi -pedantic
|
210
|
+
aaa3.la:
|
211
|
+
type: libtool_library
|
212
|
+
sources:
|
213
|
+
- aaa3.cpp
|
214
|
+
EOS
|
215
|
+
end
|
216
|
+
data = Jitsu.read Jitsu.jitsufile
|
217
|
+
Jitsu.output data
|
218
|
+
Dir['build.ninja'].length.should == 1
|
219
|
+
ninjafile = <<-EOS
|
220
|
+
cxxflags =
|
221
|
+
ldflags =
|
222
|
+
cxx = g++
|
223
|
+
ld = g++
|
224
|
+
ar = ar
|
225
|
+
libtool = libtool
|
226
|
+
|
227
|
+
rule cxx
|
228
|
+
description = CC ${in}
|
229
|
+
depfile = ${out}.d
|
230
|
+
command = ${cxx} -MMD -MF ${out}.d ${cxxflags} -c ${in} -o ${out}
|
231
|
+
|
232
|
+
rule link
|
233
|
+
description = LD ${out}
|
234
|
+
command = ${ld} ${ldflags} -o ${out} ${in}
|
235
|
+
|
236
|
+
rule archive
|
237
|
+
description = AR ${out}
|
238
|
+
command = ${ar} rT ${out} ${in}
|
239
|
+
|
240
|
+
rule ltcxx
|
241
|
+
description = CC ${in}
|
242
|
+
depfile = ${out}.d
|
243
|
+
command = ${libtool} --quiet --mode=compile ${cxx} -MMD -MF ${out}.d ${cxxflags} -c ${in}
|
244
|
+
|
245
|
+
rule ltlink
|
246
|
+
description = LD ${out}
|
247
|
+
command = ${libtool} --quiet --mode=link ${ld} ${ldflags} -o ${out} ${in}
|
248
|
+
|
249
|
+
EOS
|
250
|
+
# the targets are reversed on 1.8.7 :p
|
251
|
+
if RUBY_VERSION.start_with? '1.8'
|
252
|
+
ninjafile += <<-EOS
|
253
|
+
build aaa3.lo: ltcxx aaa3.cpp
|
254
|
+
build aaa3.la: ltlink aaa3.lo
|
255
|
+
ldflags = ${ldflags} -rpath /usr/local/lib
|
256
|
+
|
257
|
+
build aaa2.o: cxx aaa2.cpp
|
258
|
+
cxxflags = -ansi -pedantic
|
259
|
+
build aaa2.a: archive aaa2.o
|
260
|
+
|
261
|
+
build aaa1a.o: cxx aaa1a.cpp
|
262
|
+
build aaa1b.o: cxx aaa1b.cpp
|
263
|
+
build aaa1: ltlink aaa1a.o aaa1b.o aaa2.a aaa3.la
|
264
|
+
|
265
|
+
build all: phony || aaa3.la aaa2.a aaa1
|
266
|
+
EOS
|
267
|
+
else
|
268
|
+
ninjafile += <<-EOS
|
269
|
+
build aaa1a.o: cxx aaa1a.cpp
|
270
|
+
build aaa1b.o: cxx aaa1b.cpp
|
271
|
+
build aaa1: ltlink aaa1a.o aaa1b.o aaa2.a aaa3.la
|
272
|
+
|
273
|
+
build aaa2.o: cxx aaa2.cpp
|
274
|
+
cxxflags = -ansi -pedantic
|
275
|
+
build aaa2.a: archive aaa2.o
|
276
|
+
|
277
|
+
build aaa3.lo: ltcxx aaa3.cpp
|
278
|
+
build aaa3.la: ltlink aaa3.lo
|
279
|
+
ldflags = ${ldflags} -rpath /usr/local/lib
|
280
|
+
|
281
|
+
build all: phony || aaa1 aaa2.a aaa3.la
|
183
282
|
EOS
|
184
283
|
end
|
185
284
|
File.open('build.ninja', 'r').read.should == ninjafile
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: jitsu
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.
|
5
|
+
version: 0.3.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Ilkka Laukkanen
|
@@ -140,7 +140,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
140
140
|
requirements:
|
141
141
|
- - ">="
|
142
142
|
- !ruby/object:Gem::Version
|
143
|
-
hash:
|
143
|
+
hash: 994791855
|
144
144
|
segments:
|
145
145
|
- 0
|
146
146
|
version: "0"
|