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.
@@ -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 'rubygems' if RUBY_VERSION < '1.9'
2
- require 'rake'
3
- require 'rake/rdoctask'
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
- RDOC_FILES = FileList[ 'COPYING', 'README.rdoc' ] +
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
- Spec::Rake::SpecTask.new do |t|
15
- t.spec_files = FileList[ 'spec/**/*_spec.rb' ]
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
- Spec::Rake::SpecTask.new( 'spec:rcov' ) do |t|
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
- Rake::RDocTask.new do |rdoc|
26
- rdoc.rdoc_dir = 'html'
27
- rdoc.options += RDOC_OPTS
28
- rdoc.title = 'Rake for C/C++/Objective-C/Objective-C++ Projects'
29
- rdoc.rdoc_files.add RDOC_FILES
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
@@ -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 ||= find_files( @source_search_paths, @source_file_extension ).uniq
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 ||= find_files( @header_search_paths, @header_file_extension ).uniq
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
- task :environment do
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
- file @target => [ scoped_task( :environment ),
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
- task :compile => [ scoped_task( :environment ),
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
- directory @objects_path
478
+ microsecond_directory @objects_path
302
479
 
303
- task :local_config do
304
- if ! File.exist?( local_config )
305
- @logger.add( Logger::DEBUG, "Creating file '#{ local_config }'" )
306
- added_includes = @compiler_data.include_paths( missing_headers )
307
- config = Rake::LocalConfig.new( local_config )
308
- config.include_paths = added_includes
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
- file @makedepend_file => [ scoped_task( :load_local_config ),
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
- task :load_local_config => scoped_task( :local_config ) do
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 += Rake::Path.expand_all_with_root( config.include_paths, @rakefile_path )
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
- task :missing_headers => [ *generated_headers ] do
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.inspect
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 { |p| "-I#{ p }" }.join( " " )
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
- @rakefile_path = File.expand_path( File.dirname( @rakefile ) )
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.subtract_prefix( non_glob_search, directory )
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( log_level, command )
670
- `#{ command }`
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
+