paper_house 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +19 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +17 -0
  5. data/Gemfile +35 -0
  6. data/Guardfile +28 -0
  7. data/README.md +116 -0
  8. data/Rakefile +139 -0
  9. data/cucumber.yml +3 -0
  10. data/examples/c_extension/.gitignore +5 -0
  11. data/examples/c_extension/Rakefile +3 -0
  12. data/examples/c_extension/Rakefile.llvm +5 -0
  13. data/examples/c_extension/hello.c +6 -0
  14. data/examples/executable/.gitignore +4 -0
  15. data/examples/executable/Rakefile +3 -0
  16. data/examples/executable/Rakefile.llvm +5 -0
  17. data/examples/executable/hello.c +7 -0
  18. data/examples/executable_subdirs/.gitignore +4 -0
  19. data/examples/executable_subdirs/Rakefile +9 -0
  20. data/examples/executable_subdirs/includes/hello.h +1 -0
  21. data/examples/executable_subdirs/sources/hello.c +6 -0
  22. data/examples/executable_subdirs/sources/main.c +8 -0
  23. data/examples/shared_library/.gitignore +8 -0
  24. data/examples/shared_library/Rakefile +17 -0
  25. data/examples/shared_library/Rakefile.llvm +19 -0
  26. data/examples/shared_library/hello.c +6 -0
  27. data/examples/shared_library/hello.h +1 -0
  28. data/examples/shared_library/main.c +7 -0
  29. data/examples/shared_library/symlinks.rake +7 -0
  30. data/examples/shared_library_subdirs/.gitignore +8 -0
  31. data/examples/shared_library_subdirs/Rakefile +27 -0
  32. data/examples/shared_library_subdirs/includes/hello.h +1 -0
  33. data/examples/shared_library_subdirs/sources/hello.c +6 -0
  34. data/examples/shared_library_subdirs/sources/main.c +8 -0
  35. data/examples/static_library/.gitignore +7 -0
  36. data/examples/static_library/Rakefile +13 -0
  37. data/examples/static_library/Rakefile.llvm +14 -0
  38. data/examples/static_library/hello.c +6 -0
  39. data/examples/static_library/hello.h +1 -0
  40. data/examples/static_library/main.c +7 -0
  41. data/examples/static_library_subdirs/.gitignore +7 -0
  42. data/examples/static_library_subdirs/Rakefile +17 -0
  43. data/examples/static_library_subdirs/includes/hello.h +1 -0
  44. data/examples/static_library_subdirs/sources/hello.c +6 -0
  45. data/examples/static_library_subdirs/sources/main.c +8 -0
  46. data/features/c_extension_task.feature +119 -0
  47. data/features/executable_task.feature +83 -0
  48. data/features/shared_library_task.feature +209 -0
  49. data/features/static_library_task.feature +116 -0
  50. data/features/step_definitions/paper_house_steps.rb +8 -0
  51. data/features/support/env.rb +41 -0
  52. data/features/support/hooks.rb +12 -0
  53. data/lib/paper_house/auto_depends.rb +95 -0
  54. data/lib/paper_house/build_task.rb +188 -0
  55. data/lib/paper_house/c_extension_task.rb +95 -0
  56. data/lib/paper_house/cc_options.rb +81 -0
  57. data/lib/paper_house/dependency.rb +74 -0
  58. data/lib/paper_house/executable_task.rb +77 -0
  59. data/lib/paper_house/library_task.rb +64 -0
  60. data/lib/paper_house/linker_options.rb +89 -0
  61. data/lib/paper_house/platform.rb +69 -0
  62. data/lib/paper_house/safe_popen.rb +50 -0
  63. data/lib/paper_house/shared_library_task.rb +92 -0
  64. data/lib/paper_house/static_library_task.rb +65 -0
  65. data/lib/paper_house/version.rb +30 -0
  66. data/lib/paper_house.rb +30 -0
  67. data/paper_house.gemspec +34 -0
  68. data/spec/paper_house/c_extension_task_spec.rb +59 -0
  69. data/spec/paper_house/cc_options_spec.rb +59 -0
  70. data/spec/paper_house/executable_task_spec.rb +49 -0
  71. data/spec/paper_house/shared_library_task_spec.rb +94 -0
  72. data/spec/paper_house/static_library_task_spec.rb +61 -0
  73. data/spec/paper_house/version_spec.rb +31 -0
  74. data/spec/spec_helper.rb +46 -0
  75. metadata +161 -0
@@ -0,0 +1,95 @@
1
+ #
2
+ # Copyright (C) 2013 NEC Corporation
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License, version 3, as
6
+ # published by the Free Software Foundation.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License along
14
+ # with this program; if not, write to the Free Software Foundation, Inc.,
15
+ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16
+ #
17
+
18
+
19
+ require "paper_house/safe_popen"
20
+
21
+
22
+ module PaperHouse
23
+ #
24
+ # Automatically detects compilation dependencies.
25
+ #
26
+ class AutoDepends
27
+ attr_reader :data
28
+
29
+
30
+ def initialize c_file, o_file, cc, cc_options
31
+ @cc = cc
32
+ @command = "#{ @cc } -H #{ cc_options } -c #{ c_file } -o #{ o_file }"
33
+ @data = []
34
+ end
35
+
36
+
37
+ #
38
+ # Runs dependency detection.
39
+ #
40
+ def run
41
+ puts @command
42
+ exit_status = popen_command
43
+ raise "#{ @cc } failed" if exit_status != 0
44
+ end
45
+
46
+
47
+ ############################################################################
48
+ private
49
+ ############################################################################
50
+
51
+
52
+ def popen_command
53
+ SafePopen.popen( @command ) do | stdout, stderr, stdin, |
54
+ stdin.close
55
+ parse_cc_h_stderr stderr
56
+ end.exitstatus
57
+ end
58
+
59
+
60
+ def parse_cc_h_stderr stderr
61
+ stderr.each do | each |
62
+ parse_cc_h_stderr_line( each, stderr )
63
+ end
64
+ end
65
+
66
+
67
+ def parse_cc_h_stderr_line line, stderr
68
+ case line
69
+ when /^\./
70
+ @data << line.sub( /^\.+\s+/, "" ).strip
71
+ when /Multiple include guards/
72
+ filter_out_include_guards_warnings stderr
73
+ else
74
+ puts line
75
+ end
76
+ end
77
+
78
+
79
+ def filter_out_include_guards_warnings stderr
80
+ stderr.each do | each |
81
+ if /:$/=~ each
82
+ puts each
83
+ return
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
89
+
90
+
91
+ ### Local variables:
92
+ ### mode: Ruby
93
+ ### coding: utf-8-unix
94
+ ### indent-tabs-mode: nil
95
+ ### End:
@@ -0,0 +1,188 @@
1
+ #
2
+ # Copyright (C) 2013 NEC Corporation
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License, version 3, as
6
+ # published by the Free Software Foundation.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License along
14
+ # with this program; if not, write to the Free Software Foundation, Inc.,
15
+ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16
+ #
17
+
18
+
19
+ require "paper_house/auto_depends"
20
+ require "paper_house/dependency"
21
+ require "paper_house/cc_options"
22
+ require "rake/clean"
23
+ require "rake/tasklib"
24
+
25
+
26
+ module PaperHouse
27
+ # Common base class for *.c compilation tasks.
28
+ class BuildTask < Rake::TaskLib
29
+ include CcOptions
30
+
31
+
32
+ # Name of task.
33
+ attr_accessor :name
34
+
35
+
36
+ # @!attribute target_directory
37
+ # Directory where *.o files are created.
38
+ attr_writer :target_directory
39
+
40
+ def target_directory
41
+ @target_directory ||= "."
42
+ end
43
+
44
+
45
+ # @!attribute cc
46
+ # C compiler name or path.
47
+ attr_writer :cc
48
+
49
+ def cc
50
+ ENV[ "CC" ] || @cc || "gcc"
51
+ end
52
+
53
+
54
+ def initialize name, &block
55
+ @name = name.to_s
56
+ block.call self if block
57
+ define
58
+ end
59
+
60
+
61
+ # Relative path to target file.
62
+ def target_path
63
+ File.join target_directory, target_file_name
64
+ end
65
+
66
+
67
+ ############################################################################
68
+ private
69
+ ############################################################################
70
+
71
+
72
+ def define
73
+ define_main_task
74
+ define_directory_task
75
+ define_all_c_compile_tasks
76
+ define_maybe_generate_target_task
77
+ define_clean_tasks
78
+ end
79
+
80
+
81
+ def define_main_task
82
+ path = target_path
83
+ task name => [ target_directory, path ]
84
+ end
85
+
86
+
87
+ def define_directory_task
88
+ directory target_directory
89
+ end
90
+
91
+
92
+ def define_all_c_compile_tasks
93
+ sources_list.zip( objects ) do | source, object |
94
+ define_c_compile_task source, object
95
+ end
96
+ end
97
+
98
+
99
+ def define_c_compile_task source, object
100
+ task object => source do | task |
101
+ compile task.name, task.prerequisites[ 0 ]
102
+ end
103
+ end
104
+
105
+
106
+ def define_maybe_generate_target_task
107
+ file target_path => objects do | task |
108
+ next if uptodate?( task.name, task.prerequisites )
109
+ build
110
+ end
111
+ end
112
+
113
+
114
+ def build
115
+ check_sources_list
116
+ generate_target
117
+ end
118
+
119
+
120
+ def check_sources_list
121
+ if sources_list.empty?
122
+ fail "Cannot find sources (#{ @sources })."
123
+ end
124
+ end
125
+
126
+
127
+ def define_clean_tasks
128
+ define_clean_task
129
+ define_clobber_task
130
+ end
131
+
132
+
133
+ def define_clean_task
134
+ objects.each do | each |
135
+ next if not FileTest.exist?( each )
136
+ CLEAN.include each
137
+ end
138
+ end
139
+
140
+
141
+ def define_clobber_task
142
+ clobber_targets.each do | each |
143
+ next if not FileTest.exist?( each )
144
+ CLOBBER.include each
145
+ end
146
+ end
147
+
148
+
149
+ def clobber_targets
150
+ [ target_path, dependency.path ]
151
+ end
152
+
153
+
154
+ def objects
155
+ sources_list.pathmap File.join( target_directory, "%n.o" )
156
+ end
157
+
158
+
159
+ def compile o_file, c_file
160
+ return if no_need_to_compile?( o_file, c_file )
161
+ auto_depends = AutoDepends.new( c_file, o_file, cc, auto_depends_cc_options )
162
+ auto_depends.run
163
+ dependency.write o_file, auto_depends.data
164
+ end
165
+
166
+
167
+ def no_need_to_compile?( o_file, c_file )
168
+ uptodate?( o_file, dependency.read( o_file ) << c_file )
169
+ end
170
+
171
+
172
+ def auto_depends_cc_options
173
+ ( cflags + [ "-fPIC" ] + i_options ).join " "
174
+ end
175
+
176
+
177
+ def dependency
178
+ @dependency ||= Dependency.new( @name )
179
+ end
180
+ end
181
+ end
182
+
183
+
184
+ ### Local variables:
185
+ ### mode: Ruby
186
+ ### coding: utf-8-unix
187
+ ### indent-tabs-mode: nil
188
+ ### End:
@@ -0,0 +1,95 @@
1
+ #
2
+ # Copyright (C) 2013 NEC Corporation
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License, version 3, as
6
+ # published by the Free Software Foundation.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License along
14
+ # with this program; if not, write to the Free Software Foundation, Inc.,
15
+ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16
+ #
17
+
18
+
19
+ require "paper_house/library_task"
20
+ require "paper_house/linker_options"
21
+ require "paper_house/platform"
22
+
23
+
24
+ module PaperHouse
25
+ #
26
+ # Compiles *.c files into a Ruby extension library.
27
+ #
28
+ class CExtensionTask < LibraryTask
29
+ include LinkerOptions
30
+ include Platform
31
+
32
+
33
+ # Name of target library.
34
+ attr_writer :library_name
35
+
36
+
37
+ # Name of target library file.
38
+ def target_file_name
39
+ library_name + SHARED_EXT
40
+ end
41
+
42
+
43
+ # List of libraries to link.
44
+ def library_dependencies
45
+ if Platform::MAC
46
+ ( [ @library_dependencies ] << "ruby" ).flatten.compact
47
+ else
48
+ super
49
+ end
50
+ end
51
+
52
+
53
+ ############################################################################
54
+ private
55
+ ############################################################################
56
+
57
+
58
+ def generate_target
59
+ sh ( [ cc ] + cc_options ).join( " " )
60
+ end
61
+
62
+
63
+ def cc_options
64
+ [ LDSHARED, o_option, objects, ldflags, libdir_option, l_options ].flatten
65
+ end
66
+
67
+
68
+ def o_option
69
+ "-o #{ target_path }"
70
+ end
71
+
72
+
73
+ def libdir_option
74
+ "-L#{ RUBY_LIBDIR }"
75
+ end
76
+
77
+
78
+ def include_directories
79
+ ( includes + auto_includes + RUBY_INCLUDES ).uniq
80
+ end
81
+ end
82
+
83
+
84
+ #
85
+ # Alias for CExtensionTask
86
+ #
87
+ RubyLibraryTask = CExtensionTask
88
+ end
89
+
90
+
91
+ ### Local variables:
92
+ ### mode: Ruby
93
+ ### coding: utf-8-unix
94
+ ### indent-tabs-mode: nil
95
+ ### End:
@@ -0,0 +1,81 @@
1
+ #
2
+ # Copyright (C) 2013 NEC Corporation
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License, version 3, as
6
+ # published by the Free Software Foundation.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License along
14
+ # with this program; if not, write to the Free Software Foundation, Inc.,
15
+ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16
+ #
17
+
18
+
19
+ module PaperHouse
20
+ # CC option utilities.
21
+ module CcOptions
22
+ # @!attribute sources
23
+ # Glob pattern to match source files.
24
+ attr_writer :sources
25
+
26
+ def sources
27
+ @sources ||= "*.c"
28
+ end
29
+
30
+
31
+ # @!attribute cflags
32
+ # Compile options pass to C compiler.
33
+ attr_writer :cflags
34
+
35
+ def cflags
36
+ @cflags ||= []
37
+ end
38
+
39
+
40
+ # @!attribute includes
41
+ # Glob pattern to match include directories.
42
+ attr_writer :includes
43
+
44
+ def includes
45
+ @includes ||= []
46
+ FileList[ [ @includes ] ]
47
+ end
48
+
49
+
50
+ ############################################################################
51
+ private
52
+ ############################################################################
53
+
54
+
55
+ def i_options
56
+ include_directories.pathmap "-I%p"
57
+ end
58
+
59
+
60
+ def include_directories
61
+ ( includes + auto_includes ).uniq
62
+ end
63
+
64
+
65
+ def auto_includes
66
+ FileList[ sources_list.pathmap( "%d" ).uniq ]
67
+ end
68
+
69
+
70
+ def sources_list
71
+ FileList[ sources ]
72
+ end
73
+ end
74
+ end
75
+
76
+
77
+ ### Local variables:
78
+ ### mode: Ruby
79
+ ### coding: utf-8-unix
80
+ ### indent-tabs-mode: nil
81
+ ### End:
@@ -0,0 +1,74 @@
1
+ #
2
+ # Copyright (C) 2013 NEC Corporation
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License, version 3, as
6
+ # published by the Free Software Foundation.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License along
14
+ # with this program; if not, write to the Free Software Foundation, Inc.,
15
+ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16
+ #
17
+
18
+
19
+ require "pstore"
20
+ require "rake"
21
+
22
+
23
+ module PaperHouse
24
+ #
25
+ # Keeps compilation dependencies
26
+ #
27
+ class Dependency
28
+ attr_reader :path
29
+
30
+
31
+ def initialize name
32
+ @name = name
33
+ @path = File.join( Rake.original_dir, ".#{ name }.depends" )
34
+ @cache = {}
35
+ end
36
+
37
+
38
+ #
39
+ # Reads the dependency information of +object_file+.
40
+ #
41
+ def read object_file
42
+ db.transaction( true ) do | store |
43
+ store[ object_file ]
44
+ end || []
45
+ end
46
+
47
+
48
+ #
49
+ # Saves the dependency information (+object_file+ => +dependent_files+).
50
+ #
51
+ def write object_file, dependent_files
52
+ db.transaction( false ) do | store |
53
+ store[ object_file ] = dependent_files
54
+ end
55
+ end
56
+
57
+
58
+ ############################################################################
59
+ private
60
+ ############################################################################
61
+
62
+
63
+ def db
64
+ @cache[ @name ] ||= PStore.new( @path )
65
+ end
66
+ end
67
+ end
68
+
69
+
70
+ ### Local variables:
71
+ ### mode: Ruby
72
+ ### coding: utf-8-unix
73
+ ### indent-tabs-mode: nil
74
+ ### End:
@@ -0,0 +1,77 @@
1
+ #
2
+ # Copyright (C) 2013 NEC Corporation
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License, version 3, as
6
+ # published by the Free Software Foundation.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License along
14
+ # with this program; if not, write to the Free Software Foundation, Inc.,
15
+ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16
+ #
17
+
18
+
19
+ require "paper_house/build_task"
20
+ require "paper_house/linker_options"
21
+ require "paper_house/shared_library_task"
22
+ require "paper_house/static_library_task"
23
+
24
+
25
+ module PaperHouse
26
+ #
27
+ # Compiles *.c files into an executable file.
28
+ #
29
+ class ExecutableTask < BuildTask
30
+ include LinkerOptions
31
+
32
+
33
+ def initialize name, &block
34
+ super name, &block
35
+ Rake::Task[ name ].prerequisites.each do | each |
36
+ find_prerequisites each, [ StaticLibraryTask, SharedLibraryTask ]
37
+ end
38
+ end
39
+
40
+
41
+ # @!attribute executable_name
42
+ # Name of target executable file.
43
+ attr_writer :executable_name
44
+
45
+ def executable_name
46
+ @executable_name ||= @name
47
+ end
48
+ alias :target_file_name :executable_name
49
+
50
+
51
+ ############################################################################
52
+ private
53
+ ############################################################################
54
+
55
+
56
+ def generate_target
57
+ sh ( [ cc ] + cc_options ).join( " " )
58
+ end
59
+
60
+
61
+ def cc_options
62
+ [ o_option, objects, ldflags, l_options ].flatten
63
+ end
64
+
65
+
66
+ def o_option
67
+ "-o #{ target_path }"
68
+ end
69
+ end
70
+ end
71
+
72
+
73
+ ### Local variables:
74
+ ### mode: Ruby
75
+ ### coding: utf-8-unix
76
+ ### indent-tabs-mode: nil
77
+ ### End:
@@ -0,0 +1,64 @@
1
+ #
2
+ # Copyright (C) 2013 NEC Corporation
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License, version 3, as
6
+ # published by the Free Software Foundation.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License along
14
+ # with this program; if not, write to the Free Software Foundation, Inc.,
15
+ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16
+ #
17
+
18
+
19
+ require "paper_house/build_task"
20
+
21
+
22
+ module PaperHouse
23
+ # Common base class for static, shared, and ruby library tasks.
24
+ class LibraryTask < BuildTask
25
+ # Find a LibraryTask by name
26
+ def self.find_by name
27
+ ObjectSpace.each_object( self ) do | each |
28
+ return each if each.name == name.to_s
29
+ end
30
+ nil
31
+ end
32
+
33
+
34
+ def initialize name, &block
35
+ @library_dependencies = []
36
+ super name, &block
37
+ end
38
+
39
+
40
+ # Name of library.
41
+ def library_name
42
+ @library_name ||= @name
43
+ end
44
+
45
+
46
+ # Name of library.
47
+ def library_name= new_name
48
+ @library_name = /\Alib/=~ new_name ? new_name : "lib" + new_name
49
+ end
50
+
51
+
52
+ # Name of library pass to -l option.
53
+ def lname
54
+ library_name.sub( /^lib/, "" )
55
+ end
56
+ end
57
+ end
58
+
59
+
60
+ ### Local variables:
61
+ ### mode: Ruby
62
+ ### coding: utf-8-unix
63
+ ### indent-tabs-mode: nil
64
+ ### End: