From c86f96f8f8a13dfa73f136719ae42a1540ddac97 Mon Sep 17 00:00:00 2001
From: Mick Jordan <mick.jordan@oracle.com>
Date: Tue, 15 Dec 2015 13:56:05 -0800
Subject: [PATCH] FFI fixes for installation of packages with C++

---
 com.oracle.truffle.r.native/fficall/README    |  4 ++--
 .../fficall/src/common/arithmetic.c           |  5 +++++
 .../fficall/src/jni/Makefile                  | 10 +++++++--
 .../fficall/src/jni/Rinternals.c              |  8 +++++++
 .../stats/src => fficall/src/jni}/xxxpr.f     |  0
 mx.fastr/mx_fastr_pkgtest.py                  | 22 ++++++++++++++++---
 6 files changed, 42 insertions(+), 7 deletions(-)
 rename com.oracle.truffle.r.native/{library/stats/src => fficall/src/jni}/xxxpr.f (100%)

diff --git a/com.oracle.truffle.r.native/fficall/README b/com.oracle.truffle.r.native/fficall/README
index beac20fa51..8f67219eef 100644
--- a/com.oracle.truffle.r.native/fficall/README
+++ b/com.oracle.truffle.r.native/fficall/README
@@ -5,8 +5,8 @@ fficall contains the implementation of the R FFI, as described in https://cran.r
    jni
 
  'jni' contains the implementation that is based on Java JNI. 'common' contains code that has no JNI dependencies and has been extracted for
- reuse in other implementations. Note however, that common cannot be compiled in isolation, as it depends on the implementation via rffiutils.h.
- During the build symbolic lionk are made to the files in command and they are compiled with the other 'jni' files.
+ reuse in other implementations. Note however, that the common files cannot all be compiled in isolation, as they may depend on the implementation
+ via rffiutils.h. During the build symbolic links are made to the files in common and they are compiled with the other 'jni' files.
 
  The R FFI is rather baroque and defined in large set of header files in the sibling 'include' directory. In GnuR, the implementation
  of the functions is spread over the GnuR C files in 'src/main'. To ease navigation of the FastR implementation, in general, the implementation
diff --git a/com.oracle.truffle.r.native/fficall/src/common/arithmetic.c b/com.oracle.truffle.r.native/fficall/src/common/arithmetic.c
index fb36b55c42..17ea1d495f 100644
--- a/com.oracle.truffle.r.native/fficall/src/common/arithmetic.c
+++ b/com.oracle.truffle.r.native/fficall/src/common/arithmetic.c
@@ -92,6 +92,11 @@ int R_IsNaN(double x)
     return 0;
 }
 
+int R_isnancpp(double x)
+{
+   return (isnan(x)!=0);
+}
+
 /* Mainly for use in packages */
 int R_finite(double x)
 {
diff --git a/com.oracle.truffle.r.native/fficall/src/jni/Makefile b/com.oracle.truffle.r.native/fficall/src/jni/Makefile
index abde616517..b922b435e8 100644
--- a/com.oracle.truffle.r.native/fficall/src/jni/Makefile
+++ b/com.oracle.truffle.r.native/fficall/src/jni/Makefile
@@ -49,6 +49,9 @@ C_SOURCES = $(C_LOCAL_SOURCES) $(C_COMMON_SOURCES)
 C_OBJECTS := $(patsubst %.c,$(OBJ)/%.o,$(C_SOURCES))
 #$(info C_OBJECTS=$(C_OBJECTS))
 
+F_SOURCES := $(wildcard *.f)
+F_OBJECTS := $(patsubst %.f,$(OBJ)/%.o,$(F_SOURCES))
+
 JNI_INCLUDES = -I $(JAVA_HOME)/include -I $(JAVA_HOME)/include/$(JDK_OS_DIR)
 FFI_INCLUDES = -I$(TOPDIR)/include -I$(TOPDIR)/gnur/R-3.1.3/src/include -I$(TOPDIR)/include/R_ext
 
@@ -62,8 +65,8 @@ all: Makefile $(C_COMMON_SOURCES) $(C_LIB)
 links:
 	$(foreach file,$(C_COMMON_SOURCES),ln -sf $(COMMON)/$(file) $(file);)	
 
-$(C_LIB): $(OBJ) $(C_OBJECTS)
-	$(DYLIB_LD) $(DYLIB_LDFLAGS) -o $(C_LIB) $(C_OBJECTS)
+$(C_LIB): $(OBJ) $(C_OBJECTS) $(F_OBJECTS)
+	$(DYLIB_LD) $(DYLIB_LDFLAGS) -o $(C_LIB) $(C_OBJECTS) $(F_OBJECTS)
 
 $(OBJ):
 	mkdir -p $(OBJ)
@@ -74,6 +77,9 @@ $(OBJ)/%.o: %.c $(TOPDIR)/include/Rinternals.h $(C_HDRS)
 $(OBJ)/%.E: %.c $(TOPDIR)/include/Rinternals.h
 	$(CC) -E $(CFLAGS) $(INCLUDES) -c $< > $@
 
+$(OBJ)/%.o: %.f
+	$(F77) $(FFLAGS) $(FPICFLAGS) -c $< -o $@
+
 clean:
 	rm -rf $(OBJ) $(C_LIB)
 	$(foreach file,$(C_COMMON_SOURCES),rm -f $(file);)	
diff --git a/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c b/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c
index ebfb83cbc6..2dd7d6b971 100644
--- a/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c
+++ b/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c
@@ -299,6 +299,10 @@ void Rf_copyMostAttrib(SEXP x, SEXP y) {
 	unimplemented("Rf_copyMostAttrib");
 }
 
+void Rf_copyVector(SEXP x, SEXP y) {
+	unimplemented("Rf_copyVector");
+}
+
 Rboolean Rf_inherits(SEXP x, const char * klass) {
     JNIEnv *thisenv = getEnv();
     jstring klazz = (*thisenv)->NewStringUTF(thisenv, klass);
@@ -516,6 +520,10 @@ void R_FlushConsole(void) {
 	// ignored
 }
 
+void R_ProcessEvents(void) {
+	unimplemented("R_ProcessEvents");
+}
+
 // Tools package support, not in public API
 
 SEXP R_NewHashedEnv(SEXP parent, SEXP size) {
diff --git a/com.oracle.truffle.r.native/library/stats/src/xxxpr.f b/com.oracle.truffle.r.native/fficall/src/jni/xxxpr.f
similarity index 100%
rename from com.oracle.truffle.r.native/library/stats/src/xxxpr.f
rename to com.oracle.truffle.r.native/fficall/src/jni/xxxpr.f
diff --git a/mx.fastr/mx_fastr_pkgtest.py b/mx.fastr/mx_fastr_pkgtest.py
index 1a29ccb187..3e7a10fd79 100644
--- a/mx.fastr/mx_fastr_pkgtest.py
+++ b/mx.fastr/mx_fastr_pkgtest.py
@@ -89,7 +89,7 @@ def rpt_compare(args):
     Analyze test package test results by comparing with GnuR output.
     Return 0 if passed, non-zero if failed
     '''
-    parser = ArgumentParser(prog='mx rpt_compare')
+    parser = ArgumentParser(prog='mx rpt-compare')
     parser.add_argument('--fastr-dir', action='store', help='dir containing fastr results', default=os.getcwd())
     parser.add_argument('--pkg', action='store', help='pkg to compare, default all')
     parser.add_argument('--verbose', action='store_true', help='print names of files that differ')
@@ -154,11 +154,14 @@ def check_install(result, text):
     result_data = ""
 
     def find_done(index, pkgname):
+        exception = False
         for i in range(index, nlines):
             line = lines[i]
+            if 'exception' in line:
+                exception = True
             if line.startswith("* DONE"):
                 done_pkgname = line[line.find("(") + 1 : line.rfind(")")]
-                return pkgname == done_pkgname
+                return pkgname == done_pkgname and not exception
         return False
 
     start_index = None
@@ -166,8 +169,9 @@ def check_install(result, text):
         line = lines[i]
         if line.startswith("BEGIN package installation"):
             start_index = i
+            break
 
-    if start_index:
+    if start_index is not None:
         for i in range(start_index, nlines):
             line = lines[i]
             if line.startswith("* installing *source* package"):
@@ -181,6 +185,17 @@ def check_install(result, text):
 
     return result, result_data
 
+def rpt_check_install_log(args):
+    parser = ArgumentParser(prog='mx rpt-check-install-log')
+    parser.add_argument('--log', action='store', help='file containing install log', required=True)
+    args = parser.parse_args(args)
+
+    with open(args.log) as f:
+        content = f.read()
+        _, result_data = check_install(0, content)
+
+    print result_data
+
 def _extract_pkgname(line):
     sx = line.find("'")
     ex = line.rfind("'")
@@ -546,5 +561,6 @@ _commands = {
     'rpt-install-status' : [rpt_install_status, '[options]'],
     'rpt-list-testdirs' : [rpt_list_testdirs, '[options]'],
     'rpt-compare': [rpt_compare, '[options]'],
+    'rpt-check-install-log': [rpt_check_install_log, '[options]'],
     'pkgtestanalyze': [rpt_compare, '[options]'],
 }
-- 
GitLab