# This makefile can be used independently of Python, 
# in order to build a standalone C++ library.
# The Python module can also be built this way if so desired

prefix=/usr/local
build=build
src=src
soext=so

help:
	@echo 'Possible Makefile targets (use "make target" to build them):'
	@echo "- lib : this creates the libsen1den.$(soext) C++ library"
	@echo '- install : this installs the headers in $(prefix)/include and the C++ library in $(prefix)/lib. Use: "make prefix=/some/path install" in order to change this.'
	@echo "- module : this creates the sen1den.$(soext) Python module. It may be preferable to use the setup.py tool in order to integrate the module to your local python installation. Yet, building the module this way and changing PYTHONPATH is quicker for debugging."
	@echo "- jni : this add a java native interface to the C++ lib and compiles it into libsen1denjni.$(soext)"
	@echo
	@echo 'This make file takes the sources from the (sub)directory "$(src)" and builds into "$(build)" (created if it does not exist). Use make src=/where/the/src/subdir/is build=/some/other/location to change this.'
	@echo 'Other influencial variables that can be changed with "make VAR=value"'
	@echo '- CXX : The C++ compiler'
	@echo '- FLAGS : Some compilation flags to add to the compiler'
	@echo '- AR : The ar archive utility for building static libraries'
	@echo
	@echo 'In order to cross-compile the JNI lib for windows, do something like:'
	@echo '- Install MXE as described here: http://pkg.mxe.cc/
	@echo '- Compile for 32 bits windows: make build=build.w32 CXX=/usr/lib/mxe/usr/bin/i686-w64-mingw32.shared-g++ AR=/usr/lib/mxe/usr/bin/i686-w64-mingw32.shared-ar soext=dll jni'
	@echo
	@echo '- Compile for 64 bits windows: make build=build.w64 CXX=/usr/lib/mxe/usr/bin/x86_64-w64-mingw32.shared-g++ AR=/usr/lib/mxe/usr/bin/x86_64-w64-mingw32.shared-ar soext=dll jni'
	@echo
	@echo 'Cross-compiling for MacOS is not supported yet, but might be attempted with either https://github.com/multiarch/crossbuild or with https://github.com/tpoechtrager/osxcross'

# TODO: Add dll dependencies for self-contained windows dlls.
# objdump -p build.w64/java/libsen1denjni.dll|grep 'DLL Name:'
#       DLL Name: libgcc_s_seh-1.dll
#       DLL Name: libgomp-1.dll
#       DLL Name: libstdc++-6.dll
#       (and a few more that are preinstalled under windows)
# Recursing: objdump -p  /usr/lib/mxe/usr/x86_64-w64-mingw32.shared/bin/libgomp-1.dll|grep 'DLL Name:'
# finds that libwinpthread-1.dll is also needed


AR=ar

PY_FLAGS=`python-config --includes` -I$(src)/boost 

ifdef debug
	FLAGS := $(CXXFLAGS) -I$(src) -fPIC -std=c++11 -fopenmp -g -DEIGEN_UNROLLING_LIMIT=0 -DEIGEN_DONT_PARALLELIZE
else
	FLAGS := $(CXXFLAGS) -I$(src) -fPIC -std=c++11 -fopenmp -O3 -DEIGEN_UNROLLING_LIMIT=0 -DEIGEN_DONT_PARALLELIZE
endif

$(build):
	mkdir -p $(build)

#for f in `find boost/ -name '*.cpp'` ; do echo '$(build)'/${f:t:r}.o ; done | xargs
PY_OBJECTS=$(build)/arg_to_python_base.o $(build)/builtin_converters.o $(build)/from_python.o $(build)/registry.o $(build)/type_id.o $(build)/class.o $(build)/enum.o $(build)/function.o $(build)/function_doc_signature.o $(build)/inheritance.o $(build)/iterator.o $(build)/life_support.o $(build)/pickle_support.o $(build)/stl_iterator.o $(build)/dict.o $(build)/errors.o $(build)/exec.o $(build)/import.o $(build)/list.o $(build)/long.o $(build)/module.o $(build)/numeric.o $(build)/object_operators.o $(build)/object_protocol.o $(build)/slice.o $(build)/str.o $(build)/tuple.o $(build)/wrapper.o $(build)/dtype.o $(build)/matrix.o $(build)/ndarray.o $(build)/numpy.o $(build)/scalars.o $(build)/ufunc.o

#for f in `find boost/ -name '*.cpp'` ; do echo '$(build)'/"${f:t:r}.o: \$(src)/$f\n\t\$(CXX) \$(FLAGS) -c \$(src)/$f -o \$@\n"; done >> Makefile

$(build)/arg_to_python_base.o: $(src)/boost/python/converter/arg_to_python_base.cpp
	$(CXX) $(FLAGS) $(PY_FLAGS) -c $(src)/boost/python/converter/arg_to_python_base.cpp -o $@

$(build)/builtin_converters.o: $(src)/boost/python/converter/builtin_converters.cpp
	$(CXX) $(FLAGS) $(PY_FLAGS) -c $(src)/boost/python/converter/builtin_converters.cpp -o $@

$(build)/from_python.o: $(src)/boost/python/converter/from_python.cpp
	$(CXX) $(FLAGS) $(PY_FLAGS) -c $(src)/boost/python/converter/from_python.cpp -o $@

$(build)/registry.o: $(src)/boost/python/converter/registry.cpp
	$(CXX) $(FLAGS) $(PY_FLAGS) -c $(src)/boost/python/converter/registry.cpp -o $@

$(build)/type_id.o: $(src)/boost/python/converter/type_id.cpp
	$(CXX) $(FLAGS) $(PY_FLAGS) -c $(src)/boost/python/converter/type_id.cpp -o $@

$(build)/class.o: $(src)/boost/python/object/class.cpp
	$(CXX) $(FLAGS) $(PY_FLAGS) -c $(src)/boost/python/object/class.cpp -o $@

$(build)/enum.o: $(src)/boost/python/object/enum.cpp
	$(CXX) $(FLAGS) $(PY_FLAGS) -c $(src)/boost/python/object/enum.cpp -o $@

$(build)/function.o: $(src)/boost/python/object/function.cpp
	$(CXX) $(FLAGS) $(PY_FLAGS) -c $(src)/boost/python/object/function.cpp -o $@

$(build)/function_doc_signature.o: $(src)/boost/python/object/function_doc_signature.cpp
	$(CXX) $(FLAGS) $(PY_FLAGS) -c $(src)/boost/python/object/function_doc_signature.cpp -o $@

$(build)/inheritance.o: $(src)/boost/python/object/inheritance.cpp
	$(CXX) $(FLAGS) $(PY_FLAGS) -c $(src)/boost/python/object/inheritance.cpp -o $@

$(build)/iterator.o: $(src)/boost/python/object/iterator.cpp
	$(CXX) $(FLAGS) $(PY_FLAGS) -c $(src)/boost/python/object/iterator.cpp -o $@

$(build)/life_support.o: $(src)/boost/python/object/life_support.cpp
	$(CXX) $(FLAGS) $(PY_FLAGS) -c $(src)/boost/python/object/life_support.cpp -o $@

$(build)/pickle_support.o: $(src)/boost/python/object/pickle_support.cpp
	$(CXX) $(FLAGS) $(PY_FLAGS) -c $(src)/boost/python/object/pickle_support.cpp -o $@

$(build)/stl_iterator.o: $(src)/boost/python/object/stl_iterator.cpp
	$(CXX) $(FLAGS) $(PY_FLAGS) -c $(src)/boost/python/object/stl_iterator.cpp -o $@

$(build)/dict.o: $(src)/boost/python/dict.cpp
	$(CXX) $(FLAGS) $(PY_FLAGS) -c $(src)/boost/python/dict.cpp -o $@

$(build)/errors.o: $(src)/boost/python/errors.cpp
	$(CXX) $(FLAGS) $(PY_FLAGS) -c $(src)/boost/python/errors.cpp -o $@

$(build)/exec.o: $(src)/boost/python/exec.cpp
	$(CXX) $(FLAGS) $(PY_FLAGS) -c $(src)/boost/python/exec.cpp -o $@

$(build)/import.o: $(src)/boost/python/import.cpp
	$(CXX) $(FLAGS) $(PY_FLAGS) -c $(src)/boost/python/import.cpp -o $@

$(build)/list.o: $(src)/boost/python/list.cpp
	$(CXX) $(FLAGS) $(PY_FLAGS) -c $(src)/boost/python/list.cpp -o $@

$(build)/long.o: $(src)/boost/python/long.cpp
	$(CXX) $(FLAGS) $(PY_FLAGS) -c $(src)/boost/python/long.cpp -o $@

$(build)/module.o: $(src)/boost/python/module.cpp
	$(CXX) $(FLAGS) $(PY_FLAGS) -c $(src)/boost/python/module.cpp -o $@

$(build)/numeric.o: $(src)/boost/python/numeric.cpp
	$(CXX) $(FLAGS) $(PY_FLAGS) -c $(src)/boost/python/numeric.cpp -o $@

$(build)/object_operators.o: $(src)/boost/python/object_operators.cpp
	$(CXX) $(FLAGS) $(PY_FLAGS) -c $(src)/boost/python/object_operators.cpp -o $@

$(build)/object_protocol.o: $(src)/boost/python/object_protocol.cpp
	$(CXX) $(FLAGS) $(PY_FLAGS) -c $(src)/boost/python/object_protocol.cpp -o $@

$(build)/slice.o: $(src)/boost/python/slice.cpp
	$(CXX) $(FLAGS) $(PY_FLAGS) -c $(src)/boost/python/slice.cpp -o $@

$(build)/str.o: $(src)/boost/python/str.cpp
	$(CXX) $(FLAGS) $(PY_FLAGS) -c $(src)/boost/python/str.cpp -o $@

$(build)/tuple.o: $(src)/boost/python/tuple.cpp
	$(CXX) $(FLAGS) $(PY_FLAGS) -c $(src)/boost/python/tuple.cpp -o $@

$(build)/wrapper.o: $(src)/boost/python/wrapper.cpp
	$(CXX) $(FLAGS) $(PY_FLAGS) -c $(src)/boost/python/wrapper.cpp -o $@

$(build)/dtype.o: $(src)/boost/numpy/dtype.cpp
	$(CXX) $(FLAGS) $(PY_FLAGS) -c $(src)/boost/numpy/dtype.cpp -o $@

$(build)/matrix.o: $(src)/boost/numpy/matrix.cpp
	$(CXX) $(FLAGS) $(PY_FLAGS) -c $(src)/boost/numpy/matrix.cpp -o $@

$(build)/ndarray.o: $(src)/boost/numpy/ndarray.cpp
	$(CXX) $(FLAGS) $(PY_FLAGS) -c $(src)/boost/numpy/ndarray.cpp -o $@

$(build)/numpy.o: $(src)/boost/numpy/numpy.cpp
	$(CXX) $(FLAGS) $(PY_FLAGS) -c $(src)/boost/numpy/numpy.cpp -o $@

$(build)/scalars.o: $(src)/boost/numpy/scalars.cpp
	$(CXX) $(FLAGS) $(PY_FLAGS) -c $(src)/boost/numpy/scalars.cpp -o $@

$(build)/ufunc.o: $(src)/boost/numpy/ufunc.cpp
	$(CXX) $(FLAGS) $(PY_FLAGS) -c $(src)/boost/numpy/ufunc.cpp -o $@

$(build)/python.a: $(PY_OBJECTS) | $(build)
	$(AR) rcs $@ $(PY_OBJECTS)



# Main sen1den c++ file
$(build)/sen1den.o: $(src)/sen1den.cpp $(src)/sen1den.hpp | $(build)
	$(CXX) $(FLAGS) -c $(src)/sen1den.cpp -o $@

$(build)/sen1den_module.o: $(src)/sen1den_module.cpp $(src)/sen1den.hpp | $(build)
	$(CXX) $(FLAGS) $(PY_FLAGS) -c $(src)/sen1den_module.cpp -o $@
	
# Python module
$(build)/sen1den.$(soext): $(build)/sen1den_module.o $(build)/sen1den.o $(PY_OBJECTS) | $(build)
	$(CXX) $(FLAGS) $(build)/sen1den_module.o $(build)/sen1den.o $(PY_OBJECTS) $(CERES_OBJECTS) -shared -o $@

module: $(build)/sen1den.$(soext)
	@echo "Python module built in $(build)/sen1den.$(soext). You can test it locally, but please use the setup.py script for a system install."

# C++ shared library
$(build)/libsen1den.$(soext): $(build)/sen1den.o $(CERES_OBJECTS) | $(build)
	$(CXX) $(FLAGS) $(build)/sen1den.o $(CERES_OBJECTS) -shared -o $@

# C++ static library
$(build)/libsen1den.a: $(build)/sen1den.o $(CERES_OBJECTS)
	$(AR) rcs $@ $(build)/sen1den.o $(CERES_OBJECTS)

lib: $(build)/libsen1den.$(soext) $(build)/libsen1den.a

clean_python:
	rm -f $(PY_OBJECTS)

clean: clean_python
	rm -f $(build)/sen1den.$(soext) $(build)/libsen1den.$(soext) $(build)/libsen1den.a

package:
	tar cfvz sen1den.tar.gz --transform 's,^,sen1den/,' Licence_CeCILL-C_v1-en.txt Licence_LGPL_v2.1.txt Makefile MANIFEST.in README.txt requirements.txt sentinel1_denoise.py setup.py VERSION src/

install: lib
	cp $(src)/sen1den.hpp $(prefix)/include
	cp $(build)/libsen1den.$(soext) $(prefix)/lib
	cp $(build)/libsen1den.a $(prefix)/lib

.PHONY: clean clean_python module lib install package
