1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

Imports Ruby's port to NativeClient (a.k.a NaCl).

Patch by Google Inc. [ruby-core:45073].

* configure.in (RUBY_NACL): New M4 func to configure variables for
  NaCl.
  (RUBY_NACL_CHECK_PEPPER_TYPES): New M4 func to check the old names
  of Pepper interface types.
  (BTESTRUBY): New variable to specify which ruby should be run on
  "make btest". NaCl can run the built binary by sel_ldr, but it need
  rbconfig.rb. So this variable is distinguished from $MINIRUBY.
  
* thread_pthread.c: Disabled some features on NaCl.

* io.c: ditto.

* process.c: ditto.

* signal.c: ditto.

* file.c: ditto.

* missing/flock.c: ditto.

* nacl/pepper_main.c: An example implementation of Pepper application
  that embeds Ruby.

* nacl/example.html: An example of web page that uses the Pepper
  application.

* nacl/nacl-config.rb: Detects variants of NaCl SDK.

* nacl/GNUmakefile.in: Makefile template for NaCl specific build
  process.

* nacl/package.rb: script for packaging a NaCl-Ruby embedding
  application. 

* nacl/reate_nmf.rb: Wrapper script of create_nmf.py

* dln.c (dln_load): Added a hack to call on NaCl.

* util.c (ruby_getcwd): Path to the current directort is not available
  on NaCl.



git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@35672 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
yugui 2012-05-17 02:48:59 +00:00
parent 0a7aada5d1
commit 76bc2d1ed7
37 changed files with 1855 additions and 36 deletions

View file

@ -1,6 +1,53 @@
Thu May 17 11:33:07 2012 Yuki Yugui Sonoda <yugui@google.com>
Imports Ruby's port to NativeClient (a.k.a NaCl).
Patch by Google Inc. [ruby-core:45073].
* configure.in (RUBY_NACL): New M4 func to configure variables for
NaCl.
(RUBY_NACL_CHECK_PEPPER_TYPES): New M4 func to check the old names
of Pepper interface types.
(BTESTRUBY): New variable to specify which ruby should be run on
"make btest". NaCl can run the built binary by sel_ldr, but it need
rbconfig.rb. So this variable is distinguished from $MINIRUBY.
* thread_pthread.c: Disabled some features on NaCl.
* io.c: ditto.
* process.c: ditto.
* signal.c: ditto.
* file.c: ditto.
* missing/flock.c: ditto.
* nacl/pepper_main.c: An example implementation of Pepper application
that embeds Ruby.
* nacl/example.html: An example of web page that uses the Pepper
application.
* nacl/nacl-config.rb: Detects variants of NaCl SDK.
* nacl/GNUmakefile.in: Makefile template for NaCl specific build
process.
* nacl/package.rb: script for packaging a NaCl-Ruby embedding
application.
* nacl/reate_nmf.rb: Wrapper script of create_nmf.py
* dln.c (dln_load): Added a hack to call on NaCl.
* util.c (ruby_getcwd): Path to the current directort is not available
on NaCl.
Thu May 17 10:54:58 2012 Nobuyoshi Nakada <nobu@ruby-lang.org> Thu May 17 10:54:58 2012 Nobuyoshi Nakada <nobu@ruby-lang.org>
* ext/tk/extconf.rb: add -l options to $libs not $LDFLAGS, to be * ext/tk/extconf.rb: add -l options to $libs not $LDFLAGS,
to be
passed to EXTLIBS in exts.mk. passed to EXTLIBS in exts.mk.
* enc/encinit.c.erb: use %-lines to adjust indent in the generated file. * enc/encinit.c.erb: use %-lines to adjust indent in the generated file.

View file

@ -90,6 +90,8 @@ MINIRUBY = @MINIRUBY@\
$(MINIRUBYOPT) $(MINIRUBYOPT)
RUNRUBY = @RUNRUBY@ $(RUNRUBYOPT) -- $(RUN_OPTS) RUNRUBY = @RUNRUBY@ $(RUNRUBYOPT) -- $(RUN_OPTS)
XRUBY = @XRUBY@ XRUBY = @XRUBY@
BTESTRUBY = @BTESTRUBY@\
$(MINIRUBYOPT)
INSTALL = @INSTALL@ INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@ INSTALL_DATA = @INSTALL_DATA@
INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_SCRIPT = @INSTALL_SCRIPT@

View file

@ -472,7 +472,7 @@ check-ruby: test test-ruby
btest: $(TEST_RUNNABLE)-btest btest: $(TEST_RUNNABLE)-btest
no-btest: PHONY no-btest: PHONY
yes-btest: miniruby$(EXEEXT) PHONY yes-btest: miniruby$(EXEEXT) PHONY
$(BOOTSTRAPRUBY) "$(srcdir)/bootstraptest/runner.rb" --ruby="$(MINIRUBY)" $(OPTS) $(BOOTSTRAPRUBY) "$(srcdir)/bootstraptest/runner.rb" --ruby="$(BTESTRUBY)" $(OPTS)
btest-ruby: $(TEST_RUNNABLE)-btest-ruby btest-ruby: $(TEST_RUNNABLE)-btest-ruby
no-btest-ruby: PHONY no-btest-ruby: PHONY

View file

@ -51,6 +51,79 @@ target_cpu=x64
]) ])
]) ])
AC_DEFUN([RUBY_NACL],
[
AS_CASE(["${host_os}"],
[nacl], [
ac_cv_exeext=.nexe
host_vendor=chromium
ac_cv_host=chromium
AC_MSG_CHECKING([wheather \$NACL_SDK_ROOT is set])
if test x"${NACL_SDK_ROOT}" = x; then
AC_MSG_RESULT([no])
AC_MSG_ERROR([You need to set \$NACL_SDK_ROOT environment variable to build for NativeClient])
fi
AC_MSG_RESULT([yes])
nacl_cv_build_variant=glibc
AC_ARG_WITH(newlib,
AS_HELP_STRING([--with-newlib], [uses newlib version of NativeClient SDK]),
[AS_CASE([$withval],
[no], [nacl_cv_build_variant=glibc],
[yes], [nacl_cv_build_variant=newlib])])
AS_CASE(["$build_cpu"],
[x86_64|i?86], [nacl_cv_cpu_nick=x86], [nacl_cv_cpu_nick=$build_cpu])
AS_CASE(["$build_os"],
[linux*], [nacl_cv_os_nick=linux],
[darwin*], [nacl_cv_os_nick=mac],
[cygwin*|mingw*], [nacl_cv_os_nick=win],
[nacl_cv_os_nick=$build_os])
host="$host_cpu-chromium-$host_os-"
ac_tool_prefix="$host_cpu-nacl-"
AC_MSG_CHECKING([NativeClient toolchain])
if test -d \
"${NACL_SDK_ROOT}/toolchain/${nacl_cv_os_nick}_${nacl_cv_cpu_nick}_${nacl_cv_build_variant}"; then
NACL_TOOLCHAIN="${nacl_cv_os_nick}_${nacl_cv_cpu_nick}_${nacl_cv_build_variant}"
else
AS_CASE(
["${nacl_cv_build_variant}"],
[glibc], [if test \
-d "${NACL_SDK_ROOT}/toolchain/${nacl_cv_os_nick}_${nacl_cv_cpu_nick}_newlib" \
-a -d "${NACL_SDK_ROOT}/toolchain/${nacl_cv_os_nick}_${nacl_cv_cpu_nick}"; then
NACL_TOOLCHAIN="${nacl_cv_os_nick}_${nacl_cv_cpu_nick}"
fi],
[newlib], [ NACL_TOOLCHAIN="${nacl_cv_os_nick}_${nacl_cv_cpu_nick}" ])
fi
if test ! -e "${NACL_SDK_ROOT}/toolchain/${NACL_TOOLCHAIN}/${ac_tool_prefix}gcc"; then
if test "${build_cpu}" = i686 -a -e "${NACL_SDK_ROOT}/toolchain/${NACL_TOOLCHAIN}/nacl-gcc"; then
ac_tool_prefix=nacl-
fi
if test "${build_cpu}" = x86_64 -a -e "${NACL_SDK_ROOT}/toolchain/${NACL_TOOLCHAIN}/nacl-gcc"; then
ac_tool_prefix=nacl64-
fi
fi
if test -z "${NACL_TOOLCHAIN}"; then
AC_MSG_ERROR([Unrecognized --host and --build combination or NaCl SDK is not installed])
fi
PATH="${PATH}:${NACL_SDK_ROOT}/toolchain/${NACL_TOOLCHAIN}/bin"
AC_MSG_RESULT(${NACL_TOOLCHAIN})
AC_SUBST(NACL_TOOLCHAIN)
AC_SUBST(NACL_SDK_ROOT)
AC_SUBST(NACL_SDK_VARIANT, nacl_cv_build_variant)
])])
AC_DEFUN([RUBY_NACL_CHECK_PEPPER_TYPES],
[
AC_CHECK_TYPES([struct PPB_Core, struct PPB_Messaging, struct PPB_Var,
struct PPB_URLLoader, struct PPB_URLRequestInfo,
struct PPB_URLResponseInfo, struct PPB_FileRef,
struct PPP_Instance])
])
AC_DEFUN([RUBY_CPPOUTFILE], AC_DEFUN([RUBY_CPPOUTFILE],
[AC_CACHE_CHECK(whether ${CPP} accepts -o, rb_cv_cppoutfile, [AC_CACHE_CHECK(whether ${CPP} accepts -o, rb_cv_cppoutfile,
[cppflags=$CPPFLAGS [cppflags=$CPPFLAGS
@ -283,6 +356,7 @@ if test -z "${CXXFLAGS+set}"; then
cxxflags="$cxxflags "'${optflags} ${debugflags} ${warnflags}' cxxflags="$cxxflags "'${optflags} ${debugflags} ${warnflags}'
fi fi
RUBY_NACL
if test x"${build}" != x"${host}"; then if test x"${build}" != x"${host}"; then
AC_CHECK_TOOL(CC, gcc) AC_CHECK_TOOL(CC, gcc)
fi fi
@ -377,6 +451,7 @@ AC_SUBST(MAKEDIRS)
AC_CHECK_PROGS(DOT, dot) AC_CHECK_PROGS(DOT, dot)
AC_CHECK_PROGS(DOXYGEN, doxygen) AC_CHECK_PROGS(DOXYGEN, doxygen)
AS_CASE(["${host_os}"], [nacl], [AC_PATH_PROG(PYTHON, python)])
AC_CHECK_PROG(PKG_CONFIG, pkg-config, [pkg-config], [], [], AC_CHECK_PROG(PKG_CONFIG, pkg-config, [pkg-config], [], [],
[`"$as_dir/$ac_word$ac_exec_ext" --print-errors --version > /dev/null 2>&1 || echo "$as_dir/$ac_word$ac_exec_ext"`]) [`"$as_dir/$ac_word$ac_exec_ext" --print-errors --version > /dev/null 2>&1 || echo "$as_dir/$ac_word$ac_exec_ext"`])
@ -509,7 +584,7 @@ if test "$GCC" = yes; then
# -fstack-protector # -fstack-protector
AS_CASE(["$target_os"], AS_CASE(["$target_os"],
[mingw*], [ [mingw*|nacl], [
stack_protector=no stack_protector=no
], ],
[ [
@ -1135,6 +1210,14 @@ main()
], ],
[superux*], [ ac_cv_func_setitimer=no [superux*], [ ac_cv_func_setitimer=no
], ],
[nacl], [
LIBS="-lm -lnosys $LIBS"
if test "${nacl_cv_build_variant}" = "newlib"; then
RUBY_APPEND_OPTION(CPPFLAGS, -DNACL_NEWLIB)
else
RUBY_APPEND_OPTION(XCFLAGS, -fPIC)
fi
],
[ LIBS="-lm $LIBS"]) [ LIBS="-lm $LIBS"])
AC_CHECK_LIB(crypt, crypt) AC_CHECK_LIB(crypt, crypt)
AC_CHECK_LIB(dl, dlopen) # Dynamic linking for SunOS/Solaris and SYSV AC_CHECK_LIB(dl, dlopen) # Dynamic linking for SunOS/Solaris and SYSV
@ -1201,6 +1284,9 @@ AC_CHECK_MEMBERS([struct stat.st_ctimensec])
AC_CHECK_TYPES([struct timespec], [], [], [@%:@ifdef HAVE_TIME_H AC_CHECK_TYPES([struct timespec], [], [], [@%:@ifdef HAVE_TIME_H
@%:@include <time.h> @%:@include <time.h>
@%:@endif
@%:@ifdef HAVE_SYS_TIME_H
@%:@include <sys/time.h>
@%:@endif]) @%:@endif])
AC_CHECK_TYPES([struct timezone], [], [], [@%:@ifdef HAVE_TIME_H AC_CHECK_TYPES([struct timezone], [], [], [@%:@ifdef HAVE_TIME_H
@ -1263,6 +1349,8 @@ RUBY_DEFINT(intptr_t, void*)
RUBY_DEFINT(uintptr_t, void*, unsigned) RUBY_DEFINT(uintptr_t, void*, unsigned)
RUBY_DEFINT(ssize_t, size_t, [], [@%:@include <sys/types.h>]) dnl may differ from int, so not use AC_TYPE_SSIZE_T. RUBY_DEFINT(ssize_t, size_t, [], [@%:@include <sys/types.h>]) dnl may differ from int, so not use AC_TYPE_SSIZE_T.
RUBY_NACL_CHECK_PEPPER_TYPES
AC_CACHE_CHECK(for stack end address, rb_cv_stack_end_address, AC_CACHE_CHECK(for stack end address, rb_cv_stack_end_address,
[rb_cv_stack_end_address=no [rb_cv_stack_end_address=no
for addr in __libc_stack_end _SEND; do for addr in __libc_stack_end _SEND; do
@ -1451,11 +1539,11 @@ AC_CHECK_FUNCS(fmod killpg wait4 waitpid fork spawnv syscall __syscall chroot ge
getpgrp setpgrp getpgid setpgid initgroups getgroups setgroups\ getpgrp setpgrp getpgid setpgid initgroups getgroups setgroups\
getpriority getrlimit setrlimit sysconf close getpwnam_r getgrnam_r\ getpriority getrlimit setrlimit sysconf close getpwnam_r getgrnam_r\
dlopen sigprocmask sigaction sigsetjmp _setjmp _longjmp\ dlopen sigprocmask sigaction sigsetjmp _setjmp _longjmp\
setsid telldir seekdir fchmod cosh sinh tanh log2 round\ setsid telldir seekdir fchmod cosh sinh tanh log2 round llabs\
setuid setgid daemon select_large_fdset setenv unsetenv\ setuid setgid daemon select_large_fdset setenv unsetenv\
mktime timegm gmtime_r clock_gettime gettimeofday poll ppoll\ mktime timegm gmtime_r clock_gettime gettimeofday poll ppoll\
pread sendfile shutdown sigaltstack dl_iterate_phdr\ pread sendfile shutdown sigaltstack dl_iterate_phdr\
dup3 pipe2 posix_memalign memalign) dup3 pipe2 posix_memalign memalign ioctl)
AC_CACHE_CHECK(for unsetenv returns a value, rb_cv_unsetenv_return_value, AC_CACHE_CHECK(for unsetenv returns a value, rb_cv_unsetenv_return_value,
[AC_TRY_COMPILE([ [AC_TRY_COMPILE([
@ -1917,7 +2005,8 @@ if test x"$enable_pthread" = xyes; then
pthread_getattr_np pthread_attr_get_np pthread_attr_getstack\ pthread_getattr_np pthread_attr_get_np pthread_attr_getstack\
pthread_get_stackaddr_np pthread_get_stacksize_np \ pthread_get_stackaddr_np pthread_get_stacksize_np \
thr_stksegment pthread_stackseg_np pthread_getthrds_np \ thr_stksegment pthread_stackseg_np pthread_getthrds_np \
pthread_condattr_setclock pthread_sigmask) pthread_cond_initialize pthread_condattr_setclock pthread_condattr_init \
pthread_sigmask)
fi fi
if test x"$ac_cv_header_ucontext_h" = xyes; then if test x"$ac_cv_header_ucontext_h" = xyes; then
if test x"$rb_with_pthread" = xyes; then if test x"$rb_with_pthread" = xyes; then
@ -2034,11 +2123,14 @@ if test "$rb_cv_binary_elf" = yes; then
if test "$with_dln_a_out" = yes; then if test "$with_dln_a_out" = yes; then
AC_MSG_ERROR(dln_a_out does not work with ELF) AC_MSG_ERROR(dln_a_out does not work with ELF)
fi fi
AC_CHECK_HEADERS([elf.h elf_abi.h])
if test $ac_cv_header_elf_h = yes -o $ac_cv_header_elf_abi_h = yes; then
AC_LIBOBJ([addr2line]) AC_LIBOBJ([addr2line])
fi
fi fi
AS_CASE(["$target_os"], AS_CASE(["$target_os"],
[linux* | gnu* | k*bsd*-gnu | bsdi* | kopensolaris*-gnu], [ [linux* | gnu* | k*bsd*-gnu | bsdi* | kopensolaris*-gnu | nacl], [
if test "$rb_cv_binary_elf" = no; then if test "$rb_cv_binary_elf" = no; then
with_dln_a_out=yes with_dln_a_out=yes
else else
@ -2218,6 +2310,7 @@ if test "$with_dln_a_out" != yes; then
rb_cv_dlopen=yes], rb_cv_dlopen=yes],
[os2-emx*], [ LDFLAGS="$LDFLAGS -Zomf" [os2-emx*], [ LDFLAGS="$LDFLAGS -Zomf"
], ],
[nacl], [ LDSHARED='$(CC) -shared' ],
[ : ${LDSHARED='$(LD)'}]) [ : ${LDSHARED='$(LD)'}])
AC_MSG_RESULT($rb_cv_dlopen) AC_MSG_RESULT($rb_cv_dlopen)
fi fi
@ -2342,6 +2435,9 @@ AS_CASE(["$target_os"],
[*djgpp*], [ [*djgpp*], [
setup=Setup.dj setup=Setup.dj
], ],
[nacl], [
setup=Setup.nacl
],
[ [
setup=Setup setup=Setup
]) ])
@ -2352,6 +2448,7 @@ if test "$prefix" = NONE; then
prefix=$ac_default_prefix prefix=$ac_default_prefix
fi fi
BTESTRUBY='$(MINIRUBY)'
if test x"$cross_compiling" = xyes; then if test x"$cross_compiling" = xyes; then
test x"$MINIRUBY" = x && MINIRUBY="${RUBY-$BASERUBY} -I`pwd` "-r'$(arch)-fake' test x"$MINIRUBY" = x && MINIRUBY="${RUBY-$BASERUBY} -I`pwd` "-r'$(arch)-fake'
XRUBY_LIBDIR=`${RUBY-$BASERUBY} -rrbconfig -e ['puts RbConfig::CONFIG["libdir"]']` XRUBY_LIBDIR=`${RUBY-$BASERUBY} -rrbconfig -e ['puts RbConfig::CONFIG["libdir"]']`
@ -2364,6 +2461,20 @@ if test x"$cross_compiling" = xyes; then
RUNRUBY='$(MINIRUBY) -I`cd $(srcdir)/lib; pwd`' RUNRUBY='$(MINIRUBY) -I`cd $(srcdir)/lib; pwd`'
XRUBY='$(MINIRUBY)' XRUBY='$(MINIRUBY)'
TEST_RUNNABLE=no TEST_RUNNABLE=no
if test "$host_os" = "nacl"; then
if test "$build_cpu" = "$host_cpu" || test "${nacl_cv_cpu_nick}" = "x86" -a "$host_cpu" = "i686"; then
nacl_cv_sel_ldr='`$(MINIRUBY) $(srcdir)/nacl/nacl-config.rb sel_ldr`'
nacl_cv_irt_core='`$(MINIRUBY) $(srcdir)/nacl/nacl-config.rb irt_core`'
nacl_cv_runnable_ld='`$(MINIRUBY) $(srcdir)/nacl/nacl-config.rb runnable_ld`'
nacl_cv_host_lib='`$(MINIRUBY) $(srcdir)/nacl/nacl-config.rb host_lib`'
TEST_RUNNABLE=yes
BTESTRUBY="${nacl_cv_sel_ldr} -a -B ${nacl_cv_irt_core} -w 1:3 -w 2:4"
BTESTRUBY="$BTESTRUBY -- ${nacl_cv_runnable_ld} --library-path ${nacl_cv_host_lib}"
BTESTRUBY="$BTESTRUBY `pwd`/"'miniruby$(EXEEXT) -I`cd $(srcdir)/lib; pwd` -I.'
BTESTRUBY="$BTESTRUBY"' -I$(EXTOUT)/common 3>&1 4>&2 1>/dev/null 2>/dev/null '
fi
fi
else else
MINIRUBY='./miniruby$(EXEEXT) -I$(srcdir)/lib -I.' MINIRUBY='./miniruby$(EXEEXT) -I$(srcdir)/lib -I.'
MINIRUBY="$MINIRUBY"' -I$(EXTOUT)/common' MINIRUBY="$MINIRUBY"' -I$(EXTOUT)/common'
@ -2374,6 +2485,7 @@ else
fi fi
AC_SUBST(TEST_RUNNABLE) AC_SUBST(TEST_RUNNABLE)
AC_SUBST(MINIRUBY) AC_SUBST(MINIRUBY)
AC_SUBST(BTESTRUBY)
AC_SUBST(PREP) AC_SUBST(PREP)
AC_SUBST(RUNRUBY) AC_SUBST(RUNRUBY)
AC_SUBST(XRUBY) AC_SUBST(XRUBY)
@ -2600,6 +2712,7 @@ AC_CACHE_CHECK([for prefix of external symbols], rb_cv_symbol_prefix, [
SYMBOL_PREFIX="$rb_cv_symbol_prefix" SYMBOL_PREFIX="$rb_cv_symbol_prefix"
test "x$SYMBOL_PREFIX" = xNONE && SYMBOL_PREFIX='' test "x$SYMBOL_PREFIX" = xNONE && SYMBOL_PREFIX=''
MINIDLNOBJ=dmydln.o MINIDLNOBJ=dmydln.o
AS_CASE(["$target_os"], AS_CASE(["$target_os"],
[linux*], [ [linux*], [
], ],
@ -2679,7 +2792,10 @@ AS_CASE(["$target_os"],
AS_CASE(["$YACC"],[*yacc*], [ AS_CASE(["$YACC"],[*yacc*], [
XCFLAGS="$XCFLAGS -DYYMAXDEPTH=300" XCFLAGS="$XCFLAGS -DYYMAXDEPTH=300"
YACC="$YACC -Nl40000 -Nm40000" YACC="$YACC -Nl40000 -Nm40000"
])]) ])],
[nacl], [
FIRSTMAKEFILE=GNUmakefile:nacl/GNUmakefile.in
])
MINIOBJS="$MINIDLNOBJ" MINIOBJS="$MINIDLNOBJ"
AS_CASE(["$THREAD_MODEL"], AS_CASE(["$THREAD_MODEL"],

4
dir.c
View file

@ -44,6 +44,10 @@
# include "win32/dir.h" # include "win32/dir.h"
# endif # endif
#endif #endif
#if defined(__native_client__) && defined(NACL_NEWLIB)
# include "nacl/dirent.h"
# include "nacl/stat.h"
#endif
#include <errno.h> #include <errno.h>

15
dln.c
View file

@ -1318,13 +1318,28 @@ dln_load(const char *file)
# define RTLD_GLOBAL 0 # define RTLD_GLOBAL 0
#endif #endif
#ifdef __native_client__
char* p, *orig;
if (file[0] == '.' && file[1] == '/') file+=2;
orig = strdup(file);
for (p = file; *p; ++p) {
if (*p == '/') *p = '_';
}
#endif
/* Load file */ /* Load file */
if ((handle = (void*)dlopen(file, RTLD_LAZY|RTLD_GLOBAL)) == NULL) { if ((handle = (void*)dlopen(file, RTLD_LAZY|RTLD_GLOBAL)) == NULL) {
#ifdef __native_client__
free(orig);
#endif
error = dln_strerror(); error = dln_strerror();
goto failed; goto failed;
} }
init_fct = (void(*)())(VALUE)dlsym(handle, buf); init_fct = (void(*)())(VALUE)dlsym(handle, buf);
#ifdef __native_client__
strcpy(file, orig);
free(orig);
#endif
#if defined __SYMBIAN32__ #if defined __SYMBIAN32__
if (init_fct == NULL) { if (init_fct == NULL) {
init_fct = (void(*)())dlsym(handle, "1"); /* Some Symbian versions do not support symbol table in DLL, ordinal numbers only */ init_fct = (void(*)())dlsym(handle, "1"); /* Some Symbian versions do not support symbol table in DLL, ordinal numbers only */

50
ext/Setup.nacl Normal file
View file

@ -0,0 +1,50 @@
# #option nodynamic
#
# #Win32API
# bigdecimal
# continuation
# coverage
# #curses
# date
# #dbm
# digest/bubblebabble
# digest
# digest/md5
# digest/rmd160
# digest/sha1
# digest/sha2
# dl
# dl/callback
# #dl/win32
# etc
# fcntl
# fiber
# #fiddle
# #gdbm
# #iconv
# io/console
# io/nonblock
# io/wait
# #json
# json/generator
# json/parser
# mathn/complex
# mathn/rational
# nkf
# objspace
# #openssl
# pathname
# #psych
# #pty
# racc/cparse
# #readline
# ripper
# #sdbm
# #socket
# stringio
# strscan
# syck
# #syslog
# #tk
# #tk/tkutil
# #zlib

View file

@ -530,7 +530,7 @@ unless $extlist.empty?
list = $extlist.dup list = $extlist.dup
built = [] built = []
while e = list.shift while e = list.shift
s,t,i,r = e s,t,i,r,os = e
if r and !(r -= built).empty? if r and !(r -= built).empty?
l = list.size l = list.size
if (while l > 0; break true if r.include?(list[l-=1][1]) end) if (while l > 0; break true if r.include?(list[l-=1][1]) end)

View file

@ -1,6 +1,6 @@
require 'mkmf' require 'mkmf'
if /mswin|mingw|bccwin/ !~ RUBY_PLATFORM if /mswin|mingw|bccwin|nacl/ !~ RUBY_PLATFORM
have_header("sys/stropts.h") have_header("sys/stropts.h")
have_func("setresuid") have_func("setresuid")
have_header("libutil.h") have_header("libutil.h")

22
file.c
View file

@ -60,6 +60,13 @@ int flock(int, int);
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#if defined(__native_client__) && defined(NACL_NEWLIB)
# include "nacl/utime.h"
# include "nacl/stat.h"
# include "nacl/unistd.h"
#endif
#ifdef HAVE_SYS_MKDEV_H #ifdef HAVE_SYS_MKDEV_H
#include <sys/mkdev.h> #include <sys/mkdev.h>
#endif #endif
@ -3358,7 +3365,11 @@ realpath_rec(long *prefixlenp, VALUE *resolvedp, const char *unresolved, VALUE l
struct stat sbuf; struct stat sbuf;
int ret; int ret;
VALUE testpath2 = rb_str_encode_ospath(testpath); VALUE testpath2 = rb_str_encode_ospath(testpath);
#ifdef __native_client__
ret = stat(RSTRING_PTR(testpath2), &sbuf);
#else
ret = lstat(RSTRING_PTR(testpath2), &sbuf); ret = lstat(RSTRING_PTR(testpath2), &sbuf);
#endif
if (ret == -1) { if (ret == -1) {
if (errno == ENOENT) { if (errno == ENOENT) {
if (strict || !last || *unresolved_firstsep) if (strict || !last || *unresolved_firstsep)
@ -3403,6 +3414,13 @@ realpath_rec(long *prefixlenp, VALUE *resolvedp, const char *unresolved, VALUE l
} }
} }
#ifdef __native_client__
VALUE
rb_realpath_internal(VALUE basedir, VALUE path, int strict)
{
return path;
}
#else
VALUE VALUE
rb_realpath_internal(VALUE basedir, VALUE path, int strict) rb_realpath_internal(VALUE basedir, VALUE path, int strict)
{ {
@ -3476,6 +3494,7 @@ rb_realpath_internal(VALUE basedir, VALUE path, int strict)
OBJ_TAINT(resolved); OBJ_TAINT(resolved);
return resolved; return resolved;
} }
#endif
/* /*
* call-seq: * call-seq:
@ -5142,6 +5161,9 @@ rb_path_check(const char *path)
} }
#ifndef _WIN32 #ifndef _WIN32
#ifdef __native_client__
__attribute__((noinline))
#endif
int int
rb_file_load_ok(const char *path) rb_file_load_ok(const char *path)
{ {

6
gc.c
View file

@ -32,6 +32,12 @@
#ifdef HAVE_SYS_RESOURCE_H #ifdef HAVE_SYS_RESOURCE_H
#include <sys/resource.h> #include <sys/resource.h>
#endif
#if defined(__native_client__) && defined(NACL_NEWLIB)
# include "nacl/resource.h"
# undef HAVE_POSIX_MEMALIGN
# undef HAVE_MEMALIGN
#endif #endif
#if defined _WIN32 || defined __CYGWIN__ #if defined _WIN32 || defined __CYGWIN__

4
gc.h
View file

@ -2,9 +2,9 @@
#ifndef RUBY_GC_H #ifndef RUBY_GC_H
#define RUBY_GC_H 1 #define RUBY_GC_H 1
#if defined(__x86_64__) && defined(__GNUC__) #if defined(__x86_64__) && defined(__GNUC__) && !defined(__native_client__)
#define SET_MACHINE_STACK_END(p) __asm__("movq\t%%rsp, %0" : "=r" (*(p))) #define SET_MACHINE_STACK_END(p) __asm__("movq\t%%rsp, %0" : "=r" (*(p)))
#elif defined(__i386) && defined(__GNUC__) #elif defined(__i386) && defined(__GNUC__) && !defined(__native_client__)
#define SET_MACHINE_STACK_END(p) __asm__("movl\t%%esp, %0" : "=r" (*(p))) #define SET_MACHINE_STACK_END(p) __asm__("movl\t%%esp, %0" : "=r" (*(p)))
#else #else
NOINLINE(void rb_gc_set_stack_end(VALUE **stack_end_p)); NOINLINE(void rb_gc_set_stack_end(VALUE **stack_end_p));

28
io.c
View file

@ -28,7 +28,9 @@
#if defined HAVE_NET_SOCKET_H #if defined HAVE_NET_SOCKET_H
# include <net/socket.h> # include <net/socket.h>
#elif defined HAVE_SYS_SOCKET_H #elif defined HAVE_SYS_SOCKET_H
# ifndef __native_client__
# include <sys/socket.h> # include <sys/socket.h>
# endif
#endif #endif
#if defined(__BOW__) || defined(__CYGWIN__) || defined(_WIN32) || defined(__EMX__) || defined(__BEOS__) || defined(__HAIKU__) #if defined(__BOW__) || defined(__CYGWIN__) || defined(_WIN32) || defined(__EMX__) || defined(__BEOS__) || defined(__HAIKU__)
@ -47,6 +49,9 @@
#if defined(HAVE_SYS_IOCTL_H) && !defined(_WIN32) #if defined(HAVE_SYS_IOCTL_H) && !defined(_WIN32)
#include <sys/ioctl.h> #include <sys/ioctl.h>
#endif #endif
#if defined(__native_client__) && defined(NACL_NEWLIB)
# include "nacl/ioctl.h"
#endif
#if defined(HAVE_FCNTL_H) || defined(_WIN32) #if defined(HAVE_FCNTL_H) || defined(_WIN32)
#include <fcntl.h> #include <fcntl.h>
#elif defined(HAVE_SYS_FCNTL_H) #elif defined(HAVE_SYS_FCNTL_H)
@ -161,7 +166,7 @@ void
rb_maygvl_fd_fix_cloexec(int fd) rb_maygvl_fd_fix_cloexec(int fd)
{ {
/* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */ /* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */
#ifdef F_GETFD #if defined(F_GETFD) && !defined(__native_client__)
int flags, flags2, ret; int flags, flags2, ret;
flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */ flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */
if (flags == -1) { if (flags == -1) {
@ -187,7 +192,6 @@ rb_fd_fix_cloexec(int fd)
if (max_file_descriptor < fd) max_file_descriptor = fd; if (max_file_descriptor < fd) max_file_descriptor = fd;
} }
int int
rb_cloexec_open(const char *pathname, int flags, mode_t mode) rb_cloexec_open(const char *pathname, int flags, mode_t mode)
{ {
@ -1502,6 +1506,7 @@ rb_io_set_pos(VALUE io, VALUE offset)
static void clear_readconv(rb_io_t *fptr); static void clear_readconv(rb_io_t *fptr);
#if defined(HAVE_FSYNC) || !defined(_WIN32)
/* /*
* call-seq: * call-seq:
* ios.rewind -> 0 * ios.rewind -> 0
@ -1540,6 +1545,7 @@ rb_io_rewind(VALUE io)
return INT2FIX(0); return INT2FIX(0);
} }
#endif
static int static int
io_fillbuf(rb_io_t *fptr) io_fillbuf(rb_io_t *fptr)
@ -1629,6 +1635,7 @@ rb_io_eof(VALUE io)
return Qfalse; return Qfalse;
} }
#ifdef HAVE_FSYNC
/* /*
* call-seq: * call-seq:
* ios.sync -> true or false * ios.sync -> true or false
@ -1683,8 +1690,6 @@ rb_io_set_sync(VALUE io, VALUE sync)
return sync; return sync;
} }
#ifdef HAVE_FSYNC
/* /*
* call-seq: * call-seq:
* ios.fsync -> 0 or nil * ios.fsync -> 0 or nil
@ -1709,14 +1714,19 @@ rb_io_fsync(VALUE io)
if (io_fflush(fptr) < 0) if (io_fflush(fptr) < 0)
rb_sys_fail(0); rb_sys_fail(0);
#ifndef _WIN32 /* already called in io_fflush() */ # ifndef _WIN32 /* already called in io_fflush() */
if ((int)rb_thread_io_blocking_region(nogvl_fsync, fptr, fptr->fd) < 0) if ((int)rb_thread_io_blocking_region(nogvl_fsync, fptr, fptr->fd) < 0)
rb_sys_fail_path(fptr->pathv); rb_sys_fail_path(fptr->pathv);
#endif # endif
return INT2FIX(0); return INT2FIX(0);
} }
#else #else
#define rb_io_fsync rb_f_notimplement # define rb_io_fsync rb_f_notimplement
# define rb_io_sync rb_f_notimplement
static VALUE rb_io_set_sync(VALUE io, VALUE sync) {
rb_notimplement();
/* NEVER REACHED */ return Qundef;
}
#endif #endif
#ifdef HAVE_FDATASYNC #ifdef HAVE_FDATASYNC
@ -8200,10 +8210,10 @@ rb_f_select(int argc, VALUE *argv, VALUE obj)
#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
typedef unsigned long ioctl_req_t; typedef unsigned long ioctl_req_t;
#define NUM2IOCTLREQ(num) NUM2ULONG(num) # define NUM2IOCTLREQ(num) NUM2ULONG(num)
#else #else
typedef int ioctl_req_t; typedef int ioctl_req_t;
#define NUM2IOCTLREQ(num) NUM2INT(num) # define NUM2IOCTLREQ(num) NUM2INT(num)
#endif #endif
struct ioctl_arg { struct ioctl_arg {

1
iseq.c
View file

@ -1548,4 +1548,3 @@ Init_ISeq(void)
rb_define_singleton_method(rb_cISeq, "disasm", iseq_s_disasm, 1); rb_define_singleton_method(rb_cISeq, "disasm", iseq_s_disasm, 1);
rb_define_singleton_method(rb_cISeq, "disassemble", iseq_s_disasm, 1); rb_define_singleton_method(rb_cISeq, "disassemble", iseq_s_disasm, 1);
} }

View file

@ -1,7 +1,8 @@
#include "ruby/config.h" #include "ruby/config.h"
#include "ruby/ruby.h"
#if defined _WIN32 #if defined _WIN32
#elif defined HAVE_FCNTL && defined HAVE_FCNTL_H #elif defined HAVE_FCNTL && defined HAVE_FCNTL_H && !defined(__native_client__)
/* These are the flock() constants. Since this sytems doesn't have /* These are the flock() constants. Since this sytems doesn't have
flock(), the values of the constants are probably not available. flock(), the values of the constants are probably not available.

60
nacl/GNUmakefile.in Normal file
View file

@ -0,0 +1,60 @@
# Copyright 2012 Google Inc. All Rights Reserved.
# Author: yugui@google.com (Yugui Sonoda)
include Makefile
-include uncommon.mk
NACL_SDK_ROOT=@NACL_SDK_ROOT@
NACL_TOOLCHAIN=@NACL_TOOLCHAIN@
NACL_TOOLCHAIN_DIR=$(NACL_SDK_ROOT)/toolchain/$(NACL_TOOLCHAIN)
PATH+=:$(NACL_TOOLCHAIN_DIR)/bin
PYTHON=@PYTHON@
PPROGRAM=pepper-$(PROGRAM)
PEPPER_LIBS=-lppapi
PROGRAM_NMF=$(PROGRAM:.nexe=.nmf)
PPROGRAM_NMF=$(PPROGRAM:.nexe=.nmf)
GNUmakefile: $(srcdir)/nacl/GNUmakefile.in
$(PPROGRAM): $(PROGRAM) pepper_main.$(OBJEXT)
$(Q)$(MAKE) $(MFLAGS) PROGRAM=$(PPROGRAM) MAINOBJ="pepper_main.$(OBJEXT)" LIBS="$(LIBS) $(PEPPER_LIBS)" program
$(PROGRAM_NMF) $(PPROGRAM_NMF): $(@:.nmf=.nexe) nacl/create_nmf.rb
.PHONY: pprogram package show_naclflags
.SUFFIXES: .nexe .nmf
.nexe.nmf:
$(ECHO) generating manifest $@
$(Q)$(MINIRUBY) $(srcdir)/nacl/create_nmf.rb --verbose=$(V) $(@:.nmf=.nexe) $@
pepper_main.$(OBJEXT): $(srcdir)/nacl/pepper_main.c
@$(ECHO) compiling nacl/pepper_main.c
$(Q) $(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) $(COUTFLAG)$@ -c $(srcdir)/nacl/pepper_main.c
ruby.$(OBJEXT):
@$(ECHO) compiling $<
$(Q) $(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) $(COUTFLAG)$@.tmp -c $<
$(Q) $(OBJCOPY) --weaken-symbol=rb_load_file $@.tmp $@
@-$(RM) $@.tmp
file.$(OBJEXT):
@$(ECHO) compiling $<
$(Q) $(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) $(COUTFLAG)$@.tmp -c $<
$(Q) $(OBJCOPY) --weaken-symbol=rb_file_load_ok $@.tmp $@
@-$(RM) $@.tmp
all: pprogram
main: $(PROGRAM_NMF)
pprogram: showflags $(PPROGRAM) $(PPROGRAM_NMF)
program: $(PROGRAM_NMF)
prog: pprogram
package: pprogram install-lib install-ext-comm install-ext-arch
$(ECHO) generating manifest $@
$(Q)$(MINIRUBY) $(srcdir)/nacl/package.rb $(prefix)
showflags: show_naclflags
show_naclflags:
@echo " PATH = $(PATH)"
@echo " NACL_SDK_ROOT = $(NACL_SDK_ROOT)"
clean-local::
-$(RM) $(PPROGRAM) pepper_main.$(OBJEXT) $(PROGRAM_NMF) $(PPRGORAM_NMF)

34
nacl/README.nacl Normal file
View file

@ -0,0 +1,34 @@
=begin
= Native Client port of Ruby
= How to build
== Prerequisites
You need to install the following things before building NaCl port of Ruby.
* Ruby 1.9.3 or later
* Python 2.6 or later
* NativeClient SDK pepper 18 or later
* GNU make
== Steps
(1) Extract all files from the tarball:
$ tar xzf ruby-X.Y.Z.tar.gz
(2) Set NACL_SDK_ROOT environment vairanble to the path to the Native Client SDK you installed:
$ export NACL_SDK_ROOT=/home/yugui/src/nacl_sdk/pepper_16
(3) Configure
$ ./configure --prefix=/tmp/nacl-ruby --host=x86_64-nacl --with-baseruby=/path/to/ruby-1.9.3
(4) Make
$ make
$ make package
Now you have ruby.nexe. You can run it by sel_ldr in NaCl SDK.
"make package" installs "pepper-ruby.nexe", an example Pepper application that
embeds Ruby", and libraries to $prefix. You can run it by the following steps:
(5) Publish the $prefix directory on a web server
(6) Visit the example.html on the web server by a browser that implements Pepper 18 or later.
-- e.g., Chrome 18 implements Pepper 18, Chrome 19 implements Pepper 19, ...
= Copyright
* Copyright 2012 Google Inc. All Rights Reserved.
* Author: yugui@google.com (Yugui Sonoda)
=end

70
nacl/create_nmf.rb Normal file
View file

@ -0,0 +1,70 @@
#!/usr/bin/ruby
# Copyright:: Copyright 2012 Google Inc.
# License:: All Rights Reserved.
# Original Author:: Yugui Sonoda (mailto:yugui@google.com)
#
# Wrapper for create_nmf.py / generate_nmf.py
require File.join(File.dirname(__FILE__), 'nacl-config')
include NaClConfig
$verbosity = 0
def usage_and_exit
$stderr.puts "Usage: #{$PROGRAM_NAME} [--verbose=N] path/to/input.nexe path/to/output.nmf"
exit false
end
def create_dynamically_linked(nmf, exe)
cmd = [
PYTHON, CREATE_NMF,
'-o', nmf,
'-D', OBJDUMP,
'-L', HOST_LIB,
exe
]
puts cmd.join(' ') if $verbosity > 0
exec(*cmd)
end
def create_statically_linked(nmf, exe)
File.open(nmf, "w") {|f|
f.write <<-EOS.gsub(/^ {6}/, '')
{
"program": {
"#{ARCH}": {
"url": "#{exe}"
}
}
}
EOS
}
end
def main
while m = ARGV.first.match(/--([a-z-]+)(?:=(\S+))?/)
case m[1]
when 'verbose'
usage_and_exit unless m[2][/\A[0-9]+\z/]
$verbosity = m[2].to_i
when 'help'
usage_end_exit
end
ARGV.shift
end
usage_and_exit if ARGV.size < 2
exe, nmf = ARGV[0], ARGV[1]
if newlib?
create_statically_linked(nmf, exe)
else
create_dynamically_linked(nmf, exe)
end
end
if __FILE__ == $0
main()
end

15
nacl/dirent.h Normal file
View file

@ -0,0 +1,15 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
* Author: yugui@google.com (Yugui Sonoda)
*/
#ifndef RUBY_NACL_DIRENT_H
#define RUBY_NACL_DIRENT_H
/* NaCl SDK 0.3 has implementations of dir functions but no declaration in
* dirent.h */
int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
void rewinddir(DIR *dirp);
long telldir(DIR *dirp);
void seekdir(DIR *dirp, long offset);
#endif

150
nacl/example.html Normal file
View file

@ -0,0 +1,150 @@
<!DOCTYPE html>
<html>
<head>
<title>Ruby Example</title>
<script type="text/javascript">
RubyModule = null; // Global application object.
statusText = 'NO-STATUS';
rubyReady = false;
// Indicate load success.
function moduleDidLoad() {
RubyModule = document.getElementById('ruby');
form = document.getElementById('source-form');
form.style.display = "block";
updateStatus('SUCCESS');
}
function evalSource() {
if (rubyReady) {
RubyModule.postMessage('eval:' + document.getElementById("source").value);
} else {
throw "Not yet ready";
}
return false;
}
function RubyError(message) {
this.message = message;
this.toString = function() {
return message;
}
}
function FatalError(message) {
this.message = message;
}
// The 'message' event handler. This handler is fired when the NaCl module
// posts a message to the browser by calling PPB_Messaging.PostMessage()
// (in C) or pp::Instance.PostMessage() (in C++). This implementation
// simply displays the content of the message in an alert panel.
function handleMessage(message_event) {
var raw = message_event.data;
var components;
if (raw.indexOf("error") == 0) {
components = raw.split(":", 2);
throw new RubyError(components[1]);
} else if (raw.indexOf("return") == 0) {
components = raw.split(":", 2);
document.getElementById("result").value = components[1];
} else if (raw == "rubyReady") {
rubyReady = true;
} else {
throw new FatalError(raw);
}
}
// If the page loads before the Native Client module loads, then set the
// status message indicating that the module is still loading. Otherwise,
// do not change the status message.
function pageDidLoad() {
if (RubyModule == null) {
updateStatus('LOADING...');
} else {
// It's possible that the Native Client module onload event fired
// before the page's onload event. In this case, the status message
// will reflect 'SUCCESS', but won't be displayed. This call will
// display the current message.
updateStatus();
}
}
// Set the global status message. If the element with id 'statusField'
// exists, then set its HTML to the status message as well.
// opt_message The message test. If this is null or undefined, then
// attempt to set the element with id 'statusField' to the value of
// |statusText|.
function updateStatus(opt_message) {
if (opt_message)
statusText = opt_message;
var statusField = document.getElementById('status_field');
if (statusField) {
statusField.innerHTML = statusText;
}
}
</script>
</head>
<body onload="pageDidLoad()">
<h1>Native Client Module Ruby</h1>
<p>
<!-- Load the published .nexe. This includes the 'nacl' attribute which
shows how to load multi-architecture modules. Each entry in the "nexes"
object in the .nmf manifest file is a key-value pair: the key is the
instruction set architecture ('x86-32', 'x86-64', etc.); the value is a URL
for the desired NaCl module.
To load the debug versions of your .nexes, set the 'nacl' attribute to the
_dbg.nmf version of the manifest file.
Note: Since this NaCl module does not use any real-estate in the browser,
it's width and height are set to 0.
Note: The <EMBED> element is wrapped inside a <DIV>, which has both a 'load'
and a 'message' event listener attached. This wrapping method is used
instead of attaching the event listeners directly to the <EMBED> element to
ensure that the listeners are active before the NaCl module 'load' event
fires. This also allows you to use PPB_Messaging.PostMessage() (in C) or
pp::Instance.PostMessage() (in C++) from within the initialization code in
your NaCl module.
-->
<div id="listener">
<script type="text/javascript">
var listener = document.getElementById('listener');
listener.addEventListener('load', moduleDidLoad, true);
listener.addEventListener('message', handleMessage, true);
</script>
<embed name="nacl_module"
id="ruby"
width="0" height="0"
src="ruby.nmf"
type="application/x-nacl" />
<form id="source-form" action="#" method="post" style="display:none"
onsubmit="evalSource(); return false">
<table>
<tbody>
<tr>
<th>Source</th>
<td>
<textarea rows="10" cols="80" id="source"></textarea>
<input type="submit" />
</td>
</tr>
<tr>
<th>Result</th>
<td>
<textarea rows="10" cols="80" id="result"></textarea>
</td>
</tr>
</tbody>
</table>
</form>
</div>
</p>
<h2>Status</h2>
<div id="status_field">NO-STATUS</div>
</body>
</html>

7
nacl/ioctl.h Normal file
View file

@ -0,0 +1,7 @@
// Copyright 2012 Google Inc. All Rights Reserved.
// Author: yugui@google.com (Yugui Sonoda)
#ifndef RUBY_NACL_IOCTL_H
#define RUBY_NACL_IOCTL_H
int ioctl(int fd, int request, ...);
struct flock{};
#endif

61
nacl/nacl-config.rb Normal file
View file

@ -0,0 +1,61 @@
#!/usr/bin/ruby
#
# Copyright:: Copyright 2012 Google Inc.
# License:: All Rights Reserved.
# Original Author:: Yugui Sonoda (mailto:yugui@google.com)
#
# Convenient functions/constants for native client specific configurations.
require 'rbconfig'
module NaClConfig
config = RbConfig::CONFIG
cpu_nick = config['host_alias'].sub(/-gnu$|-newlib$/, '').sub(/-nacl$/, '')
ARCH = cpu_nick.sub('x86_64', 'x86-64').sub(/i.86/, 'x86-32')
HOST = ARCH.sub(/x86-../, 'x86_64') + '-nacl'
lib_suffix = config['host_cpu'][/i.86/] ? '32' : ''
PYTHON = config['PYTHON']
OBJDUMP = config['OBJDUMP']
SDK_ROOT = config['NACL_SDK_ROOT']
CREATE_NMF = [
File.join(SDK_ROOT, 'build_tools', 'nacl_sdk_scons', 'site_tools', 'create_nmf.py'),
File.join(SDK_ROOT, 'tools', 'create_nmf.py')
].find{|path| File.exist?(path) }
HOST_LIB = File.join(SDK_ROOT, 'toolchain', config['NACL_TOOLCHAIN'], HOST, "lib#{lib_suffix}")
INSTALL_PROGRAM = config['INSTALL_PROGRAM']
INSTALL_LIBRARY = config['INSTALL_DATA']
SEL_LDR = [
File.join(SDK_ROOT, 'toolchain', config['NACL_TOOLCHAIN'], 'bin', "sel_ldr_#{cpu_nick}"),
File.join(SDK_ROOT, 'tools', "sel_ldr_#{cpu_nick}")
].find{|path| File.executable?(path)}
IRT_CORE = [
File.join(SDK_ROOT, 'toolchain', config['NACL_TOOLCHAIN'], 'bin', "irt_core_#{cpu_nick}.nexe"),
File.join(SDK_ROOT, 'tools', "irt_core_#{cpu_nick}.nexe")
].find{|path| File.executable?(path)}
RUNNABLE_LD = File.join(HOST_LIB, 'runnable-ld.so')
module_function
def newlib?
RbConfig::CONFIG['NACL_SDK_VARIANT'] == 'newlib'
end
def self.config(name)
if NaClConfig::const_defined?(name.upcase)
NaClConfig::const_get(name.upcase)
elsif NaClConfig::respond_to?(name) and NaClConfig::method(name).arity == 0
NaClConfig::send(name)
else
raise ArgumentError, "No such config: #{name}"
end
end
end
if $0 == __FILE__
ARGV.each do |arg|
puts NaClConfig::config(arg)
end
end

109
nacl/package.rb Normal file
View file

@ -0,0 +1,109 @@
#!/usr/bin/ruby
# Copyright:: Copyright 2012 Google Inc.
# License:: All Rights Reserved.
# Original Author:: Yugui Sonoda (mailto:yugui@google.com)
#
# Generates a runnable package of the pepper API example.
require File.join(File.dirname(__FILE__), 'nacl-config')
require 'json'
require 'find'
require 'fileutils'
include NaClConfig
class Installation
include NaClConfig
SRC_DIRS = [ Dir.pwd, HOST_LIB ]
def initialize(destdir)
@destdir = destdir
@manifest = {
"files" => {}
}
ruby_libs.each do |path|
raise "Collision of #{path}" if @manifest['files'].key? path
@manifest['files'][path] = {
ARCH => {
"url" => path
}
}
if path[/\.so$/]
alternate_path = path.gsub('/', "_")
raise "Collision of #{alternate_path}" if @manifest['files'].key? alternate_path
@manifest['files'][alternate_path] = {
ARCH => {
"url" => path
}
}
end
end
end
def manifest
@manifest.dup
end
def install_program(basename)
do_install_binary(basename, File.join(@destdir, "bin", ARCH))
@manifest["program"] = {
ARCH => {
"url" => File.join("bin", ARCH, basename)
}
}
end
def install_library(name, basename)
do_install_binary(basename, File.join(@destdir, "lib", ARCH))
@manifest["files"][name] = {
ARCH => {
"url" => File.join("lib", ARCH, basename)
}
}
end
private
def do_install_binary(basename, dest_dir)
full_path = nil
catch(:found) {
SRC_DIRS.each do |path|
full_path = File.join(path, basename)
if File.exist? full_path
throw :found
end
end
raise Errno::ENOENT, "No such file to install: %s" % basename
}
FileUtils.mkdir_p dest_dir
system("#{INSTALL_PROGRAM} #{full_path} #{dest_dir}")
end
def ruby_libs
Find.find(RbConfig::CONFIG['rubylibdir']).select{|path| File.file?(path) }.map{|path| path.sub("#{@destdir}/", "") }
end
end
def install(destdir)
inst = Installation.new(destdir)
manifest = JSON.parse(File.read("pepper-ruby.nmf"))
program = File.basename(manifest['program'][ARCH]['url'])
inst.install_program(program)
manifest['files'].each do |name, attr|
inst.install_library(name, File.basename(attr[ARCH]["url"]))
end
File.open(File.join(destdir, "ruby.nmf"), "w") {|f|
f.puts JSON.pretty_generate(inst.manifest)
}
end
def main
install(ARGV[0])
end
if __FILE__ == $0
main()
end

924
nacl/pepper_main.c Normal file
View file

@ -0,0 +1,924 @@
/******************************************************************************
Copyright 2012 Google Inc. All Rights Reserved.
Author: yugui@google.com (Yugui Sonoda)
******************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include "ppapi/c/pp_errors.h"
#include "ppapi/c/pp_module.h"
#include "ppapi/c/pp_var.h"
#include "ppapi/c/ppb.h"
#include "ppapi/c/ppb_core.h"
#include "ppapi/c/ppb_file_ref.h"
#include "ppapi/c/ppb_instance.h"
#include "ppapi/c/ppb_messaging.h"
#include "ppapi/c/ppb_url_loader.h"
#include "ppapi/c/ppb_url_request_info.h"
#include "ppapi/c/ppb_url_response_info.h"
#include "ppapi/c/ppb_var.h"
#include "ppapi/c/ppp.h"
#include "ppapi/c/ppp_instance.h"
#include "ppapi/c/ppp_messaging.h"
#include "ruby/ruby.h"
#include "vm_core.h"
#include "eval_intern.h"
#include "gc.h"
#include "node.h"
RUBY_GLOBAL_SETUP
#ifdef HAVE_STRUCT_PPB_CORE
typedef struct PPB_Core PPB_Core;
#endif
#ifdef HAVE_STRUCT_PPB_MESSAGING
typedef struct PPB_Messaging PPB_Messaging;
#endif
#ifdef HAVE_STRUCT_PPB_VAR
typedef struct PPB_Var PPB_Var;
#endif
#ifdef HAVE_STRUCT_PPB_URLLOADER
typedef struct PPB_URLLoader PPB_URLLoader;
#endif
#ifdef HAVE_STRUCT_PPB_URLREQUESTINFO
typedef struct PPB_URLRequestInfo PPB_URLRequestInfo;
#endif
#ifdef HAVE_STRUCT_PPB_URLRESPONSEINFO
typedef struct PPB_URLResponseInfo PPB_URLResponseInfo;
#endif
#ifdef HAVE_STRUCT_PPP_INSTANCE
typedef struct PPP_Instance PPP_Instance;
#endif
static PP_Module module_id = 0;
static PPB_Core* core_interface = NULL;
static PPB_Messaging* messaging_interface = NULL;
static PPB_Var* var_interface = NULL;
static PPB_URLLoader* loader_interface = NULL;
static PPB_URLRequestInfo* request_interface = NULL;
static PPB_URLResponseInfo* response_interface = NULL;
static PPB_FileRef* fileref_interface = NULL;
static struct st_table* instance_data = NULL;
static VALUE instance_table = Qundef;
static PP_Instance current_instance = 0;
/******************************************************************************
* State of instance
******************************************************************************/
static void inst_mark(void *const ptr);
static void inst_free(void *const ptr);
static size_t inst_memsize(void *const ptr);
static const rb_data_type_t pepper_instance_data_type = {
"PepperInstance",
{ inst_mark, inst_free, inst_memsize }
};
struct PepperInstance {
PP_Instance instance;
PP_Resource url_loader;
VALUE self;
void* async_call_args;
union {
int32_t as_int;
const char* as_str;
VALUE as_value;
} async_call_result;
char buf[1000];
pthread_t th;
pthread_mutex_t mutex;
pthread_cond_t cond;
};
struct PepperInstance*
pruby_get_instance(PP_Instance instance)
{
VALUE self = rb_hash_aref(instance_table, INT2FIX(instance));
if (RTEST(self)) {
struct PepperInstance *inst;
TypedData_Get_Struct(self, struct PepperInstance, &pepper_instance_data_type, inst);
return inst;
}
else {
return NULL;
}
}
#define GET_PEPPER_INSTANCE() (pruby_get_instance(current_instance))
struct PepperInstance*
pruby_register_instance(PP_Instance instance)
{
VALUE obj;
struct PepperInstance *data;
obj = TypedData_Make_Struct(rb_cData, struct PepperInstance, &pepper_instance_data_type, data);
data->self = obj;
data->instance = instance;
data->url_loader = 0;
pthread_mutex_init(&data->mutex, NULL);
pthread_cond_init(&data->cond, NULL);
rb_hash_aset(instance_table, INT2FIX(instance), obj);
return data;
}
int
pruby_unregister_instance(PP_Instance instance)
{
VALUE inst = rb_hash_delete(instance_table, INT2FIX(instance));
return RTEST(inst);
}
static void
inst_mark(void *const ptr)
{
RUBY_MARK_ENTER("PepperInstance"0);
if (ptr) {
const struct PepperInstance* inst = (struct PepperInstance*)ptr;
RUBY_MARK_UNLESS_NULL(inst->async_call_result.as_value);
}
RUBY_MARK_LEAVE("PepperInstance"0);
}
static void
inst_free(void *const ptr)
{
ruby_xfree(ptr);
}
static size_t
inst_memsize(void *const ptr)
{
if (ptr) {
const struct PepperInstance* inst = (struct PepperInstance*)ptr;
return sizeof(*inst);
} else {
return 0;
}
}
void
pruby_async_return_int(void* data, int32_t result)
{
/* PPAPI main thread */
struct PepperInstance* const instance = (struct PepperInstance*)data;
instance->async_call_result.as_int = result;
if (pthread_cond_signal(&instance->cond)) {
perror("pepper-ruby:pthread_cond_signal");
}
}
void
pruby_async_return_str(void* data, const char *result)
{
/* PPAPI main thread */
struct PepperInstance* const instance = (struct PepperInstance*)data;
instance->async_call_result.as_str = result;
if (pthread_cond_signal(&instance->cond)) {
perror("pepper-ruby:pthread_cond_signal");
}
}
void
pruby_async_return_value(void* data, VALUE value)
{
/* PPAPI main thread */
struct PepperInstance* const instance = (struct PepperInstance*)data;
instance->async_call_result.as_value = value;
if (pthread_cond_signal(&instance->cond)) {
perror("pepper-ruby:pthread_cond_signal");
}
}
/******************************************************************************
* Conversion between Ruby's VALUE, Pepper's Var and C string
******************************************************************************/
/**
* Creates a new string PP_Var from C string. The resulting object will be a
* refcounted string object. It will be AddRef()ed for the caller. When the
* caller is done with it, it should be Release()d.
* @param[in] str C string to be converted to PP_Var
* @return PP_Var containing string.
*/
static struct PP_Var
pruby_cstr_to_var(const char* str)
{
#ifdef PPB_VAR_INTERFACE_1_0
if (var_interface != NULL)
return var_interface->VarFromUtf8(module_id, str, strlen(str));
return PP_MakeUndefined();
#else
return var_interface->VarFromUtf8(str, strlen(str));
#endif
}
/**
* Returns a mutable C string contained in the @a var or NULL if @a var is not
* string. This makes a copy of the string in the @a var and adds a NULL
* terminator. Note that VarToUtf8() does not guarantee the NULL terminator on
* the returned string. See the comments for VarToUtf8() in ppapi/c/ppb_var.h
* for more info. The caller is responsible for freeing the returned memory.
* @param[in] var PP_Var containing string.
* @return a mutable C string representation of @a var.
* @note The caller is responsible for freeing the returned string.
*/
static char*
pruby_var_to_cstr(struct PP_Var var)
{
uint32_t len = 0;
if (var_interface != NULL) {
const char* var_c_str = var_interface->VarToUtf8(var, &len);
if (len > 0) {
char* c_str = (char*)malloc(len + 1);
memcpy(c_str, var_c_str, len);
c_str[len] = '\0';
return c_str;
}
}
return NULL;
}
static struct PP_Var
pruby_str_to_var(volatile VALUE str)
{
if (!RB_TYPE_P(str, T_STRING)) {
fprintf(stderr, "[BUG] Unexpected object type: %x\n", TYPE(str));
exit(EXIT_FAILURE);
}
#ifdef PPB_VAR_INTERFACE_1_0
if (var_interface != NULL) {
return var_interface->VarFromUtf8(module_id, RSTRING_PTR(str), RSTRING_LEN(str));
}
#else
return var_interface->VarFromUtf8(RSTRING_PTR(str), RSTRING_LEN(str));
#endif
return PP_MakeUndefined();
}
static struct PP_Var
pruby_obj_to_var(volatile VALUE obj)
{
static const char* const error =
"throw 'Failed to convert the result to a JavaScript object';";
int state;
PUSH_TAG();
if ((state = EXEC_TAG()) == 0) {
obj = rb_obj_as_string(obj);
}
POP_TAG();
switch (state) {
case 0:
return pruby_str_to_var(obj);
case TAG_RAISE:
rb_set_errinfo(Qnil);
return pruby_cstr_to_var(error);
default:
fprintf(stderr, "Fatal error white converting the result to a string\n");
exit(EXIT_FAILURE);
}
}
int
pruby_var_equal_to_cstr_p(struct PP_Var lhs, const char* rhs)
{
uint32_t len = 0;
if (var_interface == NULL) {
return 0;
}
else {
const char* const cstr = var_interface->VarToUtf8(lhs, &len);
return strncmp(cstr, rhs, len) == 0;
}
}
int
pruby_var_prefixed_p(struct PP_Var var, const char* prefix)
{
uint32_t len = 0;
if (var_interface == NULL) {
return 0;
}
else {
const char* const cstr = var_interface->VarToUtf8(var, &len);
const size_t prefix_len = strlen(prefix);
return len >= prefix_len && memcmp(cstr, prefix, len) == 0;
}
}
/******************************************************************************
* Messaging
******************************************************************************/
/* Posts the given C string as a message.
* @param data pointer to a NULL-terminated string */
void
pruby_post_cstr(void* data)
{
/* PPAPI main thread */
struct PepperInstance* const instance = (struct PepperInstance*)data;
const char* const msg = (const char*)instance->async_call_args;
messaging_interface->PostMessage(instance->instance,
pruby_cstr_to_var(msg));
}
/* Posts the given Ruby VALUE as a message.
* @param data a VALUE casted to void* */
void
pruby_post_value(void* data)
{
/* PPAPI main thread */
struct PepperInstance* const instance = (struct PepperInstance*)data;
volatile VALUE value = (VALUE)instance->async_call_args;
messaging_interface->PostMessage(instance->instance, pruby_obj_to_var(value));
}
/******************************************************************************
* Ruby initialization
******************************************************************************/
static void
init_loadpath(void)
{
volatile VALUE path;
VALUE load_path = GET_VM()->load_path;
path = rb_usascii_str_new_cstr("lib/ruby/2.0.0");
rb_ary_push(load_path, path);
path = rb_usascii_str_new_cstr("lib/ruby/2.0.0/x86_64-nacl");
rb_ary_push(load_path, path);
path = rb_usascii_str_new_cstr(".");
rb_ary_push(load_path, path);
}
static void*
init_libraries(void* data)
{
extern void Init_enc();
extern void Init_ext();
int state;
struct PepperInstance* const instance = (struct PepperInstance*)data;
current_instance = instance->instance;
if (pthread_mutex_lock(&instance->mutex)) {
perror("pepper-ruby:pthread_mutex_lock");
return 0;
}
PUSH_TAG();
if ((state = EXEC_TAG()) == 0) {
init_loadpath();
Init_enc();
Init_ext();
}
POP_TAG();
pthread_mutex_unlock(&instance->mutex);
if (state) {
volatile VALUE err = rb_errinfo();
err = rb_obj_as_string(err);
} else {
instance->async_call_args = "rubyReady";
core_interface->CallOnMainThread(
0, PP_MakeCompletionCallback(pruby_post_cstr, instance), 0);
}
return NULL;
}
static int
init_libraries_if_necessary(void)
{
static int initialized = 0;
if (!initialized) {
struct PepperInstance* const instance = GET_PEPPER_INSTANCE();
int err;
initialized = 1;
err = pthread_create(&instance->th, NULL, &init_libraries, instance);
if (err) {
fprintf(stderr, "pepper_ruby:pthread_create: %s\n", strerror(err));
exit(EXIT_FAILURE);
}
pthread_detach(instance->th);
}
return 0;
}
static int
pruby_init(void)
{
RUBY_INIT_STACK;
ruby_init();
instance_table = rb_hash_new();
rb_gc_register_mark_object(instance_table);
return 0;
}
/******************************************************************************
* Ruby evaluation
******************************************************************************/
static void*
pruby_eval(void* data)
{
struct PepperInstance* const instance = (struct PepperInstance*)data;
volatile VALUE src = (VALUE)instance->async_call_args;
volatile VALUE iseq, result = Qnil;
volatile VALUE filename;
NODE* tree;
volatile int state;
rb_thread_t *th;
rb_env_t *env;
RUBY_INIT_STACK;
PUSH_TAG();
if (pthread_mutex_lock(&instance->mutex)) {
perror("pepper-ruby:pthread_mutex_lock");
return 0;
}
if ((state = EXEC_TAG()) == 0) {
th = GET_THREAD();
SAVE_ROOT_JMPBUF(th, {
th->mild_compile_error++;
tree = rb_compile_string("(pepper-ruby)", src, 1);
th->mild_compile_error--;
if (RTEST(rb_errinfo())) {
rb_exc_raise(rb_errinfo());
}
{
VALUE toplevel_binding = rb_const_get(rb_cObject, rb_intern("TOPLEVEL_BINDING"));
rb_binding_t *bind;
GetBindingPtr(toplevel_binding, bind);
GetEnvPtr(bind->env, env);
}
filename = rb_usascii_str_new("(pepper-ruby)", strlen("(pepper-ruby)"));
th->parse_in_eval--;
th->base_block = &env->block;
iseq = rb_iseq_new_main(tree, filename, filename);
th->parse_in_eval++;
th->base_block = 0;
result = rb_iseq_eval_main(iseq);
});
}
POP_TAG();
pthread_mutex_unlock(&instance->mutex);
switch (state) {
case 0:
instance->async_call_args =
rb_str_concat(rb_usascii_str_new_cstr("return:"),
rb_obj_as_string(result));
core_interface->CallOnMainThread(
0, PP_MakeCompletionCallback(pruby_post_value, instance), 0);
return NULL;
case TAG_RAISE:
result = rb_errinfo();
rb_set_errinfo(Qnil);
instance->async_call_args =
rb_str_concat(rb_usascii_str_new_cstr("error:"),
rb_obj_as_string(result));
core_interface->CallOnMainThread(
0, PP_MakeCompletionCallback(pruby_post_value, instance), 0);
return NULL;
default:
fprintf(stderr, "Fatal error\n");
exit(EXIT_FAILURE);
}
}
/******************************************************************************
* Pepper Module callbacks
******************************************************************************/
/**
* Called when the NaCl module is instantiated on the web page. The identifier
* of the new instance will be passed in as the first argument (this value is
* generated by the browser and is an opaque handle). This is called for each
* instantiation of the NaCl module, which is each time the <embed> tag for
* this module is encountered.
*
* If this function reports a failure (by returning @a PP_FALSE), the NaCl
* module will be deleted and DidDestroy will be called.
* @param[in] instance The identifier of the new instance representing this
* NaCl module.
* @param[in] argc The number of arguments contained in @a argn and @a argv.
* @param[in] argn An array of argument names. These argument names are
* supplied in the <embed> tag, for example:
* <embed id="nacl_module" dimensions="2">
* will produce two arguments, one named "id" and one named "dimensions".
* @param[in] argv An array of argument values. These are the values of the
* arguments listed in the <embed> tag. In the above example, there will
* be two elements in this array, "nacl_module" and "2". The indices of
* these values match the indices of the corresponding names in @a argn.
* @return @a PP_TRUE on success.
*/
static PP_Bool
Instance_DidCreate(PP_Instance instance,
uint32_t argc, const char* argn[], const char* argv[])
{
struct PepperInstance* data = pruby_register_instance(instance);
current_instance = instance;
return init_libraries_if_necessary() ? PP_FALSE : PP_TRUE;
}
/**
* Called when the NaCl module is destroyed. This will always be called,
* even if DidCreate returned failure. This routine should deallocate any data
* associated with the instance.
* @param[in] instance The identifier of the instance representing this NaCl
* module.
*/
static void Instance_DidDestroy(PP_Instance instance) {
struct PepperInstance* data = pruby_get_instance(instance);
core_interface->ReleaseResource(data->url_loader);
pruby_unregister_instance(instance);
}
/**
* Called when the position, the size, or the clip rect of the element in the
* browser that corresponds to this NaCl module has changed.
* @param[in] instance The identifier of the instance representing this NaCl
* module.
* @param[in] position The location on the page of this NaCl module. This is
* relative to the top left corner of the viewport, which changes as the
* page is scrolled.
* @param[in] clip The visible region of the NaCl module. This is relative to
* the top left of the plugin's coordinate system (not the page). If the
* plugin is invisible, @a clip will be (0, 0, 0, 0).
*/
#ifdef PPP_INSTANCE_INTERFACE_1_0
static void
Instance_DidChangeView(PP_Instance instance,
const struct PP_Rect* position,
const struct PP_Rect* clip)
{
}
#else
static void
Instance_DidChangeView(PP_Instance instance, PP_Resource view_resource)
{
}
#endif
/**
* Notification that the given NaCl module has gained or lost focus.
* Having focus means that keyboard events will be sent to the NaCl module
* represented by @a instance. A NaCl module's default condition is that it
* will not have focus.
*
* Note: clicks on NaCl modules will give focus only if you handle the
* click event. You signal if you handled it by returning @a true from
* HandleInputEvent. Otherwise the browser will bubble the event and give
* focus to the element on the page that actually did end up consuming it.
* If you're not getting focus, check to make sure you're returning true from
* the mouse click in HandleInputEvent.
* @param[in] instance The identifier of the instance representing this NaCl
* module.
* @param[in] has_focus Indicates whether this NaCl module gained or lost
* event focus.
*/
static void
Instance_DidChangeFocus(PP_Instance instance, PP_Bool has_focus)
{
}
/**
* Handler that gets called after a full-frame module is instantiated based on
* registered MIME types. This function is not called on NaCl modules. This
* function is essentially a place-holder for the required function pointer in
* the PPP_Instance structure.
* @param[in] instance The identifier of the instance representing this NaCl
* module.
* @param[in] url_loader A PP_Resource an open PPB_URLLoader instance.
* @return PP_FALSE.
*/
static PP_Bool
Instance_HandleDocumentLoad(PP_Instance instance, PP_Resource url_loader)
{
/* NaCl modules do not need to handle the document load function. */
return PP_FALSE;
}
/**
* Handler for messages coming in from the browser via postMessage. The
* @a var_message can contain anything: a JSON string; a string that encodes
* method names and arguments; etc. For example, you could use JSON.stringify
* in the browser to create a message that contains a method name and some
* parameters, something like this:
* var json_message = JSON.stringify({ "myMethod" : "3.14159" });
* nacl_module.postMessage(json_message);
* On receipt of this message in @a var_message, you could parse the JSON to
* retrieve the method name, match it to a function call, and then call it with
* the parameter.
* @param[in] instance The instance ID.
* @param[in] message The contents, copied by value, of the message sent from
* browser via postMessage.
*/
void
Messaging_HandleMessage(PP_Instance instance, struct PP_Var var_message)
{
char* const message = pruby_var_to_cstr(var_message);
size_t message_len = strlen(message);
current_instance = instance;
if (strstr(message, "eval:") != NULL) {
volatile VALUE src;
struct PepperInstance* const instance_data = GET_PEPPER_INSTANCE();
int err;
#define EVAL_PREFIX_LEN 5
src = rb_str_new(message + EVAL_PREFIX_LEN, message_len - EVAL_PREFIX_LEN);
instance_data->async_call_args = (void*)src;
err = pthread_create(&instance_data->th, NULL, &pruby_eval, instance_data);
if (err) {
fprintf(stderr, "pepper_ruby:pthread_create: %s\n", strerror(err));
exit(EXIT_FAILURE);
}
pthread_detach(instance_data->th);
}
free(message);
}
/**
* Entry points for the module.
* Initialize instance interface and scriptable object class.
* @param[in] a_module_id Module ID
* @param[in] get_browser_interface Pointer to PPB_GetInterface
* @return PP_OK on success, any other value on failure.
*/
PP_EXPORT int32_t
PPP_InitializeModule(PP_Module a_module_id, PPB_GetInterface get_browser_interface)
{
module_id = a_module_id;
core_interface = (PPB_Core*)(get_browser_interface(PPB_CORE_INTERFACE));
if (core_interface == NULL) return PP_ERROR_NOINTERFACE;
var_interface = (PPB_Var*)(get_browser_interface(PPB_VAR_INTERFACE));
if (var_interface == NULL) return PP_ERROR_NOINTERFACE;
messaging_interface = (PPB_Messaging*)(get_browser_interface(PPB_MESSAGING_INTERFACE));
if (messaging_interface == NULL) return PP_ERROR_NOINTERFACE;
loader_interface = (PPB_URLLoader*)(get_browser_interface(PPB_URLLOADER_INTERFACE));
if (loader_interface == NULL) return PP_ERROR_NOINTERFACE;
request_interface = (PPB_URLRequestInfo*)(get_browser_interface(PPB_URLREQUESTINFO_INTERFACE));
if (request_interface == NULL) return PP_ERROR_NOINTERFACE;
response_interface = (PPB_URLResponseInfo*)(get_browser_interface(PPB_URLRESPONSEINFO_INTERFACE));
if (response_interface == NULL) return PP_ERROR_NOINTERFACE;
fileref_interface = (PPB_FileRef*)(get_browser_interface(PPB_FILEREF_INTERFACE));
if (fileref_interface == NULL) return PP_ERROR_NOINTERFACE;
return pruby_init() ? PP_ERROR_FAILED : PP_OK;
}
/**
* Returns an interface pointer for the interface of the given name, or NULL
* if the interface is not supported.
* @param[in] interface_name name of the interface
* @return pointer to the interface
*/
PP_EXPORT const void*
PPP_GetInterface(const char* interface_name)
{
if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0) {
static PPP_Instance instance_interface = {
&Instance_DidCreate,
&Instance_DidDestroy,
&Instance_DidChangeView,
&Instance_DidChangeFocus,
&Instance_HandleDocumentLoad
};
return &instance_interface;
} else if (strcmp(interface_name, PPP_MESSAGING_INTERFACE) == 0) {
static PPP_Messaging messaging_interface = {
&Messaging_HandleMessage
};
return &messaging_interface;
}
return NULL;
}
/**
* Called before the plugin module is unloaded.
*/
PP_EXPORT void
PPP_ShutdownModule()
{
ruby_cleanup(0);
}
/******************************************************************************
* Overwrites rb_file_load_ok
******************************************************************************/
static void
load_ok_internal(void* data, int32_t unused)
{
/* PPAPI main thread */
struct PepperInstance* const instance = (struct PepperInstance*)data;
const char *const path = (const char*)instance->async_call_args;
PP_Resource req;
int result;
instance->url_loader = loader_interface->Create(instance->instance);
req = request_interface->Create(instance->instance);
request_interface->SetProperty(
req, PP_URLREQUESTPROPERTY_METHOD, pruby_cstr_to_var("HEAD"));
request_interface->SetProperty(
req, PP_URLREQUESTPROPERTY_URL, pruby_cstr_to_var(path));
result = loader_interface->Open(
instance->url_loader, req,
PP_MakeCompletionCallback(pruby_async_return_int, instance));
if (result != PP_OK_COMPLETIONPENDING) {
pruby_async_return_int(instance, result);
}
}
static void
pruby_file_fetch_check_response(void* data, int32_t unused)
{
/* PPAPI main thread */
PP_Resource res;
struct PepperInstance* const instance = (struct PepperInstance*)data;
res = loader_interface->GetResponseInfo(instance->url_loader);
if (res) {
struct PP_Var status =
response_interface->GetProperty(res, PP_URLRESPONSEPROPERTY_STATUSCODE);
if (status.type == PP_VARTYPE_INT32) {
pruby_async_return_int(instance, status.value.as_int / 100 == 2 ? PP_OK : PP_ERROR_FAILED);
return;
}
else {
messaging_interface->PostMessage(
instance->instance, pruby_cstr_to_var("Unexpected type: ResponseInfoInterface::GetProperty"));
}
}
else {
messaging_interface->PostMessage(
instance->instance, pruby_cstr_to_var("Failed to open URL: URLLoaderInterface::GetResponseInfo"));
}
pruby_async_return_int(instance, PP_ERROR_FAILED);
}
int
rb_file_load_ok(const char *path)
{
struct PepperInstance* const instance = GET_PEPPER_INSTANCE();
if (path[0] == '.' && path[1] == '/') path += 2;
instance->async_call_args = (void*)path;
core_interface->CallOnMainThread(
0, PP_MakeCompletionCallback(load_ok_internal, instance), 0);
if (pthread_cond_wait(&instance->cond, &instance->mutex)) {
perror("pepper-ruby:pthread_cond_wait");
return 0;
}
if (instance->async_call_result.as_int != PP_OK) {
fprintf(stderr, "Failed to open URL: %d: %s\n",
instance->async_call_result.as_int, path);
return 0;
}
core_interface->CallOnMainThread(
0, PP_MakeCompletionCallback(pruby_file_fetch_check_response, instance), 0);
if (pthread_cond_wait(&instance->cond, &instance->mutex)) {
perror("pepper-ruby:pthread_cond_wait");
return 0;
}
return instance->async_call_result.as_int == PP_OK;
}
/******************************************************************************
* Overwrites rb_load_file
******************************************************************************/
static void
load_file_internal(void* data, int32_t unused)
{
/* PPAPI main thread */
struct PepperInstance* const instance = (struct PepperInstance*)data;
const char *const path = (const char*)instance->async_call_args;
PP_Resource req;
int result;
instance->url_loader = loader_interface->Create(instance->instance);
req = request_interface->Create(instance->instance);
request_interface->SetProperty(
req, PP_URLREQUESTPROPERTY_METHOD, pruby_cstr_to_var("GET"));
request_interface->SetProperty(
req, PP_URLREQUESTPROPERTY_URL, pruby_cstr_to_var(path));
result = loader_interface->Open(
instance->url_loader, req,
PP_MakeCompletionCallback(pruby_async_return_int, instance));
if (result != PP_OK_COMPLETIONPENDING) {
pruby_async_return_int(instance, result);
}
}
static void
load_file_read_contents_callback(void *data, int result)
{
struct PepperInstance* const instance = (struct PepperInstance*)data;
if (result > 0) {
rb_str_buf_cat(instance->async_call_result.as_value,
instance->buf, result);
loader_interface->ReadResponseBody(
instance->url_loader, instance->buf, 1000, PP_MakeCompletionCallback(load_file_read_contents_callback, instance));
}
else if (result == 0) {
pruby_async_return_value(data, instance->async_call_result.as_value);
}
else {
pruby_async_return_value(data, INT2FIX(result));
}
}
static void
load_file_read_contents(void *data, int result)
{
struct PepperInstance* const instance = (struct PepperInstance*)data;
instance->async_call_result.as_value = rb_str_new(0, 0);
loader_interface->ReadResponseBody(
instance->url_loader, instance->buf, 1000, PP_MakeCompletionCallback(load_file_read_contents_callback, instance));
}
void*
rb_load_file(const char *path)
{
const char *real_path;
struct PepperInstance* instance;
if (path[0] != '.' || path[1] != '/') path += 2;
instance = GET_PEPPER_INSTANCE();
instance->async_call_args = (void*)path;
core_interface->CallOnMainThread(
0, PP_MakeCompletionCallback(load_file_internal, instance), 0);
if (pthread_cond_wait(&instance->cond, &instance->mutex)) {
perror("pepper-ruby:pthread_cond_wait");
return 0;
}
if (instance->async_call_result.as_int != PP_OK) {
fprintf(stderr, "Failed to open URL: %d: %s\n",
instance->async_call_result.as_int, path);
return 0;
}
core_interface->CallOnMainThread(
0, PP_MakeCompletionCallback(pruby_file_fetch_check_response, instance), 0);
if (pthread_cond_wait(&instance->cond, &instance->mutex)) {
perror("pepper-ruby:pthread_cond_wait");
return 0;
}
if (instance->async_call_result.as_int != PP_OK) return 0;
core_interface->CallOnMainThread(
0, PP_MakeCompletionCallback(load_file_read_contents, instance), 0);
if (pthread_cond_wait(&instance->cond, &instance->mutex)) {
perror("pepper-ruby:pthread_cond_wait");
return 0;
}
if (FIXNUM_P(instance->async_call_result.as_value)) {
return 0;
}
else if (RB_TYPE_P(instance->async_call_result.as_value, T_STRING)) {
VALUE str = instance->async_call_result.as_value;
return rb_compile_cstr(path, RSTRING_PTR(str), RSTRING_LEN(str), 0);
}
else {
return 0;
}
}

8
nacl/resource.h Normal file
View file

@ -0,0 +1,8 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
* Author: yugui@google.com (Yugui Sonoda)
* */
#ifndef RUBY_NACL_RESOURCE_H
#define RUBY_NACL_RESOURCE_H
int getrusage(int who, struct rusage *usage);
#endif

7
nacl/select.h Normal file
View file

@ -0,0 +1,7 @@
// Copyright 2012 Google Inc. All Rights Reserved.
// Author: yugui@google.com (Yugui Sonoda)
#ifndef RUBY_NACL_SELECT_H
#define RUBY_NACL_SELECT_H
int select(int num_fds, fd_set *in_fds, fd_set *out_fds,
fd_set *ex_fds, struct timeval *timeout);
#endif

6
nacl/signal.h Normal file
View file

@ -0,0 +1,6 @@
// Copyright 2012 Google Inc. All Rights Reserved.
// Author: yugui@google.com (Yugui Sonoda)
#ifndef RUBY_NACL_SIGNAL_H
#define RUBY_NACL_SIGNAL_H
int kill(pid_t pid, int signal);
#endif

10
nacl/stat.h Normal file
View file

@ -0,0 +1,10 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
* Author: yugui@google.com (Yugui Sonoda)
* */
#ifndef RUBY_NACL_STAT_H
#define RUBY_NACL_STAT_H
mode_t umask(mode_t mask);
struct stat;
int lstat(const char* path, struct stat* result);
#endif

9
nacl/unistd.h Normal file
View file

@ -0,0 +1,9 @@
// Copyright 2012 Google Inc. All Rights Reserved.
// Author: yugui@google.com (Yugui Sonoda)
#ifndef RUBY_NACL_UNISTD_H
#define RUBY_NACL_UNISTD_H
int seteuid(pid_t pid);
int setegid(pid_t pid);
int truncate(const char* path, off_t new_size);
int ftruncate(int fd, off_t new_size);
#endif

11
nacl/utime.h Normal file
View file

@ -0,0 +1,11 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
* Author: yugui@google.com (Yugui Sonoda)
*/
#ifndef RUBY_NACL_UTIME_H
#define RUBY_NACL_UTIME_H
#include <utime.h>
int utime(const char *filename, const struct utimbuf *times);
int utimes(const char *filename, const struct timeval times[2]);
#endif

View file

@ -62,6 +62,11 @@
#endif #endif
#include <sys/stat.h> #include <sys/stat.h>
#if defined(__native_client__) && defined(NACL_NEWLIB)
# include "nacl/stat.h"
# include "nacl/unistd.h"
#endif
#ifdef HAVE_SYS_TIMES_H #ifdef HAVE_SYS_TIMES_H
#include <sys/times.h> #include <sys/times.h>
@ -1042,7 +1047,7 @@ security(const char *str)
} }
} }
#ifdef HAVE_FORK #if defined(HAVE_FORK) && !defined(__native_client__)
#define try_with_sh(prog, argv) ((saved_errno == ENOEXEC) ? exec_with_sh((prog), (argv)) : (void)0) #define try_with_sh(prog, argv) ((saved_errno == ENOEXEC) ? exec_with_sh((prog), (argv)) : (void)0)
static void static void
exec_with_sh(const char *prog, char **argv) exec_with_sh(const char *prog, char **argv)
@ -1061,13 +1066,20 @@ exec_with_sh(const char *prog, char **argv)
#define ALLOC_ARGV_WITH_STR(n, v, s, l) \ #define ALLOC_ARGV_WITH_STR(n, v, s, l) \
(char **)(((s) = ALLOCV_N(char, (v), ARGV_SIZE(n) + (l)) + ARGV_SIZE(n)) - ARGV_SIZE(n)) (char **)(((s) = ALLOCV_N(char, (v), ARGV_SIZE(n) + (l)) + ARGV_SIZE(n)) - ARGV_SIZE(n))
#ifdef __native_client__
static int
proc_exec_v(char **argv, const char *prog)
{
rb_notimplement();
}
#else
static int static int
proc_exec_v(char **argv, const char *prog) proc_exec_v(char **argv, const char *prog)
{ {
char fbuf[MAXPATHLEN]; char fbuf[MAXPATHLEN];
#if defined(__EMX__) || defined(OS2) # if defined(__EMX__) || defined(OS2)
char **new_argv = NULL; char **new_argv = NULL;
#endif # endif
if (!prog) if (!prog)
prog = argv[0]; prog = argv[0];
@ -1077,9 +1089,9 @@ proc_exec_v(char **argv, const char *prog)
return -1; return -1;
} }
#if defined(__EMX__) || defined(OS2) # if defined(__EMX__) || defined(OS2)
{ {
#define COMMAND "cmd.exe" # define COMMAND "cmd.exe"
char *extension; char *extension;
if ((extension = strrchr(prog, '.')) != NULL && STRCASECMP(extension, ".bat") == 0) { if ((extension = strrchr(prog, '.')) != NULL && STRCASECMP(extension, ".bat") == 0) {
@ -1104,18 +1116,19 @@ proc_exec_v(char **argv, const char *prog)
} }
} }
} }
#endif /* __EMX__ */ # endif /* __EMX__ */
before_exec(); before_exec();
execv(prog, argv); execv(prog, argv);
preserving_errno(try_with_sh(prog, argv); after_exec()); preserving_errno(try_with_sh(prog, argv); after_exec());
#if defined(__EMX__) || defined(OS2) # if defined(__EMX__) || defined(OS2)
if (new_argv) { if (new_argv) {
xfree(new_argv[0]); xfree(new_argv[0]);
xfree(new_argv); xfree(new_argv);
} }
#endif # endif
return -1; return -1;
} }
#endif
int int
rb_proc_exec_n(int argc, VALUE *argv, const char *prog) rb_proc_exec_n(int argc, VALUE *argv, const char *prog)
@ -1137,6 +1150,13 @@ rb_proc_exec_n(int argc, VALUE *argv, const char *prog)
return ret; return ret;
} }
#ifdef __native_client__
int
rb_proc_exec(const char *str)
{
rb_notimplement();
}
#else
int int
rb_proc_exec(const char *str) rb_proc_exec(const char *str)
{ {
@ -1206,6 +1226,7 @@ rb_proc_exec(const char *str)
return ret; return ret;
#endif /* _WIN32 */ #endif /* _WIN32 */
} }
#endif
enum { enum {
EXEC_OPTION_PGROUP, EXEC_OPTION_PGROUP,

View file

@ -18,6 +18,10 @@
#include <errno.h> #include <errno.h>
#include "atomic.h" #include "atomic.h"
#if defined(__native_client__) && defined(NACL_NEWLIB)
# include "nacl/signal.h"
#endif
#ifdef NEED_RUBY_ATOMIC_EXCHANGE #ifdef NEED_RUBY_ATOMIC_EXCHANGE
rb_atomic_t rb_atomic_t
ruby_atomic_exchange(rb_atomic_t *ptr, rb_atomic_t val) ruby_atomic_exchange(rb_atomic_t *ptr, rb_atomic_t val)
@ -417,8 +421,6 @@ typedef RETSIGTYPE ruby_sigaction_t(int);
#define SIGINFO_ARG #define SIGINFO_ARG
#endif #endif
#ifdef POSIX_SIGNAL
#ifdef USE_SIGALTSTACK #ifdef USE_SIGALTSTACK
/* alternate stack for SIGSEGV */ /* alternate stack for SIGSEGV */
void void
@ -437,6 +439,7 @@ rb_register_sigaltstack(rb_thread_t *th)
} }
#endif /* USE_SIGALTSTACK */ #endif /* USE_SIGALTSTACK */
#ifdef POSIX_SIGNAL
static sighandler_t static sighandler_t
ruby_signal(int signum, sighandler_t handler) ruby_signal(int signum, sighandler_t handler)
{ {

View file

@ -2420,6 +2420,11 @@ rb_fd_dup(rb_fdset_t *dst, const rb_fdset_t *src)
memcpy(dst->fdset, src->fdset, size); memcpy(dst->fdset, src->fdset, size);
} }
#ifdef __native_client__
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
#endif
int int
rb_fd_select(int n, rb_fdset_t *readfds, rb_fdset_t *writefds, rb_fdset_t *exceptfds, struct timeval *timeout) rb_fd_select(int n, rb_fdset_t *readfds, rb_fdset_t *writefds, rb_fdset_t *exceptfds, struct timeval *timeout)
{ {
@ -3298,7 +3303,9 @@ mutex_free(void *ptr)
if (err) rb_bug("%s", err); if (err) rb_bug("%s", err);
} }
native_mutex_destroy(&mutex->lock); native_mutex_destroy(&mutex->lock);
#ifdef HAVE_PTHREAD_COND_INITIALIZE
native_cond_destroy(&mutex->cond); native_cond_destroy(&mutex->cond);
#endif
} }
ruby_xfree(ptr); ruby_xfree(ptr);
} }
@ -3333,7 +3340,9 @@ mutex_alloc(VALUE klass)
obj = TypedData_Make_Struct(klass, rb_mutex_t, &mutex_data_type, mutex); obj = TypedData_Make_Struct(klass, rb_mutex_t, &mutex_data_type, mutex);
native_mutex_initialize(&mutex->lock); native_mutex_initialize(&mutex->lock);
#ifdef HAVE_PTHREAD_COND_INITIALIZE
native_cond_initialize(&mutex->cond, RB_CONDATTR_CLOCK_MONOTONIC); native_cond_initialize(&mutex->cond, RB_CONDATTR_CLOCK_MONOTONIC);
#endif
return obj; return obj;
} }
@ -4781,4 +4790,3 @@ rb_reset_coverages(void)
GET_VM()->coverages = Qfalse; GET_VM()->coverages = Qfalse;
rb_remove_event_hook(update_coverage); rb_remove_event_hook(update_coverage);
} }

View file

@ -27,6 +27,9 @@
#if HAVE_SYS_PRCTL_H #if HAVE_SYS_PRCTL_H
#include <sys/prctl.h> #include <sys/prctl.h>
#endif #endif
#if defined(__native_client__) && defined(NACL_NEWLIB)
# include "nacl/select.h"
#endif
static void native_mutex_lock(pthread_mutex_t *lock); static void native_mutex_lock(pthread_mutex_t *lock);
static void native_mutex_unlock(pthread_mutex_t *lock); static void native_mutex_unlock(pthread_mutex_t *lock);
@ -137,9 +140,11 @@ static void
gvl_init(rb_vm_t *vm) gvl_init(rb_vm_t *vm)
{ {
native_mutex_initialize(&vm->gvl.lock); native_mutex_initialize(&vm->gvl.lock);
#ifdef HAVE_PTHREAD_CONDATTR_INIT
native_cond_initialize(&vm->gvl.cond, RB_CONDATTR_CLOCK_MONOTONIC); native_cond_initialize(&vm->gvl.cond, RB_CONDATTR_CLOCK_MONOTONIC);
native_cond_initialize(&vm->gvl.switch_cond, RB_CONDATTR_CLOCK_MONOTONIC); native_cond_initialize(&vm->gvl.switch_cond, RB_CONDATTR_CLOCK_MONOTONIC);
native_cond_initialize(&vm->gvl.switch_wait_cond, RB_CONDATTR_CLOCK_MONOTONIC); native_cond_initialize(&vm->gvl.switch_wait_cond, RB_CONDATTR_CLOCK_MONOTONIC);
#endif
vm->gvl.acquired = 0; vm->gvl.acquired = 0;
vm->gvl.waiting = 0; vm->gvl.waiting = 0;
vm->gvl.need_yield = 0; vm->gvl.need_yield = 0;
@ -148,9 +153,11 @@ gvl_init(rb_vm_t *vm)
static void static void
gvl_destroy(rb_vm_t *vm) gvl_destroy(rb_vm_t *vm)
{ {
#ifdef HAVE_PTHREAD_CONDATTR_INIT
native_cond_destroy(&vm->gvl.switch_wait_cond); native_cond_destroy(&vm->gvl.switch_wait_cond);
native_cond_destroy(&vm->gvl.switch_cond); native_cond_destroy(&vm->gvl.switch_cond);
native_cond_destroy(&vm->gvl.cond); native_cond_destroy(&vm->gvl.cond);
#endif
native_mutex_destroy(&vm->gvl.lock); native_mutex_destroy(&vm->gvl.lock);
} }
@ -232,6 +239,9 @@ native_mutex_destroy(pthread_mutex_t *lock)
} }
} }
#ifdef HAVE_PTHREAD_CONDATTR_INIT
int pthread_condattr_init(pthread_condattr_t *attr);
static void static void
native_cond_initialize(rb_thread_cond_t *cond, int flags) native_cond_initialize(rb_thread_cond_t *cond, int flags)
{ {
@ -266,6 +276,7 @@ native_cond_destroy(rb_thread_cond_t *cond)
rb_bug_errno("pthread_cond_destroy", r); rb_bug_errno("pthread_cond_destroy", r);
} }
} }
#endif
/* /*
* In OS X 10.7 (Lion), pthread_cond_signal and pthread_cond_broadcast return * In OS X 10.7 (Lion), pthread_cond_signal and pthread_cond_broadcast return
@ -439,20 +450,26 @@ Init_native_thread(void)
#ifdef USE_SIGNAL_THREAD_LIST #ifdef USE_SIGNAL_THREAD_LIST
native_mutex_initialize(&signal_thread_list_lock); native_mutex_initialize(&signal_thread_list_lock);
#endif #endif
#ifndef __native_client__
posix_signal(SIGVTALRM, null_func); posix_signal(SIGVTALRM, null_func);
#endif
} }
static void static void
native_thread_init(rb_thread_t *th) native_thread_init(rb_thread_t *th)
{ {
#ifdef HAVE_PTHREAD_CONDATTR_INIT
native_cond_initialize(&th->native_thread_data.sleep_cond, RB_CONDATTR_CLOCK_MONOTONIC); native_cond_initialize(&th->native_thread_data.sleep_cond, RB_CONDATTR_CLOCK_MONOTONIC);
#endif
ruby_thread_set_native(th); ruby_thread_set_native(th);
} }
static void static void
native_thread_destroy(rb_thread_t *th) native_thread_destroy(rb_thread_t *th)
{ {
#ifdef HAVE_PTHREAD_CONDATTR_INIT
native_cond_destroy(&th->native_thread_data.sleep_cond); native_cond_destroy(&th->native_thread_data.sleep_cond);
#endif
} }
#define USE_THREAD_CACHE 0 #define USE_THREAD_CACHE 0
@ -1197,6 +1214,7 @@ thread_timer(void *p)
static void static void
rb_thread_create_timer_thread(void) rb_thread_create_timer_thread(void)
{ {
#ifndef __native_client__
if (!timer_thread_id) { if (!timer_thread_id) {
pthread_attr_t attr; pthread_attr_t attr;
int err; int err;
@ -1256,6 +1274,7 @@ rb_thread_create_timer_thread(void)
} }
pthread_attr_destroy(&attr); pthread_attr_destroy(&attr);
} }
#endif
} }
static int static int

10
util.c
View file

@ -462,6 +462,15 @@ ruby_strdup(const char *str)
return tmp; return tmp;
} }
#ifdef __native_client__
char *
ruby_getcwd(void)
{
char *buf = xmalloc(2);
strcpy(buf, ".");
return buf;
}
#else
char * char *
ruby_getcwd(void) ruby_getcwd(void)
{ {
@ -490,6 +499,7 @@ ruby_getcwd(void)
#endif #endif
return buf; return buf;
} }
#endif
/**************************************************************** /****************************************************************
* *

View file

@ -92,6 +92,10 @@
#endif #endif
#endif #endif
#ifdef __native_client__
#undef OPT_DIRECT_THREADED_CODE
#endif
/* call threaded code */ /* call threaded code */
#if OPT_CALL_THREADED_CODE #if OPT_CALL_THREADED_CODE
#if OPT_DIRECT_THREADED_CODE #if OPT_DIRECT_THREADED_CODE

View file

@ -281,6 +281,7 @@ XRUBY = $(MINIRUBY)
!else !else
XRUBY = $(RUNRUBY) XRUBY = $(RUNRUBY)
!endif !endif
BTESTRUBY = $(MINIRUBY)
!ifndef RUBY !ifndef RUBY
RUBY = ruby RUBY = ruby
!endif !endif