tioga 1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. data/Tioga_README +372 -0
  2. data/lgpl.txt +504 -0
  3. data/split/Dtable/defs.h +33 -0
  4. data/split/Dtable/dtable.c +1928 -0
  5. data/split/Dtable/dtable_intern.h +144 -0
  6. data/split/Dtable/dvector.h +61 -0
  7. data/split/Dtable/extconf.rb +4 -0
  8. data/split/Dtable/include/dtable.h +35 -0
  9. data/split/Dtable/lib/Dtable_extras.rb +90 -0
  10. data/split/Dtable/namespace.h +47 -0
  11. data/split/Dtable/safe_double.h +104 -0
  12. data/split/Dtable/symbols.c +92 -0
  13. data/split/Dtable/symbols.h +52 -0
  14. data/split/Dvector/defs.h +33 -0
  15. data/split/Dvector/dvector.c +5486 -0
  16. data/split/Dvector/dvector_intern.h +142 -0
  17. data/split/Dvector/extconf.rb +4 -0
  18. data/split/Dvector/include/dvector.h +61 -0
  19. data/split/Dvector/lib/Dvector_extras.rb +328 -0
  20. data/split/Dvector/lib/Numeric_extras.rb +134 -0
  21. data/split/Dvector/namespace.h +47 -0
  22. data/split/Dvector/safe_double.h +104 -0
  23. data/split/Dvector/symbols.c +92 -0
  24. data/split/Dvector/symbols.h +52 -0
  25. data/split/Flate/defs.h +33 -0
  26. data/split/Flate/extconf.rb +19 -0
  27. data/split/Flate/flate.c +156 -0
  28. data/split/Flate/flate_intern.h +97 -0
  29. data/split/Flate/include/flate.h +98 -0
  30. data/split/Flate/namespace.h +47 -0
  31. data/split/Flate/safe_double.h +104 -0
  32. data/split/Flate/symbols.c +92 -0
  33. data/split/Flate/symbols.h +52 -0
  34. data/split/Function/defs.h +33 -0
  35. data/split/Function/dvector.h +61 -0
  36. data/split/Function/extconf.rb +4 -0
  37. data/split/Function/function.c +988 -0
  38. data/split/Function/joint_qsort.c +258 -0
  39. data/split/Function/lib/Function_extras.rb +44 -0
  40. data/split/Function/namespace.h +47 -0
  41. data/split/Function/safe_double.h +104 -0
  42. data/split/Function/symbols.c +92 -0
  43. data/split/Function/symbols.h +52 -0
  44. data/split/Tioga/axes.c +774 -0
  45. data/split/Tioga/defs.h +33 -0
  46. data/split/Tioga/dtable.h +35 -0
  47. data/split/Tioga/dvector.h +61 -0
  48. data/split/Tioga/extconf.rb +4 -0
  49. data/split/Tioga/figures.c +672 -0
  50. data/split/Tioga/figures.h +855 -0
  51. data/split/Tioga/flate.h +98 -0
  52. data/split/Tioga/init.c +524 -0
  53. data/split/Tioga/lib/Arcs_and_Circles.rb +64 -0
  54. data/split/Tioga/lib/ColorConstants.rb +274 -0
  55. data/split/Tioga/lib/Colorbars.rb +10 -0
  56. data/split/Tioga/lib/Colormaps.rb +105 -0
  57. data/split/Tioga/lib/Coordinate_Conversions.rb +194 -0
  58. data/split/Tioga/lib/Creating_Paths.rb +94 -0
  59. data/split/Tioga/lib/Doc.rb +91 -0
  60. data/split/Tioga/lib/Executive.rb +515 -0
  61. data/split/Tioga/lib/FigMkr.rb +2224 -0
  62. data/split/Tioga/lib/FigureConstants.rb +125 -0
  63. data/split/Tioga/lib/Figures_and_Plots.rb +268 -0
  64. data/split/Tioga/lib/Images.rb +278 -0
  65. data/split/Tioga/lib/Legends.rb +190 -0
  66. data/split/Tioga/lib/MarkerConstants.rb +122 -0
  67. data/split/Tioga/lib/Markers.rb +129 -0
  68. data/split/Tioga/lib/Page_Frame_Bounds.rb +567 -0
  69. data/split/Tioga/lib/Rectangles.rb +94 -0
  70. data/split/Tioga/lib/Shading.rb +100 -0
  71. data/split/Tioga/lib/Special_Paths.rb +307 -0
  72. data/split/Tioga/lib/Strokes.rb +129 -0
  73. data/split/Tioga/lib/TeX_Text.rb +454 -0
  74. data/split/Tioga/lib/TexPreamble.rb +358 -0
  75. data/split/Tioga/lib/Titles_and_Labels.rb +306 -0
  76. data/split/Tioga/lib/Transparency.rb +89 -0
  77. data/split/Tioga/lib/Using_Paths.rb +164 -0
  78. data/split/Tioga/lib/Utils.rb +74 -0
  79. data/split/Tioga/lib/X_and_Y_Axes.rb +749 -0
  80. data/split/Tioga/lib/irb_tioga.rb +122 -0
  81. data/split/Tioga/lib/tioga.rb +1 -0
  82. data/split/Tioga/lib/tioga_ui.rb +5 -0
  83. data/split/Tioga/lib/tioga_ui_cmds.rb +793 -0
  84. data/split/Tioga/makers.c +989 -0
  85. data/split/Tioga/mk_tioga_sty.rb +53 -0
  86. data/split/Tioga/namespace.h +47 -0
  87. data/split/Tioga/pdf_font_dicts.c +18253 -0
  88. data/split/Tioga/pdfcolor.c +486 -0
  89. data/split/Tioga/pdfcoords.c +505 -0
  90. data/split/Tioga/pdffile.c +342 -0
  91. data/split/Tioga/pdfimage.c +536 -0
  92. data/split/Tioga/pdfpath.c +914 -0
  93. data/split/Tioga/pdfs.h +229 -0
  94. data/split/Tioga/pdftext.c +443 -0
  95. data/split/Tioga/safe_double.h +104 -0
  96. data/split/Tioga/symbols.c +92 -0
  97. data/split/Tioga/symbols.h +52 -0
  98. data/split/Tioga/texout.c +380 -0
  99. data/split/defs.h +33 -0
  100. data/split/extconf.rb +107 -0
  101. data/split/mkmf2.rb +1612 -0
  102. data/split/namespace.h +47 -0
  103. data/split/safe_double.h +104 -0
  104. data/split/scripts/tioga +4 -0
  105. data/split/symbols.c +92 -0
  106. data/split/symbols.h +52 -0
  107. data/tests/dtable_test.data +6 -0
  108. data/tests/dvector_read_test.data +1 -0
  109. data/tests/dvector_test.data +101 -0
  110. data/tests/tc_Dtable.rb +221 -0
  111. data/tests/tc_Dvector.rb +791 -0
  112. data/tests/tc_FMkr.rb +162 -0
  113. data/tests/tc_Flate.rb +45 -0
  114. data/tests/tc_Function.rb +111 -0
  115. data/tests/ts_Tioga.rb +38 -0
  116. metadata +163 -0
data/split/defs.h ADDED
@@ -0,0 +1,33 @@
1
+ /**********************************************************************
2
+
3
+ defs.h:
4
+ some definitions that are used everywhere and that depend on some
5
+ HAVE_* macros.
6
+
7
+ Copyright (C) 2006 Vincent Fourmond
8
+
9
+ This program is free software; you can redistribute it and/or modify
10
+ it under the terms of the GNU General Library Public License as published
11
+ by the Free Software Foundation; either version 2 of the License, or
12
+ (at your option) any later version.
13
+
14
+ This program is distributed in the hope that it will be useful,
15
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ GNU Library General Public License for more details.
18
+
19
+ You should have received a copy of the GNU Library General Public License
20
+ along with this program; if not, write to the Free Software
21
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
+
23
+ **********************************************************************/
24
+
25
+
26
+ #ifdef HAVE_ISNAN
27
+ /* we use isnan and isinf, which are much faster than the workaround */
28
+ #define is_okay_number(x) (! isnan(x) && ! isinf(x))
29
+ #else
30
+ #define is_okay_number(x) ((x) - (x) == 0.0)
31
+ #define isnan(x) ((x) != (x))
32
+ /* yes, as funny as it may look NaN != NaN, and that's the only one */
33
+ #endif
data/split/extconf.rb ADDED
@@ -0,0 +1,107 @@
1
+ # main Tioga installation file
2
+
3
+ require './mkmf2.rb'
4
+
5
+ # Now, if you want to install the include file, you need to
6
+ # set the EXTCONF_RB_INCLUDE
7
+ if ENV.key?("EXTCONF_RB_INCLUDE")
8
+ include = ENV["EXTCONF_RB_INCLUDE"]
9
+ else
10
+ include = nil
11
+ end
12
+
13
+ # install Dvector include and library files into base dirs,
14
+ # and builds Dvector.so
15
+ setup_dir("Dvector", "Dobjects",
16
+ "Dobjects/Dvector", include) do |l,b,i|
17
+ b.add_sources("symbols.c")
18
+ end
19
+ # the same for Dtable
20
+ setup_dir("Dtable", "Dobjects",
21
+ "Dobjects/Dtable", include) do |l,b,i|
22
+ b.add_sources("symbols.c")
23
+ end
24
+
25
+ setup_dir("Flate", "", "Flate", include) do |l,b,i|
26
+ b.add_sources("symbols.c")
27
+ end
28
+
29
+
30
+ setup_dir("Function", "Dobjects",
31
+ "Dobjects/Function", include) do |l,b,i|
32
+ b.add_sources("symbols.c")
33
+ end
34
+
35
+
36
+ # We declare Tioga by hand, as an automatic generation would not
37
+ # take lib/TexPreamble.rb into accound (missing).
38
+ declare_library("Tioga",
39
+ "Tioga/lib/tioga.rb",
40
+ "Tioga/lib/ColorConstants.rb",
41
+ "Tioga/lib/FigMkr.rb",
42
+ "Tioga/lib/FigureConstants.rb",
43
+ "Tioga/lib/MarkerConstants.rb",
44
+ "Tioga/lib/irb_tioga.rb",
45
+ "Tioga/lib/tioga_ui_cmds.rb",
46
+ "Tioga/lib/tioga_ui.rb",
47
+ "Tioga/lib/Utils.rb",
48
+ "Tioga/lib/TexPreamble.rb")
49
+
50
+ declare_binary_library("Tioga/FigureMaker",
51
+ "Tioga/**/*.c", "symbols.c")
52
+
53
+ # The preamble stuff:
54
+ custom_rule("Tioga/lib/TexPreamble.rb",
55
+ [ "cd Tioga; " + Mkmf2.config_var("RUBY_INSTALL_NAME") +
56
+ " mk_tioga_sty.rb"],
57
+ ["Tioga/lib/ColorConstants.rb",
58
+ "Tioga/tioga.sty.in", "Tioga/mk_tioga_sty.rb"]
59
+ )
60
+
61
+ # we check the presence of zlib library
62
+ unless have_header("zlib.h") and have_library("z", "compress", "zlib.h")
63
+ puts <<"EON"
64
+ Error: you should have zlib (including development files) installed to
65
+ build and run Tioga. You can get it there:
66
+
67
+ http://www.zlib.net/
68
+
69
+ If that doesn't solve your problem, please report it on the Tioga tracker:
70
+
71
+ http://rubyforge.org/tracker/?group_id=701
72
+
73
+ EON
74
+ exit 1
75
+ end
76
+
77
+ unless have_header("ieee754.h")
78
+ puts "You lack the ieee754.h header file, which might mean lower " +
79
+ "reliability when Marshalling Dvectors and Dtables"
80
+ end
81
+
82
+ # Looking for the presence of the is_nan (implies the rest -- isfinite)
83
+ have_func("isnan","math.h")
84
+
85
+ # Installing scripts
86
+ declare_exec 'scripts/tioga'
87
+
88
+
89
+ if Config::CONFIG["target"] =~ /darwin/i
90
+ # Installing MacOS specific scripts:
91
+ # Creating the script
92
+ puts "MacOS specific installation"
93
+ custom_rule("repreview",
94
+ [ "echo '#!/bin/sh' > repreview",
95
+ "echo \"osascript '$(EXEC_INSTALL_DIR)/Reload_Preview_Document.scpt'\" '$$*' >> repreview"
96
+ ])
97
+ declare_exec 'repreview'
98
+ declare_exec 'scripts/Reload_Preview_Document.scpt'
99
+ else
100
+ puts "Skipping MacOS-specific files"
101
+ end
102
+
103
+
104
+ write_makefile
105
+
106
+
107
+
data/split/mkmf2.rb ADDED
@@ -0,0 +1,1612 @@
1
+ require 'rbconfig'
2
+ require 'fileutils'
3
+
4
+ # some global variables:
5
+ $LOCAL_LIBS = ""
6
+
7
+ # A string extension from old mkmf.rb
8
+ class String
9
+ def quote
10
+ /\s/ =~ self ? "\"#{self}\"" : self
11
+ end
12
+
13
+ # and a new function, that can come in useful in several places:
14
+ def sanitize
15
+ return self.tr("a-z./\055", "A-Z___")
16
+ end
17
+ end
18
+
19
+ # An array extension from old mkmf.rb
20
+ class Array
21
+ def quote
22
+ map {|s| s.quote}
23
+ end
24
+ end
25
+
26
+
27
+ =begin rdoc
28
+ :title: Mkmf2: a better replacement for mkmf
29
+ =end
30
+
31
+ =begin rdoc
32
+
33
+ =Mkmf2: a drop-in replacement for mkmf
34
+
35
+ Mkmf2 aims at replacing the functionnality of the old mkmf, with a better and
36
+ cleaner code. It hopefully will keep all the previous mkmf files working,
37
+ while providing
38
+ * better control over the Makefiles produced;
39
+ * installation to <tt>$HOME</tt>;
40
+ * uninstallation;
41
+ * more flexibility.
42
+
43
+ ==Background
44
+
45
+ Mkmf2 was written to supplement a missing feature on the old +mkmf.rb+: it is
46
+ not possible to install include files along with the library, and not easy
47
+ to make several libraries, that link each other, and install them... So here
48
+ comes mkmf2.rb !
49
+
50
+
51
+ ==Bugs
52
+
53
+ There are probably a huge number of bugs, or missing features, or
54
+ misleading features. In case you find one, please file a request
55
+ in the mkmf2 project on rubyforge, at the address
56
+ http://rubyforge.org/tracker/?group_id=1391
57
+
58
+ But before, please, check out the latest cvs version at
59
+ http://rubyforge.org/scm/?group_id=1391
60
+ and make sure the bug is still there...
61
+
62
+ ==Note to anyone who wishes to contribute
63
+
64
+ Please, document any code you add, and keep the
65
+ changelog up to date...
66
+
67
+ ==Copyright
68
+
69
+ This module is copyright 2006 by Vincent Fourmond. You can use and
70
+ redistribute it under the terms of the General Public License version 2.
71
+ As a special exception, you can distribute any verbatim copy along with
72
+ a program, provided that this program depends on mkmf2 to install.
73
+
74
+ =end
75
+
76
+ module Mkmf2
77
+
78
+ include Config
79
+
80
+ # The CVS tag used for the release.
81
+ CVS_TAG = '$Name$'
82
+
83
+ # The module version; it is computed from CVS_TAG
84
+ VERSION = CVS_TAG.match(/\D+(.*?)\s*\$?$/)[1].tr('_-','..')
85
+
86
+ # The entities: a list of Mkmf2::MfEntity representing what
87
+ # we are currently building.
88
+ @@entities = []
89
+
90
+ # User-defined rules:
91
+ @@user_rules = []
92
+
93
+
94
+ # we first start the module with a whole bunch of small subclasses
95
+ # that will come in really useful later.
96
+
97
+ # This class provides a crude functionnality for defining a rule
98
+ # in a Makefile.
99
+ class MfRule
100
+ attr_accessor :name, :rule, :dependencies
101
+
102
+ # converts this rule to a string that can be readily printed to
103
+ # the Makefile
104
+ def to_s
105
+ return "#{@name}: #{@dependencies.join ' '}" +
106
+ if @rule.empty? # we don't need a second line
107
+ "\n"
108
+ else
109
+ "\n\t#{@rule.join "\n\t"}\n"
110
+ end
111
+ end
112
+
113
+ # +name+:: the name of the rule.
114
+ # +rule+::
115
+ # a string or an array of lines; strings are split if necessary
116
+ # +deps+:: a string or an array of dependencies
117
+ def initialize(name, rule = nil, deps = nil)
118
+ @name = name
119
+
120
+ if rule.is_a? Array
121
+ @rule = rule
122
+ elsif rule.nil?
123
+ @rule = []
124
+ else
125
+ @rule = rule.split /\s*\n\t?\s*/
126
+ end
127
+
128
+ if deps.is_a? Array
129
+ @dependencies = deps
130
+ elsif deps.nil?
131
+ @dependencies = []
132
+ else
133
+ @dependencies = deps.split /\s+/
134
+ end
135
+ end
136
+
137
+ end
138
+
139
+ # A small class to include comments into the Makefile, just to help anyone
140
+ # who has to debug something. And it annoys me not to be able to clearly
141
+ # read the output of the test.rb script !
142
+ class MfComment < MfRule
143
+
144
+ # The actual text of the comment.
145
+ attr_accessor :text
146
+
147
+ # +str+ is the text meant to be displayed in the makefile. If it is nil
148
+ # the rule just ends up being a blank line, to allow for easy separation
149
+ # of the rules.
150
+ def initialize(str = nil)
151
+ @text = str
152
+ end
153
+
154
+ def to_s
155
+ if @text.nil?
156
+ return "\n"
157
+ else
158
+ lines = @text.to_s.split '\n'
159
+ lines.unshift ""
160
+ return "#{lines.join "\n# "}\n"
161
+ end
162
+ end
163
+
164
+ end
165
+
166
+
167
+
168
+ # An MfEntity object reprensents something that is part of the package.
169
+ # In this way, it needs to provide:
170
+ #
171
+ # * a way to *install* itself;
172
+ # * a way to *uninstall* itself;
173
+ # * a way to *clean* the source directory;
174
+ # * and, possibly, a way to *build* itself.
175
+ #
176
+ # This class should be subclassed for objects that need building.
177
+ # It should be enough though for many simple objects.
178
+ #
179
+ # The module will hold a list of all the MfEntities, and use them in turn
180
+ # to create the Makefile.
181
+ class MfEntity
182
+
183
+ # +install_files+ is a hash that associates files in the building
184
+ # tree to files where the installation is done. To be more precise
185
+ # the install path for the files is expressed relative to
186
+ # +install_path+
187
+ attr_accessor :install_files
188
+
189
+ # This name has to be registered by Mkmf2.register_name. Its lowercase
190
+ # version will be used to name the targets (install_#{name}), etc.), and
191
+ # it's uppercase version can be used as a prefix to name Makefile
192
+ # variables, that we can for instance depend on.
193
+ attr_accessor :name
194
+
195
+ # It represents the type of the entity. It should be a valid entry
196
+ # for Mkmf2.install_path.
197
+ attr_accessor :kind
198
+
199
+ # It is used to ask Mkmf2.install_files for the right rule for
200
+ # installing files (they can be data, scripts, programs, and so on...)
201
+ attr_accessor :install_rule
202
+
203
+ # The +name+ parameter is turned into a unique name and ends up as
204
+ # an identifier for the stuffs related to this element in the Makefile.
205
+ # The +install+ parameter directly becomes install_files.
206
+ # The +kind+ parameter describes the kind of thing we're going
207
+ # to install. See Mkmf2.install_path.
208
+
209
+ def initialize(name, install, kind = 'lib',
210
+ install_rule = 'install_data')
211
+
212
+ # we append kind to avoid overlaps in case of
213
+ # a malchosen name (even if this is guaranteed by register_name),
214
+ # it will look better.
215
+ @name = Mkmf2::register_name(kind + "_" + name)
216
+ @install_files = install.dup
217
+ @kind = kind
218
+ @install_rule = install_rule
219
+ end
220
+
221
+ # Returns the install path for the current object. The implementation
222
+ # should call Mkmf2.install_path with an appropriate argument.
223
+ def install_path
224
+ return Mkmf2::install_path(@kind)
225
+ end
226
+
227
+
228
+ # Returns an array containing
229
+ # * a string as the first element which should be appendended
230
+ # as a dependency for the install target
231
+ # * a set of MfRules, describing what need to be done
232
+ # for that peculiar install.
233
+
234
+ def install_rules
235
+ rules = ["install_#{@name.downcase}"]
236
+
237
+ rules.push MfComment.new("installation rules for #{name}")
238
+
239
+ rules.push MfRule.new("install_#{@name.downcase}",
240
+ Mkmf2.install_files_rules(@install_rule,
241
+ install_path,
242
+ @install_files),
243
+ ["$(#{@name.upcase}_SOURCE_FILES)",
244
+ "$(#{@name.upcase}_INSTALL_DIRS)"]
245
+ )
246
+ end
247
+
248
+ # Rules for uninstalling the entity.
249
+ # See install_rules for the return values.
250
+ def uninstall_rules
251
+ rules = ["uninstall_#{@name.downcase}"]
252
+
253
+ rules.push MfComment.new("uninstallation rules for #{name}")
254
+ files = [] # the rules to remove the installed files
255
+ dirs = [] # the directories created during install
256
+ @install_files.each_value do |v|
257
+ dest = File.join(install_path,v)
258
+ files.push Mkmf2.rule('remove',dest)
259
+ dirs << File.dirname(dest)
260
+ end
261
+ dirs.uniq!
262
+ for dir in dirs
263
+ files << Mkmf2.rule('remove_path',dir)
264
+ end
265
+ rules.push MfRule.new("uninstall_#{@name.downcase}",
266
+ files)
267
+ end
268
+
269
+ # Rules for cleaning the source directory. See #install_rules for
270
+ # an explanation about return values. This implementation does
271
+ # nothing, as there is nothing to be built.
272
+ def clean_rules
273
+ return []
274
+ end
275
+
276
+ # Rules for building the entity. See #install_rules for
277
+ # an explanation about return values.
278
+ def build_rules
279
+ return []
280
+ end
281
+
282
+ # Returns all the variables that should be added to the Makefile.
283
+ # It should return a simple hash containing the values.
284
+ def variables
285
+ # we need to define this variable:
286
+ ret = {}
287
+ install = []
288
+ source = []
289
+ dirs = []
290
+ @install_files.each do |k,f|
291
+ file = File.join(install_path,f)
292
+ install << file
293
+ source << k
294
+ dirs << File.dirname(file) + "/"
295
+ end
296
+ dirs.uniq!
297
+ ret["#{@name.upcase}_INSTALL_FILES"] =
298
+ Mkmf2.pretty_print_list(install,"#{@name.upcase}_INSTALL_FILES=")
299
+ ret["#{@name.upcase}_INSTALL_DIRS"] =
300
+ Mkmf2.pretty_print_list(dirs,"#{@name.upcase}_INSTALL_DIRS=")
301
+ ret["#{@name.upcase}_SOURCE_FILES"] =
302
+ Mkmf2.pretty_print_list(source,"#{@name.upcase}_SOURCE_FILES=")
303
+ return ret
304
+ end
305
+ end
306
+
307
+ # The class to create libraries that need to be built (that is basically
308
+ # why I wrote the whole stuff !).
309
+ class MfBinaryLibEntity < MfEntity
310
+
311
+ # The source files of the library.
312
+ attr_accessor :sources
313
+
314
+ # The object files for the library
315
+ attr_accessor :objects
316
+
317
+ # The name of the file produced in the source directory.
318
+ attr_accessor :target_file
319
+
320
+ # The libraries on which the linking does depend
321
+ attr_accessor :lib_depends
322
+
323
+ # Supplementary command-line arguments for the linking step.
324
+ # It will be used for instance to store library info.
325
+ attr_accessor :suppl_args
326
+
327
+ # +name+:: of the binary library produce, for instance "Biniou/Bidule"
328
+ # +sources+:: sources of the files, defaults to all the potential
329
+ # +C+/+C\+\++ in the current directory.
330
+ # The sources are further expanded with Dir.glob.
331
+ # If you give then name of a directory, it will be
332
+ # expanded
333
+ # +target_file+:: how the files built in the current directory
334
+ # will be called. Defaults to the same file name
335
+ # as +name+.
336
+ # +lib_depends+:: an array of objects, which designate ruby binary
337
+ # libraries that this library does depend on;
338
+
339
+ def initialize(name, sources = nil, target_file = nil,
340
+ lib_depends = nil)
341
+ if sources.nil?
342
+ sources = ["."]
343
+ end
344
+
345
+ @sources = []
346
+ add_sources(sources)
347
+
348
+
349
+ if target_file.nil?
350
+ @target_file = File.basename(name) + ".#{CONFIG["DLEXT"]}"
351
+ else
352
+ @target_file = target_file
353
+ end
354
+
355
+ install_hash = { @target_file => name + ".#{CONFIG["DLEXT"]}" }
356
+ # Then, we call the function of the parent
357
+ super(name, install_hash,'bin_lib','install_bin')
358
+ @suppl_args = ""
359
+ end
360
+
361
+ # Adds source files to the library. Can come in useful inside a block
362
+ def add_sources(*sources)
363
+ # we flatten the array, just to make sure everything is top-level
364
+ sources.flatten!
365
+
366
+ # We expand directory into the files in them
367
+ # (no subdirs)
368
+ sources.collect! do |f|
369
+ if File.directory?(f)
370
+ temp = []
371
+ for ext in Mkmf2.source_files_extensions
372
+ temp << File.join(f,"*.#{ext}")
373
+ end
374
+ temp
375
+ else
376
+ f
377
+ end
378
+ end
379
+
380
+ # Then, we expand the files:
381
+ for f in sources
382
+ files = Dir.glob(f)
383
+ if files.empty?
384
+ @sources << f
385
+ else
386
+ @sources += files
387
+ end
388
+ end
389
+
390
+ # and we update the list of current object files
391
+ @objects = @sources.collect do |f|
392
+ f.gsub(/\.[^.]+$/, ".#{CONFIG["OBJEXT"]}")
393
+ end
394
+
395
+ end
396
+ #
397
+ def build_rules
398
+ return [#"build_#{@name.downcase}",
399
+ @target_file,
400
+ # better to write this way... more clear on the
401
+ # zsh command-line completion ;-) !
402
+ MfRule.new(@target_file,
403
+ Mkmf2.rule('build_library',
404
+ "$(#{name.upcase}_OBJS)",
405
+ @suppl_args),
406
+ "$(#{name.upcase}_OBJS)")
407
+ ]
408
+ end
409
+
410
+ # This removes the object files for the target...
411
+ def clean_rules
412
+ rules = ["clean_#{@name.downcase}"]
413
+
414
+ rules.push MfComment.new("cleaning rules for #{name}")
415
+ files = [] # the rules to clean the files
416
+ @objects.each do |v|
417
+ files.push Mkmf2.rule('remove',v)
418
+ end
419
+
420
+ files.push Mkmf2.rule('remove', @target_file)
421
+ rules.push MfRule.new("clean_#{@name.downcase}",
422
+ files)
423
+ return rules
424
+ end
425
+
426
+ def variables
427
+ vars = super
428
+ # We add the object list variable
429
+ vars["#{name.upcase}_OBJS"] =
430
+ Mkmf2.pretty_print_list(@objects,"#{name.upcase}_OBJS=")
431
+ return vars
432
+ end
433
+
434
+ end
435
+
436
+ # Returns a list of the potential source files extensions.
437
+ def Mkmf2.source_files_extensions
438
+ return Mkmf2.cpp_files_extensions +
439
+ Mkmf2.c_files_extensions
440
+ end
441
+
442
+ # Return the extensions for C++ files.
443
+ def Mkmf2.cpp_files_extensions
444
+ return %w{cpp cc cxx}
445
+ end
446
+
447
+ # Return extensions for C files.
448
+ def Mkmf2.c_files_extensions
449
+ return %w{c}
450
+ end
451
+
452
+
453
+ # This function declares a shared binary library that will be built
454
+ # and installed using the appropriate functions.
455
+ #
456
+ # +libname+ is what is usually passed as an argument to the
457
+ # +create_makefile+ function of the old
458
+ #
459
+ # +sources+ is the source files. They are processed using Dir.glob, so
460
+ # they can contain wildcards.
461
+ #
462
+ # This function contends itselfs to *declare* the library, it does not
463
+ # *build* it, as this will be done by +make+.
464
+
465
+ def declare_binary_library(libname, *sources, &b)
466
+ add_entity(MfBinaryLibEntity.new(libname, sources), &b)
467
+ end
468
+
469
+ def add_entity(entity)
470
+ yield entity if block_given?
471
+ @@entities << entity
472
+ return entity
473
+ end
474
+
475
+ # This function declares a Ruby library, namely files that want
476
+ # to be installed directly in the rubylibdir (or equivalent, depending
477
+ # on the user settings).
478
+ # +target_dir+:: the target directory, relative to the installation
479
+ # directory;
480
+ # +files+:: the files to install. Defaults to "lib/**.rb"
481
+ #
482
+ # For instance,
483
+ # declare_library("Biniou", "toto.rb")
484
+ # will install the file "Biniou/toto.rb" in the common library
485
+ # directory.
486
+
487
+ def declare_library(target_dir,*files, &b)
488
+ if files.empty?
489
+ files << "lib/**/*.rb"
490
+ end
491
+ declare_file_set(target_dir, files, 'lib', false, &b)
492
+ end
493
+
494
+ # Declares a set of files that should be executed directly be the user.
495
+ def declare_exec(*files, &b)
496
+ # No need for a target directory.
497
+ declare_file_set("", files, 'exec', true, 'install_script',&b)
498
+ end
499
+
500
+ # Declares a documentation that doesn't need to be built. For the arguments,
501
+ # see #declare_library.
502
+ def declare_doc(target_dir, *files,&b)
503
+ if files.empty?
504
+ files << "doc/**/*"
505
+ end
506
+ declare_file_set(target_dir, files, 'doc', false,&b)
507
+ end
508
+
509
+ # Declares a set of include files to be installed. Defaults to
510
+ # all the files in the include subdirectory.
511
+ def declare_includes(target_dir,*files,&b)
512
+ if files.empty?
513
+ files << "include/**/*.h"
514
+ end
515
+ declare_file_set(target_dir, files, 'include', true,&b)
516
+ end
517
+
518
+
519
+
520
+ # The main place for declaring files to be installed.
521
+ # +target_dir+:: the target directory relative to the install path
522
+ # if it is nil or empty, then just install in the
523
+ # base directory.
524
+ # +files+:: the source files
525
+ # +kind+:: the kind of target (see again and again install_path)
526
+ # +basename+:: wether or not to strip the leading directories ?
527
+ # +skip+:: a regular expression (or whatever object that has a ===
528
+ # method that matches strings) saying wich files should
529
+ # be excluded. Defaults to /~$/.
530
+ # _base_dir_:: a source base directory to be stripped from the target
531
+ # name
532
+
533
+ def declare_file_set(target_dir, files, kind = 'lib',
534
+ basename = true,
535
+ rule = 'install_data',
536
+ skip = /~$/, delete = /((^.*\/)?lib\/)?/,
537
+ base_dir = false, &b)
538
+ source_files = []
539
+ for glob in files
540
+ # If glob looks like a glob, we use Dir.glob, else we add it
541
+ # without modification
542
+ if glob =~ /\*|\[|\?/
543
+ source_files += Dir[glob]
544
+ else
545
+ source_files << glob
546
+ end
547
+ end
548
+ install_hash = {}
549
+ for f in source_files
550
+ next if skip === f
551
+ next if File.directory? f
552
+ filename = if basename
553
+ File.basename(f)
554
+ else
555
+ f.dup
556
+ end
557
+ filename.gsub!(delete, '')
558
+
559
+ if target_dir.nil? or target_dir.empty?
560
+ install_hash[f] = filename
561
+ else
562
+ install_hash[f] = File.join(target_dir, filename)
563
+ end
564
+ end
565
+ add_entity(MfEntity.new(target_dir, install_hash,
566
+ kind, rule), &b)
567
+ end
568
+
569
+ @@model = "local"
570
+
571
+ # Sets the model for directory installation. There are for now
572
+ # three values:
573
+ # local:: for a standard installation (like the default in mkmf.rb)
574
+ # dist:: to use in a packageing system
575
+ # home:: to install to a home directory (basically, prefix= <tt>$HOME</tt>)
576
+ #
577
+ # Please do not modify @@model directly.
578
+
579
+ def Mkmf2.set_model(model = "local")
580
+ @@model = model
581
+ end
582
+
583
+ # Sets up a whole bunch of variables necessary for installation, depending
584
+ # on the current value of the @@model parameter. This is the place where we
585
+ # setup the variables used by the installation process, namely:
586
+ # +RUBYLIB_INSTALL_DIR+:: the directory where the text libraries
587
+ # are to be installed;
588
+ # +RUBYARCHLIB_INSTALL_DIR+:: the directory where architecture
589
+ # dependent libraries are installed;
590
+ # +INCLUDE_INSTALL_DIR+:: the directory where include files should go
591
+ # if necessary;
592
+ # And for now, that is all.
593
+ def setup_model
594
+ case @@model
595
+ when "home"
596
+ # I made a mistake for the home scheme.
597
+ # we ensure the prefix is set to $HOME
598
+ MAKEFILE_CONFIG["RUBYLIB_INSTALL_DIR"] =
599
+ "$(DESTDIR)$(HOME)/lib/ruby"
600
+ # For the HOME scheme, binaries and .rb files go
601
+ # to the same directory.
602
+ MAKEFILE_CONFIG["RUBYARCHLIB_INSTALL_DIR"] =
603
+ "$(DESTDIR)$(HOME)/lib/ruby"
604
+ MAKEFILE_CONFIG["INCLUDE_INSTALL_DIR"] =
605
+ "$(DESTDIR)$(HOME)/include"
606
+ MAKEFILE_CONFIG["EXEC_INSTALL_DIR"] =
607
+ "$(DESTDIR)$(HOME)/bin"
608
+
609
+ when "dist"
610
+ # shares some code with the previous item, don't forget to
611
+ # update *BOTH* !
612
+ MAKEFILE_CONFIG["RUBYLIB_INSTALL_DIR"] =
613
+ "$(DESTDIR)$(rubylibdir)"
614
+ MAKEFILE_CONFIG["RUBYARCHLIB_INSTALL_DIR"] =
615
+ "$(DESTDIR)$(archdir)"
616
+ MAKEFILE_CONFIG["INCLUDE_INSTALL_DIR"] =
617
+ "$(DESTDIR)$(includedir)"
618
+ MAKEFILE_CONFIG["EXEC_INSTALL_DIR"] =
619
+ File.join("$(prefix)", "bin")
620
+
621
+ when "local"
622
+ MAKEFILE_CONFIG["RUBYLIB_INSTALL_DIR"] =
623
+ "$(sitelibdir)"
624
+ MAKEFILE_CONFIG["RUBYARCHLIB_INSTALL_DIR"] =
625
+ "$(sitearchdir)"
626
+
627
+ # To make the base directory for installation, I propose
628
+ # to strip all the directories containing ruby from the
629
+ # $(sitedir) directory and strip one more directory.
630
+
631
+ basedir = MAKEFILE_CONFIG["sitedir"]
632
+ while File.basename(basedir) =~ /ruby/
633
+ basedir = File.dirname(basedir)
634
+ end
635
+ # Strip one more:
636
+ basedir = File.dirname(basedir)
637
+ MAKEFILE_CONFIG["basedir"] = basedir
638
+ MAKEFILE_CONFIG["INCLUDE_INSTALL_DIR"] =
639
+ "$(basedir)/include"
640
+ MAKEFILE_CONFIG["EXEC_INSTALL_DIR"] =
641
+ "$(basedir)/bin"
642
+ end
643
+
644
+ end
645
+
646
+
647
+ # Returns the installation path for a given thing (+what+). This function
648
+ # basically returns a simple MAKEFILE_CONFIG variable, which has otherwise
649
+ # been setup by setup_model. What is available for now:
650
+ # +lib+:: where to install .rb library
651
+ # +bin_lib+:: where to install binary libs
652
+ # +include+:: include files
653
+
654
+ def Mkmf2.install_path(what)
655
+ # we should definitely append a $(DESTDIR) to every single
656
+ # directory we return, since it will make debugging
657
+
658
+ case what
659
+ when 'lib'
660
+ return Mkmf2.config_var('RUBYLIB_INSTALL_DIR')
661
+ when 'exec'
662
+ return Mkmf2.config_var('EXEC_INSTALL_DIR')
663
+ when 'bin_lib'
664
+ return Mkmf2.config_var('RUBYARCHLIB_INSTALL_DIR')
665
+ when 'include'
666
+ return Mkmf2.config_var('INCLUDE_INSTALL_DIR')
667
+ else
668
+ raise "Unkown installation directory specification: #{what}"
669
+ end
670
+ end
671
+
672
+ @@registered_names = {} # a hash containing already registered names
673
+ # to avoid namespace clobbering.
674
+
675
+ # Register a new name, making sure the name returned is unique.
676
+ def Mkmf2.register_name(name)
677
+ # first, transform all that is not letter into underscore
678
+ name.gsub!(/[^a-zA-Z]/,'_')
679
+ # pretty-print a bit
680
+ name.gsub!(/^_|_$/,'')
681
+ name.gsub!(/_+/, '_')
682
+ name.downcase!
683
+ # then, increment the number
684
+ if @@registered_names[name]
685
+ i = 1
686
+ while @@registered_names["#{name}_#{i}"]
687
+ i += 1
688
+ end
689
+ name = "#{name}_#{i}"
690
+ end
691
+ @@registered_names[name] = true
692
+ return name
693
+ end
694
+
695
+
696
+ # Stores which configuration variables are used
697
+ @@config_variables_used = []
698
+ # Returns the given config key, that will be used to write a rule
699
+ # in the Makefile. For better output, the function does store a list of
700
+ # all the config variables which are in use, and simply outputs
701
+ # +$(VARIABLE)+.
702
+ def Mkmf2.config_var(str)
703
+ @@config_variables_used << str
704
+ return "$(#{str})"
705
+ end
706
+
707
+ # This hash says which of the "CONFIG" variables we should make available
708
+ # as a global variable -- and use it back to output the variables. If non
709
+ # nil, the second part says which name it should have as global variable.
710
+ MKMF_GLOBAL_VARIABLES = {
711
+ "CFLAGS" => nil,
712
+ "CXXFLAGS" => nil,
713
+ "LDFLAGS" => nil,
714
+ "DLDFLAGS" => nil,
715
+ "CPPFLAGS" => nil,
716
+ "LIBS" => nil,
717
+ "LIBRUBYARG" => nil,
718
+ "LOCAL_LIBS" => nil,
719
+ "libs" => nil,
720
+ }
721
+
722
+
723
+ # Takes the config variables, turn them into global variables.
724
+ def config_to_global
725
+ for var,name in MKMF_GLOBAL_VARIABLES
726
+ name = var if name.nil?
727
+ value = MAKEFILE_CONFIG[var].to_s # make sure its a string
728
+ # in case it doesn't exist there...
729
+ # Nice trick to get around quoting...
730
+ block = eval "proc {|x| $#{name} = x}"
731
+ block.call(value)
732
+ end
733
+ $LIBRUBYARG = "" # seems the default in mkmf.rb
734
+ end
735
+
736
+ # Takes the global variables taken from the config, and put them back into
737
+ # the config hash.
738
+ def global_to_config
739
+ for var,name in MKMF_GLOBAL_VARIABLES
740
+ name = var if name.nil?
741
+ value = eval "$#{name}"
742
+ MAKEFILE_CONFIG[var] = value
743
+ end
744
+ end
745
+
746
+
747
+
748
+ # A constant to get a configuration variable
749
+ MAKE_VARIABLE = /\$\((\w+)\)/
750
+
751
+ # List config variables referenced to by the string _str_. If
752
+ # hash is specified, only config variables that are keys of this hash
753
+ # will be listed.
754
+ def subvars(str, hash = nil)
755
+ vars = []
756
+ str.gsub(MAKE_VARIABLE) { |k|
757
+ # we add the key to the list only if it exists, else the
758
+ # environment variable gets overridden by what is written
759
+ # in the Makefile (for $HOME, for instance)
760
+ vars << $1 if ( hash.nil? || hash.key?($1) )
761
+ }
762
+ return vars
763
+ end
764
+
765
+ # A way to deal with compound make variables (that is,
766
+ # make variables that get more than just themselves on the output)
767
+
768
+ COMPOUND_MAKE_VARIABLES = {
769
+ "CFLAGS" => "$(CFLAGS) $(ARCH_FLAG)",
770
+ "DLDFLAGS" => "$(DLDFLAGS) $(ARCH_FLAG)",
771
+ "LIBS" => "$(LIBRUBYARG) $(libs) $(LIBS)",
772
+ }
773
+
774
+
775
+ # Returns the contents of a "compound" variable.
776
+ def compound_var_expand(var, value = nil, hash = MAKEFILE_CONFIG)
777
+ if value.nil?
778
+ value = MAKEFILE_CONFIG[var]
779
+ end
780
+ COMPOUND_MAKE_VARIABLES[var].gsub("$(#{var})",value)
781
+ end
782
+
783
+
784
+ # Returns a string containing all the configuration variables. We
785
+ # use the MAKEFILE_CONFIG for more flexibility in the Makefile: the
786
+ # variables can then be redefined on the make command-line.
787
+ def output_config_variables
788
+ str = ""
789
+ keys = @@config_variables_used.uniq
790
+ global_to_config
791
+ new_keys = []
792
+ begin
793
+ # we merge the new keys with the old
794
+ keys += new_keys
795
+ keys.uniq!
796
+ new_keys = []
797
+ keys.each do |k|
798
+ if MAKEFILE_CONFIG.key? k
799
+ new_keys += subvars(MAKEFILE_CONFIG[k], MAKEFILE_CONFIG)
800
+ end
801
+ if COMPOUND_MAKE_VARIABLES.key? k
802
+ new_keys += subvars(COMPOUND_MAKE_VARIABLES[k], MAKEFILE_CONFIG)
803
+ end
804
+ end
805
+ end until (keys + new_keys).uniq.length == keys.length
806
+
807
+ for var in keys.uniq.sort
808
+ # We output the variable only if it is not empty: makes
809
+ # it a lot easier to modify them from outside...
810
+ if COMPOUND_MAKE_VARIABLES.key?(var)
811
+ str += "#{var}=#{compound_var_expand(var)}\n"
812
+ elsif MAKEFILE_CONFIG[var] =~ /\S/
813
+ str += "#{var}=#{MAKEFILE_CONFIG[var]}\n"
814
+ end
815
+ end
816
+ return str
817
+ end
818
+
819
+
820
+ # This hash contains replacements for basic filesystem functions
821
+ # based on ruby and FileUtils. They are used only if the corresponding
822
+ # element is missing in CONFIG. They also contains some other default
823
+ # values for possibly missing CONFIG keys.
824
+ CONFIG_DEFAULTS = {
825
+ # first, a short for the rest...
826
+ "RB_FILE_UTILS" => "$(RUBY_INSTALL_NAME) -r fileutils",
827
+ "INSTALL_SCRIPT" =>
828
+ "$(RB_FILE_UTILS) -e 'FileUtils.install(ARGV[0],ARGV[1],:mode => 0755)'",
829
+ "INSTALL_DATA" =>
830
+ "$(RB_FILE_UTILS) -e 'FileUtils.install(ARGV[0],ARGV[1],:mode => 0644)'",
831
+ "INSTALL_PROGRAM" => "$(INSTALL_SCRIPT) ",
832
+ "MAKEDIRS" =>
833
+ "$(RB_FILE_UTILS) -e 'FileUtils.makedirs(ARGV)'",
834
+ "RM" =>
835
+ "$(RB_FILE_UTILS) -e 'FileUtils.rm(ARGV)'",
836
+ "RM_PATH" => # a trick to remove a path
837
+ "$(RB_FILE_UTILS) -e 'd = ARGV[0]; begin ;while FileUtils.rmdir d, :verbose=>true; d = File.dirname(d);end; rescue ; end;'",
838
+ "DEFINES" => "",
839
+ "LIBARG" => "-l%s",
840
+ "LIBS_SUP" => "",
841
+ }
842
+
843
+ # This functions checks for missing features in the CONFIG hash and
844
+ # supplements them using the FILE_UTILS_COMMAND hash if necessary.
845
+ def check_missing_features
846
+ CONFIG.delete("INSTALL_SCRIPT") # Not consistent, it's better to use
847
+ # the Fileutils stuff
848
+ for key, val in CONFIG_DEFAULTS
849
+ if CONFIG.key?(key) and CONFIG[key] =~ /\w/
850
+ # everything is fine
851
+ else
852
+ # we supplement the feature.
853
+ MAKEFILE_CONFIG[key] = val
854
+ end
855
+ end
856
+ end
857
+
858
+ # Takes a list of CONFIG variables and returns them joined by spaces.
859
+ def Mkmf2.config_join(*vars)
860
+ return vars.collect { |v|
861
+ Mkmf2.config_var(v)
862
+ }.join(' ')
863
+ end
864
+
865
+
866
+ # Returns the way to represent the dependencies of a rule in the
867
+ # Makefile.
868
+ def Mkmf2.mf_deps
869
+ return " $(@D)"
870
+ end
871
+
872
+ # Returns the way to represent the current target in the Makefile.
873
+ def Mkmf2.mf_target
874
+ return " $@"
875
+ end
876
+
877
+ # A small helper function to write quickly rules, based on a configuration
878
+ # item.
879
+ def Mkmf2.mf_rule(cfg,*args)
880
+ if args.empty?
881
+ return Mkmf2.config_var(cfg) +
882
+ Mkmf2.mf_deps + Mkmf2.mf_target
883
+ else
884
+ return Mkmf2.config_var(cfg) + ' ' + args.join(' ')
885
+ end
886
+ end
887
+
888
+ # This function returns the common build rules for C and C++ files.
889
+ def Mkmf2.common_build_rules
890
+ rules = []
891
+ for ext in Mkmf2.c_files_extensions
892
+ rules << MfRule.new(".#{ext}.#{CONFIG["OBJEXT"]}",
893
+ Mkmf2.config_join("CC",
894
+ "CFLAGS",
895
+ "CPPFLAGS",
896
+ "INCLUDEDIRS",
897
+ "DEFINES") +
898
+ " -c $< #{CONFIG["OUTFLAG"]} $@"
899
+ )
900
+ end
901
+
902
+ # The same, but with C++:
903
+ for ext in Mkmf2.cpp_files_extensions
904
+ rules << MfRule.new(".#{ext}.#{CONFIG["OBJEXT"]}",
905
+ Mkmf2.config_join("CXX",
906
+ "CXXFLAGS",
907
+ "CPPFLAGS",
908
+ "INCLUDEDIRS",
909
+ "DEFINES") +
910
+ " -c $< #{CONFIG["OUTFLAG"]} $@"
911
+ )
912
+ end
913
+ # A simple rule for making directories:
914
+ rules << MfRule.new("%/",
915
+ Mkmf2.config_join("MAKEDIRS") + " $@")
916
+ return rules
917
+ end
918
+
919
+ # Now, the infrastructure for dealing with include and library
920
+ # directories:
921
+ @@include_path = [Mkmf2.config_var("rubylibdir"),
922
+ Mkmf2.config_var("archdir"),
923
+ '.',
924
+ File.join('.','include')
925
+ ]
926
+
927
+
928
+ # Adds one or more +paths+ to the current include path.
929
+ def add_include_path(*paths)
930
+ @@include_path += paths.flatten
931
+ end
932
+
933
+ def output_include_path
934
+ return @@include_path.collect {|v|
935
+ "-I#{v}"
936
+ }.join(' ')
937
+ end
938
+
939
+ @@library_path = []
940
+
941
+ # Adds one or more +paths+ to the current library path.
942
+ def add_library_path(*paths)
943
+ @@library_path += paths.flatten
944
+ end
945
+
946
+ def output_library_path
947
+ return @@library_path.collect {|v|
948
+ "-L#{v}"
949
+ }.join(' ')
950
+ end
951
+
952
+ # I know this is bad design, but that's the best I think of for now.
953
+ # This function better be called before using MAKEFILE_CONFIG directly.
954
+ def update_makefile_config
955
+ global_to_config
956
+ setup_paths_variables
957
+ end
958
+
959
+ # Sets up the various variables pertaining to include
960
+ # and library paths.
961
+ def setup_paths_variables
962
+ MAKEFILE_CONFIG["INCLUDEDIRS"] = output_include_path
963
+ MAKEFILE_CONFIG["LIBDIRS"] = output_library_path
964
+ end
965
+
966
+ # A recommandation for line size in the Makefile
967
+ MAKEFILE_LINE_SIZE = 40
968
+
969
+ # Returns a string where all the elements are joined together. The lines
970
+ # will break if they exceed +line_size+, but the elements themselves
971
+ # will not be broken. They will be indented
972
+ def Mkmf2.pretty_print_list(list, indent = 0,
973
+ line_size = MAKEFILE_LINE_SIZE)
974
+ if indent.is_a? String
975
+ indent = indent.length
976
+ end
977
+ lines = []
978
+ for elem in list
979
+ if lines.last.nil? ||
980
+ (lines.last + elem).length > line_size
981
+ lines << elem.dup # necessary to force ruby to create
982
+ else
983
+ lines.last.concat(' ' + elem)
984
+ end
985
+ end
986
+ return lines.join("\\\n#{' ' * indent}")
987
+ end
988
+
989
+
990
+ # Returns the string corresponding to a rule, given by the string +rule+,
991
+ # which can take the following values:
992
+ # +install_data+:: returns the rule for installing a data file to a
993
+ # given place
994
+ # +install_script+:: the rule for installing code at a given place
995
+ # +remove+:: to remove files
996
+ # +directory+:: to create a directory
997
+ # +build_library+:: to build a library; in that case, the first argument
998
+ # is the name of the target, and the ones after
999
+ # the objects.
1000
+ #
1001
+ # the optional arguments are the arguments to the rule, if they exist. Else,
1002
+ # they default to $(@D) $@ (or something like that).
1003
+
1004
+ def Mkmf2.rule(rule, *args)
1005
+ case rule
1006
+ when 'install_data'
1007
+ return Mkmf2.mf_rule("INSTALL_DATA",args)
1008
+ when 'install_script'
1009
+ return Mkmf2.mf_rule("INSTALL_SCRIPT",args)
1010
+ when 'install_bin'
1011
+ return Mkmf2.mf_rule("INSTALL_PROGRAM",args)
1012
+ when 'remove'
1013
+ return "-" + Mkmf2.mf_rule("RM",args)
1014
+ when 'remove_path'
1015
+ return "-" + Mkmf2.mf_rule("RM_PATH", args)
1016
+ when 'directory' # to create a directory
1017
+ return Mkmf2.mf_rule("MAKEDIRS", args)
1018
+ when 'build_library'
1019
+ return Mkmf2.mf_rule("LDSHARED",
1020
+ Mkmf2.config_join("DLDFLAGS",
1021
+ "LIBDIRS"),
1022
+ CONFIG["OUTFLAG"],
1023
+ "$@", # the target,
1024
+ args, # and the source
1025
+ # The libraries should better come in the end,
1026
+ # since for instance the standard linux ld
1027
+ # does only link with the symbols that have been
1028
+ # reported missing in the previous files.
1029
+ Mkmf2.config_join("LIBRUBYARG_SHARED",
1030
+ # we shouldn't forget this one !!
1031
+ "LOCAL_LIBS",
1032
+ "LIBS",
1033
+ # and then, the global libraries
1034
+ # that have been added using
1035
+ # have_library
1036
+ "LIBS_SUP")
1037
+ )
1038
+ end
1039
+ end
1040
+
1041
+ @@directories = {}
1042
+ # Register a directory that we might need to create. Make sure that
1043
+ # the rules don't appear twice.
1044
+ def Mkmf2.register_dir(dir)
1045
+ if ! @@directories.key?(dir)
1046
+ @@directories[dir] = true
1047
+ end
1048
+ end
1049
+
1050
+ # Return the rules to create the necessary directories
1051
+ def directory_rules
1052
+ rules = []
1053
+ for dir in @@directories.keys
1054
+ rules << MfRule.new(dir, Mkmf2.rule('directory',dir))
1055
+ end
1056
+ return rules
1057
+ end
1058
+
1059
+
1060
+ # A small helper function to extract the install directory name
1061
+ # for one file. +file+ is the file, +install_dir+ where we want to
1062
+ # install it. This should take care of messy dots.
1063
+ def Mkmf2.dest_dir(file, install_dir)
1064
+ dir = File::dirname(file)
1065
+ if dir == "."
1066
+ return install_dir
1067
+ else
1068
+ return File.join(install_dir,dir)
1069
+ end
1070
+ end
1071
+
1072
+ # A helper function for MfEntity instances that will have to install
1073
+ # files into directories.
1074
+ # +rule+:: the rule to use, see Mkmf2::rule
1075
+ # +install_path+:: the installation path
1076
+ # +files+:: a hash containing original -> destination pairs.
1077
+
1078
+ def Mkmf2.install_files(rule, install_path,files)
1079
+ rules = []
1080
+ files.each do |k,v|
1081
+ destdir = Mkmf2.dest_dir(v, install_path)
1082
+ Mkmf2.register_dir(destdir)
1083
+ rules.push(MfRule.new(File.join(install_path,v),
1084
+ Mkmf2::rule(rule, k,
1085
+ File.join(install_path,v)),
1086
+ [k,destdir]))
1087
+ # depends on both the file
1088
+ # that will be installed and the directory where to install it.
1089
+ end
1090
+
1091
+ return rules
1092
+ end
1093
+
1094
+ # The companion of install_files, returning a list of strings
1095
+ # rather than MfRules. Bascially behaves the same way. It is probably
1096
+ # a better thing to use this function now.
1097
+ def Mkmf2.install_files_rules(rule, install_path,files)
1098
+ rules = []
1099
+ files.each do |k,v|
1100
+ dir = File::dirname(v)
1101
+ Mkmf2.register_dir(Mkmf2.dest_dir(v,install_path))
1102
+ rules.push Mkmf2::rule(rule, k, File.join(install_path,v))
1103
+
1104
+ # depends on both the file
1105
+ # that will be installed and the directory where to install it.
1106
+ end
1107
+
1108
+ return rules
1109
+ end
1110
+
1111
+ # Small helper function for write_makefile. +target+ is
1112
+ # a hash containing a "deps" array and a "rules" array
1113
+ # which are created in case of need.
1114
+ def unwrap_rules(target, source)
1115
+ # we first make sure that the keys exist, even if we don't
1116
+ # have anything to append to them.
1117
+ if ! target.has_key? "deps"
1118
+ target["deps"] = []
1119
+ end
1120
+ if ! target.has_key? "rules"
1121
+ target["rules"] = []
1122
+ end
1123
+
1124
+ return if source.empty?
1125
+ target["deps"] << source.shift
1126
+ target["rules"] += source
1127
+ end
1128
+
1129
+ # Writes the Makefile using @@entities -- and others...
1130
+ def write_makefile(file_name = "Makefile")
1131
+ puts "Writing #{file_name}"
1132
+
1133
+ install = {}
1134
+ uninstall = {}
1135
+ build = {}
1136
+ clean = {}
1137
+ vars = []
1138
+
1139
+
1140
+
1141
+ for entity in @@entities
1142
+ t = entity.install_rules
1143
+ unwrap_rules(install,t)
1144
+
1145
+ t = entity.uninstall_rules
1146
+ unwrap_rules(uninstall,t)
1147
+
1148
+ t = entity.build_rules
1149
+ unwrap_rules(build,t)
1150
+
1151
+ t = entity.clean_rules
1152
+ unwrap_rules(clean,t)
1153
+
1154
+ vars << entity.variables
1155
+ end
1156
+
1157
+ # Common rules:
1158
+ common = Mkmf2.common_build_rules()
1159
+
1160
+ # Setup the path variables:
1161
+ setup_paths_variables
1162
+ dir_rules = directory_rules()
1163
+
1164
+ # OK, now, everything is prepared, we just need to create the
1165
+ # makefile and output everything into it...
1166
+
1167
+ f = open(file_name, File::WRONLY|File::CREAT|File::TRUNC)
1168
+
1169
+
1170
+ # First, the variables in use:
1171
+ f.puts "# Configurations variables, from rbconfig.rb"
1172
+ f.puts output_config_variables
1173
+
1174
+ # build has to be the first target so that simply
1175
+ # invoking make does the building, but not the installing.
1176
+ # now, the main rules
1177
+ f.puts "\n\n# main rules"
1178
+ # we force the dependence on build for install so that
1179
+ # ruby library files don't get installed before the c code is
1180
+ # compiled...
1181
+ # build is output first so that invoking make without
1182
+ # arguments builds.
1183
+ f.print MfRule.new("build", nil, build["deps"]).to_s
1184
+ f.print MfRule.new("install", nil, ["build"] + install["deps"]).to_s
1185
+ f.print MfRule.new("uninstall", nil, uninstall["deps"]).to_s
1186
+ f.print MfRule.new("clean",
1187
+ [Mkmf2.rule('remove',"**/*~")], # remove archive files
1188
+ # by default in the clean target.
1189
+ clean["deps"]).to_s
1190
+
1191
+ # Add a distclean rule, to make debuild happy.
1192
+ f.print <<"EOR"
1193
+ distclean: clean
1194
+ \t@-$(RM) Makefile extconf.h conftest.* mkmf2.log
1195
+ \t@-$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES)
1196
+ EOR
1197
+
1198
+ # Phony targets:
1199
+ f.puts ".PHONY: build install uninstall"
1200
+
1201
+ f.puts "\n\n# Common rules:"
1202
+ common.each {|v|
1203
+ f.print v.to_s
1204
+ }
1205
+
1206
+
1207
+ # We write the variables:
1208
+ f.puts "\n\n# entities-dependent variables"
1209
+ for v in vars
1210
+ v.each do |k,v|
1211
+ f.print "#{k}=#{v}\n"
1212
+ end
1213
+ end
1214
+
1215
+ f.puts "\n\n# Rules to make directories"
1216
+
1217
+ # directory rules
1218
+ for rule in dir_rules
1219
+ f.print rule.to_s
1220
+ end
1221
+
1222
+ f.puts "\n\n# entities-dependent rules"
1223
+ # We write the rules
1224
+ for rule in (install['rules'] +
1225
+ uninstall['rules'] +
1226
+ build['rules'] + clean['rules'])
1227
+ f.print rule.to_s
1228
+ end
1229
+
1230
+ if @@user_rules.length > 0
1231
+ f.puts "\n\n# User-defined rules"
1232
+ for rule in @@user_rules
1233
+ f.puts rule.to_s
1234
+ end
1235
+ end
1236
+
1237
+
1238
+ f.close # not necessary, but good practice ;-) ??
1239
+
1240
+ end
1241
+
1242
+ # Adds a custom rule to the Makefile. If only the first argument
1243
+ # is specified, it is written as is to the Makefile. If at least the
1244
+ # second or the third is non-nil, a MfRule is created with the arguments
1245
+ # and written to the Makefile.
1246
+ def custom_rule(str, rule = nil, deps = nil)
1247
+ if rule || deps
1248
+ @@user_rules << MfRule.new(str, rule, deps)
1249
+ else
1250
+ @@user_rules << str
1251
+ end
1252
+ end
1253
+
1254
+ # *The* compatibility function with the mkmf.rb !
1255
+ def create_makefile(target)
1256
+ declare_library(File.dirname(target))
1257
+ declare_binary_library(target, "**/*.c")
1258
+
1259
+ write_makefile
1260
+ end
1261
+
1262
+ # A function to ease the task of producing several libraries from the
1263
+ # same source tree. It sets up a library context for one directory,
1264
+ # adding it to the include path, and taking care of the files in:
1265
+ # +lib/+:: the ruby library files;
1266
+ # +include/+:: the include files
1267
+ #
1268
+ # +dir+ is the directory in the source, +target_dir+ the base directory
1269
+ # for target files. It is pretty rudimentary, but should do the job
1270
+ # for many cases (and especially Tioga ;-) !). +name+ is the name
1271
+ # of the binary library. If nil, doesn't try to build a binary library.
1272
+ # +include_dir+ is the target name for includes. If +nil+, doesn't
1273
+ # try to install them.
1274
+ #
1275
+ # You can use either the return value or a block to change somehow the
1276
+ # behavior of the different objects produced (like adding a binary library
1277
+ # for instance).
1278
+
1279
+ def setup_dir(dir, target_dir, bin_name = nil,
1280
+ include_dir = nil)
1281
+ add_include_path(dir, File.join(dir, 'include'))
1282
+
1283
+ lib = declare_library(target_dir, "#{dir}/lib/**/*.rb")
1284
+ binlib = declare_binary_library(bin_name,
1285
+ "#{dir}/**/*.c") if ! bin_name.nil?
1286
+ include = declare_includes(include_dir,
1287
+ "#{dir}/include/**/*.h") if ! include_dir.nil?
1288
+ yield lib, binlib, include if block_given?
1289
+ [lib, binlib, include]
1290
+ end
1291
+
1292
+ # the module variable that will hold the command-line arguments:
1293
+ # even with a similar name, the contents of this variable will
1294
+ # be quite different from the old $configure_args
1295
+ @@configure_args = {}
1296
+
1297
+ # Parses command-line arguments, wiping the ones that we understood.
1298
+ def parse_cmdline
1299
+ $*.delete_if do |arg|
1300
+ if arg =~ /^--(.*)/ # does look like a command-line argument...
1301
+ case $1
1302
+ when "local" # installation to sitedir
1303
+ Mkmf2.set_model("local")
1304
+ true
1305
+ when "dist"
1306
+ Mkmf2.set_model("dist")
1307
+ true
1308
+ when "home"
1309
+ Mkmf2.set_model("home")
1310
+ true
1311
+ when /^--with(.*)/ # this is my understanding of the
1312
+ # with-config stuff. It is a complete rewrite, I don't like
1313
+ # much the old code
1314
+ rhs = $1 # right-hand side
1315
+ case rhs
1316
+ when /-([\w-]+)=(.*)/
1317
+ @@configure_args[$1] = $2
1318
+ when /out-([\w-]+)$/
1319
+ @@configure_args[$1] = false
1320
+ when /-([\w-]+)$/
1321
+ @@configure_args[$1] = true
1322
+ else
1323
+ raise "Argument #{arg} not understood"
1324
+ end
1325
+ else
1326
+ false
1327
+ end
1328
+ else
1329
+ false
1330
+ end
1331
+ end
1332
+ end
1333
+
1334
+ # This function is a try at reproducing the functionnality of the
1335
+ # old mkmf.rb's dir_config. It is not a copy, and might not work
1336
+ # well in all situations. Basically, if --with-target-dir has been
1337
+ # specified, use dir/include dir/lib. If --with-target-(include|lib)
1338
+ # have been specified, use them !
1339
+ def dir_config(target)
1340
+ ldir = nil
1341
+ idir = nil
1342
+ if @@configure_args.key?("#{target}-lib")
1343
+ ldir = @@configure_args["#{target}-lib"]
1344
+ elsif @@configure_args.key?("#{target}-dir")
1345
+ ldir = File::join(@@configure_args["#{target}-dir"], "lib")
1346
+ end
1347
+ if ldir
1348
+ add_library_path(ldir.split(File::PATH_SEPARATOR))
1349
+ end
1350
+
1351
+ if @@configure_args.key?("#{target}-include")
1352
+ idir = @@configure_args["#{target}-include"]
1353
+ elsif @@configure_args.key?("#{target}-dir")
1354
+ idir = File::join(@@configure_args["#{target}-dir"], "include")
1355
+ end
1356
+ if idir
1357
+ add_include_path(idir.split(File::PATH_SEPARATOR))
1358
+ end
1359
+ return [idir, ldir]
1360
+ end
1361
+
1362
+ ###########################################################################
1363
+ # This module is copied verbatim from the old mkmf.rb code. It comes dead #
1364
+ # useful for logging things. I hope it will not cause licence conflicts. #
1365
+ ###########################################################################
1366
+
1367
+ module Logging
1368
+ @log = nil
1369
+ @logfile = 'mkmf2.log'
1370
+ @orgerr = $stderr.dup
1371
+ @orgout = $stdout.dup
1372
+ @postpone = 0
1373
+
1374
+ def self::open
1375
+ @log ||= File::open(@logfile, 'w')
1376
+ @log.sync = true
1377
+ $stderr.reopen(@log)
1378
+ $stdout.reopen(@log)
1379
+ yield
1380
+ ensure
1381
+ $stderr.reopen(@orgerr)
1382
+ $stdout.reopen(@orgout)
1383
+ end
1384
+
1385
+ def self::message(*s)
1386
+ @log ||= File::open(@logfile, 'w')
1387
+ @log.sync = true
1388
+ @log.printf(*s)
1389
+ end
1390
+
1391
+ def self::logfile file
1392
+ @logfile = file
1393
+ if @log and not @log.closed?
1394
+ @log.flush
1395
+ @log.close
1396
+ @log = nil
1397
+ end
1398
+ end
1399
+
1400
+ def self::postpone
1401
+ tmplog = "mkmftmp#{@postpone += 1}.log"
1402
+ open do
1403
+ log, *save = @log, @logfile, @orgout, @orgerr
1404
+ @log, @logfile, @orgout, @orgerr = nil, tmplog, log, log
1405
+ begin
1406
+ log.print(open {yield})
1407
+ @log.close
1408
+ File::open(tmplog) {|t| FileUtils.copy_stream(t, log)}
1409
+ ensure
1410
+ @log, @logfile, @orgout, @orgerr = log, *save
1411
+ @postpone -= 1
1412
+ rm_f tmplog
1413
+ end
1414
+ end
1415
+ end
1416
+ end
1417
+
1418
+ # Also from old mkmf.rb
1419
+ CONFTEST_C = "conftest.c"
1420
+
1421
+ def xsystem(command)
1422
+ Logging::open do
1423
+ puts command.quote
1424
+ system(command)
1425
+ end
1426
+ end
1427
+
1428
+ # Also from old mkmf.rb
1429
+ def log_src(src)
1430
+ Logging::message <<"EOM", src
1431
+ checked program was:
1432
+ /* begin */
1433
+ %s/* end */
1434
+
1435
+ EOM
1436
+ end
1437
+
1438
+ # Also from old mkmf.rb
1439
+ def create_tmpsrc(src)
1440
+ src = yield(src) if block_given?
1441
+ src = src.sub(/[^\n]\z/, "\\&\n")
1442
+ open(CONFTEST_C, "wb") do |cfile|
1443
+ cfile.print src
1444
+ end
1445
+ src
1446
+ end
1447
+
1448
+ # Also from old mkmf.rb
1449
+ def try_do(src, command, &b)
1450
+ src = create_tmpsrc(src, &b)
1451
+ xsystem(command)
1452
+ ensure
1453
+ log_src(src)
1454
+ end
1455
+
1456
+ # Also from old mkmf.rb
1457
+ def checking_for(m, fmt = nil)
1458
+ f = caller[0][/in `(.*)'$/, 1] and f << ": " #` for vim
1459
+ m = "checking for #{m}... "
1460
+ print m
1461
+ a = r = nil
1462
+ Logging::postpone do
1463
+ r = yield
1464
+ a = (fmt ? fmt % r : r ? "yes" : "no") << "\n"
1465
+ "#{f}#{m}-------------------- #{a}\n"
1466
+ end
1467
+ puts a
1468
+ $stdout.flush
1469
+ Logging::message "--------------------\n\n"
1470
+ r
1471
+ end
1472
+
1473
+ # also taken straight from mkmf.rb
1474
+ def rm_f(*files)
1475
+ FileUtils.rm_f(Dir[files.join("\0")])
1476
+ end
1477
+
1478
+ # A small wrapper around Config::expand which diminishes the size of the code
1479
+ # and makes sure the MAKEFILE_CONFIG hash is updated.
1480
+ def expand_vars(str)
1481
+ update_makefile_config
1482
+ string = Config::expand(str,MAKEFILE_CONFIG)
1483
+ # then, we need to turn all the remaining $(THING) into $THING, so that
1484
+ # the shell doesn't spawn subshells ?
1485
+ return string.gsub(/\$\((\w+)\)/) { "$#$1" }
1486
+ end
1487
+
1488
+ # Add defines to the build
1489
+ def add_define(d)
1490
+ MAKEFILE_CONFIG["DEFINES"] +=
1491
+ " -D_#{d}"
1492
+ end
1493
+
1494
+ # This is a compatibility function with the previous mkmf.rb. It does check
1495
+ # for the presence of a header in the current include directories. If found,
1496
+ # it returns true and sets the define HAVE_...
1497
+ def have_header(header, &b)
1498
+ checking_for header do
1499
+ if try_do("#include <#{header}>",
1500
+ expand_vars("$(CPP) $(INCLUDEDIRS) " \
1501
+ "$(CPPFLAGS) $(CFLAGS) $(DEFINES) "\
1502
+ "#{CONFTEST_C} $(CPPOUTFILE)"),&b)
1503
+ add_define("HAVE_#{header.sanitize}")
1504
+ true
1505
+ else
1506
+ false
1507
+ end
1508
+ end
1509
+ ensure
1510
+ rm_f("conftest*")
1511
+ end
1512
+
1513
+ # The same as have_header, but fails if the header is not found...
1514
+ def require_header(header, message = nil ,&b)
1515
+ if ! have_header(header,&b)
1516
+ if message
1517
+ puts message
1518
+ end
1519
+ raise "Header #{header} not found, stopping\n"
1520
+ end
1521
+ end
1522
+
1523
+ def mkmf2_init
1524
+ check_missing_features
1525
+ parse_cmdline
1526
+ setup_model
1527
+ config_to_global
1528
+ end
1529
+
1530
+ def headers(header)
1531
+ headers = ""
1532
+ if header
1533
+ if header.is_a?(Array)
1534
+ header.each {|h|
1535
+ headers += "#include <#{h.to_s}>\n"
1536
+ }
1537
+ else
1538
+ headers += "#include <#{header.to_s}>\n"
1539
+ end
1540
+ end
1541
+ return headers
1542
+ end
1543
+
1544
+ # Tries to link the given code with the extra flags given
1545
+ def try_link(code, extras = "")
1546
+ return try_do(code,
1547
+ expand_vars("$(CC) $(OUTFLAG)conftest $(INCFLAGS) " +
1548
+ "#{CONFTEST_C} " +
1549
+ " -I$(hdrdir) $(CPPFLAGS) $(CFLAGS) $(src)" +
1550
+ " $(LIBPATH) $(LDFLAGS) $(ARCH_FLAG) " +
1551
+ " $(LOCAL_LIBS) $(LIBS) $(LIBS_SUP) #{extras}"
1552
+ )
1553
+ )
1554
+ ensure
1555
+ rm_f("conftest*")
1556
+ end
1557
+
1558
+ def try_func(func, extra, h)
1559
+ headers = headers(h)
1560
+
1561
+ try_link(<<"SRC", extra) or try_link(<<"SRC", extra)
1562
+ #{headers}
1563
+ /*top*/
1564
+ int main() { return 0; }
1565
+ int t() { #{func}(); return 0; }
1566
+ SRC
1567
+ #{headers}
1568
+ /*top*/
1569
+ int main() { return 0; }
1570
+ int t() { void ((*volatile p)()); p = (void ((*)()))#{func}; return 0; }
1571
+ SRC
1572
+ end
1573
+
1574
+
1575
+ # Compatibility function from mkmf.rb. Checks if the compiler
1576
+ # can find the given function in the given library. If the function
1577
+ # is not given, we look for main but it's definitely not a good idea.
1578
+ # +header+ is a header that can be included to get the prototype for
1579
+ # this function. It can possibly be an array, in which case it is
1580
+ # interpreted as a list of headers that should be included.
1581
+
1582
+ def have_library(lib, func = nil, header=nil, &b)
1583
+ if func.nil?
1584
+ func = "main"
1585
+ end
1586
+ libarg = "#{MAKEFILE_CONFIG["LIBARG"]%lib}"
1587
+ checking_for "#{func}() in #{libarg}" do
1588
+ if try_func(func, libarg, header)
1589
+ add_define("HAVE_#{lib.sanitize}")
1590
+ MAKEFILE_CONFIG["LIBS_SUP"] += " #{libarg}"
1591
+ true
1592
+ else
1593
+ false
1594
+ end
1595
+ end
1596
+ end
1597
+
1598
+ # Returns true if a function could be found
1599
+ def have_func(func, header = nil)
1600
+ checking_for "#{func}() " do
1601
+ if try_func(func, "", header)
1602
+ add_define("HAVE_#{func.sanitize}")
1603
+ true
1604
+ else
1605
+ false
1606
+ end
1607
+ end
1608
+ end
1609
+ end
1610
+
1611
+ include Mkmf2
1612
+ mkmf2_init