Fix appveyor windows build (#420)

* Fix msvcc dll build by adding dllexport decorations to all API declarations

* Fix appveyor build for VS 2013

Use the new -DFFI_BUILDING_DLL for producing a working DLL. Update the
msvcc.sh wrapper script to successfully compile the testsuite files.

* MSVC build: suppress warnings in testsuite

* fix testsuite on appveyor
diff --git a/.appveyor.yml b/.appveyor.yml
index ccb918a..c388fc6 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -28,8 +28,8 @@
           $env:HOST="x86-pc-windows"
         } Else {
           $env:VCVARS_PLATFORM="amd64"
-          $env:BUILD="x86_64-pc-cygwin"
-          $env:HOST="x86_64-pc-winnt"
+          $env:BUILD="x86_64-w64-cygwin"
+          $env:HOST="x86_64-w64-cygwin"
       }
   - 'appveyor DownloadFile http://cygwin.com/setup-x86.exe -FileName setup.exe'
   - 'setup.exe -qnNdO -R "%CYG_ROOT%" -s "%CYG_MIRROR%" -l "%CYG_CACHE%" -P dejagnu >NUL'
@@ -40,7 +40,9 @@
 
 build_script:
   - c:\cygwin\bin\sh -lc "(cd $OLDPWD; ./autogen.sh;)"
-  - c:\cygwin\bin\sh -lc "(cd $OLDPWD; ./configure CC='/cygdrive/c/projects/libffi/.travis/compile cl -nologo' CXX='/cygdrive/c/projects/libffi/.travis/compile cl -nologo' LD=link CPP='cl -nologo -EP' AR='/cygdrive/c/projects/libffi/.travis/ar-lib lib' NM='dumpbin -symbols' STRIP=':' --build=$BUILD --host=$HOST; cp src/x86/ffitarget.h include; make; find .; make check; cat `find ./ -name libffi.log`)"
+  - c:\cygwin\bin\sh -lc "(cd $OLDPWD; ./configure CC='/cygdrive/c/projects/libffi/msvcc.sh -m64' CXX='/cygdrive/c/projects/libffi/msvcc.sh -m64' LD='link' CPP='cl -nologo -EP' CXXCPP='cl -nologo -EP' CPPFLAGS='-DFFI_BUILDING_DLL' AR='/cygdrive/c/projects/libffi/.travis/ar-lib lib' NM='dumpbin -symbols' STRIP=':' --build=$BUILD --host=$HOST;)"
+  - c:\cygwin\bin\sh -lc "(cd $OLDPWD; cp src/x86/ffitarget.h include; make; find .;)"
+  - c:\cygwin\bin\sh -lc "(cd $OLDPWD; cp `find . -name 'libffi-?.dll'` $HOST/testsuite/; make check; cat `find ./ -name libffi.log`)"
 
 # FIXME: "make check" currently fails.  It just looks like msvcc needs
 # to learn about -L and -l options.  If you add "make check; cat `find
diff --git a/include/ffi.h.in b/include/ffi.h.in
index d76d8e6..39cde46 100644
--- a/include/ffi.h.in
+++ b/include/ffi.h.in
@@ -108,6 +108,32 @@
   struct _ffi_type **elements;
 } ffi_type;
 
+/* Need minimal decorations for DLLs to work on Windows.  GCC has
+   autoimport and autoexport.  Always mark externally visible symbols
+   as dllimport for MSVC clients, even if it means an extra indirection
+   when using the static version of the library.
+   Besides, as a workaround, they can define FFI_BUILDING if they
+   *know* they are going to link with the static library.  */
+#if defined _MSC_VER
+# if defined FFI_BUILDING_DLL /* Building libffi.DLL with msvcc.sh */
+#  define FFI_API __declspec(dllexport)
+# elif !defined FFI_BUILDING  /* Importing libffi.DLL */
+#  define FFI_API __declspec(dllimport)
+# else                        /* Building/linking static library */
+#  define FFI_API
+# endif
+#else
+# define FFI_API
+#endif
+
+/* The externally visible type declarations also need the MSVC DLL
+   decorations, or they will not be exported from the object file.  */
+#if defined LIBFFI_HIDE_BASIC_TYPES
+# define FFI_EXTERN FFI_API
+#else
+# define FFI_EXTERN extern FFI_API
+#endif
+
 #ifndef LIBFFI_HIDE_BASIC_TYPES
 #if SCHAR_MAX == 127
 # define ffi_type_uchar                ffi_type_uint8
@@ -157,19 +183,6 @@
  #error "long size not supported"
 #endif
 
-/* Need minimal decorations for DLLs to works on Windows.  GCC has
-   autoimport and autoexport.  Rely on Libtool to help MSVC export
-   from a DLL, but always declare data to be imported for MSVC
-   clients.  This costs an extra indirection for MSVC clients using
-   the static version of the library, but don't worry about that.
-   Besides, as a workaround, they can define FFI_BUILDING if they
-   *know* they are going to link with the static library.  */
-#if defined _MSC_VER && !defined FFI_BUILDING
-#define FFI_EXTERN extern __declspec(dllimport)
-#else
-#define FFI_EXTERN extern
-#endif
-
 /* These are defined in types.c.  */
 FFI_EXTERN ffi_type ffi_type_void;
 FFI_EXTERN ffi_type ffi_type_uint8;
@@ -256,26 +269,31 @@
 #endif
 
 
+FFI_API 
 void ffi_raw_call (ffi_cif *cif,
 		   void (*fn)(void),
 		   void *rvalue,
 		   ffi_raw *avalue);
 
-void ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw);
-void ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args);
-size_t ffi_raw_size (ffi_cif *cif);
+FFI_API void ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw);
+FFI_API void ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args);
+FFI_API size_t ffi_raw_size (ffi_cif *cif);
 
 /* This is analogous to the raw API, except it uses Java parameter
    packing, even on 64-bit machines.  I.e. on 64-bit machines longs
    and doubles are followed by an empty 64-bit word.  */
 
+FFI_API
 void ffi_java_raw_call (ffi_cif *cif,
 			void (*fn)(void),
 			void *rvalue,
 			ffi_java_raw *avalue);
 
+FFI_API
 void ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_java_raw *raw);
+FFI_API
 void ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_java_raw *raw, void **args);
+FFI_API
 size_t ffi_java_raw_size (ffi_cif *cif);
 
 /* ---- Definitions for closures ----------------------------------------- */
@@ -307,10 +325,10 @@
 # endif
 #endif
 
-void *ffi_closure_alloc (size_t size, void **code);
-void ffi_closure_free (void *);
+FFI_API void *ffi_closure_alloc (size_t size, void **code);
+FFI_API void ffi_closure_free (void *);
 
-ffi_status
+FFI_API ffi_status
 ffi_prep_closure (ffi_closure*,
 		  ffi_cif *,
 		  void (*fun)(ffi_cif*,void*,void**,void*),
@@ -322,7 +340,7 @@
 #endif
   ;
 
-ffi_status
+FFI_API ffi_status
 ffi_prep_closure_loc (ffi_closure*,
 		      ffi_cif *,
 		      void (*fun)(ffi_cif*,void*,void**,void*),
@@ -383,26 +401,26 @@
 
 } ffi_java_raw_closure;
 
-ffi_status
+FFI_API ffi_status
 ffi_prep_raw_closure (ffi_raw_closure*,
 		      ffi_cif *cif,
 		      void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
 		      void *user_data);
 
-ffi_status
+FFI_API ffi_status
 ffi_prep_raw_closure_loc (ffi_raw_closure*,
 			  ffi_cif *cif,
 			  void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
 			  void *user_data,
 			  void *codeloc);
 
-ffi_status
+FFI_API ffi_status
 ffi_prep_java_raw_closure (ffi_java_raw_closure*,
 		           ffi_cif *cif,
 		           void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*),
 		           void *user_data);
 
-ffi_status
+FFI_API ffi_status
 ffi_prep_java_raw_closure_loc (ffi_java_raw_closure*,
 			       ffi_cif *cif,
 			       void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*),
@@ -419,22 +437,24 @@
   void     (*fun)(ffi_cif*,void*,void**,void*);
 } ffi_go_closure;
 
-ffi_status ffi_prep_go_closure (ffi_go_closure*, ffi_cif *,
+FFI_API ffi_status ffi_prep_go_closure (ffi_go_closure*, ffi_cif *,
 				void (*fun)(ffi_cif*,void*,void**,void*));
 
-void ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
+FFI_API void ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
 		  void **avalue, void *closure);
 
 #endif /* FFI_GO_CLOSURES */
 
 /* ---- Public interface definition -------------------------------------- */
 
+FFI_API 
 ffi_status ffi_prep_cif(ffi_cif *cif,
 			ffi_abi abi,
 			unsigned int nargs,
 			ffi_type *rtype,
 			ffi_type **atypes);
 
+FFI_API
 ffi_status ffi_prep_cif_var(ffi_cif *cif,
 			    ffi_abi abi,
 			    unsigned int nfixedargs,
@@ -442,11 +462,13 @@
 			    ffi_type *rtype,
 			    ffi_type **atypes);
 
+FFI_API
 void ffi_call(ffi_cif *cif,
 	      void (*fn)(void),
 	      void *rvalue,
 	      void **avalue);
 
+FFI_API
 ffi_status ffi_get_struct_offsets (ffi_abi abi, ffi_type *struct_type,
 				   size_t *offsets);
 
diff --git a/msvcc.sh b/msvcc.sh
index 9ed6bd1..9a252f8 100755
--- a/msvcc.sh
+++ b/msvcc.sh
@@ -52,11 +52,17 @@
 safeseh="-safeseh"
 output=
 libpaths=
+libversion=7
+verbose=
 
 while [ $# -gt 0 ]
 do
   case $1
   in
+    --verbose)
+      $verbose=1
+      shift 1
+    ;;
     --version)
       args="-help"
       shift 1
@@ -162,23 +168,30 @@
     ;;
     -L)
       p=$(cygpath -m $2)
-      linkargs="$linkargs /LIBPATH:$p"
+      linkargs="$linkargs -LIBPATH:$p"
       shift 2
     ;;
     -L*)
       p=$(cygpath -m ${1#-L})
-      linkargs="$linkargs /LIBPATH:$p"
+      linkargs="$linkargs -LIBPATH:$p"
       shift 1
     ;;
+    -link)
+      # add next argument verbatim to linker args
+      linkargs="$linkargs $2"
+      shift 2
+      ;;
     -l*)
       case $1
       in
-          -lffi)
-	      linkargs="$linkargs lib${1#-l}.a"
-	      ;;
-	  *)
-	      # linkargs="$linkargs ${1#-l}.lib"
-	      ;;
+        -lffi)
+          linkargs="$linkargs lib${1#-l}-${libversion}.lib"
+          ;;
+        *)
+          # ignore other libraries like -lm, hope they are
+          # covered by MSVCRT
+          # linkargs="$linkargs ${1#-l}.lib"
+          ;;
       esac
       shift 1
     ;;
@@ -195,6 +208,15 @@
       # libffi tests -pedantic with -Wall, so drop it also.
       shift 1
     ;;
+    -warn)
+      # ignore -warn all from libtool as well.
+      if test "$2" = "all"; then
+        shift 2
+      else
+        args="$args -warn"
+        shift 1
+      fi
+    ;;
     -Werror)
       args="$args -WX"
       shift 1
@@ -248,7 +270,7 @@
 	linkargs="$linkargs -OPT:REF -OPT:ICF -INCREMENTAL:NO"
     fi
 
-    args="$args /link $linkargs"
+    args="$args -link $linkargs"
 fi
 
 if [ -n "$static_crt" ]; then
@@ -266,12 +288,19 @@
       outdir="."
     fi
     ppsrc="$outdir/$(basename $src|sed 's/.S$/.asm/g')"
-    echo "$cl -nologo -EP $includes $defines $src > $ppsrc"
+
+    if test -n "$verbose"; then
+      echo "$cl -nologo -EP $includes $defines $src > $ppsrc"
+    fi
+
     "$cl" -nologo -EP $includes $defines $src > $ppsrc || exit $?
     output="$(echo $output | sed 's%/F[dpa][^ ]*%%g')"
     args="-nologo $safeseh $single $output $ppsrc"
 
-    echo "$ml $args"
+    if test -n "$verbose"; then
+      echo "$ml $args"
+    fi
+
     eval "\"$ml\" $args"
     result=$?
 
@@ -279,13 +308,21 @@
     #mv *.obj $outdir
 else
     args="$md $args"
-    echo "$cl $args"
+
+    if test -n "$verbose"; then
+      echo "$cl $args"
+    fi
     # Return an error code of 1 if an invalid command line parameter is passed
-    # instead of just ignoring it.
+    # instead of just ignoring it. Any output that is not a warning or an
+    # error is filtered so this command behaves more like gcc. cl.exe prints
+    # the name of the compiled file otherwise, which breaks the dejagnu checks
+    # for excess warnings and errors.
     eval "(\"$cl\" $args 2>&1 1>&3 | \
-          awk '{print \$0} /D9002/ {error=1} END{exit error}' >&2) 3>&1"
+          awk '{print \$0} /D9002/ {error=1} END{exit error}' >&2) 3>&1 | \
+          awk '/warning|error/'"
     result=$?
 fi
 
 exit $result
 
+# vim: noai:ts=4:sw=4
diff --git a/src/types.c b/src/types.c
index 7e80aec..9ec27f6 100644
--- a/src/types.c
+++ b/src/types.c
@@ -38,6 +38,7 @@
   char c;					\
   type x;					\
 };						\
+FFI_EXTERN					\
 maybe_const ffi_type ffi_type_##name = {	\
   sizeof(type),					\
   offsetof(struct struct_align_##name, x),	\
@@ -52,6 +53,7 @@
   char c;						\
   _Complex type x;					\
 };							\
+FFI_EXTERN						\
 maybe_const ffi_type ffi_type_complex_##name = {	\
   sizeof(_Complex type),				\
   offsetof(struct struct_align_complex_##name, x),	\
@@ -60,7 +62,7 @@
 }
 
 /* Size and alignment are fake here. They must not be 0. */
-const ffi_type ffi_type_void = {
+FFI_EXTERN const ffi_type ffi_type_void = {
   1, 1, FFI_TYPE_VOID, NULL
 };
 
diff --git a/testsuite/libffi.bhaible/bhaible.exp b/testsuite/libffi.bhaible/bhaible.exp
index 7f615e6..6a0bb45 100644
--- a/testsuite/libffi.bhaible/bhaible.exp
+++ b/testsuite/libffi.bhaible/bhaible.exp
@@ -25,7 +25,15 @@
 # flags to disable warnings for now.
 if { [string match $compiler_vendor "gnu"] } {
     set warning_options "-Wno-unused-variable -Wno-unused-parameter -Wno-unused-but-set-variable -Wno-uninitialized";
-} else {
+}
+if { [string match $compiler_vendor "microsoft"] } {
+    # -wd4996  suggest use of vsprintf_s instead of vsprintf
+    # -wd4116  unnamed type definition
+    # -wd4101  unreferenced local variable
+    # -wd4244  warning about implicit double to float conversion
+    set warning_options "-wd4996 -wd4116 -wd4101 -wd4244";
+}
+if { ![string match $compiler_vendor "microsoft"] && ![string match $compiler_vendor "gnu"] } {
     set warning_options "-Wno-unused-variable -Wno-unused-parameter -Wno-uninitialized";
 }
 
diff --git a/testsuite/libffi.bhaible/test-call.c b/testsuite/libffi.bhaible/test-call.c
index 82cc79e..5897887 100644
--- a/testsuite/libffi.bhaible/test-call.c
+++ b/testsuite/libffi.bhaible/test-call.c
@@ -25,8 +25,6 @@
 #include "alignof.h"
 #include <stdarg.h>
 
-#include "testcases.c"
-
 /* libffi testsuite local changes -------------------------------- */
 #ifdef DGTEST
 /* Redefine exit(1) as a test failure */
@@ -34,7 +32,7 @@
 int count = 0;
 char rbuf1[2048];
 char rbuf2[2048];
-int fprintf(FILE *stream, const char *format, ...)
+int _fprintf(FILE *stream, const char *format, ...)
 {
   va_list args;
   va_start(args, format);
@@ -60,9 +58,12 @@
 
   return 0;
 }
+#define fprintf _fprintf
 #endif
 /* --------------------------------------------------------------- */
 
+#include "testcases.c"
+
 #ifndef ABI_NUM
 #define ABI_NUM FFI_DEFAULT_ABI
 #endif
diff --git a/testsuite/libffi.bhaible/test-callback.c b/testsuite/libffi.bhaible/test-callback.c
index 7a435ae..7ddee68 100644
--- a/testsuite/libffi.bhaible/test-callback.c
+++ b/testsuite/libffi.bhaible/test-callback.c
@@ -25,8 +25,6 @@
 #include "alignof.h"
 #include <stdarg.h>
 
-#include "testcases.c"
-
 /* libffi testsuite local changes -------------------------------- */
 #ifdef DGTEST
 /* Redefine exit(1) as a test failure */
@@ -34,7 +32,7 @@
 int count = 0;
 char rbuf1[2048];
 char rbuf2[2048];
-int fprintf(FILE *stream, const char *format, ...)
+int _fprintf(FILE *stream, const char *format, ...)
 {
   va_list args;
   va_start(args, format);
@@ -60,9 +58,12 @@
 
   return 0;
 }
+#define fprintf _fprintf
 #endif
 /* --------------------------------------------------------------- */
 
+#include "testcases.c"
+
 #ifndef ABI_NUM
 #define ABI_NUM FFI_DEFAULT_ABI
 #endif
diff --git a/testsuite/libffi.call/call.exp b/testsuite/libffi.call/call.exp
index bc2bdc3..ab47415 100644
--- a/testsuite/libffi.call/call.exp
+++ b/testsuite/libffi.call/call.exp
@@ -19,9 +19,22 @@
 
 global srcdir subdir
 
+if { [string match $compiler_vendor "microsoft"] } {
+    # -wd4005  macro redefinition
+    # -wd4244  implicit conversion to type of smaller size
+    # -wd4305  truncation to smaller type
+    # -wd4477  printf %lu of uintptr_t
+    # -wd4312  implicit conversion to type of greater size
+    # -wd4311  pointer truncation to unsigned long
+    # -EHsc    C++ Exception Handling (no SEH exceptions)
+    set additional_options "-wd4005 -wd4244 -wd4305 -wd4477 -wd4312 -wd4311 -EHsc";
+} else {
+    set additional_options "";
+}
+
 set tlist [lsort [glob -nocomplain -- $srcdir/$subdir/*.{c,cc}]]
 
-run-many-tests $tlist ""
+run-many-tests $tlist $additional_options
 
 dg-finish