tioga 1.4

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