rake-builder 0.0.14 → 0.0.15
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +7 -0
- data/Rakefile +12 -32
- data/lib/rake/builder.rb +219 -42
- data/lib/rake/builder/version.rb +7 -5
- data/lib/rake/local_config.rb +19 -16
- data/lib/rake/microsecond.rb +70 -0
- data/lib/rake/once_task.rb +36 -0
- data/lib/rake/path.rb +12 -2
- data/spec/c_project_spec.rb +12 -5
- data/spec/cpp_project_spec.rb +8 -6
- data/spec/dependencies_spec.rb +138 -16
- data/spec/generated_files_spec.rb +7 -5
- data/spec/libraries_spec.rb +7 -5
- data/spec/local_config_spec.rb +51 -3
- data/spec/logger_spec.rb +2 -1
- data/spec/microsecond_task_spec.rb +32 -0
- data/spec/objective_c_project_spec.rb +9 -3
- data/spec/paths_spec.rb +1 -1
- data/spec/spec_helper.rb +8 -8
- data/spec/target_spec.rb +2 -2
- metadata +145 -74
data/README.rdoc
CHANGED
@@ -15,6 +15,12 @@ Here is a typical example:
|
|
15
15
|
builder.header_search_paths = [ 'include' ]
|
16
16
|
end
|
17
17
|
|
18
|
+
= Dependencies
|
19
|
+
|
20
|
+
* makedepend
|
21
|
+
** linux: package 'xutils-dev'
|
22
|
+
** OS X: already installed
|
23
|
+
|
18
24
|
= Installation
|
19
25
|
|
20
26
|
$ sudo gem install rake-builder
|
@@ -57,6 +63,7 @@ The file should be a YAML structure, and must include a version.
|
|
57
63
|
|
58
64
|
Currently, the following can be configured:
|
59
65
|
* extra include paths: :include_paths
|
66
|
+
* extra compilation options (e.g. defines): :compilation_options
|
60
67
|
|
61
68
|
=== Example '.rake-builder'
|
62
69
|
|
data/Rakefile
CHANGED
@@ -1,40 +1,20 @@
|
|
1
|
-
require
|
2
|
-
require '
|
3
|
-
require '
|
4
|
-
require 'spec/rake/spectask'
|
5
|
-
$:.unshift( File.dirname( __FILE__ ) + '/lib' )
|
6
|
-
require 'rake/builder/version'
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require 'rcov/rcovtask' if RUBY_VERSION < '1.9'
|
3
|
+
require 'rspec/core/rake_task'
|
7
4
|
|
8
|
-
|
9
|
-
FileList[ 'lib/**/*.rb' ] +
|
10
|
-
FileList[ 'examples/README.rdoc' ] +
|
11
|
-
FileList[ 'examples/**/Rakefile' ]
|
12
|
-
RDOC_OPTS = [ '--quiet', '--main', 'README.rdoc', '--inline-source' ]
|
5
|
+
task :default => :spec
|
13
6
|
|
14
|
-
|
15
|
-
t.
|
16
|
-
t.spec_opts += [ '--color', '--format specdoc' ]
|
7
|
+
RSpec::Core::RakeTask.new do | t |
|
8
|
+
t.pattern = 'spec/**/*_spec.rb'
|
17
9
|
end
|
18
10
|
|
19
|
-
|
20
|
-
t.spec_files = FileList[ 'spec/**/*_spec.rb' ]
|
21
|
-
t.rcov = true
|
22
|
-
t.rcov_opts = [ '--exclude spec' ]
|
23
|
-
end
|
11
|
+
if RUBY_VERSION < '1.9'
|
24
12
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
end
|
13
|
+
RSpec::Core::RakeTask.new( 'spec:rcov' ) do |t|
|
14
|
+
t.pattern = 'spec/**/*_spec.rb'
|
15
|
+
t.rcov = true
|
16
|
+
t.rcov_opts = [ '--exclude', 'spec/,/gems/' ]
|
17
|
+
end
|
31
18
|
|
32
|
-
desc "Build the gem"
|
33
|
-
task :build do
|
34
|
-
system "gem build rake-builder.gemspec"
|
35
19
|
end
|
36
20
|
|
37
|
-
desc "Publish gem version #{ Rake::Builder::VERSION::STRING }"
|
38
|
-
task :release => :build do
|
39
|
-
system "gem push rake-builder-#{ Rake::Builder::VERSION::STRING }.gem"
|
40
|
-
end
|
data/lib/rake/builder.rb
CHANGED
@@ -1,12 +1,17 @@
|
|
1
1
|
require 'rubygems' if RUBY_VERSION < '1.9'
|
2
|
+
require 'json'
|
2
3
|
require 'logger'
|
3
4
|
require 'rake'
|
4
5
|
require 'rake/tasklib'
|
5
6
|
require 'rake/path'
|
6
7
|
require 'rake/local_config'
|
7
8
|
require 'rake/file_task_alias'
|
9
|
+
require 'rake/microsecond'
|
10
|
+
require 'rake/once_task'
|
8
11
|
require 'compiler'
|
9
12
|
|
13
|
+
include Rake::DSL
|
14
|
+
|
10
15
|
module Rake
|
11
16
|
|
12
17
|
class Formatter < Logger::Formatter
|
@@ -17,14 +22,6 @@ module Rake
|
|
17
22
|
|
18
23
|
class Builder < TaskLib
|
19
24
|
|
20
|
-
module VERSION #:nodoc:
|
21
|
-
MAJOR = 0
|
22
|
-
MINOR = 0
|
23
|
-
TINY = 13
|
24
|
-
|
25
|
-
STRING = [ MAJOR, MINOR, TINY ].join('.')
|
26
|
-
end
|
27
|
-
|
28
25
|
class BuilderError < StandardError
|
29
26
|
attr_accessor :namespace
|
30
27
|
|
@@ -154,12 +151,190 @@ module Rake
|
|
154
151
|
# Name of the generated file containing source - header dependencies
|
155
152
|
attr_reader :makedepend_file
|
156
153
|
|
154
|
+
# The file containing local settings such as include paths
|
155
|
+
attr_reader :local_config
|
156
|
+
|
157
157
|
# Temporary files generated during compilation and linking
|
158
158
|
attr_accessor :generated_files
|
159
159
|
|
160
160
|
# Each instance has its own logger
|
161
161
|
attr_accessor :logger
|
162
162
|
|
163
|
+
# All Rake::Builder instaces that get defined
|
164
|
+
# This allows us to create scripts for configure
|
165
|
+
@instances = []
|
166
|
+
|
167
|
+
def self.instances
|
168
|
+
@instances
|
169
|
+
end
|
170
|
+
|
171
|
+
def self.define_global
|
172
|
+
desc "Create input files for configure script creation"
|
173
|
+
task :autoconf, [:project_title, :version] => [] do | task, args |
|
174
|
+
project_title = args.project_title or raise "Please supply a project_title parameter"
|
175
|
+
version = decide_version( args.version )
|
176
|
+
if File.exist?( 'configure.ac' )
|
177
|
+
raise "The file 'configure.ac' already exists"
|
178
|
+
end
|
179
|
+
if File.exist?( 'Makefile.am' )
|
180
|
+
raise "The file 'Makefile.am' already exists"
|
181
|
+
end
|
182
|
+
create_configure_ac project_title, version
|
183
|
+
create_makefile_am
|
184
|
+
end
|
185
|
+
|
186
|
+
desc "A file containing the major.minor.revision version information"
|
187
|
+
file 'VERSION' do
|
188
|
+
raise <<-EOT
|
189
|
+
In order to create autoconf files, you need to create a file called VERSION in the root directory of the project.
|
190
|
+
The file should contain the version of the project, like this:
|
191
|
+
1.2.3
|
192
|
+
EOT
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def self.create_configure_ac( project_title, version )
|
197
|
+
source = Rake::Path.relative_path( instances[ 0 ].source_files[ 0 ], instances[ 0 ].rakefile_path )
|
198
|
+
File.open( 'configure.ac', 'w' ) do | f |
|
199
|
+
f.write <<EOT
|
200
|
+
AC_PREREQ(2.61)
|
201
|
+
AC_INIT(#{project_title}, #{ version })
|
202
|
+
AC_CONFIG_SRCDIR([#{ source }])
|
203
|
+
AC_CONFIG_HEADER([config.h])
|
204
|
+
AM_INIT_AUTOMAKE([#{project_title}], [#{ version }])
|
205
|
+
|
206
|
+
# Checks for programs.
|
207
|
+
AC_PROG_CXX
|
208
|
+
AC_PROG_CC
|
209
|
+
AC_PROG_RANLIB
|
210
|
+
|
211
|
+
# Checks for libraries.
|
212
|
+
|
213
|
+
# Checks for header files.
|
214
|
+
|
215
|
+
# Checks for typedefs, structures, and compiler characteristics.
|
216
|
+
AC_HEADER_STDBOOL
|
217
|
+
AC_C_CONST
|
218
|
+
AC_C_INLINE
|
219
|
+
AC_STRUCT_TM
|
220
|
+
|
221
|
+
# Checks for library functions.
|
222
|
+
AC_FUNC_LSTAT
|
223
|
+
AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK
|
224
|
+
AC_FUNC_MEMCMP
|
225
|
+
AC_HEADER_STDC
|
226
|
+
AC_CHECK_FUNCS([memset strcasecmp])
|
227
|
+
|
228
|
+
AC_CONFIG_FILES([Makefile])
|
229
|
+
|
230
|
+
AC_OUTPUT
|
231
|
+
EOT
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
def self.create_makefile_am
|
236
|
+
libraries = []
|
237
|
+
binaries = []
|
238
|
+
instances.each do | instance |
|
239
|
+
entry = instance.makefile_am_entry
|
240
|
+
case entry[ :type ]
|
241
|
+
when :static_library, :shared_library
|
242
|
+
libraries << entry
|
243
|
+
else
|
244
|
+
binaries << entry
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
File.open( 'Makefile.am', 'w' ) do | f |
|
249
|
+
if libraries.size > 0
|
250
|
+
names = libraries.map { | lib | lib[ :name ] }.join( ' ' )
|
251
|
+
f.write "lib_LIBRARIES = #{ names }\n\n"
|
252
|
+
libraries.each do | lib |
|
253
|
+
f.write <<EOT
|
254
|
+
#{ lib[ :label ] }_SOURCES = #{ lib[ :sources ] }
|
255
|
+
#{ lib[ :label ] }_CPPFLAGS = #{ lib[ :compiler_flags ] }
|
256
|
+
|
257
|
+
EOT
|
258
|
+
end
|
259
|
+
end
|
260
|
+
if binaries.size > 0
|
261
|
+
names = binaries.map { | bin | bin[ :name ] }.join( ' ' )
|
262
|
+
f.write "bin_PROGRAMS = #{ names }\n\n"
|
263
|
+
binaries.each do | bin |
|
264
|
+
f.write <<EOT
|
265
|
+
#{ bin[ :label ] }_SOURCES = #{ bin[ :sources ] }
|
266
|
+
#{ bin[ :label ] }_CPPFLAGS = #{ bin[ :compiler_flags ] }
|
267
|
+
|
268
|
+
EOT
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
def makefile_am_entry
|
276
|
+
primary_name = Rake::Path.relative_path( target, rakefile_path, :initial_dot_slash => false )
|
277
|
+
sources = source_files.map{ | file | Rake::Path.relative_path( file, rakefile_path) }.join( ' ' )
|
278
|
+
sources_label = primary_name.gsub( %r(\.), '_' )
|
279
|
+
|
280
|
+
{
|
281
|
+
:type => @target_type,
|
282
|
+
:name => primary_name,
|
283
|
+
:label => sources_label,
|
284
|
+
:sources => sources,
|
285
|
+
:compiler_flags => compiler_flags
|
286
|
+
}
|
287
|
+
end
|
288
|
+
|
289
|
+
#########################################
|
290
|
+
# VERSION file
|
291
|
+
|
292
|
+
def self.decide_version( parameter_version )
|
293
|
+
acceptable_version_string = %r(^(\d+)\.(\d+)\.(\d+)$)
|
294
|
+
if parameter_version && parameter_version !~ acceptable_version_string
|
295
|
+
raise "The supplied version number '#{ parameter_version }' is badly formatted. It should consist of three numbers separated by ."
|
296
|
+
end
|
297
|
+
file_version = load_file_version
|
298
|
+
if file_version && file_version !~ acceptable_version_string
|
299
|
+
raise "Your VERSION file contains a version number '#{ parameter_version }' which is badly formatted. It should consist of three numbers separated by ."
|
300
|
+
end
|
301
|
+
case
|
302
|
+
when parameter_version.nil? && file_version.nil?
|
303
|
+
raise <<-EOT
|
304
|
+
This task requires a project version: major.minor.revision (e.g. 1.03.0567)
|
305
|
+
Please do one of the following:
|
306
|
+
- supply a version parameter: rake autoconf[project_name,version]
|
307
|
+
- create a VERSION file.
|
308
|
+
EOT
|
309
|
+
when file_version.nil?
|
310
|
+
save_file_version parameter_version
|
311
|
+
return parameter_version
|
312
|
+
when parameter_version.nil?
|
313
|
+
return file_version
|
314
|
+
when file_version != parameter_version
|
315
|
+
raise <<-EOT
|
316
|
+
The version parameter supplied is different to the value in the VERSION file
|
317
|
+
EOT
|
318
|
+
else
|
319
|
+
return file_version
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
def self.load_file_version
|
324
|
+
if File.exist?( 'VERSION' )
|
325
|
+
version = File.read( 'VERSION' )
|
326
|
+
version.strip!
|
327
|
+
else
|
328
|
+
nil
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
def self.save_file_version( version )
|
333
|
+
File.open( 'VERSION', 'w' ) { | f | f.write "#{ version }/n" }
|
334
|
+
end
|
335
|
+
|
336
|
+
self.define_global
|
337
|
+
|
163
338
|
def initialize( &block )
|
164
339
|
save_rakefile_info( block )
|
165
340
|
initialize_attributes
|
@@ -167,22 +342,23 @@ module Rake
|
|
167
342
|
configure
|
168
343
|
define_tasks
|
169
344
|
define_default
|
345
|
+
self.class.instances << self
|
170
346
|
end
|
171
347
|
|
172
|
-
private
|
173
|
-
|
174
348
|
# Source files found in source_search_paths
|
175
349
|
def source_files
|
176
|
-
@source_files
|
177
|
-
@source_files
|
350
|
+
return @source_files if @source_files
|
351
|
+
@source_files = find_files( @source_search_paths, @source_file_extension ).uniq
|
178
352
|
end
|
179
353
|
|
180
354
|
# Header files found in header_search_paths
|
181
355
|
def header_files
|
182
|
-
@header_files
|
183
|
-
@header_files
|
356
|
+
return @header_files if @header_files
|
357
|
+
@header_files = find_files( @header_search_paths, @header_file_extension ).uniq
|
184
358
|
end
|
185
359
|
|
360
|
+
private
|
361
|
+
|
186
362
|
def initialize_attributes
|
187
363
|
@architecture = 'i386'
|
188
364
|
@compiler_data = Compiler::Base.for( :gcc )
|
@@ -220,7 +396,7 @@ module Rake
|
|
220
396
|
raise BuilderError.new( "The target name cannot be nil", task_namespace ) if @target.nil?
|
221
397
|
raise BuilderError.new( "The target name cannot be an empty string", task_namespace ) if @target == ''
|
222
398
|
@objects_path = Rake::Path.expand_with_root( @objects_path, @rakefile_path )
|
223
|
-
@target = @target
|
399
|
+
@target = File.expand_path( @target, @rakefile_path )
|
224
400
|
@target_type ||= type( @target )
|
225
401
|
raise BuilderError.new( "Building #{ @target_type } targets is not supported", task_namespace ) if ! TARGET_TYPES.include?( @target_type )
|
226
402
|
|
@@ -233,6 +409,7 @@ module Rake
|
|
233
409
|
|
234
410
|
@default_task ||= :build
|
235
411
|
@target_prerequisites << @rakefile
|
412
|
+
@local_config = Rake::Path.expand_with_root( '.rake-builder', @rakefile_path )
|
236
413
|
|
237
414
|
@makedepend_file = @objects_path + '/.' + target_basename + '.depend.mf'
|
238
415
|
|
@@ -260,7 +437,7 @@ module Rake
|
|
260
437
|
end
|
261
438
|
|
262
439
|
def define
|
263
|
-
|
440
|
+
once_task :environment do
|
264
441
|
logger.level = Logger::DEBUG if ENV[ 'DEBUG' ]
|
265
442
|
end
|
266
443
|
|
@@ -276,7 +453,7 @@ module Rake
|
|
276
453
|
FileTaskAlias.define_task( :build, @target )
|
277
454
|
|
278
455
|
desc "Build '#{ target_basename }'"
|
279
|
-
|
456
|
+
microsecond_file @target => [ scoped_task( :environment ),
|
280
457
|
scoped_task( :compile ),
|
281
458
|
*@target_prerequisites ] do | t |
|
282
459
|
shell "rm -f #{ t.name }"
|
@@ -289,7 +466,7 @@ module Rake
|
|
289
466
|
desc "Compile all sources"
|
290
467
|
# Only import dependencies when we're compiling
|
291
468
|
# otherwise makedepend gets run on e.g. 'rake -T'
|
292
|
-
|
469
|
+
once_task :compile => [ scoped_task( :environment ),
|
293
470
|
@makedepend_file,
|
294
471
|
scoped_task( :load_makedepend ),
|
295
472
|
*object_files ]
|
@@ -298,34 +475,35 @@ module Rake
|
|
298
475
|
define_compile_task( src )
|
299
476
|
end
|
300
477
|
|
301
|
-
|
478
|
+
microsecond_directory @objects_path
|
302
479
|
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
config.save
|
310
|
-
end
|
480
|
+
file scoped_task( local_config ) do
|
481
|
+
@logger.add( Logger::DEBUG, "Creating file '#{ local_config }'" )
|
482
|
+
added_includes = @compiler_data.include_paths( missing_headers )
|
483
|
+
config = Rake::LocalConfig.new( local_config )
|
484
|
+
config.include_paths = added_includes
|
485
|
+
config.save
|
311
486
|
end
|
312
487
|
|
313
|
-
|
488
|
+
microsecond_file @makedepend_file => [ scoped_task( :load_local_config ),
|
314
489
|
scoped_task( :missing_headers ),
|
315
490
|
@objects_path,
|
316
491
|
*project_files ] do
|
492
|
+
system('which makedepend >/dev/null')
|
493
|
+
raise 'makedepend not found' unless $?.success?
|
317
494
|
@logger.add( Logger::DEBUG, "Analysing dependencies" )
|
318
495
|
command = "makedepend -f- -- #{ include_path } -- #{ file_list( source_files ) } 2>/dev/null > #{ @makedepend_file }"
|
319
496
|
shell command
|
320
497
|
end
|
321
498
|
|
322
|
-
|
499
|
+
once_task scoped_task( :load_local_config ) => scoped_task( local_config ) do
|
323
500
|
config = LocalConfig.new( local_config )
|
324
501
|
config.load
|
325
|
-
@include_paths
|
502
|
+
@include_paths += Rake::Path.expand_all_with_root( config.include_paths, @rakefile_path )
|
503
|
+
@compilation_options += config.compilation_options
|
326
504
|
end
|
327
505
|
|
328
|
-
|
506
|
+
once_task scoped_task( :missing_headers ) => [ *generated_headers ] do
|
329
507
|
missing_headers
|
330
508
|
end
|
331
509
|
|
@@ -354,7 +532,7 @@ module Rake
|
|
354
532
|
|
355
533
|
desc "List generated files (which are removed with 'rake #{ scoped_task( :clean ) }')"
|
356
534
|
task :generated_files do
|
357
|
-
puts generated_files.
|
535
|
+
puts generated_files.to_json
|
358
536
|
end
|
359
537
|
|
360
538
|
# Re-implement :clean locally for project and within namespace
|
@@ -513,7 +691,8 @@ EOT
|
|
513
691
|
# Compiling and linking parameters
|
514
692
|
|
515
693
|
def include_path
|
516
|
-
@include_paths.map
|
694
|
+
paths = @include_paths.map{ | file | Rake::Path.relative_path( file, rakefile_path) }
|
695
|
+
paths.map { |p| "-I#{ p }" }.join( ' ' )
|
517
696
|
end
|
518
697
|
|
519
698
|
def compiler_flags
|
@@ -534,11 +713,6 @@ EOT
|
|
534
713
|
|
535
714
|
# Paths
|
536
715
|
|
537
|
-
def local_config
|
538
|
-
filename = '.rake-builder'
|
539
|
-
Rake::Path.expand_with_root( filename, @rakefile_path )
|
540
|
-
end
|
541
|
-
|
542
716
|
def save_rakefile_info( block )
|
543
717
|
if RUBY_VERSION < '1.9'
|
544
718
|
# Hack the path from the block String representation
|
@@ -546,7 +720,8 @@ EOT
|
|
546
720
|
else
|
547
721
|
@rakefile = block.source_location[ 0 ]
|
548
722
|
end
|
549
|
-
@
|
723
|
+
@rakefile = File.expand_path( @rakefile )
|
724
|
+
@rakefile_path = File.dirname( @rakefile )
|
550
725
|
end
|
551
726
|
|
552
727
|
def object_path( source_path_name )
|
@@ -600,6 +775,7 @@ EOT
|
|
600
775
|
def project_files
|
601
776
|
source_files + header_files
|
602
777
|
end
|
778
|
+
public :project_files
|
603
779
|
|
604
780
|
def file_list( files, delimiter = ' ' )
|
605
781
|
files.join( delimiter )
|
@@ -646,7 +822,7 @@ EOT
|
|
646
822
|
FileList[ search ].each do | pathname |
|
647
823
|
full_path = Rake::Path.expand_with_root( pathname, @rakefile_path )
|
648
824
|
directory = File.dirname( full_path )
|
649
|
-
relative = Rake::Path.
|
825
|
+
relative = Rake::Path.relative_path( directory, non_glob_search )
|
650
826
|
memo << { :source_file => pathname, :relative_path => relative }
|
651
827
|
end
|
652
828
|
else
|
@@ -666,10 +842,11 @@ EOT
|
|
666
842
|
end
|
667
843
|
|
668
844
|
def shell( command, log_level = Logger::DEBUG )
|
669
|
-
@logger.add(
|
670
|
-
|
845
|
+
@logger.add(log_level, command)
|
846
|
+
system command, {:out => '/dev/null', :err => '/dev/null'}
|
671
847
|
end
|
672
848
|
|
673
849
|
end
|
674
850
|
|
675
851
|
end
|
852
|
+
|