1 |
# Copyright 1999-2009 Gentoo Foundation |
2 |
# Distributed under the terms of the GNU General Public License v2 |
3 |
# $Header: /var/cvsroot/gentoo-x86/eclass/ruby-ng.eclass,v 1.11 2010/04/26 15:07:58 a3li Exp $ |
4 |
# |
5 |
# @ECLASS: ruby-ng.eclass |
6 |
# @MAINTAINER: |
7 |
# Ruby herd <ruby@gentoo.org> |
8 |
# |
9 |
# Author: Diego E. Pettenò <flameeyes@gentoo.org> |
10 |
# |
11 |
# Author: Alex Legler <a3li@gentoo.org> |
12 |
# |
13 |
# Author: Hans de Graaff <graaff@gentoo.org> |
14 |
# |
15 |
# @BLURB: An eclass for installing Ruby packages with proper support for multiple Ruby slots. |
16 |
# @DESCRIPTION: |
17 |
# The Ruby eclass is designed to allow an easier installation of Ruby packages |
18 |
# and their incorporation into the Gentoo Linux system. |
19 |
# |
20 |
# Currently available targets are: |
21 |
# * ruby18 - Ruby (MRI) 1.8.x |
22 |
# * ruby19 - Ruby (MRI) 1.9.x |
23 |
# * ree18 - Ruby Enterprise Edition 1.8.x |
24 |
# * jruby - JRuby |
25 |
# |
26 |
# This eclass does not define the implementation of the configure, |
27 |
# compile, test, or install phases. Instead, the default phases are |
28 |
# used. Specific implementations of these phases can be provided in |
29 |
# the ebuild either to be run for each Ruby implementation, or for all |
30 |
# Ruby implementations, as follows: |
31 |
# |
32 |
# * each_ruby_configure |
33 |
# * all_ruby_configure |
34 |
|
35 |
# @ECLASS-VARIABLE: USE_RUBY |
36 |
# @DESCRIPTION: |
37 |
# This variable contains a space separated list of targets (see above) a package |
38 |
# is compatible to. It must be set before the `inherit' call. There is no |
39 |
# default. All ebuilds are expected to set this variable. |
40 |
|
41 |
# @ECLASS-VARIABLE: RUBY_PATCHES |
42 |
# @DESCRIPTION: |
43 |
# A String or Array of filenames of patches to apply to all implementations. |
44 |
|
45 |
# @ECLASS-VARIABLE: RUBY_OPTIONAL |
46 |
# @DESCRIPTION: |
47 |
# Set the value to "yes" to make the dependency on a Ruby interpreter optional. |
48 |
|
49 |
inherit eutils toolchain-funcs |
50 |
|
51 |
EXPORT_FUNCTIONS src_unpack src_prepare src_configure src_compile src_test src_install pkg_setup |
52 |
|
53 |
case ${EAPI} in |
54 |
0|1) |
55 |
die "Unsupported EAPI=${EAPI} (too old) for ruby-ng.eclass" ;; |
56 |
2) ;; |
57 |
*) |
58 |
die "Unknown EAPI=${EAPI} for ruby-ng.eclass" |
59 |
esac |
60 |
|
61 |
# @FUNCTION: ruby_implementation_depend |
62 |
# @USAGE: target [comparator [version]] |
63 |
# @RETURN: Package atom of a Ruby implementation to be used in dependencies. |
64 |
# @DESCRIPTION: |
65 |
# This function returns the formal package atom for a Ruby implementation. |
66 |
# |
67 |
# `target' has to be one of the valid values for USE_RUBY (see above) |
68 |
# |
69 |
# Set `comparator' and `version' to include a comparator (=, >=, etc.) and a |
70 |
# version string to the returned string |
71 |
ruby_implementation_depend() { |
72 |
local rubypn= |
73 |
local rubyslot= |
74 |
|
75 |
case $1 in |
76 |
ruby18) |
77 |
rubypn="dev-lang/ruby" |
78 |
rubyslot=":1.8" |
79 |
;; |
80 |
ruby19) |
81 |
rubypn="dev-lang/ruby" |
82 |
rubyslot=":1.9" |
83 |
;; |
84 |
ree18) |
85 |
rubypn="dev-lang/ruby-enterprise" |
86 |
rubyslot=":1.8" |
87 |
;; |
88 |
jruby) |
89 |
rubypn="dev-java/jruby" |
90 |
rubyslot="" |
91 |
;; |
92 |
*) die "$1: unknown Ruby implementation" |
93 |
esac |
94 |
|
95 |
echo "$2${rubypn}$3${rubyslot}" |
96 |
} |
97 |
|
98 |
# @FUNCTION: ruby_samelib |
99 |
# @RETURN: use flag string with current ruby implementations |
100 |
# @DESCRIPTION: |
101 |
# Convenience function to output the use dependency part of a |
102 |
# dependency. Used as a building block for ruby_add_rdepend() and |
103 |
# ruby_add_bdepend(), but may also be useful in an ebuild to specify |
104 |
# more complex dependencies. |
105 |
ruby_samelib() { |
106 |
local res= |
107 |
for _ruby_implementation in $USE_RUBY; do |
108 |
has -${_ruby_implementation} $@ || \ |
109 |
res="${res}ruby_targets_${_ruby_implementation}?," |
110 |
done |
111 |
|
112 |
echo "[${res%,}]" |
113 |
} |
114 |
|
115 |
_ruby_implementation_depend() { |
116 |
echo "ruby_targets_${1}? ( ${2}[ruby_targets_${1}] )" |
117 |
} |
118 |
|
119 |
_ruby_add_bdepend() { |
120 |
local atom=$1 |
121 |
local conditions=$2 |
122 |
|
123 |
for condition in $conditions; do |
124 |
hasq $condition "$IUSE" || IUSE="${IUSE} $condition" |
125 |
atom="${condition}? ( ${atom} )" |
126 |
done |
127 |
|
128 |
DEPEND="${DEPEND} ${atom}" |
129 |
RDEPEND="${RDEPEND}" |
130 |
} |
131 |
|
132 |
_ruby_add_rdepend() { |
133 |
local atom=$1 |
134 |
local conditions=$2 |
135 |
|
136 |
for condition in $conditions; do |
137 |
hasq $condition "$IUSE" || IUSE="${IUSE} $condition" |
138 |
atom="${condition}? ( ${atom} )" |
139 |
done |
140 |
|
141 |
RDEPEND="${RDEPEND} ${atom}" |
142 |
_ruby_add_bdepend "$atom" test |
143 |
} |
144 |
|
145 |
# @FUNCTION: ruby_add_rdepend |
146 |
# @USAGE: [conditions] atom |
147 |
# @DESCRIPTION: |
148 |
# Adds the specified atom(s) with optional use condition(s) to |
149 |
# RDEPEND, taking the current set of ruby targets into account. This |
150 |
# makes sure that all ruby dependencies of the package are installed |
151 |
# for the same ruby targets. Use this function for all ruby |
152 |
# dependencies instead of setting RDEPEND yourself. Both atom and |
153 |
# conditions can be a space-separated list of atoms or conditions. |
154 |
ruby_add_rdepend() { |
155 |
local atoms= |
156 |
local conditions= |
157 |
case $# in |
158 |
1) |
159 |
atoms=$1 |
160 |
;; |
161 |
2) |
162 |
conditions=$1 |
163 |
atoms=$2 |
164 |
;; |
165 |
*) |
166 |
die "bad number of arguments to $0" |
167 |
;; |
168 |
esac |
169 |
|
170 |
for atom in $atoms; do |
171 |
_ruby_add_rdepend "${atom}$(ruby_samelib)" "$conditions" |
172 |
done |
173 |
} |
174 |
|
175 |
# @FUNCTION: ruby_add_bdepend |
176 |
# @USAGE: [conditions] atom |
177 |
# @DESCRIPTION: |
178 |
# Adds the specified atom(s) with optional use condition(s) to both |
179 |
# DEPEND and RDEPEND, taking the current set of ruby targets into |
180 |
# account. This makes sure that all ruby dependencies of the package |
181 |
# are installed for the same ruby targets. Use this function for all |
182 |
# ruby dependencies instead of setting DEPEND and RDEPEND |
183 |
# yourself. Both atom and conditions can be a space-separated list of |
184 |
# atoms or conditions. |
185 |
ruby_add_bdepend() { |
186 |
local atoms= |
187 |
local conditions= |
188 |
case $# in |
189 |
1) |
190 |
atoms=$1 |
191 |
;; |
192 |
2) |
193 |
conditions=$1 |
194 |
atoms=$2 |
195 |
;; |
196 |
*) |
197 |
die "bad number of arguments to $0" |
198 |
;; |
199 |
esac |
200 |
|
201 |
for atom in $atoms; do |
202 |
_ruby_add_bdepend "${atom}$(ruby_samelib)" "$conditions" |
203 |
done |
204 |
} |
205 |
|
206 |
for _ruby_implementation in $USE_RUBY; do |
207 |
IUSE="${IUSE} ruby_targets_${_ruby_implementation}" |
208 |
|
209 |
# If you specify RUBY_OPTIONAL you also need to take care of |
210 |
# ruby useflag and dependency. |
211 |
if [[ ${RUBY_OPTIONAL} != "yes" ]]; then |
212 |
DEPEND="${DEPEND} ruby_targets_${_ruby_implementation}? ( $(ruby_implementation_depend $_ruby_implementation) )" |
213 |
RDEPEND="${RDEPEND} ruby_targets_${_ruby_implementation}? ( $(ruby_implementation_depend $_ruby_implementation) )" |
214 |
fi |
215 |
done |
216 |
|
217 |
_ruby_invoke_environment() { |
218 |
old_S=${S} |
219 |
sub_S=${S#${WORKDIR}/} |
220 |
|
221 |
# Special case, for the always-lovely GitHub fetches. With this, |
222 |
# we allow the star glob to just expand to whatever directory it's |
223 |
# called. |
224 |
if [[ ${sub_S} = *"*" ]]; then |
225 |
pushd "${WORKDIR}"/all &>/dev/null |
226 |
sub_S=$(eval ls -d ${sub_S}) |
227 |
popd &>/dev/null |
228 |
fi |
229 |
|
230 |
environment=$1; shift |
231 |
|
232 |
my_WORKDIR="${WORKDIR}"/${environment} |
233 |
S="${my_WORKDIR}"/"${sub_S}" |
234 |
|
235 |
if [[ -d "${S}" ]]; then |
236 |
pushd "$S" &>/dev/null |
237 |
elif [[ -d "${my_WORKDIR}" ]]; then |
238 |
pushd "${my_WORKDIR}" &>/dev/null |
239 |
else |
240 |
pushd "${WORKDIR}" &>/dev/null |
241 |
fi |
242 |
|
243 |
ebegin "Running ${_PHASE:-${EBUILD_PHASE}} phase for $environment" |
244 |
"$@" |
245 |
popd &>/dev/null |
246 |
|
247 |
S=${old_S} |
248 |
} |
249 |
|
250 |
_ruby_each_implementation() { |
251 |
local invoked=no |
252 |
for _ruby_implementation in ${USE_RUBY}; do |
253 |
# only proceed if it's requested |
254 |
use ruby_targets_${_ruby_implementation} || continue |
255 |
|
256 |
local _ruby_name=$_ruby_implementation |
257 |
|
258 |
# Add all USE_RUBY values where the flag name diverts from the binary here |
259 |
case $_ruby_implementation in |
260 |
ree18) |
261 |
_ruby_name=rubyee18 |
262 |
;; |
263 |
esac |
264 |
|
265 |
RUBY=$(type -p $_ruby_name 2>/dev/null) |
266 |
invoked=yes |
267 |
|
268 |
if [[ -n "$1" ]]; then |
269 |
_ruby_invoke_environment $_ruby_implementation "$@" |
270 |
fi |
271 |
|
272 |
unset RUBY |
273 |
done |
274 |
|
275 |
[[ ${invoked} == "no" ]] && die "You need to select at least one Ruby implementation by setting RUBY_TARGETS in /etc/make.conf." |
276 |
} |
277 |
|
278 |
# @FUNCTION: ruby-ng_pkg_setup |
279 |
# @DESCRIPTION: |
280 |
# Check whether at least one ruby target implementation is present. |
281 |
ruby-ng_pkg_setup() { |
282 |
# This only checks that at least one implementation is present |
283 |
# before doing anything; by leaving the parameters empty we know |
284 |
# it's a special case. |
285 |
_ruby_each_implementation |
286 |
} |
287 |
|
288 |
# @FUNCTION: ruby-ng_src_unpack |
289 |
# @DESCRIPTION: |
290 |
# Unpack the source archive. |
291 |
ruby-ng_src_unpack() { |
292 |
mkdir "${WORKDIR}"/all |
293 |
pushd "${WORKDIR}"/all &>/dev/null |
294 |
|
295 |
# We don't support an each-unpack, it's either all or nothing! |
296 |
if type all_ruby_unpack &>/dev/null; then |
297 |
_ruby_invoke_environment all all_ruby_unpack |
298 |
else |
299 |
[[ -n ${A} ]] && unpack ${A} |
300 |
fi |
301 |
|
302 |
popd &>/dev/null |
303 |
} |
304 |
|
305 |
_ruby_apply_patches() { |
306 |
for patch in "${RUBY_PATCHES[@]}"; do |
307 |
if [ -f "${patch}" ]; then |
308 |
epatch "${patch}" |
309 |
elif [ -f "${FILESDIR}/${patch}" ]; then |
310 |
epatch "${FILESDIR}/${patch}" |
311 |
else |
312 |
die "Cannot find patch ${patch}" |
313 |
fi |
314 |
done |
315 |
|
316 |
# This is a special case: instead of executing just in the special |
317 |
# "all" environment, this will actually copy the effects on _all_ |
318 |
# the other environments, and is thus executed before the copy |
319 |
type all_ruby_prepare &>/dev/null && all_ruby_prepare |
320 |
} |
321 |
|
322 |
_ruby_source_copy() { |
323 |
# Until we actually find a reason not to, we use hardlinks, this |
324 |
# should reduce the amount of disk space that is wasted by this. |
325 |
cp -prl all ${_ruby_implementation} \ |
326 |
|| die "Unable to copy ${_ruby_implementation} environment" |
327 |
} |
328 |
|
329 |
# @FUNCTION: ruby-ng_src_prepare |
330 |
# @DESCRIPTION: |
331 |
# Apply patches and prepare versions for each ruby target |
332 |
# implementation. Also carry out common clean up tasks. |
333 |
ruby-ng_src_prepare() { |
334 |
# Way too many Ruby packages are prepared on OSX without removing |
335 |
# the extra data forks, we do it here to avoid repeating it for |
336 |
# almost every other ebuild. |
337 |
find . -name '._*' -delete |
338 |
|
339 |
_ruby_invoke_environment all _ruby_apply_patches |
340 |
|
341 |
_PHASE="source copy" \ |
342 |
_ruby_each_implementation _ruby_source_copy |
343 |
|
344 |
if type each_ruby_prepare &>/dev/null; then |
345 |
_ruby_each_implementation each_ruby_prepare |
346 |
fi |
347 |
} |
348 |
|
349 |
# @FUNCTION: ruby-ng_src_configure |
350 |
# @DESCRIPTION: |
351 |
# Configure the package. |
352 |
ruby-ng_src_configure() { |
353 |
if type each_ruby_configure &>/dev/null; then |
354 |
_ruby_each_implementation each_ruby_configure |
355 |
fi |
356 |
|
357 |
type all_ruby_configure &>/dev/null && \ |
358 |
_ruby_invoke_environment all all_ruby_configure |
359 |
} |
360 |
|
361 |
# @FUNCTION: ruby-ng_src_compile |
362 |
# @DESCRIPTION: |
363 |
# Compile the package. |
364 |
ruby-ng_src_compile() { |
365 |
if type each_ruby_compile &>/dev/null; then |
366 |
_ruby_each_implementation each_ruby_compile |
367 |
fi |
368 |
|
369 |
type all_ruby_compile &>/dev/null && \ |
370 |
_ruby_invoke_environment all all_ruby_compile |
371 |
} |
372 |
|
373 |
# @FUNCTION: ruby-ng_src_test |
374 |
# @DESCRIPTION: |
375 |
# Run tests for the package. |
376 |
ruby-ng_src_test() { |
377 |
if type each_ruby_test &>/dev/null; then |
378 |
_ruby_each_implementation each_ruby_test |
379 |
fi |
380 |
|
381 |
type all_ruby_test &>/dev/null && \ |
382 |
_ruby_invoke_environment all all_ruby_test |
383 |
} |
384 |
|
385 |
_each_ruby_check_install() { |
386 |
local libruby_basename=$(${RUBY} -rrbconfig -e 'puts Config::CONFIG["LIBRUBY_SO"]') |
387 |
local libruby_soname=$(scanelf -qS "/usr/$(get_libdir)/${libruby_basename}" | awk '{ print $1 }') |
388 |
local sitedir=$(${RUBY} -rrbconfig -e 'puts Config::CONFIG["sitedir"]') |
389 |
local sitelibdir=$(${RUBY} -rrbconfig -e 'puts Config::CONFIG["sitelibdir"]') |
390 |
|
391 |
# Look for wrong files in sitedir |
392 |
if [[ -d "${D}${sitedir}" ]]; then |
393 |
local f=$(find "${D}${sitedir}" -mindepth 1 -maxdepth 1 -not -wholename "${D}${sitelibdir}") |
394 |
if [[ -n ${f} ]]; then |
395 |
eerror "Found files in sitedir, outsite sitelibdir:" |
396 |
eerror "${f}" |
397 |
die "Misplaced files in sitedir" |
398 |
fi |
399 |
fi |
400 |
|
401 |
# The current implementation lacks libruby (i.e.: jruby) |
402 |
[[ -z ${libruby_soname} ]] && return 0 |
403 |
|
404 |
scanelf -qnR "${D}${sitedir}" \ |
405 |
| fgrep -v "${libruby_soname}" \ |
406 |
> "${T}"/ruby-ng-${_ruby_implementation}-mislink.log |
407 |
|
408 |
if [[ -s "${T}"/ruby-ng-${_ruby_implementation}-mislink.log ]]; then |
409 |
ewarn "Extensions installed for ${_ruby_implementation} with missing links to ${libruby}" |
410 |
ewarn $(< "${T}"/ruby-ng-${_ruby_implementation}-mislink.log ) |
411 |
die "Missing links to ${libruby}" |
412 |
fi |
413 |
} |
414 |
|
415 |
# @FUNCTION: ruby-ng_src_install |
416 |
# @DESCRIPTION: |
417 |
# Install the package for each ruby target implementation. |
418 |
ruby-ng_src_install() { |
419 |
if type each_ruby_install &>/dev/null; then |
420 |
_ruby_each_implementation each_ruby_install |
421 |
fi |
422 |
|
423 |
type all_ruby_install &>/dev/null && \ |
424 |
_ruby_invoke_environment all all_ruby_install |
425 |
|
426 |
_PHASE="check install" \ |
427 |
_ruby_each_implementation _each_ruby_check_install |
428 |
} |
429 |
|
430 |
# @FUNCTION: ruby_rbconfig_value |
431 |
# @USAGE: rbconfig item |
432 |
# @RETURN: Returns the value of the given rbconfig item of the Ruby interpreter in ${RUBY}. |
433 |
ruby_rbconfig_value() { |
434 |
echo $(${RUBY} -rrbconfig -e "puts Config::CONFIG['$1']") |
435 |
} |
436 |
|
437 |
# @FUNCTION: doruby |
438 |
# @USAGE: file [file...] |
439 |
# @DESCRIPTION: |
440 |
# Installs the specified file(s) into the sitelibdir of the Ruby interpreter in ${RUBY}. |
441 |
doruby() { |
442 |
[[ -z ${RUBY} ]] && die "\$RUBY is not set" |
443 |
( # don't want to pollute calling env |
444 |
insinto $(ruby_rbconfig_value 'sitelibdir') |
445 |
insopts -m 0644 |
446 |
doins "$@" |
447 |
) || die "failed to install $@" |
448 |
} |
449 |
|
450 |
# @FUNCTION: ruby_get_libruby |
451 |
# @RETURN: The location of libruby*.so belonging to the Ruby interpreter in ${RUBY}. |
452 |
ruby_get_libruby() { |
453 |
${RUBY} -rrbconfig -e 'puts File.join(Config::CONFIG["libdir"], Config::CONFIG["LIBRUBY"])' |
454 |
} |
455 |
|
456 |
# @FUNCTION: ruby_get_hdrdir |
457 |
# @RETURN: The location of the header files belonging to the Ruby interpreter in ${RUBY}. |
458 |
ruby_get_hdrdir() { |
459 |
local rubyhdrdir=$(ruby_rbconfig_value 'rubyhdrdir') |
460 |
|
461 |
if [[ "${rubyhdrdir}" = "nil" ]] ; then |
462 |
rubyhdrdir=$(ruby_rbconfig_value 'archdir') |
463 |
fi |
464 |
|
465 |
echo "${rubyhdrdir}" |
466 |
} |
467 |
|
468 |
# @FUNCTION: ruby_get_version |
469 |
# @RETURN: The version of the Ruby interpreter in ${RUBY}, or what 'ruby' points to. |
470 |
ruby_get_version() { |
471 |
local ruby=${RUBY:-$(type -p ruby 2>/dev/null)} |
472 |
|
473 |
echo $(${ruby} -e 'puts RUBY_VERSION') |
474 |
} |
475 |
|
476 |
# @FUNCTION: ruby_get_implementation |
477 |
# @RETURN: The implementation of the Ruby interpreter in ${RUBY}, or what 'ruby' points to. |
478 |
ruby_get_implementation() { |
479 |
local ruby=${RUBY:-$(type -p ruby 2>/dev/null)} |
480 |
|
481 |
case $(${ruby} --version) in |
482 |
*Enterprise*) |
483 |
echo "ree" |
484 |
;; |
485 |
*jruby*) |
486 |
echo "jruby" |
487 |
;; |
488 |
*) |
489 |
echo "mri" |
490 |
;; |
491 |
esac |
492 |
} |