rake-builder 0.0.16 → 0.0.17
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +2 -1
- data/README.md +178 -0
- data/examples/07_multiple_targets/Rakefile +16 -0
- data/examples/07_multiple_targets/main.c +7 -0
- data/lib/rake/builder/version.rb +1 -1
- data/lib/rake/builder.rb +56 -41
- data/lib/rake/microsecond.rb +8 -4
- data/spec/autoconf_spec.rb +191 -0
- data/spec/cpp_project_spec.rb +26 -1
- metadata +49 -61
- data/README.rdoc +0 -143
data/COPYING
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
Copyright (c) 2010 Joe Yates
|
1
|
+
Copyright (c) 2010-2012 Joe Yates
|
2
2
|
|
3
3
|
Permission is hereby granted, free of charge, to any person obtaining
|
4
4
|
a copy of this software and associated documentation files (the
|
@@ -18,3 +18,4 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
18
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
19
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
20
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
+
|
data/README.md
ADDED
@@ -0,0 +1,178 @@
|
|
1
|
+
rake-builder
|
2
|
+
============
|
3
|
+
|
4
|
+
*Rake for C, C++, Objective-C and Objective-C++ Projects*
|
5
|
+
|
6
|
+
* [Source code]
|
7
|
+
* [Documentation]
|
8
|
+
* [Rubygem]
|
9
|
+
|
10
|
+
[Source code]: http://github.com/joeyates/rake-builder "Source code at GitHub"
|
11
|
+
[Documentation]: http://rdoc.info/projects/joeyates/rake-builder "Documentation at Rubydoc.info"
|
12
|
+
[Rubygem]: http://rubygems.org/gems/rake-builder "Ruby gem at rubygems.org"
|
13
|
+
|
14
|
+
Hello World! Example
|
15
|
+
====================
|
16
|
+
|
17
|
+
(See the 'examples' directory for source).
|
18
|
+
|
19
|
+
Rakefile:
|
20
|
+
```ruby
|
21
|
+
require 'rubygems' if RUBY_VERSION < '1.9'
|
22
|
+
require 'rake'
|
23
|
+
require 'rake/builder'
|
24
|
+
|
25
|
+
Rake::Builder.new do |builder|
|
26
|
+
builder.target = 'hello_world_cpp'
|
27
|
+
end
|
28
|
+
```
|
29
|
+
|
30
|
+
main.cpp
|
31
|
+
```cpp
|
32
|
+
#include <iostream>
|
33
|
+
|
34
|
+
int main(int argc, char *argv[]) {
|
35
|
+
std::cout << "Hello World!\n";
|
36
|
+
|
37
|
+
return 0;
|
38
|
+
}
|
39
|
+
```
|
40
|
+
|
41
|
+
The Hello World! project should build and run:
|
42
|
+
|
43
|
+
```shell
|
44
|
+
$ rake run
|
45
|
+
Hello World!
|
46
|
+
```
|
47
|
+
|
48
|
+
Installation
|
49
|
+
============
|
50
|
+
|
51
|
+
Dependencies
|
52
|
+
------------
|
53
|
+
|
54
|
+
* makedepend
|
55
|
+
* linux: package 'xutils-dev'
|
56
|
+
* OS X: already installed
|
57
|
+
|
58
|
+
Gem
|
59
|
+
---
|
60
|
+
|
61
|
+
```shell
|
62
|
+
$ (sudo) gem install rake-builder
|
63
|
+
```
|
64
|
+
|
65
|
+
Usage
|
66
|
+
=====
|
67
|
+
|
68
|
+
Examples
|
69
|
+
--------
|
70
|
+
See the 'examples' directory.
|
71
|
+
|
72
|
+
If you've installed the gem system-wide, type the following to go to
|
73
|
+
the correct directory:
|
74
|
+
|
75
|
+
```shell
|
76
|
+
$ cd `gem environment gemdir`/gems/rake-builder-nnn
|
77
|
+
$ cd examples
|
78
|
+
```
|
79
|
+
|
80
|
+
Project Configuration
|
81
|
+
---------------------
|
82
|
+
|
83
|
+
In order to build on a specific computer, you will need
|
84
|
+
to indicate information like non-standard
|
85
|
+
include paths.
|
86
|
+
|
87
|
+
Rake::Builder collects all such information in one file:
|
88
|
+
'.rake-builder'
|
89
|
+
|
90
|
+
This file should be created in the same directory as the Rakefile.
|
91
|
+
|
92
|
+
The file should be a YAML structure, and must include a version.
|
93
|
+
|
94
|
+
Currently, the following can be configured:
|
95
|
+
* extra include paths: :include_paths
|
96
|
+
* extra compilation options (e.g. defines): :compilation_options
|
97
|
+
|
98
|
+
### Example '.rake-builder'
|
99
|
+
|
100
|
+
```yaml
|
101
|
+
---
|
102
|
+
:rake_builder:
|
103
|
+
:config_file:
|
104
|
+
:version: "1.0"
|
105
|
+
:include_paths:
|
106
|
+
- /opt/local/include
|
107
|
+
- /usr/include/c++/4.2.1
|
108
|
+
```
|
109
|
+
|
110
|
+
Default Tasks
|
111
|
+
-------------
|
112
|
+
|
113
|
+
* compile
|
114
|
+
* build
|
115
|
+
* run - executables only
|
116
|
+
* install
|
117
|
+
* clean
|
118
|
+
|
119
|
+
Installing Headers
|
120
|
+
------------------
|
121
|
+
|
122
|
+
If you install a static library, your headers will also be installed.
|
123
|
+
Ensure that you use file globs, e.g. './include/**/*.h',
|
124
|
+
as these will ensure that your headers are installed in the correct subdirectories.
|
125
|
+
|
126
|
+
Project
|
127
|
+
=======
|
128
|
+
|
129
|
+
Status
|
130
|
+
------
|
131
|
+
|
132
|
+
* Builds C, C++ and Objective-C projects using [GCC](http://gcc.gnu.org/).
|
133
|
+
|
134
|
+
Dependency Resolution
|
135
|
+
---------------------
|
136
|
+
|
137
|
+
Task dependencies must ensure that out of date files are recreated as needed.
|
138
|
+
|
139
|
+
![rake-builder Dependency Resolution](http://github.com/downloads/joeyates/rake-builder/RakeBuilderDependencyStructure.png "rake-builder Dependency Resolution")
|
140
|
+
|
141
|
+
Limitations
|
142
|
+
-----------
|
143
|
+
|
144
|
+
### File Modification Times
|
145
|
+
|
146
|
+
Rake's FileTask decides whether a file needs rebuilding by comparing on disk file
|
147
|
+
modification times (see the private method *out_of_date?*, which returns true if the
|
148
|
+
dependency was modified *after* the dependent).
|
149
|
+
Unfortunately, most modern file systems hold modification times in whole
|
150
|
+
seconds. If a dependency and a dependent were modificed during the same second,
|
151
|
+
**even if the dependency were modified later**, *out_of_date?* returns *false*
|
152
|
+
which is not the correct answer.
|
153
|
+
|
154
|
+
This problem is mostly felt in testing, where file modification times are temporarily
|
155
|
+
modified to test dependencies. Also, tests wait for second to complete after building.
|
156
|
+
|
157
|
+
#### File Modification Time Resolutions
|
158
|
+
|
159
|
+
* [Ext3](http://en.wikipedia.org/wiki/Ext3) - resolution: 1s
|
160
|
+
* [Ext4](http://en.wikipedia.org/wiki/Ext4) - resolution: 1 microsecond
|
161
|
+
* [Hierarchical_File_System](http://en.wikipedia.org/wiki/Hierarchical_File_System) - resolution: 1s
|
162
|
+
* [HFS_Plus](http://en.wikipedia.org/wiki/HFS_Plus) - resolution: 1s
|
163
|
+
|
164
|
+
### Source Files with the Same Name
|
165
|
+
|
166
|
+
Currently, object files from all source files are placed in the same directory.
|
167
|
+
So, if there are two source files with the same name, they will overwrite each other.
|
168
|
+
|
169
|
+
Alternatives
|
170
|
+
------------
|
171
|
+
|
172
|
+
* GNU build system, a.k.a. Autotools: autoconf, configure, make, etc.
|
173
|
+
* [Boost.Build](http://www.boost.org/boost-build2/)
|
174
|
+
* [CMake](http://www.cmake.org/)
|
175
|
+
* [SCons](http://www.scons.org/)
|
176
|
+
* [waf](http://code.google.com/p/waf/)
|
177
|
+
* [fbuild](https://github.com/felix-lang/fbuild)
|
178
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rubygems' if RUBY_VERSION < '1.9'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/builder'
|
4
|
+
|
5
|
+
Rake::Builder.new do |builder|
|
6
|
+
builder.target = 'foo/target_1'
|
7
|
+
builder.objects_path = 'foo/objects'
|
8
|
+
builder.programming_language = 'c'
|
9
|
+
end
|
10
|
+
|
11
|
+
Rake::Builder.new do |builder|
|
12
|
+
builder.target = 'bar/target_2'
|
13
|
+
builder.objects_path = 'bar/objects'
|
14
|
+
builder.programming_language = 'c'
|
15
|
+
end
|
16
|
+
|
data/lib/rake/builder/version.rb
CHANGED
data/lib/rake/builder.rb
CHANGED
@@ -64,17 +64,23 @@ module Rake
|
|
64
64
|
'c' => {
|
65
65
|
:source_file_extension => 'c',
|
66
66
|
:compiler => 'gcc',
|
67
|
-
:linker => 'gcc'
|
67
|
+
:linker => 'gcc',
|
68
|
+
:ar => 'ar',
|
69
|
+
:ranlib => 'ranlib'
|
68
70
|
},
|
69
71
|
'c++' => {
|
70
72
|
:source_file_extension => 'cpp',
|
71
73
|
:compiler => 'g++',
|
72
|
-
:linker => 'g++'
|
74
|
+
:linker => 'g++',
|
75
|
+
:ar => 'ar',
|
76
|
+
:ranlib => 'ranlib'
|
73
77
|
},
|
74
78
|
'objective-c' => {
|
75
79
|
:source_file_extension => 'm',
|
76
80
|
:compiler => 'gcc',
|
77
|
-
:linker => 'gcc'
|
81
|
+
:linker => 'gcc',
|
82
|
+
:ar => 'ar',
|
83
|
+
:ranlib => 'ranlib'
|
78
84
|
},
|
79
85
|
}
|
80
86
|
|
@@ -84,6 +90,12 @@ module Rake
|
|
84
90
|
# The linker that will be used
|
85
91
|
attr_accessor :linker
|
86
92
|
|
93
|
+
# Toolchain setting - ar
|
94
|
+
attr_accessor :ar
|
95
|
+
|
96
|
+
# Toolchain setting - ranlib
|
97
|
+
attr_accessor :ranlib
|
98
|
+
|
87
99
|
# Extension of source files (default 'cpp' for C++ and 'c' for C)
|
88
100
|
attr_accessor :source_file_extension
|
89
101
|
|
@@ -173,29 +185,20 @@ module Rake
|
|
173
185
|
task :autoconf, [:project_title, :version] => [] do | task, args |
|
174
186
|
project_title = args.project_title or raise "Please supply a project_title parameter"
|
175
187
|
version = decide_version( args.version )
|
176
|
-
if File.exist?(
|
188
|
+
if File.exist?('configure.ac')
|
177
189
|
raise "The file 'configure.ac' already exists"
|
178
190
|
end
|
179
|
-
if File.exist?(
|
191
|
+
if File.exist?('Makefile.am')
|
180
192
|
raise "The file 'Makefile.am' already exists"
|
181
193
|
end
|
182
194
|
create_configure_ac project_title, version
|
183
195
|
create_makefile_am
|
184
196
|
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
197
|
end
|
195
198
|
|
196
199
|
def self.create_configure_ac( project_title, version )
|
197
200
|
source = Rake::Path.relative_path( instances[ 0 ].source_files[ 0 ], instances[ 0 ].rakefile_path )
|
198
|
-
File.open(
|
201
|
+
File.open('configure.ac', 'w') do | f |
|
199
202
|
f.write <<EOT
|
200
203
|
AC_PREREQ(2.61)
|
201
204
|
AC_INIT(#{project_title}, #{ version })
|
@@ -262,8 +265,10 @@ EOT
|
|
262
265
|
f.write "bin_PROGRAMS = #{ names }\n\n"
|
263
266
|
binaries.each do | bin |
|
264
267
|
f.write <<EOT
|
265
|
-
#{ bin[ :label ] }_SOURCES
|
268
|
+
#{ bin[ :label ] }_SOURCES = #{ bin[ :sources ] }
|
266
269
|
#{ bin[ :label ] }_CPPFLAGS = #{ bin[ :compiler_flags ] }
|
270
|
+
#{ bin[ :label ] }_LDFLAGS = -L.
|
271
|
+
#{ bin[ :label ] }_LDADD = #{ bin[ :libraries ] }
|
267
272
|
|
268
273
|
EOT
|
269
274
|
end
|
@@ -282,7 +287,8 @@ EOT
|
|
282
287
|
:name => primary_name,
|
283
288
|
:label => sources_label,
|
284
289
|
:sources => sources,
|
285
|
-
:compiler_flags => compiler_flags
|
290
|
+
:compiler_flags => compiler_flags,
|
291
|
+
:libraries => library_dependencies_list,
|
286
292
|
}
|
287
293
|
end
|
288
294
|
|
@@ -292,11 +298,11 @@ EOT
|
|
292
298
|
def self.decide_version( parameter_version )
|
293
299
|
acceptable_version_string = %r(^(\d+)\.(\d+)\.(\d+)$)
|
294
300
|
if parameter_version && parameter_version !~ acceptable_version_string
|
295
|
-
raise "The supplied version number '#{
|
301
|
+
raise "The supplied version number '#{parameter_version}' is badly formatted. It should consist of three numbers separated by ."
|
296
302
|
end
|
297
303
|
file_version = load_file_version
|
298
304
|
if file_version && file_version !~ acceptable_version_string
|
299
|
-
raise "Your VERSION file contains a version number '#{
|
305
|
+
raise "Your VERSION file contains a version number '#{file_version}' which is badly formatted. It should consist of three numbers separated by ."
|
300
306
|
end
|
301
307
|
case
|
302
308
|
when parameter_version.nil? && file_version.nil?
|
@@ -321,16 +327,13 @@ EOT
|
|
321
327
|
end
|
322
328
|
|
323
329
|
def self.load_file_version
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
else
|
328
|
-
nil
|
329
|
-
end
|
330
|
+
return nil unless File.exist?('VERSION')
|
331
|
+
version = File.read('VERSION')
|
332
|
+
version.strip
|
330
333
|
end
|
331
334
|
|
332
335
|
def self.save_file_version( version )
|
333
|
-
File.open(
|
336
|
+
File.open('VERSION', 'w') { |f| f.write "#{version}\n" }
|
334
337
|
end
|
335
338
|
|
336
339
|
self.define_global
|
@@ -348,7 +351,7 @@ EOT
|
|
348
351
|
# Source files found in source_search_paths
|
349
352
|
def source_files
|
350
353
|
return @source_files if @source_files
|
351
|
-
@source_files = find_files( @source_search_paths, @source_file_extension ).uniq
|
354
|
+
@source_files = find_files( @source_search_paths, @source_file_extension ).uniq.sort
|
352
355
|
end
|
353
356
|
|
354
357
|
# Header files found in header_search_paths
|
@@ -387,6 +390,8 @@ EOT
|
|
387
390
|
raise BuilderError.new( "Don't know how to build '#{ @programming_language }' programs", task_namespace ) if KNOWN_LANGUAGES[ @programming_language ].nil?
|
388
391
|
@compiler ||= KNOWN_LANGUAGES[ @programming_language ][ :compiler ]
|
389
392
|
@linker ||= KNOWN_LANGUAGES[ @programming_language ][ :linker ]
|
393
|
+
@ar ||= KNOWN_LANGUAGES[ @programming_language ][ :ar ]
|
394
|
+
@ranlib ||= KNOWN_LANGUAGES[ @programming_language ][ :ranlib ]
|
390
395
|
@source_file_extension ||= KNOWN_LANGUAGES[ @programming_language ][ :source_file_extension ]
|
391
396
|
|
392
397
|
@source_search_paths = Rake::Path.expand_all_with_root( @source_search_paths, @rakefile_path )
|
@@ -458,9 +463,10 @@ EOT
|
|
458
463
|
*@target_prerequisites ] do | t |
|
459
464
|
shell "rm -f #{ t.name }"
|
460
465
|
build_commands.each do | command |
|
461
|
-
shell
|
466
|
+
stdout, stderr = shell(command)
|
467
|
+
raise BuildFailure.new("Error: command '#{command}' failed: #{stderr} #{stdout}") if not $?.success?
|
462
468
|
end
|
463
|
-
raise BuildFailure.new(
|
469
|
+
raise BuildFailure.new("'#{@target}' not created") if not File.exist?(@target)
|
464
470
|
end
|
465
471
|
|
466
472
|
desc "Compile all sources"
|
@@ -485,10 +491,12 @@ EOT
|
|
485
491
|
config.save
|
486
492
|
end
|
487
493
|
|
488
|
-
microsecond_file @makedepend_file => [
|
489
|
-
|
490
|
-
|
491
|
-
|
494
|
+
microsecond_file @makedepend_file => [
|
495
|
+
scoped_task( :load_local_config ),
|
496
|
+
scoped_task( :missing_headers ),
|
497
|
+
@objects_path,
|
498
|
+
*project_files
|
499
|
+
] do
|
492
500
|
system('which makedepend >/dev/null')
|
493
501
|
raise 'makedepend not found' unless $?.success?
|
494
502
|
@logger.add( Logger::DEBUG, "Analysing dependencies" )
|
@@ -520,13 +528,13 @@ EOT
|
|
520
528
|
File.open( @makedepend_file ).each_line do |line|
|
521
529
|
next if line !~ /:\s/
|
522
530
|
mapped_object_file = $`
|
523
|
-
|
531
|
+
header_files = $'.chomp
|
524
532
|
# TODO: Why does it work,
|
525
533
|
# if I make the object (not the source) depend on the header?
|
526
534
|
source_file = object_to_source[ mapped_object_file ]
|
527
535
|
object_file = object_path( source_file )
|
528
536
|
object_file_task = Rake.application[ object_file ]
|
529
|
-
object_file_task.enhance(
|
537
|
+
object_file_task.enhance(header_files.split(' '))
|
530
538
|
end
|
531
539
|
end
|
532
540
|
|
@@ -661,8 +669,8 @@ EOT
|
|
661
669
|
when :executable
|
662
670
|
[ "#{ @linker } -o #{ @target } #{ file_list( object_files ) } #{ link_flags }" ]
|
663
671
|
when :static_library
|
664
|
-
[ "ar -cq #{ @target } #{ file_list( object_files ) }",
|
665
|
-
"ranlib #{ @target }" ]
|
672
|
+
[ "#{ @ar } -cq #{ @target } #{ file_list( object_files ) }",
|
673
|
+
"#{ @ranlib } #{ @target }" ]
|
666
674
|
when :shared_library
|
667
675
|
[ "#{ @linker } -shared -o #{ @target } #{ file_list( object_files ) } #{ link_flags }" ]
|
668
676
|
end
|
@@ -696,8 +704,10 @@ EOT
|
|
696
704
|
end
|
697
705
|
|
698
706
|
def compiler_flags
|
699
|
-
flags = include_path
|
700
|
-
|
707
|
+
flags = include_path
|
708
|
+
options = compilation_options.join( ' ' )
|
709
|
+
flags << ' ' + options if options != ''
|
710
|
+
flags << ' ' + architecture_option if RUBY_PLATFORM =~ /darwin/i
|
701
711
|
flags
|
702
712
|
end
|
703
713
|
|
@@ -841,9 +851,14 @@ EOT
|
|
841
851
|
end
|
842
852
|
end
|
843
853
|
|
844
|
-
def shell(
|
854
|
+
def shell(command, log_level = Logger::DEBUG)
|
845
855
|
@logger.add(log_level, command)
|
846
|
-
|
856
|
+
originals = $stdout, $stderr
|
857
|
+
stdout, stderr = StringIO.new, StringIO.new
|
858
|
+
$stdout, $stderr = stdout, stderr
|
859
|
+
system command, {:out => :out, :err => :err}
|
860
|
+
$stdout, $stderr = *originals
|
861
|
+
[stdout.read, stderr.read]
|
847
862
|
end
|
848
863
|
|
849
864
|
end
|
data/lib/rake/microsecond.rb
CHANGED
@@ -35,21 +35,25 @@ module Rake
|
|
35
35
|
include FileUtils
|
36
36
|
|
37
37
|
attr_accessor :timestamp
|
38
|
+
attr_accessor :path
|
38
39
|
|
39
40
|
def self.define_task( *args, &block )
|
40
|
-
task
|
41
|
+
task = super(*args, &block)
|
42
|
+
task.path = args[0]
|
41
43
|
task.timestamp = nil
|
42
44
|
task
|
43
45
|
end
|
44
46
|
|
45
47
|
def needed?
|
46
|
-
exists = File.directory?(
|
47
|
-
|
48
|
+
exists = File.directory?(self.path)
|
49
|
+
if exists && @timestamp.nil?
|
50
|
+
@timestamp = File.stat(self.path).mtime
|
51
|
+
end
|
48
52
|
! exists
|
49
53
|
end
|
50
54
|
|
51
55
|
def execute(*args)
|
52
|
-
mkdir_p self.
|
56
|
+
mkdir_p self.path, :verbose => false
|
53
57
|
@timestamp = Time.now
|
54
58
|
super(*args)
|
55
59
|
end
|
@@ -0,0 +1,191 @@
|
|
1
|
+
load File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
describe 'autoconf' do
|
4
|
+
|
5
|
+
include RakeBuilderHelper
|
6
|
+
|
7
|
+
before :each do
|
8
|
+
Rake::Task.clear
|
9
|
+
Rake::Builder.define_global
|
10
|
+
|
11
|
+
@project = cpp_task(:executable)
|
12
|
+
|
13
|
+
@args = Rake::TaskArguments.new(
|
14
|
+
[:project_title, :version],
|
15
|
+
['my_title', '1.0.0'],
|
16
|
+
)
|
17
|
+
File.stub!(:exist?).and_return(false)
|
18
|
+
@files = {
|
19
|
+
'VERSION' => stub('File', :write => nil),
|
20
|
+
'configure.ac' => stub('File', :write => nil),
|
21
|
+
'Makefile.am' => stub('File', :write => nil),
|
22
|
+
}
|
23
|
+
# Capture text saved to files
|
24
|
+
@output = {}
|
25
|
+
File.stub!(:open) do |(filename, perms), &block|
|
26
|
+
file = @files[filename]
|
27
|
+
file.stub!(:write) do |s|
|
28
|
+
@output[filename] = s
|
29
|
+
end
|
30
|
+
block.call file
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'invocation' do
|
35
|
+
|
36
|
+
it "has an 'autoconf' task" do
|
37
|
+
task_names.include?('autoconf').
|
38
|
+
should be_true
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'requires a project_title parameter' do
|
42
|
+
@args = Rake::TaskArguments.new([], [])
|
43
|
+
|
44
|
+
expect do
|
45
|
+
Rake::Task['autoconf'].execute(@args)
|
46
|
+
end. to raise_error(RuntimeError, /supply a project_title/)
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'version parameter' do
|
50
|
+
|
51
|
+
it 'should be nn.nn.nn' do
|
52
|
+
@args = Rake::TaskArguments.new(
|
53
|
+
[:project_title, :version],
|
54
|
+
['my_title', 'foo'],
|
55
|
+
)
|
56
|
+
|
57
|
+
expect do
|
58
|
+
Rake::Task['autoconf'].execute(@args)
|
59
|
+
end. to raise_error(RuntimeError, /The supplied version number 'foo' is badly formatted/)
|
60
|
+
end
|
61
|
+
|
62
|
+
context 'when missing' do
|
63
|
+
|
64
|
+
before :each do
|
65
|
+
@args = Rake::TaskArguments.new(
|
66
|
+
[:project_title],
|
67
|
+
['my_title', ],
|
68
|
+
)
|
69
|
+
File.stub(:read).with('VERSION').and_return('2.3.444')
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'checks for a VERSION file' do
|
73
|
+
File.should_receive(:exist?).with('VERSION').and_return(true)
|
74
|
+
|
75
|
+
Rake::Task['autoconf'].execute(@args)
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'fails without a VERSION file' do
|
79
|
+
expect do
|
80
|
+
Rake::Task['autoconf'].execute(@args)
|
81
|
+
end. to raise_error(RuntimeError, /This task requires a project version/)
|
82
|
+
end
|
83
|
+
|
84
|
+
context 'with a VERSION file' do
|
85
|
+
|
86
|
+
before :each do
|
87
|
+
File.stub(:exist?).with('VERSION').and_return(true)
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'reads the file' do
|
91
|
+
File.should_receive(:read).with('VERSION').and_return('2.3.444')
|
92
|
+
|
93
|
+
Rake::Task['autoconf'].execute(@args)
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'uses the version' do
|
97
|
+
Rake::Task['autoconf'].execute(@args)
|
98
|
+
|
99
|
+
@output['configure.ac']. should =~ /AC_INIT\(.*?, 2\.3\.444\)/
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
it "fails if 'configure.ac' exists" do
|
111
|
+
File.should_receive(:exist?).with('configure.ac').and_return(true)
|
112
|
+
|
113
|
+
expect do
|
114
|
+
Rake::Task['autoconf'].execute(@args)
|
115
|
+
end. to raise_error(RuntimeError, /'configure.ac' already exists/)
|
116
|
+
end
|
117
|
+
|
118
|
+
it "fails if 'Makefile.am' exists" do
|
119
|
+
File.should_receive(:exist?).with('Makefile.am').and_return(true)
|
120
|
+
|
121
|
+
expect do
|
122
|
+
Rake::Task['autoconf'].execute(@args)
|
123
|
+
end. to raise_error(RuntimeError, /'Makefile.am' already exists/)
|
124
|
+
end
|
125
|
+
|
126
|
+
context 'configure.ac' do
|
127
|
+
|
128
|
+
it 'is created' do
|
129
|
+
File. should_receive(:open).
|
130
|
+
with('configure.ac', 'w')
|
131
|
+
|
132
|
+
Rake::Task['autoconf'].execute(@args)
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'has the title' do
|
136
|
+
Rake::Task['autoconf'].execute(@args)
|
137
|
+
|
138
|
+
@output['configure.ac']. should =~ /AC_INIT\(my_title, /
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'has the version' do
|
142
|
+
Rake::Task['autoconf'].execute(@args)
|
143
|
+
|
144
|
+
@output['configure.ac']. should =~ /AC_INIT\(.*?, 1\.0\.0\)/
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'checks for a source file' do
|
148
|
+
Rake::Task['autoconf'].execute(@args)
|
149
|
+
|
150
|
+
@output['configure.ac']. should =~ /AC_CONFIG_SRCDIR\(\[cpp_project\/main\.cpp\]\)/
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'references the Makefile' do
|
154
|
+
Rake::Task['autoconf'].execute(@args)
|
155
|
+
|
156
|
+
@output['configure.ac']. should =~ /AC_CONFIG_FILES\(\[Makefile\]\)/
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
context 'Makefile.am' do
|
162
|
+
|
163
|
+
it 'is created' do
|
164
|
+
File. should_receive(:open).
|
165
|
+
with('Makefile.am', 'w')
|
166
|
+
|
167
|
+
Rake::Task['autoconf'].execute(@args)
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'has sources' do
|
171
|
+
Rake::Task['autoconf'].execute(@args)
|
172
|
+
|
173
|
+
@output['Makefile.am']. should =~ /the_executable_SOURCES\s*=\s+cpp_project\/main\.cpp/
|
174
|
+
end
|
175
|
+
|
176
|
+
it 'has flags' do
|
177
|
+
Rake::Task['autoconf'].execute(@args)
|
178
|
+
|
179
|
+
@output['Makefile.am']. should =~ /the_executable_CPPFLAGS\s*=/
|
180
|
+
end
|
181
|
+
|
182
|
+
it 'has libraries' do
|
183
|
+
Rake::Task['autoconf'].execute(@args)
|
184
|
+
|
185
|
+
@output['Makefile.am']. should =~ /the_executable_LDADD\s*=/
|
186
|
+
end
|
187
|
+
|
188
|
+
end
|
189
|
+
|
190
|
+
end
|
191
|
+
|
data/spec/cpp_project_spec.rb
CHANGED
@@ -1,5 +1,30 @@
|
|
1
1
|
load File.dirname(__FILE__) + '/spec_helper.rb'
|
2
2
|
|
3
|
+
describe '#source_files' do
|
4
|
+
|
5
|
+
include RakeBuilderHelper
|
6
|
+
|
7
|
+
before( :each ) do
|
8
|
+
Rake::Path.stub!(:find_files).with(anything, 'h').and_return(['a.h'])
|
9
|
+
Rake::Path.stub!(:find_files).with(anything, 'cpp').and_return(['a.cpp'])
|
10
|
+
|
11
|
+
Rake::Task.clear
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should find files with the .cpp extension' do
|
15
|
+
Rake::Path.should_receive(:find_files).with(anything, 'cpp').and_return(['a.cpp'])
|
16
|
+
|
17
|
+
cpp_task(:executable)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should allow configuration of source extension' do
|
21
|
+
Rake::Path.should_receive(:find_files).with(anything, 'cc').and_return(['a.cc'])
|
22
|
+
|
23
|
+
cpp_task(:executable) { |p| p.source_file_extension = 'cc' }
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
3
28
|
describe 'when building an executable' do
|
4
29
|
|
5
30
|
include RakeBuilderHelper
|
@@ -48,7 +73,7 @@ describe 'when building an executable' do
|
|
48
73
|
end
|
49
74
|
|
50
75
|
it 'has a \'run\' task' do
|
51
|
-
|
76
|
+
task_names.include?('run'). should be_true
|
52
77
|
end
|
53
78
|
|
54
79
|
it 'builds the program with \'run\'' do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rake-builder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.17
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-01-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -60,23 +60,7 @@ dependencies:
|
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: 2.3.0
|
62
62
|
- !ruby/object:Gem::Dependency
|
63
|
-
name: pry
|
64
|
-
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
|
-
requirements:
|
67
|
-
- - ! '>='
|
68
|
-
- !ruby/object:Gem::Version
|
69
|
-
version: '0'
|
70
|
-
type: :development
|
71
|
-
prerelease: false
|
72
|
-
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
|
-
requirements:
|
75
|
-
- - ! '>='
|
76
|
-
- !ruby/object:Gem::Version
|
77
|
-
version: '0'
|
78
|
-
- !ruby/object:Gem::Dependency
|
79
|
-
name: pry-doc
|
63
|
+
name: pry-plus
|
80
64
|
requirement: !ruby/object:Gem::Requirement
|
81
65
|
none: false
|
82
66
|
requirements:
|
@@ -101,53 +85,56 @@ files:
|
|
101
85
|
- CHANGES
|
102
86
|
- COPYING
|
103
87
|
- Rakefile
|
104
|
-
- README.
|
88
|
+
- README.md
|
105
89
|
- lib/compiler.rb
|
106
|
-
- lib/rake/path.rb
|
107
90
|
- lib/rake/once_task.rb
|
91
|
+
- lib/rake/microsecond.rb
|
92
|
+
- lib/rake/file_task_alias.rb
|
108
93
|
- lib/rake/builder/qt_builder.rb
|
109
94
|
- lib/rake/builder/version.rb
|
110
95
|
- lib/rake/local_config.rb
|
111
|
-
- lib/rake/
|
96
|
+
- lib/rake/path.rb
|
112
97
|
- lib/rake/builder.rb
|
113
|
-
- lib/rake/microsecond.rb
|
114
|
-
- examples/04_zlib/include/main.h
|
115
|
-
- examples/05_tests/include/units.h
|
116
98
|
- examples/05_tests/include/main.h
|
99
|
+
- examples/05_tests/include/units.h
|
117
100
|
- examples/03_search_paths/include/main.h
|
118
|
-
- examples/
|
101
|
+
- examples/04_zlib/include/main.h
|
102
|
+
- examples/07_multiple_targets/main.c
|
119
103
|
- examples/04_zlib/src/main.c
|
120
|
-
- examples/
|
121
|
-
- examples/
|
104
|
+
- examples/02_hello_world_c/main.c
|
105
|
+
- examples/01_hello_world_cpp/main.cpp
|
122
106
|
- examples/05_tests/test/test_unit.cpp
|
107
|
+
- examples/05_tests/src/units.cpp
|
108
|
+
- examples/05_tests/src/main.cpp
|
123
109
|
- examples/03_search_paths/src/main.cpp
|
124
|
-
- examples/01_hello_world_cpp/main.cpp
|
125
110
|
- examples/06_hello_world_objective_c/main.m
|
126
111
|
- examples/README.rdoc
|
127
|
-
- examples/02_hello_world_c/Rakefile
|
128
|
-
- examples/04_zlib/Rakefile
|
129
|
-
- examples/05_tests/Rakefile
|
130
|
-
- examples/03_search_paths/Rakefile
|
131
112
|
- examples/01_hello_world_cpp/Rakefile
|
113
|
+
- examples/05_tests/Rakefile
|
132
114
|
- examples/06_hello_world_objective_c/Rakefile
|
133
|
-
-
|
134
|
-
-
|
115
|
+
- examples/07_multiple_targets/Rakefile
|
116
|
+
- examples/03_search_paths/Rakefile
|
117
|
+
- examples/04_zlib/Rakefile
|
118
|
+
- examples/02_hello_world_c/Rakefile
|
119
|
+
- spec/spec_helper.rb
|
120
|
+
- spec/cpp_project/main.h
|
121
|
+
- spec/cpp_project/main.cpp
|
122
|
+
- spec/generated_files_spec.rb
|
123
|
+
- spec/c_project/main.c
|
124
|
+
- spec/c_project/main.h
|
125
|
+
- spec/c_project_spec.rb
|
135
126
|
- spec/objective_c_project/main.h
|
136
|
-
- spec/
|
137
|
-
- spec/
|
127
|
+
- spec/objective_c_project/main.m
|
128
|
+
- spec/target_spec.rb
|
129
|
+
- spec/microsecond_task_spec.rb
|
138
130
|
- spec/cpp_project_spec.rb
|
131
|
+
- spec/logger_spec.rb
|
139
132
|
- spec/dependencies_spec.rb
|
140
133
|
- spec/objective_c_project_spec.rb
|
141
|
-
- spec/
|
142
|
-
- spec/
|
143
|
-
- spec/target_spec.rb
|
134
|
+
- spec/paths_spec.rb
|
135
|
+
- spec/local_config_spec.rb
|
144
136
|
- spec/libraries_spec.rb
|
145
|
-
- spec/
|
146
|
-
- spec/cpp_project/main.h
|
147
|
-
- spec/cpp_project/main.cpp
|
148
|
-
- spec/spec_helper.rb
|
149
|
-
- spec/c_project/main.c
|
150
|
-
- spec/c_project/main.h
|
137
|
+
- spec/autoconf_spec.rb
|
151
138
|
homepage: http://github.com/joeyates/rake-builder
|
152
139
|
licenses: []
|
153
140
|
post_install_message:
|
@@ -162,7 +149,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
162
149
|
version: '0'
|
163
150
|
segments:
|
164
151
|
- 0
|
165
|
-
hash:
|
152
|
+
hash: 4353605042528954080
|
166
153
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
167
154
|
none: false
|
168
155
|
requirements:
|
@@ -171,7 +158,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
171
158
|
version: '0'
|
172
159
|
segments:
|
173
160
|
- 0
|
174
|
-
hash:
|
161
|
+
hash: 4353605042528954080
|
175
162
|
requirements: []
|
176
163
|
rubyforge_project: nowarning
|
177
164
|
rubygems_version: 1.8.23
|
@@ -179,22 +166,23 @@ signing_key:
|
|
179
166
|
specification_version: 3
|
180
167
|
summary: Rake for C/C++ Projects
|
181
168
|
test_files:
|
182
|
-
- spec/
|
183
|
-
- spec/
|
169
|
+
- spec/spec_helper.rb
|
170
|
+
- spec/cpp_project/main.h
|
171
|
+
- spec/cpp_project/main.cpp
|
172
|
+
- spec/generated_files_spec.rb
|
173
|
+
- spec/c_project/main.c
|
174
|
+
- spec/c_project/main.h
|
175
|
+
- spec/c_project_spec.rb
|
184
176
|
- spec/objective_c_project/main.h
|
185
|
-
- spec/
|
186
|
-
- spec/
|
177
|
+
- spec/objective_c_project/main.m
|
178
|
+
- spec/target_spec.rb
|
179
|
+
- spec/microsecond_task_spec.rb
|
187
180
|
- spec/cpp_project_spec.rb
|
181
|
+
- spec/logger_spec.rb
|
188
182
|
- spec/dependencies_spec.rb
|
189
183
|
- spec/objective_c_project_spec.rb
|
190
|
-
- spec/
|
191
|
-
- spec/
|
192
|
-
- spec/target_spec.rb
|
184
|
+
- spec/paths_spec.rb
|
185
|
+
- spec/local_config_spec.rb
|
193
186
|
- spec/libraries_spec.rb
|
194
|
-
- spec/
|
195
|
-
- spec/cpp_project/main.h
|
196
|
-
- spec/cpp_project/main.cpp
|
197
|
-
- spec/spec_helper.rb
|
198
|
-
- spec/c_project/main.c
|
199
|
-
- spec/c_project/main.h
|
187
|
+
- spec/autoconf_spec.rb
|
200
188
|
has_rdoc:
|
data/README.rdoc
DELETED
@@ -1,143 +0,0 @@
|
|
1
|
-
= rake-builder - Rake for C, C++, Objective-C and Objective-C++ Projects
|
2
|
-
|
3
|
-
rake-builder builds C, C++, Objective-C and Objective-C++
|
4
|
-
projects.
|
5
|
-
|
6
|
-
Here is a typical example:
|
7
|
-
|
8
|
-
require 'rubygems' if RUBY_VERSION < '1.9'
|
9
|
-
require 'rake'
|
10
|
-
require 'rake/builder'
|
11
|
-
|
12
|
-
Rake::Builder.new do |builder|
|
13
|
-
builder.target = 'my_program'
|
14
|
-
builder.source_search_paths = [ 'src' ]
|
15
|
-
builder.header_search_paths = [ 'include' ]
|
16
|
-
end
|
17
|
-
|
18
|
-
= Dependencies
|
19
|
-
|
20
|
-
* makedepend
|
21
|
-
** linux: package 'xutils-dev'
|
22
|
-
** OS X: already installed
|
23
|
-
|
24
|
-
= Installation
|
25
|
-
|
26
|
-
$ sudo gem install rake-builder
|
27
|
-
|
28
|
-
= Hello World! Example
|
29
|
-
|
30
|
-
See the 'examples' directory.
|
31
|
-
|
32
|
-
The Hello World! project should build and run:
|
33
|
-
|
34
|
-
$ cd examples/01_hello_world_cpp
|
35
|
-
$ rake run
|
36
|
-
Hello World!
|
37
|
-
|
38
|
-
= Usage
|
39
|
-
|
40
|
-
See the 'examples' directory.
|
41
|
-
|
42
|
-
If you've installed the gem system-wide, type the following to go to
|
43
|
-
the correct directory:
|
44
|
-
|
45
|
-
$ cd `gem environment gemdir`/gems/rake-builder-nnn
|
46
|
-
$ cd examples
|
47
|
-
|
48
|
-
== Project Configuration
|
49
|
-
|
50
|
-
In order to build on a specific computer, you will need
|
51
|
-
to indicate information like non-standard
|
52
|
-
include paths.
|
53
|
-
|
54
|
-
Rake::Builder collects all such information in one file:
|
55
|
-
'.rake-builder'
|
56
|
-
|
57
|
-
For namespaced tasks, e.g. 'test:build', the file is '.rake-builer.test'
|
58
|
-
|
59
|
-
This file should be created in the same
|
60
|
-
directory as the Rakefile.
|
61
|
-
|
62
|
-
The file should be a YAML structure, and must include a version.
|
63
|
-
|
64
|
-
Currently, the following can be configured:
|
65
|
-
* extra include paths: :include_paths
|
66
|
-
* extra compilation options (e.g. defines): :compilation_options
|
67
|
-
|
68
|
-
=== Example '.rake-builder'
|
69
|
-
|
70
|
-
---
|
71
|
-
:rake_builder:
|
72
|
-
:config_file:
|
73
|
-
:version: "1.0"
|
74
|
-
:include_paths:
|
75
|
-
- /opt/local/include
|
76
|
-
- /usr/include/c++/4.2.1
|
77
|
-
|
78
|
-
= Default Tasks
|
79
|
-
|
80
|
-
* compile
|
81
|
-
* build
|
82
|
-
* run - executables only
|
83
|
-
* install
|
84
|
-
* clean
|
85
|
-
|
86
|
-
= Installing Headers
|
87
|
-
|
88
|
-
If you install a static library, your headers will also be installed.
|
89
|
-
Ensure that you use file globs, e.g. './include/**/*.h',
|
90
|
-
as these will ensure that your headers are installed in the correct subdirectories.
|
91
|
-
|
92
|
-
= Online
|
93
|
-
|
94
|
-
* {Source code}[http://github.com/joeyates/rake-builder]
|
95
|
-
* Documentation[http://rdoc.info/projects/joeyates/rake-builder]
|
96
|
-
* Gem[http://rubygems.org/gems/rake-builder]
|
97
|
-
|
98
|
-
= Dependencies
|
99
|
-
|
100
|
-
Task dependencies must ensure that out of date files are recreated as needed.
|
101
|
-
|
102
|
-
http://github.com/downloads/joeyates/rake-builder/RakeBuilderDependencyStructure.png
|
103
|
-
|
104
|
-
= Limitations
|
105
|
-
|
106
|
-
== File Modification Times
|
107
|
-
|
108
|
-
Rake's FileTask decides whether a file needs rebuilding by comparing on disk file
|
109
|
-
modification times (see the private method <em>out_of_date?</em>, which returns true if the
|
110
|
-
dependency was modified *after* the dependent).
|
111
|
-
Unfortunately, most modern file systems hold modification times in whole
|
112
|
-
seconds. If a dependency and a dependent were modificed during the same second,
|
113
|
-
<b>even if the dependency were modified later</b>, <em>out_of_date?</em> returns *false*
|
114
|
-
which is not the correct answer.
|
115
|
-
|
116
|
-
This problem is mostly felt in testing, where file modification times are temporarily
|
117
|
-
modified to test dependencies. Also, tests wait for second to complete after building.
|
118
|
-
|
119
|
-
=== File Modification Time Resolutions
|
120
|
-
|
121
|
-
* Ext3[http://en.wikipedia.org/wiki/Ext3] - resolution: 1s
|
122
|
-
* Ext4[http://en.wikipedia.org/wiki/Ext4] - resolution: 1 microsecond
|
123
|
-
* Hierarchical_File_System[http://en.wikipedia.org/wiki/Hierarchical_File_System] - resolution: 1s
|
124
|
-
* HFS_Plus[http://en.wikipedia.org/wiki/HFS_Plus] - resolution: 1s
|
125
|
-
|
126
|
-
== Source Files with the Same Name
|
127
|
-
|
128
|
-
Currently, object files from all source files are placed in the same directory.
|
129
|
-
So, if there are two source files with the same name, they will overwrite each other.
|
130
|
-
|
131
|
-
= Status
|
132
|
-
|
133
|
-
* Builds C, C++ and Objective-C projects using GCC[http://gcc.gnu.org/].
|
134
|
-
|
135
|
-
= Alternatives
|
136
|
-
|
137
|
-
* GNU build system, a.k.a. Autotools: autoconf, configure, make, etc.
|
138
|
-
* Boost.Build
|
139
|
-
* CMake
|
140
|
-
* rakepp - another customisation of Rake for C++ projects
|
141
|
-
* Scons
|
142
|
-
* waf[http://code.google.com/p/waf/]
|
143
|
-
* http://felix-lang.org/blog/2010/aug/30/fbuild-0-2/
|