#
# Makefile for JNA native bits
# Copyright (c) 2007-2010 Timothy Wall All Rights Reserved
#
# You may need to run 'ant javah' at the root before performing a build from 
# this directory.
#
# To build with debug information, use 'make DEBUG=true'
#
# Supported platforms (built and tested):
#
#   Windows 2000/XP/2003/Vista (x86)
#   Darwin/OS X (i386/x86_64/ppc)
#   Linux (i386/amd64) 
#   Solaris (i386/amd64/sparc/sparcv9)
#   FreeBSD (i386/amd64)
#

# Systems which support POSIX signals may be able to support VM crash
# protection simply by defining HAVE_PROTECTION.  This has been enabled
# only for those platforms on which it has been tested successfully.

OS=$(shell uname | sed -e 's/\(CYGWIN\|MINGW32\).*/win32/g' \
                        -e 's/SunOS.*/solaris/g' \
                        -e 's/FreeBSD.*/freebsd/g' \
                        -e 's/OpenBSD.*/openbsd/g' \
                        -e 's/Darwin.*/darwin/g' \
                        -e 's/Linux.*/linux/g')

JNA_JNI_VERSION=3.2.2 # auto-generated by ant
CHECKSUM=c870290c36c8d3fdf85db7c782febc3f # auto-generated by ant

JAVA_INCLUDES=-I"$(JAVA_HOME)/include" \
              -I"$(JAVA_HOME)/include/$(OS)"

BUILD=../build/native
JAVAH=$(BUILD)
INSTALLDIR=../build/$(OS)
JNIDISPATCH_OBJS=$(BUILD)/dispatch.o $(BUILD)/callback.o $(EXTRAOBJS)
RSRC=$(BUILD)/rsrc.o
ifneq ($(DYNAMIC_LIBFFI),true)
FFI_SRC=$(shell pwd)/libffi
FFI_BUILD=$(BUILD)/libffi
FFI_LIB=$(FFI_BUILD)/.libs/libffi$(ARSFX)
FFI_ENV=CC="$(CC)" CFLAGS="$(COPT) $(CDEBUG)" CPPFLAGS="$(CDEFINES)"
FFI_CONFIG=--enable-static --disable-shared --with-pic=yes
endif
LIBRARY=$(BUILD)/$(LIBPFX)jnidispatch$(JNISFX)
TESTLIB=$(BUILD)/$(LIBPFX)testlib$(LIBSFX)
TESTLIB2=$(BUILD)/$(LIBPFX)testlib2$(LIBSFX)

# Reasonable defaults based on GCC
LIBPFX=lib
LIBSFX=.so
ARSFX=.a
JNISFX=$(LIBSFX)
CC=gcc
LD=gcc
LIBS=
# Default to Sun recommendations for JNI compilation
COPT=-O2 -fno-omit-frame-pointer -fno-strict-aliasing 
CASM=-S
ifeq ($(DEBUG),true)
CDEBUG=-g
endif
CFLAGS_EXTRA=
COUT=-o $@
CINCLUDES=$(JAVA_INCLUDES) -I"$(JAVAH)" -I$(FFI_BUILD)/include
CDEFINES=-D_REENTRANT
PCFLAGS=-W -Wall -Wno-unused -Wno-parentheses
CFLAGS=$(PCFLAGS) $(CFLAGS_EXTRA) $(COPT) $(CDEBUG) $(CDEFINES) $(CINCLUDES) \
       -DJNA_JNI_VERSION='"$(JNA_JNI_VERSION)"' -DCHECKSUM='"$(CHECKSUM)"'
LDFLAGS=-o $@ -shared 
ifeq ($(DYNAMIC_LIBFFI),true)
CFLAGS += $(shell pkg-config --cflags libffi 2>/dev/null || echo)
LIBS += $(shell pkg-config --libs libffi 2>/dev/null || echo -lffi)
else
# -static-libgcc avoids gcc library incompatibilities across linux systems
LDFLAGS += -static-libgcc
endif
# Avoid bug in X11-based 1.5/1.6 VMs; dynamically load instead of linking
# See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6539705
#LIBS=-L"$(LIBDIR)" -ljawt 
STRIP=strip -x
# end defaults

ifeq ($(OS),win32)
ARCH=$(shell uname -m | sed 's/i.86/i386/g')
CDEFINES=-DHAVE_PROTECTION -DPSAPI_VERSION=1
LIBS=-lpsapi
WINDRES=windres
EXTRAOBJS=$(RSRC)
STRIP=@echo
LIBPFX=
LIBSFX=.dll

ifeq ($(CC),gcc)
CC += -mno-cygwin
LD += -mno-cygwin -Wl,--add-stdcall-alias
endif

ifeq ($(ARCH),amd64)

WINDRES=/usr/local/mingw64-cross/bin/x86_64-pc-mingw32-windres

# Uncomment to enable MINGW64 cross compiler
# Should build properly as of 090601, but lacks SEH, so MSVC build is preferred
#MINGW = x86_64-pc-mingw32-gcc
ifneq ($(MINGW),)
CC = $(MINGW) -m64 -mno-cygwin
LD = $(CC)
LDFLAGS=-o $@ -shared
LIBS= -lmingwex -lpsapi -lkernel32 -lmsvcrt 
FFI_CONFIG += --host=x86_64-pc-mingw32
else
# MSVC (wrapper scripts)
CC=$(FFI_SRC)/../cc.sh -m64
LD=$(FFI_SRC)/../ld.sh -m64
COPT=
LIBS=psapi.lib
ARSFX=.lib
FFI_CONFIG += --host=x86_64-pc-mingw32 && rm -f include/ffitarget.h && cp $(FFI_SRC)/include/*.h $(FFI_SRC)/src/x86/ffitarget.h include
FFI_ENV += LD="$(LD)" CPP=cpp
endif
endif
endif

ifeq ($(OS),linux)
ARCH=$(shell uname -m | sed 's/i.86/i386/g')
PCFLAGS+=-fPIC
CDEFINES+=-DHAVE_PROTECTION
LDFLAGS+=-Wl,-soname,$@
endif

ifeq ($(OS),freebsd)
ARCH=$(shell uname -m | sed 's/i.86/i386/g')
PCFLAGS+=-fPIC
CINCLUDES+=-I/usr/X11R6/include
LDFLAGS=-o $@ -shared 
CDEFINES+=-DHAVE_PROTECTION -DFFI_MMAP_EXEC_WRIT
endif

ifeq ($(OS),openbsd)
ARCH=$(shell uname -m | sed 's/i.86/i386/g')
PCFLAGS+=-fPIC
CINCLUDES+=-I/usr/X11R6/include
LDFLAGS=-o $@ -shared 
CDEFINES+=-DHAVE_PROTECTION -DFFI_MMAP_EXEC_WRIT
endif

ifeq ($(OS),solaris)
ifeq ($(ARCH),)
ARCH=$(shell uname -p)
endif
PCFLAGS+=-fPIC
CDEFINES+=-DHAVE_PROTECTION -DFFI_MMAP_EXEC_WRIT
ifeq ($(ARCH), sparcv9)
  # alter CC instead of PCFLAGS, since we need to pass it down to libffi 
  # configure and some of the other settings in PCFLAGS might make the build 
  # choke
  CC += -m64  
  LD += -m64 
endif
endif

# Enable 64-bit builds if the arch demands it
ifeq ($(CC),gcc)
ifeq ($(ARCH),amd64)
  CC += -m64
  LD += -m64
endif
endif

ifeq ($(OS),darwin)
ARCH=$(shell arch)
ifeq ($(ARCH),ppc)
ALT_ARCHS=i386
else
ALT_ARCHS=ppc
endif
LIBSFX=.dylib
JNISFX=.jnilib
ifneq ($(SDKROOT),)
SYSLIBROOT=-Wl,-syslibroot,$(SDKROOT)
ISYSROOT=-isysroot $(SDKROOT)
ARCHFLAGS=-arch ppc -arch i386
ifneq ($(findstring 10.5,$(SDKROOT)),)
ALT_ARCHS+=x86_64 
ARCHFLAGS+=-arch x86_64
endif
endif
PCFLAGS+=$(ISYSROOT) -x objective-c
CDEFINES+=-DTARGET_RT_MAC_CFM=0 -DFFI_MMAP_EXEC_WRIT
LDFLAGS=$(ARCHFLAGS) -dynamiclib -o $@ -framework JavaVM \
  -compatibility_version $(shell echo ${JNA_JNI_VERSION}|sed 's/^\([0-9][0-9]*\).*/\1/g') \
  -current_version $(JNA_JNI_VERSION) \
  -mmacosx-version-min=10.3 \
  -install_name ${@F} \
  $(SYSLIBROOT)
# JAWT linkage handled by -framework JavaVM
LIBS=
endif

# Unfortunately, we have to use different libffi include files depending on 
# the target, so we can't do a simple universal build on darwin.  Do 
# separate builds, then merge the results.
$(BUILD)/%.o : %.c dispatch.h $(FFI_LIB)
	@mkdir -p $(BUILD)
ifneq ($(SDKROOT),)
	$(CC) -arch $(ARCH) $(CFLAGS) -c $< -o $@.$(ARCH)
	for arch in $(ALT_ARCHS); do \
	  $(CC) -arch $$arch -I$(BUILD)/libffi.$$arch/include $(CFLAGS) -c $< -o $@.$$arch; \
	done
	lipo -create -output $@ $@.*
else
	$(CC) $(CFLAGS) -c $< $(COUT)
endif

all: $(LIBRARY) $(TESTLIB) $(TESTLIB2)

install:
	mkdir $(INSTALLDIR)
	cp $(LIBRARY) $(INSTALLDIR)

$(RSRC): $(BUILD)/jnidispatch.rc
	$(WINDRES) -i $< -o $@ \
          || (echo > $@.c && $(CC) $(CFLAGS) -c $@.c $(COUT))

$(LIBRARY): $(JNIDISPATCH_OBJS) $(FFI_LIB) 
	$(LD) $(LDFLAGS) $(JNIDISPATCH_OBJS) $(FFI_LIB) $(LIBS)

$(TESTLIB): $(BUILD)/testlib.o 
	$(LD) $(LDFLAGS) $<

ifeq ($(ARSFX),.lib)
TESTDEP=$(TESTLIB:.dll=.lib)
else
TESTDEP=$(TESTLIB)
endif
$(TESTLIB2): $(BUILD)/testlib2.o 
	$(LD) $(LDFLAGS) $< $(TESTDEP)

ifneq ($(DYNAMIC_LIBFFI),true)
$(FFI_LIB):
	@mkdir -p $(FFI_BUILD)
	@if [ ! -f $(FFI_BUILD)/Makefile ]; then \
	  echo "Configuring libffi ($(ARCH))"; \
	  (cd $(FFI_BUILD) \
	    && $(FFI_ENV) $(FFI_SRC)/configure $(FFI_CONFIG)); \
	fi
	$(MAKE) -C $(FFI_BUILD)
ifneq ($(SDKROOT),)
	@for arch in $(ALT_ARCHS); do \
	  mkdir -p $(BUILD)/libffi.$$arch; \
	  if [ ! -f $(BUILD)/libffi.$$arch/Makefile ]; then \
	    echo "Configuring libffi ($$arch)"; \
	    (cd $(BUILD)/libffi.$$arch \
	     && CC="$(CC)" CFLAGS="-arch $$arch $(ISYSROOT) $(COPT) $(CDEBUG)" CPPFLAGS="$(CDEFINES)" \
                LDFLAGS="-arch $$arch" \
               $(FFI_SRC)/configure $(FFI_CONFIG) --host=$$arch-apple-darwin --disable-dependency-tracking); \
	  fi; \
	  $(MAKE) -C $(BUILD)/libffi.$$arch; \
	done
	/usr/bin/libtool -static -o $@.tmp $(FFI_BUILD)/.libs/${@F} $(BUILD)/libffi.*/.libs/${@F}
	mv $@.tmp $@
endif
endif

clean:
	$(RM) -rf $(BUILD) 

version:
	@echo version=$(JNA_JNI_VERSION)

#EOF
