cmake_minimum_required(VERSION 2.8)
project (OIOSDS C)

include(CheckIncludeFile)
include(CheckLibraryExists)
include(CheckTypeSize)
#include(FindFLEX)
#include(FindBISON)
include(FindCURL)
include(FindPythonInterp)
include(FindZLIB)
find_package(PkgConfig)

if (NOT DEFINED OIOSDS_RELEASE)
	set(OIOSDS_RELEASE master)
endif ()
if (NOT DEFINED OIOSDS_API_VERSION_SHORT)
	set(OIOSDS_API_VERSION_SHORT "1.0")
endif ()

set(OIOSDS_API_VERSION "${OIOSDS_RELEASE}/${OIOSDS_API_VERSION_SHORT}")

if (NOT ABI_VERSION)
	set(ABI_VERSION 0)
endif()

set(CMAKE_C_FLAGS "-g -fPIC -pipe -Wall -Wextra -std=gnu99")

# XXX(jfs): necessary to benefit from zero'ed static allocation of structures
# as proposed by C99. (we only allocate the first field and let the compiler
# init the others to zero.
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-missing-field-initializers")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-error=missing-braces")

if (CMAKE_COMPILER_IS_GNUCC)
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wunused")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-variadic-macros")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wsequence-point")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wredundant-decls")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wshadow")

	# gcc >= 4.2
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wcomment")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wmain")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wparentheses")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wfloat-equal")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wunsafe-loop-optimizations")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wunused-but-set-parameter")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wunused-but-set-variable")

	# gcc >= 4.6
	set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wmissing-prototypes")
	#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wconversion")
	#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wswitch-enum")
endif()

set(CMAKE_C_FLAGS_DEBUG          "-O0 -fno-inline")
set(CMAKE_C_FLAGS_RELEASE        "-O2")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -fno-inline")
set(CMAKE_C_FLAGS_MINSIZEREL     "-Os -s")

add_definitions(-D_REENTRANT)
add_definitions(-D_LARGE_FILES)
add_definitions(-D_LARGEFILE_SOURCE)
add_definitions(-D_LARGEFILE64_SOURCE)
add_definitions(-D_FILE_OFFSET_BITS=64)
add_definitions(-DHAVE_SOCKLEN_T)
add_definitions(-DOIOSDS_API_VERSION="${OIOSDS_API_VERSION}")
if (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
	MESSAGE("DEBUG symbols enabled")
	add_definitions(-DG_ERRORCHECK_MUTEXES)
	add_definitions(-DHAVE_EXTRA_ASSERT=1)
	add_definitions(-DHAVE_EXTRA_DEBUG=1)
endif()

if (DEFINED STACK_PROTECTOR)
	set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector-all")
endif()
if (SOCKET_OPTIMIZED)
	add_definitions(-D_GNU_SOURCE)
	add_definitions(-DHAVE_SOCKET3)
	add_definitions(-DHAVE_ACCEPT4)
endif()
if (FORBID_SLICE)
	add_definitions(-DHAVE_NO_SLICE)
endif()
if (ALLOW_BACKTRACE)
	add_definitions(-DHAVE_BACKTRACE)
endif()
if (SOCKET_LINGER_ONOFF)
	add_definitions(-DSOCK_DEFAULT_LINGER_ONOFF=${SOCKET_LINGER_ONOFF})
endif ()
if (SOCKET_LINGER_DELAY)
	add_definitions(-DSOCK_DEFAULT_LINGER_DELAY=${SOCKET_LINGER_DELAY})
endif ()
if (FORBID_DEPRECATED)
	add_definitions(-DG_DISABLE_DEPRECATED=1)
endif ()

MESSAGE("FORBID_SLICE ${FORBID_SLICE}")
MESSAGE("STACK_PROTECTOR ${STACK_PROTECTOR}")
MESSAGE("FORBID_DEPRECATED ${FORBID_DEPRECATED}")
MESSAGE("SOCKET_OPTIMIZED ${SOCKET_OPTIMIZED}")
MESSAGE("SOCKET_LINGER_ONOFF ${SOCKET_LINGER_ONOFF}")
MESSAGE("SOCKET_LINGER_DELAY ${SOCKET_LINGER_DELAY}")

###-------------------------------------------------------------------------###

macro (dir2macro2 N D)
	if (${N})
		add_definitions(-D${N}=${${N}})
		MESSAGE("CFLAGS: ${N} = ${${N}}")
	else ()
		add_definitions(-D${N}=${D})
		MESSAGE("CFLAGS: ${N} = ${D} (default)")
	endif ()
endmacro ()

macro (dir2macro N)
	if (${N})
		add_definitions(-D${N}=${${N}})
		MESSAGE("CFLAGS: ${N} = ${${N}}")
	else ()
		MESSAGE("CFLAGS: ${N} left to default")
	endif ()
endmacro ()

macro(test_CLI var msg)
	if (${var})
		MESSAGE(STATUS "FOUND CLI ${msg} : ${${var}}")
	else ()
		MESSAGE(FATAL_ERROR "NOT FOUND CLI ${msg}")
	endif ()
endmacro()

function (print_found arg)
	MESSAGE (STATUS "### ${arg} F=${${arg}_FOUND} V=${${arg}_VERSION} I=${${arg}_INCLUDE_DIRS} LD=${${arg}_LIBRARY_DIRS} L=${${arg}_LIBRARIES} H=${${arg}_HEADER}")
endfunction()

function (check_found)
	foreach (arg ${ARGN})
		print_found (${arg})
	endforeach()
	foreach (arg ${ARGN})
		if (NOT ${arg}_FOUND)
			MESSAGE(FATAL_ERROR " ${arg} not found")
		endif ()
	endforeach ()
endfunction()

macro (option_or_system _PREFIX _LIB)

	# Set configured defaults
	if (NOT DEFINED ${_PREFIX}_INCLUDE_DIRS)
		set (${_PREFIX}_INCLUDE_DIRS "${DEFAULT_INCLUDE_DIRS}" )
	endif ()
	if (NOT DEFINED ${_PREFIX}_LIBRARY_DIRS)
		set (${_PREFIX}_LIBRARY_DIRS "${DEFAULT_LIBRARY_DIRS}" )
	endif ()

	# Override with CLI options
	if (DEFINED ${_PREFIX}_INCDIR)
		set (${_PREFIX}_INCLUDE_DIRS ${${_PREFIX}_INCDIR} )
	endif ()
	if (DEFINED ${_PREFIX}_LIBDIR)
		set (${_PREFIX}_LIBRARY_DIRS ${${_PREFIX}_LIBDIR} )
	endif ()

	# Check expected elements are present
	find_library (${_PREFIX}_LIBRARIES ${_LIB} ${${_PREFIX}_LIBRARY_DIRS})
	set (_FOUND true)
	set (_HEADERS "")
	foreach (arg ${ARGN})
		if (_FOUND)
			find_file (_HEADER ${arg} ${${_PREFIX}_INCLUDE_DIRS})
			if (NOT _HEADER OR _HEADER MATCHES ".*NOTFOUND$")
				set (_FOUND false)
			else ()
				set (_HEADERS "${_HEADERS}:${_HEADER}")
			endif ()
			unset(_HEADER CACHE)
		endif ()
	endforeach ()

	if (NOT ${_PREFIX}_LIBRARIES OR ${_PREFIX}_LIBRARIES MATCHES ".*NOTFOUND$")
		set (${_PREFIX}_FOUND true )
	endif ()
	set (${_PREFIX}_FOUND ${_FOUND} )
	set (${_PREFIX}_HEADER "${_HEADERS}")
	unset(_FOUND CACHE)
	unset(_HEADERS CACHE)
endmacro ()

macro(bin_prefix T N)
	if (NOT DEFINED EXE_PREFIX)
		set(EXE_PREFIX "oio")
	endif ()
	set_target_properties(${T} PROPERTIES OUTPUT_NAME ${EXE_PREFIX}${N})
endmacro ()

###-------------------------------------------------------------------------###

dir2macro("GCLUSTER_RUN_DIR")
dir2macro("GCLUSTER_ETC_DIR")

dir2macro("GCLUSTER_CONFIG_FILE_PATH")
dir2macro("GCLUSTER_CONFIG_DIR_PATH")
dir2macro("GCLUSTER_CONFIG_LOCAL_PATH")
dir2macro("GCLUSTER_AGENT_SOCK_PATH")

dir2macro("GS_CONFIG_NSINFO_REFRESH")

dir2macro("OIO_EVT_BEANSTALKD_DEFAULT_PRIO")
dir2macro("OIO_EVT_BEANSTALKD_DEFAULT_DELAY")
dir2macro("OIO_EVT_BEANSTALKD_DEFAULT_TTR")

dir2macro("OIO_ETC_DIR")
dir2macro("OIO_CONFIG_FILE_PATH")
dir2macro("OIO_CONFIG_DIR_PATH")
dir2macro("OIO_CONFIG_LOCAL_PATH")
dir2macro("OIO_DEFAULT_STGPOL")
dir2macro("OIO_DEFAULT_CHUNKMETHOD")
dir2macro("OIO_DEFAULT_MIMETYPE")

dir2macro("PROXYD_PREFIX")
dir2macro("PROXYD_HEADER_PREFIX")
dir2macro("PROXYD_HEADER_MODE")
dir2macro("PROXYD_HEADER_REQID")
dir2macro("PROXYD_HEADER_NOEMPTY")
dir2macro("PROXYD_PATH_MAXLEN")
dir2macro("PROXYD_DEFAULT_TTL_CSM0")
dir2macro("PROXYD_DEFAULT_MAX_CSM0")
dir2macro("PROXYD_DEFAULT_TTL_SERVICES")
dir2macro("PROXYD_DEFAULT_MAX_SERVICES")
dir2macro("PROXYD_PERIOD_RELOAD_NSINFO")
dir2macro("PROXYD_PERIOD_RELOAD_CSURL")
dir2macro("PROXYD_PERIOD_RELOAD_SRVTYPES")
dir2macro("PROXYD_PERIOD_RELOAD_M0INFO")
dir2macro("PROXYD_TTL_DEAD_LOCAL_SERVICES")
dir2macro("PROXYD_TTL_DOWN_SERVICES")
dir2macro("PROXYD_TTL_KNOWN_SERVICES")
dir2macro("PROXYD_DEFAULT_TIMEOUT_CONSCIENCE")
dir2macro("PROXYD_DEFAULT_PERIOD_DOWNSTREAM")
dir2macro("PROXYD_DEFAULT_PERIOD_UPSTREAM")

dir2macro("OIO_EVTQ_MAXPENDING")

dir2macro("SQLX_DIR_SCHEMAS")
dir2macro("SQLX_ADMIN_PREFIX_SYS")
dir2macro("SQLX_ADMIN_PREFIX_USER")
dir2macro("SQLX_ADMIN_INITFLAG")
dir2macro("SQLX_ADMIN_STATUS")
dir2macro("SQLX_ADMIN_REFERENCE")
dir2macro("SQLX_ADMIN_BASENAME")
dir2macro("SQLX_ADMIN_BASETYPE")
dir2macro("SQLX_ADMIN_NAMESPACE")

dir2macro("M2V2_ADMIN_PREFIX_SYS")
dir2macro("M2V2_ADMIN_PREFIX_USER")
dir2macro("M2V2_ADMIN_VERSION")
dir2macro("M2V2_ADMIN_QUOTA")
dir2macro("M2V2_ADMIN_SIZE")
dir2macro("M2V2_ADMIN_CTIME")
dir2macro("M2V2_ADMIN_VERSIONING_POLICY")
dir2macro("M2V2_ADMIN_STORAGE_POLICY")
dir2macro("M2V2_ADMIN_KEEP_DELETED_DELAY")

dir2macro("META2_INIT_FLAG")

dir2macro("COMMON_CNX_TIMEOUT")
dir2macro("COMMON_CLIENT_TIMEOUT")
dir2macro("M2V2_CLIENT_TIMEOUT")
dir2macro("M2V2_CLIENT_TIMEOUT_HUGE")
dir2macro("M1V2_CLIENT_TIMEOUT")
dir2macro("M0V2_CLIENT_TIMEOUT")
dir2macro("CS_CLIENT_TIMEOUT")

dir2macro("SERVER_DEFAULT_EPOLL_MAXEV")
dir2macro("SERVER_DEFAULT_ACCEPT_MAX")
dir2macro("SERVER_DEFAULT_THP_MAXUNUSED")
dir2macro("SERVER_DEFAULT_THP_MAXWORKERS")
dir2macro("SERVER_DEFAULT_THP_IDLE")
dir2macro("SERVER_DEFAULT_CNX_IDLE")
dir2macro("SERVER_DEFAULT_CNX_LIFETIME")
dir2macro("SERVER_DEFAULT_CNX_INACTIVE")
dir2macro("DAEMON_DEFAULT_TIMEOUT_READ")
dir2macro("DAEMON_DEFAULT_TIMEOUT_ACCEPT")

###-------------------------------------------------------------------------###

if (NOT DEFINED CMAKE_INSTALL_PREFIX)
	set (CMAKE_INSTALL_PREFIX "/usr/local")
endif ()
MESSAGE(STATUS "Installation prefix : ${CMAKE_INSTALL_PREFIX}")


if (LD_LIBEXECDIR)
	MESSAGE("LD_LIBEXECDIR explicitely set to ${LD_LIBEXECDIR}")
else ()
	set (LD_LIBEXECDIR "libexec")
	MESSAGE("LD_LIBEXECDIR set to ${LD_LIBEXECDIR} (default)")
endif ()

if (LD_LIBDIR)
	MESSAGE("LD_LIBDIR explicitely set to ${LD_LIBDIR}")
else()
	CHECK_TYPE_SIZE(long SIZEOF_LONG)
	MESSAGE(STATUS "sizeof(long) = ${SIZEOF_LONG}")
	if (SIZEOF_LONG EQUAL 8)
		set (LD_LIBDIR "lib64")
	else ()
		set (LD_LIBDIR "lib")
	endif ()
	MESSAGE("LD_LIBDIR set to ${LD_LIBDIR} (default)")
endif()

if (PKGCONFIG_DIRECTORY)
	MESSAGE("PKGCONFIG_DIRECTORY explicitely set to ${PKGCONFIG_DIRECTORY}")
else ()
	set(PKGCONFIG_DIRECTORY "${CMAKE_INSTALL_PREFIX}/${LD_LIBDIR}/pkgconfig")
	MESSAGE("PKGCONFIG_DIRECTORY set to ${PKGCONFIG_DIRECTORY} (default)")
endif ()

set (GRIDD_PLUGINS_DIRECTORY "${LD_LIBDIR}/grid")
if (DEFINED GRIDD_PLUGINS)
	set(GRIDD_PLUGINS_DIRECTORY "${GRIDD_PLUGINS}")
endif ()

###-------------------------------------------------------------------------###

if (NOT SDK_ONLY)
find_program(BISON_EXECUTABLE bison)
find_program(FLEX_EXECUTABLE flex)
test_CLI(FLEX_EXECUTABLE "flex")
test_CLI(BISON_EXECUTABLE "bison")
endif(NOT SDK_ONLY)

# Set defaults
set(DEFAULT_LIBRARY_DIRS "/usr/${LD_LIBDIR}")
set(DEFAULT_INCLUDE_DIRS "/usr/include")
set(LZO_INCLUDE_DIRS "${DEFAULT_INCLUDE_DIRS}/lzo")
set(APACHE2_LIBRARY_DIRS "${DEFAULT_LIBRARY_DIRS}/httpd")
set(APACHE2_INCLUDE_DIRS "${DEFAULT_INCLUDE_DIRS}/httpd")
set(ATTR_INCLUDE_DIRS "${DEFAULT_INCLUDE_DIRS}/attr")
set(ZK_INCLUDE_DIRS "${DEFAULT_INCLUDE_DIRS}/zookeeper")

# check system configuration
pkg_search_module(JSONC json json-c)
pkg_check_modules(GLIB2 REQUIRED glib-2.0 gthread-2.0 gmodule-2.0)
pkg_check_modules(CURL curl libcurl)

if (NOT SDK_ONLY)
pkg_check_modules(APR REQUIRED apr-1)
pkg_check_modules(SQLITE3 REQUIRED sqlite3)
pkg_check_modules(ZMQ libzmq>=4.0.0)
# Optional cache libraries
pkg_search_module(HIREDIS hiredis)
pkg_search_module(LIBMEMCACHED libmemcached)

endif (NOT SDK_ONLY)

# Load CLI-overriden configuration
option_or_system(CURL curl curl/curl.h)
option_or_system(JSONC json-c json.h)

if (NOT SDK_ONLY)
option_or_system(ASN1C asn1cskeletons)
option_or_system(APACHE2 modules/mod_webdav.so httpd.h)
option_or_system(ATTR attr attr/xattr.h)
option_or_system(LIBRAIN rain librain.h)
option_or_system(LZO lzo2 lzo1.h lzo1x.h lzoutil.h)
option_or_system(ZK zookeeper_mt zookeeper.h)
option_or_system(ZLIB z zlib.h)
option_or_system(ZMQ zmq zmq.h zmq_utils.h)

if (ASN1C_EXE)
	set(ASN1C_EXECUTABLE ${ASN1C_EXE})
else()
	find_program(ASN1C_EXECUTABLE asn1c)
endif()
MESSAGE("asn1c at ${ASN1C_EXECUTABLE}")
set(ASN1C_EXE_OPTS "-fwide-types")
endif (NOT SDK_ONLY)

# Check every required module is present
print_found("HIREDIS")
print_found("LIBMEMCACHED")
check_found("CURL" "GLIB2" "JSONC")

if (NOT SDK_ONLY)
check_found("APR" "APACHE2" "ASN1C" "ATTR" "LIBRAIN" "LZO"
		"SQLITE3" "ZMQ" "ZK" "PYTHONINTERP")

if (DEFINED APACHE2_MODDIR)
	set (APACHE2_MODULES_DIRS ${APACHE2_MODDIR})
else ()
	set (APACHE2_MODULES_DIRS ${APACHE2_LIBRARY_DIRS}/modules)
endif ()
endif (NOT SDK_ONLY)

ENABLE_TESTING()

set(CMAKE_LIBRARY_PATH "")
set(CMAKE_INCLUDE_PATH "")
include_directories(AFTER
		${GLIB2_INCLUDE_DIRS})

link_directories(${GLIB2_LIBRARY_DIRS})

add_subdirectory(./core)

if (NOT SDK_ONLY)
add_subdirectory(./metautils/lib)
add_subdirectory(./cache)
add_subdirectory(./cluster/lib)

add_subdirectory(./cluster/conscience)
add_subdirectory(./cluster/module)
add_subdirectory(./cluster/tools)
add_subdirectory(./gridd/main)
add_subdirectory(./gridd/plugins/msg_fallback)
add_subdirectory(./gridd/plugins/msg_ping)
add_subdirectory(./gridd/plugins/msg_stats)
add_subdirectory(./meta0v2)
add_subdirectory(./meta1v2)
add_subdirectory(./meta2v2)
add_subdirectory(./proxy)
add_subdirectory(./rainx)
add_subdirectory(./events)
add_subdirectory(./rawx-apache2/src)
add_subdirectory(./rawx-lib/src)
add_subdirectory(./rawx-lib/tools)
add_subdirectory(./resolver)
add_subdirectory(./server)
add_subdirectory(./sqliterepo)
add_subdirectory(./sqlx)
add_subdirectory(./tools)
add_subdirectory(./tests/unit)
add_subdirectory(./tests/func)
endif (NOT SDK_ONLY)

