rake-builder 0.0.16 → 0.0.17
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/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
|
+

|
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/
|