paper_house 0.4.0

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.
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: