aboutsummaryrefslogtreecommitdiff
path: root/waflib/Tools/ruby.py
blob: 8d92a79a16179d3b62d957135b0d73c34e35710d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#!/usr/bin/env python
# encoding: utf-8
# daniel.svensson at purplescout.se 2008
# Thomas Nagy 2016-2018 (ita)

"""
Support for Ruby extensions. A C/C++ compiler is required::

	def options(opt):
		opt.load('compiler_c ruby')
	def configure(conf):
		conf.load('compiler_c ruby')
		conf.check_ruby_version((1,8,0))
		conf.check_ruby_ext_devel()
		conf.check_ruby_module('libxml')
	def build(bld):
		bld(
			features = 'c cshlib rubyext',
			source = 'rb_mytest.c',
			target = 'mytest_ext',
			install_path = '${ARCHDIR_RUBY}')
		bld.install_files('${LIBDIR_RUBY}', 'Mytest.rb')
"""

import os
from waflib import Errors, Options, Task, Utils
from waflib.TaskGen import before_method, feature, extension
from waflib.Configure import conf

@feature('rubyext')
@before_method('apply_incpaths', 'process_source', 'apply_bundle', 'apply_link')
def init_rubyext(self):
	"""
	Add required variables for ruby extensions
	"""
	self.install_path = '${ARCHDIR_RUBY}'
	self.uselib = self.to_list(getattr(self, 'uselib', ''))
	if not 'RUBY' in self.uselib:
		self.uselib.append('RUBY')
	if not 'RUBYEXT' in self.uselib:
		self.uselib.append('RUBYEXT')

@feature('rubyext')
@before_method('apply_link', 'propagate_uselib_vars')
def apply_ruby_so_name(self):
	"""
	Strip the *lib* prefix from ruby extensions
	"""
	self.env.cshlib_PATTERN = self.env.cxxshlib_PATTERN = self.env.rubyext_PATTERN

@conf
def check_ruby_version(self, minver=()):
	"""
	Checks if ruby is installed.
	If installed the variable RUBY will be set in environment.
	The ruby binary can be overridden by ``--with-ruby-binary`` command-line option.
	"""

	ruby = self.find_program('ruby', var='RUBY', value=Options.options.rubybinary)

	try:
		version = self.cmd_and_log(ruby + ['-e', 'puts defined?(VERSION) ? VERSION : RUBY_VERSION']).strip()
	except Errors.WafError:
		self.fatal('could not determine ruby version')
	self.env.RUBY_VERSION = version

	try:
		ver = tuple(map(int, version.split('.')))
	except Errors.WafError:
		self.fatal('unsupported ruby version %r' % version)

	cver = ''
	if minver:
		cver = '> ' + '.'.join(str(x) for x in minver)
		if ver < minver:
			self.fatal('ruby is too old %r' % ver)

	self.msg('Checking for ruby version %s' % cver, version)

@conf
def check_ruby_ext_devel(self):
	"""
	Check if a ruby extension can be created
	"""
	if not self.env.RUBY:
		self.fatal('ruby detection is required first')

	if not self.env.CC_NAME and not self.env.CXX_NAME:
		self.fatal('load a c/c++ compiler first')

	version = tuple(map(int, self.env.RUBY_VERSION.split(".")))

	def read_out(cmd):
		return Utils.to_list(self.cmd_and_log(self.env.RUBY + ['-rrbconfig', '-e', cmd]))

	def read_config(key):
		return read_out('puts RbConfig::CONFIG[%r]' % key)

	cpppath = archdir = read_config('archdir')

	if version >= (1, 9, 0):
		ruby_hdrdir = read_config('rubyhdrdir')
		cpppath += ruby_hdrdir
		if version >= (2, 0, 0):
			cpppath += read_config('rubyarchhdrdir')
		cpppath += [os.path.join(ruby_hdrdir[0], read_config('arch')[0])]

	self.check(header_name='ruby.h', includes=cpppath, errmsg='could not find ruby header file', link_header_test=False)

	self.env.LIBPATH_RUBYEXT = read_config('libdir')
	self.env.LIBPATH_RUBYEXT += archdir
	self.env.INCLUDES_RUBYEXT = cpppath
	self.env.CFLAGS_RUBYEXT = read_config('CCDLFLAGS')
	self.env.rubyext_PATTERN = '%s.' + read_config('DLEXT')[0]

	# ok this is really stupid, but the command and flags are combined.
	# so we try to find the first argument...
	flags = read_config('LDSHARED')
	while flags and flags[0][0] != '-':
		flags = flags[1:]

	# we also want to strip out the deprecated ppc flags
	if len(flags) > 1 and flags[1] == "ppc":
		flags = flags[2:]

	self.env.LINKFLAGS_RUBYEXT = flags
	self.env.LINKFLAGS_RUBYEXT += read_config('LIBS')
	self.env.LINKFLAGS_RUBYEXT += read_config('LIBRUBYARG_SHARED')

	if Options.options.rubyarchdir:
		self.env.ARCHDIR_RUBY = Options.options.rubyarchdir
	else:
		self.env.ARCHDIR_RUBY = read_config('sitearchdir')[0]

	if Options.options.rubylibdir:
		self.env.LIBDIR_RUBY = Options.options.rubylibdir
	else:
		self.env.LIBDIR_RUBY = read_config('sitelibdir')[0]

@conf
def check_ruby_module(self, module_name):
	"""
	Check if the selected ruby interpreter can require the given ruby module::

		def configure(conf):
			conf.check_ruby_module('libxml')

	:param module_name: module
	:type  module_name: string
	"""
	self.start_msg('Ruby module %s' % module_name)
	try:
		self.cmd_and_log(self.env.RUBY + ['-e', 'require \'%s\';puts 1' % module_name])
	except Errors.WafError:
		self.end_msg(False)
		self.fatal('Could not find the ruby module %r' % module_name)
	self.end_msg(True)

@extension('.rb')
def process(self, node):
	return self.create_task('run_ruby', node)

class run_ruby(Task.Task):
	"""
	Task to run ruby files detected by file extension .rb::

		def options(opt):
			opt.load('ruby')

		def configure(ctx):
			ctx.check_ruby_version()

		def build(bld):
			bld.env.RBFLAGS = '-e puts "hello world"'
			bld(source='a_ruby_file.rb')
	"""
	run_str = '${RUBY} ${RBFLAGS} -I ${SRC[0].parent.abspath()} ${SRC}'

def options(opt):
	"""
	Add the ``--with-ruby-archdir``, ``--with-ruby-libdir`` and ``--with-ruby-binary`` options
	"""
	opt.add_option('--with-ruby-archdir', type='string', dest='rubyarchdir', help='Specify directory where to install arch specific files')
	opt.add_option('--with-ruby-libdir', type='string', dest='rubylibdir', help='Specify alternate ruby library path')
	opt.add_option('--with-ruby-binary', type='string', dest='rubybinary', help='Specify alternate ruby binary')