cmake_minimum_required(VERSION 2.6)
set(CMAKE_LEGACY_CYGWIN_WIN32 0)


project(cppcms)
set(CPPCMS_PACKAGE_NAME "CppCMS")
set(CPPCMS_PACKAGE_STRING "CppCMS/1.2.1")
set(CPPCMS_PACKAGE_VERSION "1.2.1")

set(CPPCMS_VERSION "1.2.1")
set(CPPCMS_SOVERSION "1")

set(BOOSTER_SOVERSION "0")
set(BOOSTER_VERSION "0.2.0")



include(CheckFunctionExists)
include(CheckCXXSourceCompiles)
include(CheckLibraryExists)
include(CPack)
enable_testing()

#############################################################################
#
# Setup default build options
#
#############################################################################

if(NOT LIBDIR)
	set(LIBDIR lib CACHE STRING "Library installation directory" FORCE)
endif()


option(DISABLE_SHARED		"Disable shared libraries build" OFF)
option(DISABLE_STATIC		"Disable static libraries build" OFF)
option(DISABLE_GCRYPT		"Disable usage of gcrypt library" OFF)
option(DISABLE_OPENSSL		"Disable usage of openssl library" OFF)
option(DISABLE_FCGI		"Disable fastcgi web server api" OFF)
option(DISABLE_SCGI		"Disable scgi web server api" OFF)
option(DISABLE_HTTP		"Disable http web server" OFF)
option(DISABLE_CACHE		"Disable cache beckend" OFF)
option(DISABLE_TCPCACHE		"Disable distributed cache beckend" OFF)
option(DISABLE_GZIP		"Disable support of gzip output compression" OFF)
option(USE_STLPORT		"Build with STLPort library" OFF)

if(USE_STLPORT) 
	find_path(STLPORT_INCLUDE stlport/iostream)
	find_library(STLPORT_LIB stlport)
	if(NOT STLPORT_INCLUDE OR NOT STLPORT_LIB)
		message(FATAL_ERROR "Can't find stlport include or library")
	else()
		include_directories(${STLPORT_INCLUDE}/stlport)
	endif()
endif()

if(CMAKE_CXX_COMPILER_ID STREQUAL "SunPro")
	option(DISABLE_PREFORK_CACHE	"Disable prefork-cache beckend" ON)
else()
	option(DISABLE_PREFORK_CACHE	"Disable prefork-cache beckend" OFF)
endif()

add_subdirectory(booster)

include_directories(booster)
include_directories(src)
include_directories(private)
include_directories(cppcms_boost)
include_directories(${CMAKE_BINARY_DIR})
include_directories(${CMAKE_CURRENT_BINARY_DIR})
include_directories(${CMAKE_CURRENT_BINARY_DIR}/booster)
include_directories(${CMAKE_SOURCE_DIR})

if(DISABLE_CACHE)
	set(DISABLE_PREFORK_CACHE ON)
	set(DISABLE_TCPCACHE ON)
endif()

if(WIN32 OR CYGWIN)
	set(IS_WINDOWS TRUE)
else()
	set(IS_WINDOWS FALSE)
endif()

if(WIN32 AND NOT CYGWIN)
	set(WINDOWS_NATIVE TRUE)
else()
	set(WINDOWS_NATIVE FALSE)
endif()

if(CYGWIN)
	set(IS_CYGWIN TRUE)
else()
	set(IS_CYGWIN FALSE)
endif()





#############################################################################
#
# Setup various build flags for different supported compilers and systems
#
#############################################################################

if(CMAKE_COMPILER_IS_GNUCXX)
	check_cxx_source_compiles(
		"#if __GNUC__ < 4
		#error
		#endif
		int main() {}"
		GCC_IS_GCC4)

	set(CXX_FLAGS "-Wall -Wextra")
	set(C_FLAGS "-Wall -Wextra")

	if(CMAKE_SYSTEM_NAME STREQUAL "SunOS")
		set(CXX_FLAGS "${CXX_FLAGS} -pthreads")
	endif()

	if(NOT GCC_IS_GCC4)
		# Uninitalized checks are bogous under gcc-3.4
		set(CXX_FLAGS "${CXX_FLAGS} -Wno-uninitialized")
	endif()

	if(IS_WINDOWS)
		if(GCC_IS_GCC4) 
			# Very important, otherwise process would not start under cygwin
			set(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -Wl,--enable-auto-import")
		else()
			# gcc-3 does not have shared library for libstdc++ -- cause dll faitures with locale
			set(DISABLE_SHARED ON)
		endif()
	endif()

	if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR CMAKE_SYSTEM_NAME STREQUAL "NetBSD")
		message("Addign rdynamic")
		set(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -rdynamic")
	endif()

elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
	set(CXX_FLAGS "-Wall -Wextra")
	if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
		set(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -rdynamic")
	endif()

elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
	set(CXX_FLAGS "-Wall")
	set(C_FLAGS "-Wall")
elseif(MSVC)
	set(CXX_FLAGS "/EHsc /W3")
	set(C_FLAGS "/W3")
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "SunPro")
	#
	# We use STL port under Sun Studio, standard library is broken
	#
	
	set(CXX_FLAGS "-library=stlport4 -xannotate=no")

	if(CMAKE_SYSTEM_NAME STREQUAL "SunOS")
		set(CXX_FLAGS "${CXX_FLAGS} -mt")
	endif()
endif()

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX_FLAGS}")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${C_FLAGS}")

#############################################################################
#
# Set default RelWithDebInfo build
#
#############################################################################

if(NOT CMAKE_BUILD_TYPE)
  set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING
        "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel."
	      FORCE)
endif(NOT CMAKE_BUILD_TYPE)

if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
	if(MSVC)
		set(ZLIB_SUFFIX "d")
		if(NOT CPPCMS_SUFFIX)
			set(CPPCMS_SUFFIX "-d")
		else()
			set(CPPCMS_SUFFIX "${CPPCMS_SUFFIX}d")
		endif()
	endif()
endif()

check_cxx_source_compiles(
	"#include <stdint.h> 
	int main(){int32_t x; int64_t y; return 0; }"
	CPPCMS_HAVE_STDINT_H)

check_cxx_source_compiles(
	"#include <inttypes.h> 
	int main(){int32_t x; int64_t y; return 0; }"
	CPPCMS_HAVE_INTTYPES_H)

check_function_exists(atoll CPPCMS_HAVE_ATOLL)
check_function_exists(_atoi64 CPPCMS_HAVE_ATOI64)
check_function_exists(snprintf CPPCMS_HAVE_SNPRINTF)
check_function_exists(stat CPPCMS_HAVE_STAT)
check_function_exists(_stat CPPCMS_HAVE__STAT)

set(CPPCMS_LIBRARY_SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX})
set(CPPCMS_LIBRARY_PREFIX ${CMAKE_SHARED_LIBRARY_PREFIX})

#
# Atomic API tests
#


check_cxx_source_compiles(
	"#include <string> 
	int main() { std::wstring s; }"
	CPPCMS_HAVE_STD_WSTRING)

check_cxx_source_compiles(
	"#include <time.h> 
	int main() { struct tm t; char const *p=t.tm_zone; long o=t.tm_gmtoff; }"
	CPPCMS_HAVE_BSD_TM)

check_cxx_source_compiles(
	"#include <string> 
	int main() { std::u16string s16; std::u32string s32; }"
	CPPCMS_HAVE_CPP0X_UXSTRING)

check_cxx_source_compiles(
	"#include <list> 
	int main(){std::list<int> l; auto p=l.begin();}"
	CPPCMS_HAVE_CPP_0X_AUTO)

check_cxx_source_compiles(
	"#include <list> 
	int main(){std::list<int> l; decltype(l.begin()) p=l.begin();}"
	CPPCMS_HAVE_CPP_0X_DECLTYPE)

check_cxx_source_compiles(
	"#include <list> 
	int main(){std::list<int> l; typeof(l.begin()) p=l.begin();}"
	CPPCMS_HAVE_GCC_TYPEOF)

check_cxx_source_compiles(
	"#include <list> 
	int main(){std::list<int> l; __typeof__(l.begin()) p=l.begin();}"
	CPPCMS_HAVE_UNDERSCORE_TYPEOF)
check_cxx_source_compiles(
       "#ifndef _FILE_OFFSET_BITS
	#define _FILE_OFFSET_BITS 64
	#endif
	#include <stdio.h>
	#include <stdlib.h>
	int main()
	{
		char is_big[sizeof(off_t) >= 8 ? 1 : -1];
		fseeko(0,0,0);
	}"
	CPPCMS_HAVE_FSEEKO
)

check_cxx_source_compiles(
	"#include <stdio.h>
	int main()
	{ _fseeki64(0,0,0); }"
	CPPCMS_HAVE_FSEEKI64
)
if(NOT DISABLE_GZIP)
	find_library(ZLIB NAMES z zdll zlib${ZLIB_SUFFIX} zlib)
	find_path(ZLIB_INCLUDE_DIR zlib.h)
	if(NOT ZLIB OR NOT ZLIB_INCLUDE_DIR)
		message(FATAL_ERROR "Can't fild zlib")
	endif()
	include_directories(${ZLIB_INCLUDE_DIR})
endif()


if(IS_WINDOWS)
	set(WS2_32 ws2_32)
	set(WSOCK32 wsock32)
else()
	check_function_exists(dlopen CPPCMS_HAVE_DLOPEN)
	if(NOT CPPCMS_HAVE_DLOPEN)
		check_library_exists(dl dlopen "" CPPCMS_HAVE_LIB_DL)
		if(NOT CPPCMS_HAVE_LIB_DL)
			message(FATAL_ERROR " No library with dlopen found")
		else(NOT CPPCMS_HAVE_LIB_DL)
			find_library(LIB_DL dl)
		endif(NOT CPPCMS_HAVE_LIB_DL)
	endif(NOT CPPCMS_HAVE_DLOPEN)
	
	check_function_exists(socket CPPCMS_HAVE_SOCKET)
	if(NOT CPPCMS_HAVE_SOCKET)
		check_library_exists(socket socket "" CPPCMS_HAVE_LIB_SOCKET)
		if(NOT CPPCMS_HAVE_LIB_SOCKET)
			message(FATAL_ERROR " No library with socket found")
		else(NOT CPPCMS_HAVE_LIB_SOCKET)
			find_library(LIB_SOCKET socket)
		endif(NOT CPPCMS_HAVE_LIB_SOCKET)
	endif(NOT CPPCMS_HAVE_SOCKET)

	check_function_exists(gethostbyname CPPCMS_HAVE_GETHOSTBYNAME)
	if(NOT CPPCMS_HAVE_GETHOSTBYNAME)
		check_library_exists(socket gethostbyname "" LIB_SOCKGETHOSTBYNAME)
		if(NOT LIB_SOCKGETHOSTBYNAME)
			check_library_exists(nsl gethostbyname "" CPPCMS_HAVE_LIB_NSL)
			if(NOT CPPCMS_HAVE_LIB_NSL)
				message(FATAL_ERROR " No library with gethostbyname found")
			else(NOT CPPCMS_HAVE_LIB_NSL)
				find_library(LIB_NSL nsl)
			endif(NOT CPPCMS_HAVE_LIB_NSL)
		endif(NOT LIB_SOCKGETHOSTBYNAME)
	endif(NOT CPPCMS_HAVE_GETHOSTBYNAME)
endif() 


check_function_exists(canonicalize_file_name CPPCMS_HAVE_CANONICALIZE_FILE_NAME)
check_function_exists(pthread_mutexattr_setpshared CPPCMS_HAS_THREAD_PSHARED_LIBC)
if(NOT CPPCMS_HAS_THREAD_PSHARED_LIBC AND LIB_PTHREAD)
	check_library_exists(${LIB_PTHREAD} pthread_mutexattr_setpshared "" CPPCMS_HAS_THREAD_PSHARED_PTHREAD)
endif()

if(CPPCMS_HAS_THREAD_PSHARED_LIBC OR CPPCMS_HAS_THREAD_PSHARED_PTHREAD)
	set(CPPCMS_HAS_THREAD_PSHARED ON)
else()
	set(CPPCMS_HAS_THREAD_PSHARED OFF)
endif()


add_definitions(-DCPPCMS_BOOST_ALL_NO_LIB)

if(DISABLE_TCPCACHE)
	set(CPPCMS_NO_TCP_CACHE 1)
endif()

if(DISABLE_CACHE)
	set(CPPCMS_NO_CACHE 1)
endif()

if(DISABLE_PREFORK_CACHE)
	set(CPPCMS_NO_PREFOK_CACHE 1)
endif()

if(DISABLE_GZIP)
	set(CPPCMS_NO_GZIP 1)
endif()



set(CPPCMS_PUBLIC_HEADERS ${CMAKE_CURRENT_BINARY_DIR}/cppcms/config.h)


set(CPPCMS_SOURCES 
	src/service.cpp 
	src/cgi_api.cpp 
	src/http_request.cpp 
	src/http_response.cpp 
	src/http_context.cpp 
	src/cppcms_error.cpp 
	src/cppcms_error_category.cpp 
	src/thread_pool.cpp 
	src/applications_pool.cpp 
	src/application.cpp 
	src/url_dispatcher.cpp 
	src/url_mapper.cpp 
	src/http_cookie.cpp  
	src/http_file.cpp  
	src/http_content_type.cpp
	src/util.cpp 
	src/base64.cpp 
	src/base_view.cpp 
	src/base_content.cpp 
	src/views_pool.cpp
	src/internal_file_server.cpp 
	src/json.cpp 
	src/encoding.cpp 
	src/form.cpp 
	src/filters.cpp
	src/cache_pool.cpp
	src/cache_interface.cpp
	src/cache_storage.cpp
	src/forwarder.cpp
	src/session_pool.cpp
	src/hmac_encryptor.cpp
	src/aes_encryptor.cpp
	src/md5.cpp
	src/urandom.cpp
	src/aes.cpp
	src/session_cookies.cpp
	src/session_dual.cpp
	src/session_sid.cpp
	src/session_interface.cpp
	src/session_memory_storage.cpp
	src/rpc_json.cpp
	src/mount_point.cpp
	src/archive.cpp
	src/crypto.cpp
	src/xss.cpp
	src/copy_filter.cpp
	src/send_timeout.cpp
	src/http_content_filter.cpp
	src/plugin.cpp
	src/capi/session.cpp

)

if(NOT DISABLE_TCPCACHE)
	set(CPPCMS_SOURCES ${CPPCMS_SOURCES}
		src/tcp_cache_client.cpp
		src/cache_over_ip.cpp
		src/tcp_messenger.cpp
		src/tcp_connector.cpp
		src/tcp_cache_server.cpp
		src/session_tcp_storage.cpp
		)
endif()

if(NOT DISABLE_GCRYPT)
	find_path(GCRYPT_INCLUDE_DIR gcrypt.h)
	find_library(LIB_GCRYPT gcrypt)
endif()

if(NOT DISABLE_OPENSSL)
	find_path(OPENSSL_INCLUDE_DIR openssl/aes.h)
	find_library(LIB_OPENSSL NAMES crypto libcrypto libeay32)
endif()

if (OPENSSL_INCLUDE_DIR AND LIB_OPENSSL)
	set(LIB_CRYPT ${LIB_OPENSSL})
	set(CPPCMS_HAVE_OPENSSL 1)
	include_directories(${OPENSSL_INCLUDE_DIR})
elseif(GCRYPT_INCLUDE_DIR AND LIB_GCRYPT)
	set(LIB_CRYPT ${LIB_GCRYPT})
	set(CPPCMS_HAVE_GCRYPT 1)
	include_directories(${GCRYPT_INCLUDE_DIR})
endif()


if(NOT LIB_CRYPT)
	message("GNU-TLS Gcrypt or OpenSSL librarys are not found, disabling AES encryption support")
endif()

if(NOT DISABLE_FCGI)
	set(CPPCMS_SOURCES ${CPPCMS_SOURCES} src/fastcgi_api.cpp)
	set(CPPCMS_HAS_FCGI 1)
endif()

if(NOT DISABLE_SCGI)
	set(CPPCMS_SOURCES ${CPPCMS_SOURCES} src/scgi_api.cpp)
	set(CPPCMS_HAS_SCGI 1)
endif()


if(NOT DISABLE_HTTP)
	set(CPPCMS_SOURCES ${CPPCMS_SOURCES} src/http_api.cpp)
	set(CPPCMS_HAS_HTTP 1)
endif()
	

if(WINDOWS_NATIVE)
	if(NOT DISABLE_GZIP)
		set(CPPCMS_SOURCES ${CPPCMS_SOURCES} src/session_win32_file_storage.cpp)
	endif()
	set(CPPCMS_SOURCES ${CPPCMS_SOURCES} src/winservice.cpp)
else()
	if(NOT DISABLE_GZIP)
		set(CPPCMS_SOURCES ${CPPCMS_SOURCES} src/session_posix_file_storage.cpp)
	endif()
	set(CPPCMS_SOURCES ${CPPCMS_SOURCES} src/daemonize.cpp)
endif()

if(NOT DISABLE_SHARED)
	add_library(cppcms SHARED ${CPPCMS_SOURCES})
	set(CPPCMS_LIB cppcms)
else(NOT DISABLE_SHARED)
	set(CPPCMS_LIB cppcms-static)
endif(NOT DISABLE_SHARED)

if(NOT DISABLE_STATIC)
	add_library(cppcms-static STATIC ${CPPCMS_SOURCES})
endif(NOT DISABLE_STATIC)

if(DISABLE_SHARED OR DISABLE_STATIC)
	set(CPPCMS_LIBS ${CPPCMS_LIB})
else(DISABLE_SHARED OR DISABLE_STATIC)
	set(CPPCMS_LIBS cppcms; cppcms-static)
endif(DISABLE_SHARED OR DISABLE_STATIC)


foreach(ALIB ${CPPCMS_LIBS})
	if(DISABLE_SHARED)
		target_link_libraries(${ALIB} booster-static)
	else(DISABLE_SHARED)
		target_link_libraries(${ALIB} booster)
	endif(DISABLE_SHARED)
	if(LIB_CRYPT)
		target_link_libraries(${ALIB} ${LIB_CRYPT})
	endif(LIB_CRYPT)
	
	if(WS2_32 AND WSOCK32)
		target_link_libraries(${ALIB} ${WS2_32})
		target_link_libraries(${ALIB} ${WSOCK32})
	endif(WS2_32 AND WSOCK32) 

	if(LIB_SOCKGETHOSTBYNAME)
		target_link_libraries(${ALIB} ${LIB_SOCKGETHOSTBYNAME})
	endif(LIB_SOCKGETHOSTBYNAME)
	if(LIB_NSL)
		target_link_libraries(${ALIB} ${LIB_NSL})
	endif(LIB_NSL)

	if(LIB_SOCKET)
		target_link_libraries(${ALIB} ${LIB_SOCKET})
	endif(LIB_SOCKET)
	
	if(LIB_DL)
		target_link_libraries(${ALIB} ${LIB_DL})
	endif(LIB_DL)

	if(NOT DISABLE_GZIP)
		target_link_libraries(${ALIB} ${ZLIB})
	endif()
	if(USE_STLPORT AND STLPORT_LIB)
		target_link_libraries(${ALIB} ${STLPORT_LIB})
	endif()
endforeach(ALIB)


find_program(PYTHON NAMES python2 python)
if(NOT PYTHON)
	message(FATAL_ERROR "Can't build without Python interpreter")
endif(NOT PYTHON)



# Templates builds

add_custom_command(
	OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/skin1.cpp
	COMMAND ${PYTHON} ${CMAKE_CURRENT_SOURCE_DIR}/bin/cppcms_tmpl_cc 
		-s skin1 
		-o ${CMAKE_CURRENT_BINARY_DIR}/skin1.cpp 
			${CMAKE_CURRENT_SOURCE_DIR}/src/hello_world_skin1.tmpl 
			${CMAKE_CURRENT_SOURCE_DIR}/src/hello_world_view1.tmpl
	DEPENDS 
		${CMAKE_CURRENT_SOURCE_DIR}/bin/cppcms_tmpl_cc 
		${CMAKE_CURRENT_SOURCE_DIR}/src/hello_world_skin1.tmpl 
		${CMAKE_CURRENT_SOURCE_DIR}/src/hello_world_view1.tmpl)

add_custom_command(
	OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/skin2.cpp
	COMMAND ${PYTHON} ${CMAKE_CURRENT_SOURCE_DIR}/bin/cppcms_tmpl_cc 
		-s skin2 
		-o ${CMAKE_CURRENT_BINARY_DIR}/skin2.cpp 
			${CMAKE_CURRENT_SOURCE_DIR}/src/hello_world_skin2.tmpl 
			${CMAKE_CURRENT_SOURCE_DIR}/src/hello_world_view1.tmpl
	DEPENDS 
		${CMAKE_CURRENT_SOURCE_DIR}/bin/cppcms_tmpl_cc 
		${CMAKE_CURRENT_SOURCE_DIR}/src/hello_world_skin2.tmpl 
		${CMAKE_CURRENT_SOURCE_DIR}/src/hello_world_view1.tmpl)

add_custom_command(
	OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/tc_skin_a.cpp
	COMMAND ${PYTHON} ${CMAKE_CURRENT_SOURCE_DIR}/bin/cppcms_tmpl_cc 
		-o ${CMAKE_CURRENT_BINARY_DIR}/tc_skin_a.cpp 
			${CMAKE_CURRENT_SOURCE_DIR}/tests/tc_skin_a.tmpl
	DEPENDS 
		${CMAKE_CURRENT_SOURCE_DIR}/bin/cppcms_tmpl_cc 
		${CMAKE_CURRENT_SOURCE_DIR}/tests/tc_skin_a.tmpl)

add_custom_command(
	OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/tc_skin_b.cpp
	COMMAND ${PYTHON} ${CMAKE_CURRENT_SOURCE_DIR}/bin/cppcms_tmpl_cc 
		-o ${CMAKE_CURRENT_BINARY_DIR}/tc_skin_b.cpp 
			${CMAKE_CURRENT_SOURCE_DIR}/tests/tc_skin_b.tmpl
	DEPENDS 
		${CMAKE_CURRENT_SOURCE_DIR}/bin/cppcms_tmpl_cc 
		${CMAKE_CURRENT_SOURCE_DIR}/tests/tc_skin_b.tmpl)

add_custom_command(
	OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/tc_skin.cpp
	COMMAND ${PYTHON} ${CMAKE_CURRENT_SOURCE_DIR}/bin/cppcms_tmpl_cc 
		-o ${CMAKE_CURRENT_BINARY_DIR}/tc_skin.cpp 
			${CMAKE_CURRENT_SOURCE_DIR}/tests/tc_skin.tmpl
	DEPENDS 
		${CMAKE_CURRENT_SOURCE_DIR}/bin/cppcms_tmpl_cc 
		${CMAKE_CURRENT_SOURCE_DIR}/tests/tc_skin.tmpl)



add_custom_command(
	OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/tc_sep_skin_a.cpp ${CMAKE_CURRENT_BINARY_DIR}/tc_sep_skin_a.h
	COMMAND ${PYTHON} ${CMAKE_CURRENT_SOURCE_DIR}/bin/cppcms_tmpl_cc 
		-o ${CMAKE_CURRENT_BINARY_DIR}/tc_sep_skin_a.cpp -H ${CMAKE_CURRENT_BINARY_DIR}/tc_sep_skin_a.h
			${CMAKE_CURRENT_SOURCE_DIR}/tests/tc_skin_a.tmpl
	DEPENDS 
		${CMAKE_CURRENT_SOURCE_DIR}/bin/cppcms_tmpl_cc 
		${CMAKE_CURRENT_SOURCE_DIR}/tests/tc_skin_a.tmpl)

add_custom_command(
	OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/tc_sep_skin_b.cpp ${CMAKE_CURRENT_BINARY_DIR}/tc_sep_skin_b.h
	COMMAND ${PYTHON} ${CMAKE_CURRENT_SOURCE_DIR}/bin/cppcms_tmpl_cc 
		-o ${CMAKE_CURRENT_BINARY_DIR}/tc_sep_skin_b.cpp -H ${CMAKE_CURRENT_BINARY_DIR}/tc_sep_skin_b.h
			${CMAKE_CURRENT_SOURCE_DIR}/tests/tc_skin_b.tmpl
	DEPENDS 
		${CMAKE_CURRENT_SOURCE_DIR}/bin/cppcms_tmpl_cc 
		${CMAKE_CURRENT_SOURCE_DIR}/tests/tc_skin_b.tmpl)

add_custom_command(
	OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/tc_sep_skin.cpp ${CMAKE_CURRENT_BINARY_DIR}/tc_sep_skin.h
	COMMAND ${PYTHON} ${CMAKE_CURRENT_SOURCE_DIR}/bin/cppcms_tmpl_cc 
		-o ${CMAKE_CURRENT_BINARY_DIR}/tc_sep_skin.cpp -H ${CMAKE_CURRENT_BINARY_DIR}/tc_sep_skin.h
			${CMAKE_CURRENT_SOURCE_DIR}/tests/tc_skin.tmpl
	DEPENDS 
		${CMAKE_CURRENT_SOURCE_DIR}/bin/cppcms_tmpl_cc 
		${CMAKE_CURRENT_SOURCE_DIR}/tests/tc_skin.tmpl)

add_custom_command(
	OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/tc_plugin.cpp 
	COMMAND ${PYTHON} ${CMAKE_CURRENT_SOURCE_DIR}/bin/cppcms_tmpl_cc 
		-o ${CMAKE_CURRENT_BINARY_DIR}/tc_plugin.cpp
			${CMAKE_CURRENT_SOURCE_DIR}/tests/tc_plugin.tmpl
	DEPENDS 
		${CMAKE_CURRENT_BINARY_DIR}/tc_sep_skin.h
		${CMAKE_CURRENT_SOURCE_DIR}/bin/cppcms_tmpl_cc 
		${CMAKE_CURRENT_SOURCE_DIR}/tests/tc_skin.tmpl
		${CMAKE_CURRENT_SOURCE_DIR}/tests/tc_plugin.tmpl
		)


add_custom_command(
	OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/tc_plugin2.cpp 
	COMMAND ${PYTHON} ${CMAKE_CURRENT_SOURCE_DIR}/bin/cppcms_tmpl_cc 
		-o ${CMAKE_CURRENT_BINARY_DIR}/tc_plugin2.cpp
			${CMAKE_CURRENT_SOURCE_DIR}/tests/tc_plugin2.tmpl
	DEPENDS 
		${CMAKE_CURRENT_BINARY_DIR}/tc_sep_skin.h
		${CMAKE_CURRENT_SOURCE_DIR}/bin/cppcms_tmpl_cc 
		${CMAKE_CURRENT_SOURCE_DIR}/tests/tc_skin.tmpl
		${CMAKE_CURRENT_SOURCE_DIR}/tests/tc_plugin2.tmpl
		)






if(NOT DISABLE_SHARED)
	add_custom_command(
		OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/skin3.cpp
		COMMAND ${PYTHON} ${CMAKE_CURRENT_SOURCE_DIR}/bin/cppcms_tmpl_cc 
			-s skin3 
			-o ${CMAKE_CURRENT_BINARY_DIR}/skin3.cpp 
				${CMAKE_CURRENT_SOURCE_DIR}/src/hello_world_skin2.tmpl 
				${CMAKE_CURRENT_SOURCE_DIR}/src/hello_world_view1.tmpl
		DEPENDS 
			${CMAKE_CURRENT_SOURCE_DIR}/bin/cppcms_tmpl_cc 
			${CMAKE_CURRENT_SOURCE_DIR}/src/hello_world_skin2.tmpl 
			${CMAKE_CURRENT_SOURCE_DIR}/src/hello_world_view1.tmpl)
	add_library(skin3 SHARED skin3.cpp)
	set(SKIN3_DEFS DLL_EXPORT)
	set_target_properties(skin3 PROPERTIES
				COMPILE_DEFINITIONS "${SKIN3_DEFS}")
	target_link_libraries(skin3 ${CPPCMS_LIB})

	foreach(SKIN tc_skin_a tc_skin_b tc_skin tc_sep_skin_a tc_sep_skin_b tc_sep_skin tc_plugin tc_plugin2)
		add_library(${SKIN} SHARED ${CMAKE_CURRENT_BINARY_DIR}/${SKIN}.cpp)
		target_link_libraries(${SKIN} ${CPPCMS_LIB})
		if(IS_WINDOWS)
			set_target_properties(${SKIN} PROPERTIES COMPILE_DEFINITIONS DLL_EXPORT)
		endif()
	endforeach()
	target_link_libraries(tc_plugin2 tc_sep_skin)

	add_library(plugin SHARED tests/test_plugin_so.cpp)
	target_link_libraries(plugin ${CPPCMS_LIB})
	if(IS_WINDOWS)
		set_target_properties(plugin PROPERTIES COMPILE_DEFINITIONS DLL_EXPORT)
	endif()



endif(NOT DISABLE_SHARED)



add_executable(hello_world src/hello_world.cpp skin1.cpp skin2.cpp)
target_link_libraries(hello_world ${CPPCMS_LIB})

if(NOT DISABLE_TCPCACHE)
	add_executable(cppcms_scale src/cache_server_main.cpp)
	target_link_libraries(cppcms_scale ${CPPCMS_LIB})
	if(WIN32 OR CYGWIN)
		set_target_properties(cppcms_scale PROPERTIES COMPILE_DEFINITIONS DLL_EXPORT)
	endif()
endif()

add_executable(cppcms_make_key src/make_key.cpp)
target_link_libraries(cppcms_make_key ${CPPCMS_LIB})

add_executable(cppcms_config_find_param src/cppcms_config_find_param.cpp src/json.cpp)
if(DISABLE_SHARED)
	target_link_libraries(cppcms_config_find_param booster-static)
else(DISABLE_SHARED)
	target_link_libraries(cppcms_config_find_param booster)
endif(DISABLE_SHARED)

#########################################
# Tests
#########################################

set(ALL_TESTS 
	form_test
	proto_test
	pool_test
	disco_test
	http_timeouts_test
	file_server_test
	encryptor_test
	storage_test
	json_test
	base64_test
	forwarder_test
	jsonrpc_test
	cookie_test
	multipart_parser_test
	content_type_parser_test
	serialization_test
	status_test
	xss_test
	rewrite_test
	url_mapper_test
	copy_filter_test
	gzip_test
	session_interface_test
	secure_post_test
	mount_point_test
	todec_test
	hash_map_test
	response_test
	file_buffer_test
	filter_test
	plugin_test
	)

if(NOT DISABLE_PREFORK_CACHE AND NOT IS_WINDOWS)
	set(ALL_TESTS ${ALL_TESTS} allocator_test)
endif()

if(NOT DISABLE_TCPCACHE)
	set(ALL_TESTS ${ALL_TESTS} cache_backend_test cache_frontend_test)
endif()

if(NOT DISABLE_SHARED)
	set(ALL_TESTS ${ALL_TESTS} 
		tc_test
		loadable_storage_test
		)
endif()

if(NOT IS_WINDOWS)
	set(ALL_TESTS ${ALL_TESTS} cppcms_service_test)
endif()

foreach(TEST ${ALL_TESTS})
	add_executable(${TEST} tests/${TEST}.cpp)
	target_link_libraries(${TEST} ${CPPCMS_LIB})
endforeach()

add_executable(external_session_test tests/external_session_test.c)
target_link_libraries(external_session_test ${CPPCMS_LIB})
set(ALL_TESTS ${ALL_TESTS} external_session_test)
if(NOT DISABLE_GZIP)
	target_link_libraries(response_test ${ZLIB})
endif()

#####################################
# End of tests
#####################################

# These are use export
if(IS_WINDOWS AND NOT DISABLE_SHARED)
	set_target_properties(${ALL_TESTS} hello_world cppcms PROPERTIES
				COMPILE_DEFINITIONS DLL_EXPORT)
endif()

set_target_properties(${CPPCMS_LIBS} PROPERTIES CLEAN_DIRECT_OUTPUT 1)
set_target_properties(${CPPCMS_LIBS} PROPERTIES OUTPUT_NAME "cppcms${CPPCMS_SUFFIX}")
if(IS_WINDOWS)
	set_target_properties(${CPPCMS_LIBS} PROPERTIES VERSION ${CPPCMS_SOVERSION} SOVERSION ${CPPCMS_SOVERSION})
else()
	set_target_properties(${CPPCMS_LIBS} PROPERTIES VERSION ${CPPCMS_VERSION} SOVERSION ${CPPCMS_SOVERSION})
endif()

set_target_properties(${CPPCMS_LIBS} PROPERTIES 
			PUBLIC_HEADER "${CPPCMS_PUBLIC_HEADERS}")
			
if(MSVC AND NOT DISABLE_STATIC)
	set_target_properties(cppcms-static PROPERTIES PREFIX "lib")
endif(MSVC AND NOT DISABLE_STATIC)

configure_file(config.cmake.h cppcms/config.h)

set(CPPCMS_INSTALL_TARGETS ${CPPCMS_LIBS} cppcms_config_find_param cppcms_make_key)
if(NOT DISABLE_TCPCACHE)
	set(CPPCMS_INSTALL_TARGETS ${CPPCMS_INSTALL_TARGETS} cppcms_scale)
endif()

#################
# Installation
#################


install(TARGETS ${CPPCMS_INSTALL_TARGETS} 
	RUNTIME DESTINATION bin
	LIBRARY DESTINATION ${LIBDIR}
	ARCHIVE DESTINATION ${LIBDIR}
	PUBLIC_HEADER DESTINATION include/cppcms)
install(PROGRAMS bin/cppcms_tmpl_cc bin/cppcms_run
	DESTINATION bin)

install(DIRECTORY cppcms DESTINATION include
        PATTERN ".svn" EXCLUDE)


#############
# TESTS
#############
		


set(CNF "${CMAKE_CURRENT_SOURCE_DIR}/tests")

add_test(base64_test base64_test)
add_test(todec_test todec_test)
add_test(response_test response_test)
add_test(encryptor_test encryptor_test "${CNF}")
add_test(storage_test storage_test)
add_test(json_test json_test)
add_test(hash_map_test hash_map_test)
if(NOT DISABLE_PREFORK_CACHE AND NOT IS_WINDOWS)
	add_test(allocator_test allocator_test)
endif()

add_test(multipart_parser_test multipart_parser_test "${CNF}")
add_test(content_type_parser_test content_type_parser_test)
if(NOT DISABLE_TCPCACHE)
	add_test(cache_backend_test cache_backend_test)
endif()
add_test(serialization_test serialization_test)
add_test(xss_test xss_test)
add_test(rewrite_test rewrite_test)
add_test(url_mapper_test url_mapper_test)
add_test(copy_filter_test copy_filter_test)
add_test(mount_point_test mount_point_test)
add_test(file_buffer_test file_buffer_test)
if(NOT DISABLE_SHARED)
	add_test(tc_test_shared tc_test "--shared" "${CNF}")
	add_test(tc_test_separate tc_test "--separate" "${CNF}")
	add_test(plugin_test plugin_test "${CMAKE_CURRENT_BINARY_DIR}")
endif()

add_test(status_test
	status_test "-c" "${CNF}/status_test.js" 
	"--test-exec=${PYTHON} ${CNF}/status_test.py")

add_test(pool_test
	pool_test "-c" "${CNF}/pool_test.js" 
	"--test-exec=${PYTHON} ${CNF}/pool_test.py")

add_test(filter_test
	filter_test "-c" "${CNF}/filter_test.js" 
	"--test-exec=${PYTHON} ${CNF}/filter_test.py")

add_test(async_status_test
	status_test "-c" "${CNF}/status_test.js" "--test-async=async"
	"--test-exec=${PYTHON} ${CNF}/status_test.py async")

add_test(form_test
	form_test "-c" "${CNF}/form_test.js" 
	"--test-exec=${PYTHON} ${CNF}/form_test.py")

add_test(cookie_test
	cookie_test "-c" "${CNF}/cookie_test.js" 
	"--test-exec=${PYTHON} ${CNF}/cookie_test.py")


add_test(internal_forwarder_test 
	forwarder_test "-c" "${CNF}/forwarder_test.js" 
	"--test-exec=${PYTHON} ${CNF}/forwarder_test.py"
	"--test-internal=true")

add_test(forwarder_test
	forwarder_test "-c" "${CNF}/forwarder_test.js" 
	"--test-exec=${PYTHON} ${CNF}/forwarder_test.py"
	"--test-internal=false")

add_test(jsonrpc_test
	jsonrpc_test "-c" "${CNF}/jsonrpc_test.js"
	"--test-exec=${PYTHON} ${CNF}/jsonrpc_test.py")

add_test(http_timeouts_test_read
	http_timeouts_test "-c" "${CNF}/proto_test.js" 
	"--service-api=http" "--service-port=8080" "--service-ip=127.0.0.1" "--http-timeout=5" "--logging-level=debug"
	"--test-write=false"
	"--test-exec=${PYTHON} ${CNF}/http_timeouts_test.py read")

#
# In future maybe
#
#if(${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
#	set(HTTP_TIMEOUT 15)
#else()
#	set(HTTP_TIMEOUT 5)
#endif()
#

set(HTTP_TIMEOUT 15)

add_test(http_timeouts_test_write
	http_timeouts_test "-c" "${CNF}/proto_test.js" 
	"--service-api=http" "--service-port=8080" "--service-ip=127.0.0.1" "--http-timeout=${HTTP_TIMEOUT}" "--logging-level=debug" "--service-sndbuf=32786" "--service-rcvbuf=32768"
	"--test-write=true"
	"--test-exec=${PYTHON} ${CNF}/http_timeouts_test.py write ${HTTP_TIMEOUT}")


add_test(file_server_test
	file_server_test "-c" "${CNF}/file_server_test.js" 
	"--test-exec=${PYTHON} ${CNF}/file_server_test.py"
	"-U" "${CNF}"
	)

add_test(file_server_test_no_links
	file_server_test "-c" "${CNF}/file_server_test.js" "--file_server-check_symlink=false" 
	"--test-exec=${PYTHON} ${CNF}/file_server_test.py no_links"
	"-U" "${CNF}"
	)

add_test(file_server_with_listing_test
	file_server_test "-c" "${CNF}/file_server_test.js" 
	"--file_server-listing=true"
	"--test-exec=${PYTHON} ${CNF}/file_server_test.py listing"
	"-U" "${CNF}"
	)



add_test(file_server_test_async
	file_server_test "-c" "${CNF}/file_server_test.js" "--file_server-async=true"
	"--test-exec=${PYTHON} ${CNF}/file_server_test.py"
	"-U" "${CNF}"
	)

add_test(file_server_test_no_links_async
	file_server_test "-c" "${CNF}/file_server_test.js" "--file_server-check_symlink=false" "--file_server-async=true" 
	"--test-exec=${PYTHON} ${CNF}/file_server_test.py no_links"
	"-U" "${CNF}"
	)

add_test(file_server_with_listing_test_async
	file_server_test "-c" "${CNF}/file_server_test.js" "--file_server-async=true" 
	"--file_server-listing=true"
	"--test-exec=${PYTHON} ${CNF}/file_server_test.py listing"
	"-U" "${CNF}"
	)

add_test(disco_test_http 
	disco_test "-c" "${CNF}/proto_test.js" 
	"--service-api=http" "--service-port=8080" "--service-ip=127.0.0.1"
	"--test-exec=${PYTHON} ${CNF}/disco_test.py http")

add_test(disco_test_fastcgi_tcp 
	disco_test "-c" "${CNF}/proto_test.js" 
	"--service-api=fastcgi" "--service-port=8080" "--service-ip=127.0.0.1"
	"--test-exec=${PYTHON} ${CNF}/disco_test.py fastcgi_tcp")

add_test(disco_test_scgi_tcp 
	disco_test "-c" "${CNF}/proto_test.js" 
	"--service-api=scgi" "--service-port=8080" "--service-ip=127.0.0.1"
	"--test-exec=${PYTHON} ${CNF}/disco_test.py scgi_tcp")

add_test(secure_post_test
	secure_post_test "-c" "${CNF}/secure_post_test.js" 
	"--test-exec=${PYTHON} ${CNF}/secure_post_test.py"
	)


if(NOT IS_WINDOWS)
	add_test(disco_test_fastcgi_unix 
		disco_test "-c" "${CNF}/proto_test.js" 
		"--service-api=fastcgi" "--service-socket=/tmp/cppcms_test_socket"
		"--test-exec=${PYTHON} ${CNF}/disco_test.py fastcgi_unix")

	add_test(disco_test_scgi_unix 
		disco_test "-c" "${CNF}/proto_test.js" 
		"--service-api=scgi" "--service-socket=/tmp/cppcms_test_socket"
		"--test-exec=${PYTHON} ${CNF}/disco_test.py scgi_unix")
endif()

if(NOT DISABLE_GZIP)
	add_test(gzip_test
		gzip_test "--service-api=http"  "--http-script=/test"
		"--test-exec=${PYTHON} ${CNF}/gzip_test.py")
	if(NOT DISABLE_TCPCACHE)
		add_test(cache_frontend_test cache_frontend_test)
	endif()
endif()




if(NOT IS_WINDOWS)
	add_test(cppcms_service_test "${CNF}/service_test" "${PYTHON}" "${CMAKE_CURRENT_BINARY_DIR}")
endif()


add_test(external_session_test external_session_test "${CNF}/external_session_test.js")
foreach(LOC client server both)
	foreach(EXP renew browser fixed)
		add_test(session_interface_test_${LOC}_${EXP}
			 session_interface_test -c "${CNF}/session_interface_test.js"
			 "--session-expire=${EXP}" "--session-location=${LOC}"
			 "--test-exec=${PYTHON} ${CNF}/session_interface_test.py ${LOC} ${EXP}")
	endforeach()
endforeach()

foreach(TYPE async sync nonblocking)
	add_test(proto_test_${TYPE}_http 
		proto_test "-c" "${CNF}/proto_test.js" 
		"--test-async=${TYPE}" "--service-api=http" "--service-port=8080" "--service-ip=127.0.0.1"
		"--test-exec=${PYTHON} ${CNF}/proto_test.py http")
	add_test(proto_test_${TYPE}_scgi 
		proto_test "-c" "${CNF}/proto_test.js" 
		"--test-async=${TYPE}" "--service-api=scgi" "--service-port=8080" "--service-ip=127.0.0.1"
		"--test-exec=${PYTHON} ${CNF}/proto_test.py scgi_tcp")
	add_test(proto_test_${TYPE}_fastcgi 
		proto_test "-c" "${CNF}/proto_test.js" 
		"--test-async=${TYPE}" "--service-api=fastcgi" "--service-port=8080" "--service-ip=127.0.0.1"
		"--test-exec=${PYTHON} ${CNF}/proto_test.py fastcgi_tcp")
	if(NOT IS_WINDOWS)
		add_test(proto_test_${TYPE}_scgi_unix
			proto_test "-c" "${CNF}/proto_test.js" 
			"--test-async=${TYPE}" "--service-api=scgi" "--service-socket=/tmp/cppcms_test_socket"
			"--test-exec=${PYTHON} ${CNF}/proto_test.py scgi_unix")
		add_test(proto_test_${TYPE}_fastcgi_unix
			proto_test "-c" "${CNF}/proto_test.js" 
			"--test-async=${TYPE}" "--service-api=fastcgi" "--service-socket=/tmp/cppcms_test_socket"
			"--test-exec=${PYTHON} ${CNF}/proto_test.py fastcgi_unix")
	endif()
endforeach()

if(NOT DISABLE_SHARED)
	add_library(loadable_storage SHARED tests/loadable_storage.cpp)
	target_link_libraries(loadable_storage ${CPPCMS_LIB})
	if(WIN32 OR CYGWIN)
		set_target_properties(loadable_storage PROPERTIES COMPILE_DEFINITIONS DLL_EXPORT)
	endif()
	add_test(loadable_storage_pass 
		loadable_storage_test
		--service-api=http
		--session-location=server
		--session-server-storage=external
		"--session-server-shared_object=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}loadable_storage${CMAKE_SHARED_LIBRARY_SUFFIX}"
		--session-server-entry_point=my_sessions_generator
		--session-server-settings-must_be_set=false
		)
	add_test(loadable_storage_fail
		loadable_storage_test
		--service-api=http
		--session-location=server
		--session-server-storage=external
		"--session-server-shared_object=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}loadable_storage${CMAKE_SHARED_LIBRARY_SUFFIX}"
		--session-server-entry_point=my_sessions_generator
		--session-server-settings-must_be_set_incorrect=false
		)
	set_tests_properties(loadable_storage_fail PROPERTIES WILL_FAIL TRUE)
endif()



set(TESTS_WITH_TIMEOUT
	forwarder_test 
	jsonrpc_test 
	proto_test_sync_http
	proto_test_async_http
	proto_test_sync_scgi
	proto_test_async_scgi)

if(NOT DISABLE_TCPCACHE)
	set(TESTS_WITH_TIMEOUT ${TESTS_WITH_TIMEOUT} cache_backend_test)
endif()

set_tests_properties( 
	${TESTS_WITH_TIMEOUT}
	PROPERTIES TIMEOUT 120)

if(NOT IS_WINDOWS)
	set_tests_properties(
		proto_test_sync_scgi_unix
		proto_test_async_scgi_unix
		PROPERTIES TIMEOUT 120)

endif()


