aboutsummaryrefslogtreecommitdiffstats
path: root/classes/rubyv2.bbclass
blob: 1dfb047ba9972ff4bd462cf2b715f72fe3b7fc0d (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
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
# copied from: https://layers.openembedded.org/layerindex/branch/master/layer/meta-rubygems/
#
#  - One local modifcation was made to copy an extconf.rb from UNPACKDIR to the
#    build.
#  - This copy will eventually be deleted, once factoring happens between the
#    two classes.

## SPDX-License-Identifier: MIT, BSD-2-Clause
## Copyright (c) 2015, Michaël Burtin
## Copyright (c) 2020, Konrad Weihmann

GEMLIB_VERSION = "3.3.0"

GEM_SRC ?= "https://rubygems.org/gems"

# Enforce IPv4 connection - IPv6 seems to be broken
# nooelint: oelint.vars.specific,oelint.vars.pathhardcode.bindir
# FETCHCMD_wget ?= "/usr/bin/env wget -t 2 -T 30 --passive-ftp -4"

GEM_NAME ?= ""
GEM_VERSION ?= "${PV}"

# SRC_URI = "${GEM_SRC}/${GEM_FILENAME}"
GEMPREFIX = "gem-"

UNPACKDIR ??= "${WORKDIR}/gem-dl"

# S = "${UNPACKDIR}/${GEM_NAME}-${GEM_VERSION}"

GEM_FILENAME = "${GEM_NAME}-${GEM_VERSION}.gem"
GEM_FILE ?= "${UNPACKDIR}/${GEM_FILENAME}"
GEM_BUILT_FILE = "${UNPACKDIR}/${GEM_FILENAME}"

GEM_SPEC_FILENAME = "${GEM_FILENAME}spec"
GEM_SPEC_FILE ?= "${S}/${GEM_SPEC_FILENAME}"
GEM_SPEC_CACHE ?= "${T}/.gems"

GEM_DIR = "${libdir}/ruby/gems/${GEMLIB_VERSION}"
RUBY_SITEDIR = "${libdir}/ruby/site_ruby/"
GEM_HOME = "${D}${GEM_DIR}"
GEM_PATH:class-target = "${RECIPE_SYSROOT}${GEM_DIR}:${RECIPE_SYSROOT}${GEM_DIR}:${GEM_HOME}"
GEM_PATH:class-native = "${RECIPE_SYSROOT_NATIVE}${GEM_DIR}:${GEM_HOME}"

# Disable the very strict versioning with ~>
GEM_DISABLE_STRICT_VER ?= "1"

GEM_INSTALL_FLAGS ?= ""

# Use the following to define extra depend/rdepends
# which cannot be seen by the package updater
EXTRA_RDEPENDS ?= ""
EXTRA_DEPENDS ?= ""

RUBYLIB_EXTRA_PATHS ?= ""

def extra_paths(d):
    res = (d.getVar('RUBYLIB_EXTRA_PATHS') or '').split(' ')
    if res:
        return ':' + ':'.join(res)
    return ''

RUBYLIB:class-target = "${STAGING_LIBDIR_NATIVE}/ruby/${GEMLIB_VERSION}/${@get_build_platform_folder(d)}${@extra_paths(d)}"
RUBYPLATFORM ?= "ruby"
RUBYPLATFORM:class-target ?= "${@get_target_platform_folder(d)}"
CFLAGS:append = " -DHAVE_GCC_CAS"

def get_gem_name_from_bpn(d):
    bpn = (d.getVar('BPN', True) or "")
    gemPrefix = (d.getVar('GEMPREFIX', True) or "")
    if bpn.startswith(gemPrefix):
        gemName = bpn[len(gemPrefix):]
    else:
        gemName = bpn
    return gemName

def get_build_platform_folder(d):
    build_arch = d.getVar("BUILD_ARCH")
    build_os = d.getVar("BUILD_OS")
    if build_os.endswith("linux"):
        build_os = build_os.replace('linux', 'linux-gnu')
    return build_arch + "-" + build_os

def get_target_platform_folder(d):
    target_arch = d.getVar("HOST_ARCH")
    target_os = d.getVar("HOST_OS")
    if target_os.endswith("linux"):
        target_os = target_os.replace('linux', 'linux-gnu')
    return target_arch + "-" + target_os

do_gem_unpack() {
    return

    export RUBYLIB=${RUBYLIB}

    cd ${UNPACKDIR}
    # GEM_FILE might not exist if SRC_URI was overloaded
    [ ! -e ${GEM_FILE} ] && return 0

    gem unpack -V ${GEM_FILE}
}

DEPENDS:append = " ruby-native ${EXTRA_DEPENDS}"
DEPENDS:append:class-target = " ruby ruby-native ${EXTRA_DEPENDS}"

python () {
    d.appendVarFlag('do_gem_unpack', 'depends', ' ruby-native:do_populate_sysroot')
}

do_gem_unpack[vardepsexclude] += "prefix_native"
addtask do_gem_unpack after do_unpack before do_patch

python do_unpack:append() {
    # as the actual unpack happens in do_gem_unpack
    # we will work around insane-class checks
    # by just creating the needed directories here
    os.makedirs(d.expand('${S}'), exist_ok=True)
    os.makedirs(d.expand('${UNPACKDIR}'), exist_ok=True)
}

do_generate_spec() {
    export RUBYLIB=${RUBYLIB}
    export GEM_SPEC=${GEM_SPEC_CACHE}

    if [ -e "${UNPACKDIR}/${GEM_SPEC_FILE}" ]; then
	cp -f "${UNPACKDIR}/${GEM_SPEC_FILE}" "${S}/${GEM_SPEC_FILE}"
	return 0
    fi

    # GEM_FILE might not exist if SRC_URI was overloaded
    [ ! -e ${GEM_FILE} ] && return 0

    gem spec -V --ruby ${GEM_FILE} > ${GEM_SPEC_FILE}

    # lift the version bindings to be less strict
    if [ "${GEM_DISABLE_STRICT_VER}" -eq "1" ]; then
        sed -i 's#=[[:space:]]*[0-9]\+\.[0-9]\+#!=0#g' ${GEM_SPEC_FILE}
        sed -i 's#~>#>=#g' ${GEM_SPEC_FILE}
        sed -i 's#<=[[:space:]]*[0-9]\+\.[0-9]\+\.[0-9]\+#!=0#g' ${GEM_SPEC_FILE}
        sed -i 's#<[[:space:]]*[0-9]\+\.[0-9]\+\.[0-9]\+#!=0#g' ${GEM_SPEC_FILE}
        sed -i 's#<[[:space:]]*[0-9]\+\.[0-9]\+#!=0#g' ${GEM_SPEC_FILE}
        sed -i 's#>!=#!=#g' ${GEM_SPEC_FILE}
        sed -i 's#!!=#!=#g' ${GEM_SPEC_FILE}
        sed -i 's#<!=0#!=0#g' ${GEM_SPEC_FILE}
    fi
}

do_generate_spec[vardepsexclude] += "prefix_native"
addtask do_generate_spec after do_gem_unpack before do_patch

python do_arch_patch_config() {
    import re
    if bb.data.inherits_class('native', d):
        return
    target_cpu, target_vendor, target_os = get_target_platform_folder(d).split('-')

    _map = {
        "AR": d.expand("${AR}"),
        "arch": d.expand("${RUBYPLATFORM}"),
        "archincludedir": "$(includedir)",
        "archlibdir": "$(libdir)",
        "AS": d.expand("${AS}"),
        "CC": d.expand("${CC}"),
        "CFLAGS": d.expand("${CFLAGS}"),
        "CPP": d.expand("${CPP}"),
        "CPPFLAGS": d.expand("${CPPFLAGS}"),
        "cppflags": d.expand("${CPPFLAGS}"),
        "CROSS_COMPILING": "yes",
        "CXX": d.expand("${CXX}"),
        "CXXFLAGS": d.expand("${CFLAGS}"),
        "DLEXT": d.expand("so.${PV}"),
        "host_alias": "-".join([target_cpu, target_vendor]),
        "host_cpu": target_cpu,
        "host_os": target_os,
        "host": get_target_platform_folder(d),
        "includedir": d.expand("${STAGING_INCDIR}"),
        "LD": d.expand("${LD}"),
        "LDFLAGS": d.expand("${LDFLAGS}"),
        "libdir": d.getVar("STAGING_LIBDIR"),
        "libexecdir": "$(exec_prefix)/libexec",
        "NM": d.expand("${NM}"),
        "OBJDUMP": d.expand("${OBJDUMP}"),
        "RANLIB": d.expand("${RANLIB}"),
        "SOEXT": d.expand("so.${PV}"),
        "STRIP": d.expand("${STRIP}"),
        "target_alias": "-".join([target_cpu, target_vendor]),
        "target_cpu": target_cpu,
        "target_os": target_os,
        "target": get_target_platform_folder(d),
        "TEST_RUNNABLE": "no",
        #"DLDFLAGS": d.expand("${LDFLAGS}"),
    }

    cnt = ""
    for item in d.expand("${RUBYLIB}").split(':'):
        item = os.path.join(item, 'rbconfig.rb')
        if not os.path.isfile(item) or not os.path.exists(item):
            continue
        with open(item) as i:
            cnt = i.read()

        for m in re.finditer(r'^(\s+|\t+)CONFIG\[\"(?P<var>.*)\"\]\s+=\s+\"(?P<value>.*)\"$', cnt, re.MULTILINE):
            if m.group("var") in _map:
                _rpl = '  CONFIG["{}"] = "{}"'.format(m.group("var"), _map[m.group("var")])
                bb.note("Replace {} by {}".format(m.group(0), _rpl))
                cnt = cnt.replace(m.group(0), _rpl)

        with open(item, "w") as o:
            o.write(cnt)
}

do_arch_patch_config[doc] = "patches the correct compiler settings into the cross template"
addtask do_arch_patch_config after do_generate_spec do_gem_unpack before do_compile

rubyv2_do_compile() {
    export GEM_PATH=${GEM_PATH}
    export GEM_HOME=${GEM_HOME}
    export GEM_SPEC=${GEM_SPEC_CACHE}
    export RUBYLIB=${RUBYLIB}

    export LANG="en_US.UTF-8"
    export LANGUAGE="en_US.UTF-8"
    export LC_ALL="en_US.UTF-8"

    if [ -f ${UNPACKDIR}/extconf.rb ]; then
	cp extconf.rb extconf.orig
	cp ${UNPACKDIR}/extconf.rb extconf.rb
    fi

    # Older versions of gem build don't understand -o flag, so try it once more without
    # it, if the command is failing
    gem build -V ${GEM_SPEC_FILE} -o ${GEM_BUILT_FILE} || gem build -V ${GEM_SPEC_FILE}

    # for the install step
    do_generate_spec
}

python do_rubyv2_fix_libs() {
    # as ruby dynloader expects the shared .so files
    # without extension we will create symlinks to the
    # properly versioned file
    for root, dirs, files in os.walk(d.expand("${GEM_HOME}")):
        for f in files:
            if f.endswith(d.expand("so.${PV}")):
                _filename = os.path.basename(f)
                while "." in _filename:
                    try:
                        os.symlink(os.path.basename(f), os.path.join(root, _filename))
                    except:
                        pass
                    _filename, _ = os.path.splitext(_filename)
}

RUBY_INSTALL_EXTRA_FLAGS ?= ""

rubyv2_do_install() {
    export GEM_PATH=${GEM_PATH}
    export GEM_SPEC=${GEM_SPEC_CACHE}
    export RUBYLIB=${RUBYLIB}

    gem uninstall ${GEM_NAME} --version ${GEM_VERSION} -x -q -V || true

    gem install --local --bindir ${D}${bindir} ${GEM_BUILT_FILE} --install-dir=${GEM_HOME} -E --backtrace --norc --no-user-install --ignore-dependencies --force --conservative -V ${RUBY_INSTALL_EXTRA_FLAGS} -- ${GEM_INSTALL_FLAGS}

    # remove all object files
    find ${GEM_HOME} -name "*.o" -type f -exec rm -f {} \;
}

EXPORT_FUNCTIONS do_compile do_install
do_install[postfuncs] += "do_rubyv2_fix_libs"

PACKAGES =+ "${PN}-examples ${PN}-tests"

FILES:${PN}-dbg += "\
    /usr/src/debug/* \
    ${libdir}/ruby/**/.debug \
"
FILES:${PN}-staticdev += "\
    ${libdir}/ruby/gems/gems/**/.libs/*.a \
"
FILES:${PN}-dev += "\
    ${GEM_DIR}/extensions/*/*/*/gem_make.out \
    ${GEM_DIR}/extensions/*/*/*/mkmf.log \
    ${GEM_DIR}/build_info \
    ${GEM_DIR}/cache \
    ${GEM_DIR}/gems/*/debian.template \
    ${GEM_DIR}/gems/*/ext/ \
    ${GEM_DIR}/gems/*/spec/ \
    ${GEM_DIR}/gems/*/lib/generators \
    ${GEM_DIR}/gems/*/patches \
"
FILES:${PN}-tests = "\
    ${GEM_DIR}/gems/*/tests \
    ${GEM_DIR}/gems/*/test \
"
FILES:${PN}-examples = "\
    ${GEM_DIR}/gems/*/example \
    ${GEM_DIR}/gems/*/samples \
"
FILES:${PN}-doc += "\
    ${GEM_DIR}/gems/*/doc \
    ${GEM_DIR}/doc \
"
FILES:${PN} += "\
    ${GEM_DIR}/extensions \
    ${GEM_DIR}/gems \
    ${GEM_DIR}/specifications \
    ${RUBY_SITEDIR} \
    ${libdir}/ruby/gems/${GEMLIB_VERSION}/plugins \
"

RDEPENDS:${PN}:append:class-target = " ruby ${EXTRA_RDEPENDS}"
RDEPENDS:${PN}-tests:append:class-target = " ruby"

# the ruby dynamic linker just uses plain .so files
# so we have to supply symlinks as part of the base package
INSANE_SKIP:${PN} += "dev-so"
# sadly the shared objects also contain some hard coded
# host paths, which are not easy to be removed
INSANE_SKIP:${PN} += "buildpaths"
# we don't care what is actually needed for the dev-package
INSANE_SKIP:${PN}-dev += "file-rdeps"
# same issue for the dev package with buildpaths
INSANE_SKIP:${PN}-dev += "buildpaths"
# some of the doc utils contain host specific full paths
# as they are mostly in binary format we are just going to
# ignore it here
INSANE_SKIP:${PN}-doc += "buildpaths"