diff --git a/com.oracle.truffle.r.native/fficall/src/jni/Rembedded.c b/com.oracle.truffle.r.native/fficall/src/jni/Rembedded.c index 390e9016ca0c570cf5f91c62daa2146755b4bb00..af0a6d0093c85443143aced3efcf735413de3604 100644 --- a/com.oracle.truffle.r.native/fficall/src/jni/Rembedded.c +++ b/com.oracle.truffle.r.native/fficall/src/jni/Rembedded.c @@ -35,6 +35,7 @@ SA_TYPE SaveAction; // ?? typedef jint (JNICALL *JNI_CreateJavaVMFunc) (JavaVM **pvm, void **penv, void *args); + static void *dlopen_jvmlib(char *libpath) { void *handle = dlopen(libpath, RTLD_GLOBAL | RTLD_NOW); if (handle == NULL) { @@ -59,11 +60,18 @@ static int process_vmargs(int argc, char *argv[], char *vmargv[], char *uargv[]) return vcount; } +char *get_classpath(char *r_home); + int Rf_initialize_R(int argc, char *argv[]) { if (initialized) { fprintf(stderr, "%s", "R is already initialized\n"); exit(1); } + char *r_home = getenv("R_HOME"); + if (r_home == NULL) { + printf("R_HOME must be set\n"); + exit(1); + } struct utsname utsname; uname(&utsname); char jvmlib_path[256]; @@ -94,17 +102,8 @@ int Rf_initialize_R(int argc, char *argv[]) { exit(1); } - // TODO getting the correct classpath is hard, need a helper program - char *vm_cp = getenv("FASTR_CLASSPATH"); - if (vm_cp == NULL) { - printf("Rf_initialize_R: FASTR_CLASSPATH env var not set\n"); - exit(1); - } - int cplen = (int) strlen(vm_cp); - - char *cp = malloc(cplen + 32); - strcpy(cp, "-Djava.class.path="); - strcat(cp, vm_cp); + char *vm_cp = get_classpath(r_home); + //printf("cp %s\n", vm_cp); char **vmargs = malloc(argc * sizeof(char*)); char **uargs = malloc(argc * sizeof(char*)); @@ -113,7 +112,7 @@ int Rf_initialize_R(int argc, char *argv[]) { argv = uargs; JavaVMOption vm_options[1 + vmargc]; - vm_options[0].optionString = cp; + vm_options[0].optionString = vm_cp; for (int i = 0; i < vmargc; i++) { vm_options[i + 1].optionString = vmargs[i]; } @@ -432,3 +431,70 @@ void R_runHandlers(InputHandler *handlers, fd_set *mask) { } int R_wait_usec; + +#include <unistd.h> +#include <errno.h> + +void perror_exit(char *msg) { + perror(msg); + exit(1); +} + +// support for getting the correct classpath for the VM +// We use $R_HOME/bin/exec/Rclasspath to do this to emulate what happens +// during normal execution +char *get_classpath(char *r_home) { + int pipefd[2]; + if (pipe(pipefd) == -1) { + perror_exit("pipe"); + } + pid_t pid = fork(); + if (pid == -1) { + perror("fork"); + } + if (pid == 0) { + // child + char path[1024]; + strcpy(path, r_home); + strcat(path, "/bin/exec/Rclasspath"); + while ((dup2(pipefd[1], STDOUT_FILENO) == -1) && (errno == EINTR)) {} + close(pipefd[1]); + close(pipefd[0]); + int rc = execl(path, (char *)NULL); + if (rc == -1) { + perror_exit("exec"); + } + return NULL; + } else { + // parent + const char *cpdef = "-Djava.class.path="; + char *buf = malloc(4096); + strcpy(buf, cpdef); + char *bufptr = buf + strlen(cpdef); + int max = 4096 - strlen(cpdef); + close(pipefd[1]); + while (1) { + int count = read(pipefd[0], bufptr, max); + if (count == -1) { + if (errno == EINTR) { + continue; + } else { + perror_exit("read"); + } + } else if (count == 0) { + // scrub any newline + bufptr--; + if (*bufptr != '\n') { + bufptr++; + } + *bufptr = 0; + break; + } else { + bufptr += count; + } + } + close(pipefd[0]); + wait(NULL); + return buf; + } +} diff --git a/com.oracle.truffle.r.native/run/Makefile b/com.oracle.truffle.r.native/run/Makefile index 491f44da1a5fe2654e5dafa3956fc038dc8acc06..9ce5d09c938b1651bc51e93bd54f1772ef67f4e4 100644 --- a/com.oracle.truffle.r.native/run/Makefile +++ b/com.oracle.truffle.r.native/run/Makefile @@ -65,7 +65,8 @@ $(FASTR_BIN_DIR)/R: Makefile R.sh Rscript.sh Rscript_exec.sh cp R.sh $(FASTR_BIN_DIR)/exec/R cp Rscript_exec.sh $(FASTR_BIN_DIR)/execRscript/Rscript cp Rscript.sh $(FASTR_BIN_DIR)/Rscript - chmod +x $(FASTR_BIN_DIR)/exec/R $(FASTR_BIN_DIR)/execRscript/Rscript $(FASTR_BIN_DIR)/Rscript + cp Rclasspath.sh $(FASTR_BIN_DIR)/exec/Rclasspath + chmod +x $(FASTR_BIN_DIR)/exec/R $(FASTR_BIN_DIR)/execRscript/Rscript $(FASTR_BIN_DIR)/Rscript $(FASTR_BIN_DIR)/exec/Rclasspath cp $(SUPPORT_SCRIPTS) $(FASTR_BIN_DIR) sed -e 's!^\(R_HOME_DIR=\)\(.*\)!\1"$(FASTR_R_HOME)"!' < $(R_SCRIPT) > $(FASTR_BIN_DIR)/R chmod +x $(FASTR_BIN_DIR)/R diff --git a/mx.fastr/mx_fastr.py b/mx.fastr/mx_fastr.py index ff4533e1df81730be1bf29c7a1468887ee6b5833..5eabc5bc2537204abe4b50327c776bb2be0520b4 100644 --- a/mx.fastr/mx_fastr.py +++ b/mx.fastr/mx_fastr.py @@ -117,6 +117,9 @@ def do_run_r(args, command, extraVmArgs=None, jdk=None, **kwargs): vmArgs.append(_command_class_dict[command.lower()]) return mx.run_java(vmArgs + args, jdk=jdk, **kwargs) +def r_classpath(args): + print mx.classpath(_r_command_project) + def _sanitize_vmArgs(jdk, vmArgs): ''' jdk/vm dependent analysis of vmArgs to remove those that are not appropriate for the @@ -535,6 +538,7 @@ _commands = { 'rembed' : [rembed, '[options]'], 'installpkgs' : [installpkgs, '[options]'], 'installcran' : [installpkgs, '[options]'], + 'r-cp' : [r_classpath, '[options]'], } mx.update_commands(_fastr_suite, _commands)