##########################################################################################
##########################################################################################
########################                                        ##########################
########################          HELib Improved Makefile       ##########################
########################                                        ##########################
##########################################################################################
##########################################################################################
#
# DESCRIPTION: Improved Makefile for HElib project (Shai Halevi), allowing the install of
#              this library as a shared library and greatly simplifying its usage: the lib
#              can now be linked when compiling a program using the flag [-lfhe]. Plus,
#              all header files (.h) are installed in a folder called 'fhe/'.
#              In order to use the library in your own .cpp code, use this formula (or
#              similar for other .h) at the top of the file:
#                       #include <fhe/FHE.h>
#
#              This makefile allows the compilation&linking of .cpp files. A file fname.cpp
#              can be target of this recipe in order to create an executable:
#                       make fname_x
#
#              Some configuration may be required in the Makefile variables to accomodate
#              the settings of a given OS.
#
# AUTHOR: Alberto Ibarrondo (github @ibarrond)
# DATE: 16/10/2017
#
# LICENSE:    
#     Copyright (C) 2012-2017 IBM Corp.
#
#     This program is Licensed under the Apache License, Version 2.0
#    (the "License"); you may not use this file except in compliance
#     with the License. You may obtain a copy of the License at
#       http://www.apache.org/licenses/LICENSE-2.0
#     Unless required by applicable law or agreed to in writing, software
#     distributed under the License is distributed on an "AS IS" BASIS,
#     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#     See the License for the specific language governing permissions and
#     limitations under the License. See accompanying LICENSE file.
# 



$(info IMPROVED HELIB MAKEFILE)
$(info HElib requires NTL version 10.0.0 or higher, see http://shoup.net/ntl)
$(info If you get compilation errors, try to add/remove -std=c++11 in Makefile)
$(info For a list if all the available commands, run >make info)



##########################################################################################
#                                  MAKEFILE VARIABLES                                    #
##########################################################################################

#................................. COMPILER & LINKER .....................................
CC = g++
CFLAGS= -g -O2 -std=c++11 -pthread -DFHE_THREADS -DFHE_BOOT_THREADS -DFHE_DCRT_THREADS
#          -Wfatal-errors -Wshadow -Wall -fmax-errors=2

# Useful flags:
#   -std=c++11
#   -DNO_HALF_SIZE_PRIME  tells helib to not use the half size prime
#                  in the prime chain
#
#   -DFHE_THREADS  tells helib to enable generic multithreading capabilities;
#                  must be used with a thread-enabled NTL and the -pthread
#                  flag should be passed to gcc
#
#   -DFHE_DCRT_THREADS  tells HElib to use a multithreading strategy at the
#                  DoubleCRT level; requires -DFHE_THREADS (see above)
#
#   -DFHE_BOOT_THREADS  tells helib to use a multithreading strategy for
#                  bootstrapping; requires -DFHE_THREADS (see above)
#
#   -DEVALMAP_CACHED=1 Cache some constants for bootstrapping
#
#        * EVALMAP_CACHED=0 caches these constants as ZZX'es, this takes
#                  less space but it means that they still need to be converted
#                  to DoubleCRT's with every recryption operation. 
#
#        * EVALMAP_CACHED=1 caches these constants directly as DoubleCRT's,
#                  this may take a significant amount of memeory.
#
#  If you get compilation errors, you may need to add -std=c++11 or -std=c++0x
#
#
#


#.................................. LIBRARY ATTRIBUTES .......................................
LIBNAME = fhe
	                                # Prefix 'lib' and extension '.la' are added later on
VERSION = 1:0:0
	                                # Library version, independent from packet/repo version
LIBDIR = /usr/local/lib
	                                # Directory where library will be installed
INCLUDE_DIR = /usr/local/include
	                                # Directory where headers will be installed


# NOTE: NTL & GMP are distributed under LGPL (v2.1), they can be linked as dynamic libraries.
GMP=-lgmp
NTL=-lntl
HELIB=-l$(LIBNAME)
LDLIBS = -L$(LIBDIR) $(NTL) $(GMP) -lm


#......................................  LIBTOOL  ............................................
LIBTOOL=libtool
	                                # May not be installed(e.g.: sudo apt install libtool-bin)
LIBTOOL_COMPILE =--mode=compile
	                                # Mode for prog/lib compilation. It uses $(CC) as compiler
LIBTOOL_LINK=--mode=link
	                                # Mode for prog/lib linking. It uses $(CC) as linker
LIBTOOL_INSTALL=--mode=install
	                                # Mode to install. It uses 'cp', recipe 'make install'
LIBTOOL_UNINSTALL=--mode=uninstall
	                                # Mode to uninstall. It uses 'rm', recipe 'make uninstall'
LIBTOOL_CLEAN=--mode=clean
	                                # Mode for cleaning. It uses 'rm', recipe 'make clean'
RPATH=-rpath $(LIBDIR)


#...................................... HEADER FILES .........................................
HEADER = *.h

#...................................... SOURCE FILES .........................................
SRC = KeySwitching.cpp EncryptedArray.cpp FHE.cpp Ctxt.cpp CModulus.cpp FHEContext.cpp \
	PAlgebra.cpp DoubleCRT.cpp NumbTh.cpp bluestein.cpp IndexSet.cpp timing.cpp \
	replicate.cpp hypercube.cpp matching.cpp powerful.cpp BenesNetwork.cpp \
	permutations.cpp PermNetwork.cpp OptimizePermutations.cpp eqtesting.cpp \
	polyEval.cpp extractDigits.cpp EvalMap.cpp recryption.cpp debugging.cpp \
	matmul.cpp intraSlot.cpp binaryArith.cpp binaryCompare.cpp tableLookup.cpp

#............................... LIBRARY INTERMEDIATE FILES ..................................
LOBJ = NumbTh.lo timing.lo bluestein.lo PAlgebra.lo CModulus.lo FHEContext.lo \
	    IndexSet.lo DoubleCRT.lo FHE.lo KeySwitching.lo Ctxt.lo EncryptedArray.lo \
	    replicate.lo hypercube.lo matching.lo powerful.lo BenesNetwork.lo \
	    permutations.lo PermNetwork.lo OptimizePermutations.lo eqtesting.lo \
	    polyEval.lo extractDigits.lo EvalMap.lo recryption.lo debugging.lo \
	    matmul.lo intraSlot.lo binaryArith.lo binaryCompare.lo tableLookup.lo

#.................................. LIBRARY  FINAL FILES .....................................
LIB_LA = lib$(LIBNAME).la



##############################################################################################
#                                      BUILD FHE LIBRARY                                         #
##############################################################################################

all: $(LIB_LA)

# COMPILATION: Create each .lo object from the cpp source code and all headers
%.lo: %.cpp $(HEADER)
	$(LIBTOOL) $(LIBTOOL_COMPILE) $(CC) $(CFLAGS) -fpic -c $< 

# LINKING: Merging all .lo objects into a single .la to use for both static & shared libs
$(LIB_LA): $(LOBJ)
	$(LIBTOOL) $(LIBTOOL_LINK) $(CC) $(CFLAGS) -c -o $@ $^ $(RPATH) $(LDLIBS) -version-info $(VERSION)



##############################################################################################
#                                      INSTALL FHE LIBRARY                                     #
##############################################################################################

install: $(LIB_LA)
	$(LIBTOOL) $(LIBTOOL_INSTALL) cp $(LIB_LA) $(LIBDIR)
	ldconfig
	cp -t $(INCLUDE_DIR) $(HEADER)



##############################################################################################
#                                   CREATE BINARIES WITH FHE                                     #
##############################################################################################

%_x: %.cpp
	$(CC) $(CFLAGS) -o $@ $< $(LDLIBS) $(HELIB)



##############################################################################################
#                                        TEST PROGRAMS                                         #
##############################################################################################

TESTPROGS = Test_General_x \
	        Test_PAlgebra_x \
	        Test_IO_x \
	        Test_Replicate_x \
	        Test_LinPoly_x \
	        Test_matmul_x \
	        Test_matmul1D_x \
	        Test_Powerful_x \
	        Test_Permutations_x \
	        Test_Timing_x \
	        Test_PolyEval_x \
	        Test_extractDigits_x \
	        Test_EvalMap_x \
	        Test_bootstrapping_x

test: $(TESTPROGS)

check: Test_General_x Test_matmul_x Test_matmul1D_x Test_LinPoly_x Test_Permutations_x \
	Test_PolyEval_x Test_Replicate_x Test_EvalMap_x Test_extractDigits_x Test_bootstrapping_x
	./Test_General_x R=1 k=10 p=2 r=2 noPrint=1
	./Test_General_x R=1 k=10 p=2 d=2 noPrint=1
	./Test_General_x R=2 k=10 p=7 r=2 noPrint=1
	./Test_matmul_x m=1365
	./Test_matmul1D_x m=96 p=7
	./Test_LinPoly_x noPrint=1
	./Test_Permutations_x noPrint=1
	./Test_PolyEval_x p=7 r=2 d=34 noPrint=1
	./Test_Replicate_x m=1247 noPrint=1
	./Test_EvalMap_x mvec="[7 3 221]" gens="[3979 3095 3760]" ords="[6 2 -8]" noPrint=1
	./Test_extractDigits_x m=2047 p=5 noPrint=1
	./Test_bootstrapping_x noPrint=1
	./Test_bootstrapping_x p=7 noPrint=1



##############################################################################################
#                                        UNINSTALL & CLEAN                                     #
##############################################################################################

uninstall: 
	$(LIBTOOL) $(LIBTOOL_UNINSTALL) rm -f $(LIBDIR)/$(LIB_LA)
	ldconfig
	cd $(INCLUDE_DIR)
	rm -rf $(HEADER)
	cd -

clean:
	$(LIBTOOL) $(LIBTOOL_CLEAN) rm -f $(LIB_LA)
	rm -rf .libs/ .deps/
	rm -f *.o *_x *_x.exe *.a *.lo *.la *.so



##############################################################################################
#                                        ADDITIONAL INFO                                     #
##############################################################################################


info:
	: HElib requires NTL version 10.0.0 or higher
	: Compilation flags are 'CFLAGS=$(CFLAGS)'
	: Commands Available:
	: * make - compile & link the library
	: * make install - library available in the host. Requires root 
	: * make check - test all functionalities
	: * make fileName_x - Compile & Link binary filename.cpp with HElib and its dependencies
	: * make clean - remove all library files from the folder
	: * make uninstall - remove library from host. Requires root
	: If errors occur, try adding/removing '-std=c++11' in Makefile
	
