cmake_minimum_required(VERSION 3.13)
cmake_policy(SET CMP0017 NEW) # need include() with .cmake
if (POLICY CMP0177)
	cmake_policy(SET CMP0177 OLD)
endif()
project(PIP)
set(PIP_MAJOR    5)
set(PIP_MINOR    7)
set(PIP_REVISION 0)
set(PIP_SUFFIX   _beta)
set(PIP_COMPANY  SHS)
set(PIP_DOMAIN   org.SHS)

set(GIT_CMAKE_DIR)
if (NOT DEFINED SHSTKPROJECT)
	set(ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
	file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cmake-download/CMakeLists.txt"
"# This file was generated by PIP CMake, don`t edit it!
cmake_minimum_required(VERSION 3.13)
project(cmake-download NONE)
include(ExternalProject)
ExternalProject_Add(cmake
	GIT_REPOSITORY    https://git.shstk.ru/SHS/cmake.git
	GIT_TAG           \"origin/master\"
	GIT_CONFIG        \"advice.detachedHead=false\"
	SOURCE_DIR        \"${CMAKE_CURRENT_BINARY_DIR}/cmake-src\"
	BINARY_DIR        \"${CMAKE_CURRENT_BINARY_DIR}/cmake-build\"
	INSTALL_COMMAND   \"\"
	TEST_COMMAND      \"\"
)
")
	execute_process(COMMAND "${CMAKE_COMMAND}" -G "${CMAKE_GENERATOR}" .
		RESULT_VARIABLE result
		WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/cmake-download)
	if(result)
		message(FATAL_ERROR "CMake step for cmake failed: ${result}")
	endif()
	execute_process(COMMAND "${CMAKE_COMMAND}" --build .
		RESULT_VARIABLE result
		WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/cmake-download)
	if(result)
		message(FATAL_ERROR "Build step for cmake failed: ${result}")
	endif()
	install(CODE "execute_process(COMMAND \"${CMAKE_COMMAND}\" --build \"${CMAKE_CURRENT_BINARY_DIR}/cmake-build\" --target install)")
	set(GIT_CMAKE_DIR "${CMAKE_CURRENT_BINARY_DIR}/cmake-src")
endif()

list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
if (NOT "x${GIT_CMAKE_DIR}" STREQUAL "x")
	list(APPEND CMAKE_MODULE_PATH "${GIT_CMAKE_DIR}")
endif()
include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
include(CheckFunctionExists)
include(PIPMacros)
include(SHSTKMacros)

shstk_begin_project(PIP)
set(PIP_VERSION "${PIP_VERSION}" CACHE STRING "")

set(_ICU_DEFAULT OFF)
if((NOT DEFINED WIN32) AND (NOT DEFINED ANDROID_PLATFORM) AND (NOT DEFINED APPLE))
	set(_ICU_DEFAULT ON)
endif()
set(PIP_DLL_DIR "${CMAKE_CURRENT_BINARY_DIR}" CACHE STRING "")

# Options
option(ICU "ICU support for convert codepages" ${_ICU_DEFAULT})
option(STD_IOSTREAM "Building with std iostream operators support" OFF)
option(INTROSPECTION "Build with introspection" OFF)
option(TESTS "Build tests" OFF)
option(TESTS_RUN "Run tests before install step" OFF)
option(COVERAGE "Build project with coverage info" OFF)
option(PIP_FFTW_F "Support fftw module for float" ON)
option(PIP_FFTW_L "Support fftw module for long double" ON)
option(PIP_FFTW_Q "Support fftw module for quad double" OFF)
option(PIP_MANUAL_TEST "Build dev test (main.cpp)" OFF)
set(PIP_UTILS 1)
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
set(CMAKE_CXX_STANDARD 11)

shstk_is_parent_exists(_pe)
if (_pe)
	set(BUILDING_pip 1 PARENT_SCOPE)
	set(pip_ROOT_SRC "${CMAKE_CURRENT_SOURCE_DIR}" PARENT_SCOPE)
	set(pip_ROOT_SRC "${CMAKE_CURRENT_SOURCE_DIR}")
endif()


# Basic
set(PIP_MODULES)
set(LIBS_MAIN)
set(LIBS_STATUS)
set(HDRS)
set(PHDRS)
set(HDR_DIRS)
set(PIP_UTILS_LIST)
set(PIP_TESTS_LIST)
set(PIP_EXPORTS)
set(PIP_3PL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/3rd")

set(PIP_SRC_MODULES "console;crypt;compress;usb;fftw;opencl;io_utils;client_server;cloud;lua;http_client;http_server;mqtt_client")
foreach(_m ${PIP_SRC_MODULES})
	set(PIP_MSG_${_m} "no")
	string(TOUPPER "${_m}" _mu)
	option(PIP_BUILD_${_mu} "Build \"${_m}\" module" ON)
endforeach()

macro(pip_module NAME LIBS LABEL INCLUDES SOURCES MSG)
	set(CPPS)
	set(HS)
	set(PHS)
	set(CRES)
	file(GLOB_RECURSE CPPS "libs/${NAME}/*.cpp" "libs/${NAME}/*.c")
	file(GLOB_RECURSE HS   "libs/${NAME}/*.h")
	file(GLOB_RECURSE PHS  "libs/${NAME}/*_p.h")
	file(GLOB_RECURSE RES  "libs/${NAME}/*.conf")
	if (NOT "x${PHS}" STREQUAL "x")
		list(REMOVE_ITEM HS ${PHS})
	endif()
	if (NOT "x${SOURCES}" STREQUAL "x")
		foreach (_s ${SOURCES})
			file(GLOB_RECURSE ASRC "${_s}/*.cpp" "${_s}/*.c")
			list(APPEND CPPS ${ASRC})
		endforeach()
	endif()
	list(APPEND HDRS ${HS})
	list(APPEND PHDRS ${PHS})

	if(${CMAKE_VERSION} VERSION_LESS "3.8.0")
	else()
		source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES ${CPPS} ${HS} ${PHS})
	endif()
	set(_target "pip_${NAME}")
	set(_libs "${LIBS}")
	if ("${NAME}" STREQUAL "main")
		set(_target "pip")
	else()
		list(APPEND _libs "pip")
	endif()
	string(TOUPPER "${_target}" DEF_NAME)

	set(PIP_MSG_${NAME} "yes${MSG}")
	import_version(${_target} PIP)
	set_deploy_property(${_target} ${PIP_LIB_TYPE}
		LABEL "${LABEL}"
		FULLNAME "${PIP_DOMAIN}.${_target}"
		COMPANY  "${PIP_COMPANY}"
		INFO "Platform-Independent Primitives")
	make_rc(${_target} _RC)

	set(LINK_LIBS)
	foreach (_l ${_libs})
		if (${${_l}_FOUND})
			list(APPEND LINK_LIBS ${${_l}_LIBRARIES})
		else()
			list(APPEND LINK_LIBS ${_l})
		endif()
	endforeach()

	if (NOT "x${RES}" STREQUAL "x")
		pip_resources(CRES "${RES}")
	endif()
	add_definitions(-D${DEF_NAME})
	add_library(${_target} ${PIP_LIB_TYPE} ${CPPS} ${CRES} ${_RC} ${HS} ${PHS})
	target_include_directories(${_target} PUBLIC ${PIP_INCLUDES})
	if (NOT "x${RES}" STREQUAL "x")
		add_dependencies(${_target} pip_rc)
	endif()
	if (NOT "x${INCLUDES}" STREQUAL "x")
		target_include_directories(${_target} PRIVATE ${INCLUDES})
	endif()
	list(APPEND PIP_EXPORTS "${DEF_NAME}_EXPORT")
	target_link_libraries(${_target} ${LINK_LIBS})
	list(APPEND PIP_MODULES ${_target})
	if (NOT "x${LIBS}" STREQUAL "x")
		list(APPEND LIBS_STATUS ${LIBS})
	endif()
endmacro()

macro(pip_find_lib NAME)
	find_library(${NAME}_LIBRARIES ${NAME} ${ARGN})
	set(${NAME}_FOUND FALSE)
	if(${NAME}_LIBRARIES)
		set(${NAME}_FOUND TRUE)
	endif()
endmacro()

# Version
list(APPEND HDRS "${CMAKE_CURRENT_BINARY_DIR}/pip_version.h")


if (NOT DEFINED PIP_CMG)
	if (CMAKE_CROSSCOMPILING OR (DEFINED ANDROID_PLATFORM))
		set(PIP_CMG "pip_cmg")
		set(PIP_RC "pip_rc")
		set(PIP_TR "pip_tr")
		set(PIP_DEPLOY_TOOL "deploy_tool")
	else()
		set(PIP_CMG "${CMAKE_CURRENT_BINARY_DIR}/utils/code_model_generator/pip_cmg")
		set(PIP_RC "${CMAKE_CURRENT_BINARY_DIR}/utils/resources_compiler/pip_rc")
		set(PIP_TR "${CMAKE_CURRENT_BINARY_DIR}/utils/translator/pip_tr")
		set(PIP_DEPLOY_TOOL "${CMAKE_CURRENT_BINARY_DIR}/utils/deploy_tool/deploy_tool")
	endif()
endif()


# Compiler
get_filename_component(C_COMPILER "${CMAKE_C_COMPILER}" NAME)


# Main lib
file(GLOB PIP_FOLDERS LIST_DIRECTORIES TRUE "${CMAKE_CURRENT_SOURCE_DIR}/libs/main/*")
list(APPEND PIP_FOLDERS "${CMAKE_CURRENT_SOURCE_DIR}/libs/main")
set(PIP_INCLUDES "${CMAKE_CURRENT_BINARY_DIR}")
foreach(F ${PIP_FOLDERS})
	if (IS_DIRECTORY "${F}")
		list(APPEND PIP_INCLUDES "${F}")
	endif()
endforeach(F)

if (TESTS)
	set(PIP_ROOT_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}")
	add_subdirectory(tests)
endif()

if(PIP_FREERTOS)
	add_definitions(-DPIP_FREERTOS)
	set(ICU OFF)
	set(LOCAL ON)
endif()

# Check Bessel functions
set(CMAKE_REQUIRED_INCLUDES math.h)
set(CMAKE_REQUIRED_LIBRARIES m)
CHECK_FUNCTION_EXISTS(j0 PIP_MATH_J0)
CHECK_FUNCTION_EXISTS(j1 PIP_MATH_J1)
CHECK_FUNCTION_EXISTS(jn PIP_MATH_JN)
CHECK_FUNCTION_EXISTS(y0 PIP_MATH_Y0)
CHECK_FUNCTION_EXISTS(y1 PIP_MATH_Y1)
CHECK_FUNCTION_EXISTS(yn PIP_MATH_YN)
if(PIP_MATH_J0)
	add_definitions(-DPIP_MATH_J0)
endif()
if(PIP_MATH_J1)
	add_definitions(-DPIP_MATH_J1)
endif()
if(PIP_MATH_JN)
	add_definitions(-DPIP_MATH_JN)
endif()
if(PIP_MATH_Y0)
	add_definitions(-DPIP_MATH_Y0)
endif()
if(PIP_MATH_Y1)
	add_definitions(-DPIP_MATH_Y1)
endif()
if(PIP_MATH_YN)
	add_definitions(-DPIP_MATH_YN)
endif()

# Check if build debug version
if (PIP_BUILD_DEBUG)
	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3 -Wall")
	add_definitions(-DPIP_DEBUG)
else()
	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -Wall")
endif()

set(PIP_COVERAGE "no")
if (COVERAGE)
	find_program(GCOV_EXECUTABLE gcov)
	if (GCOV_EXECUTABLE)
		set(PIP_COVERAGE "yes")
		set(CMAKE_CXX_FLAGS  "${CMAKE_CXX_FLAGS} --coverage")
		set(CMAKE_EXE_LINKER_FLAGS  "${CMAKE_EXE_LINKER_FLAGS} --coverage")
	else()
		message(STATUS "GCOV_EXECUTABLE: not found")
	endif()
endif()


# Check if std::iostream operators support
set(PIP_STD_IOSTREAM "no")
if(STD_IOSTREAM)
	set(PIP_STD_IOSTREAM "yes")
	add_definitions(-DPIP_STD_IOSTREAM)
endif()


# Check if ICU used for PIString and PIChar
set(PIP_ICU "no")
if(ICU)
	pip_find_lib(icuuc)
	if (icuuc_FOUND)
		set(PIP_ICU "yes")
		add_definitions(-DPIP_ICU)
		list(APPEND LIBS_MAIN icuuc)
	else()
		message(STATUS "Warning: ICU requested, but not found. Build without ICU")
	endif()
endif()


# Check if PIP should be built with introspection
set(_PIP_DEFS "")
set(_PIP_DEFS_FILE "${CMAKE_CURRENT_BINARY_DIR}/pip_defs.h")
set(PIP_INTROSPECTION "no")
if(INTROSPECTION)
	set(PIP_INTROSPECTION "yes")
	add_definitions(-DPIP_INTROSPECTION)
	set(_PIP_DEFS "PIP_INTROSPECTION")
endif()
if ((NOT DEFINED _PIP_SAVED_DEFS) OR (NOT "x${_PIP_SAVED_DEFS}" STREQUAL "x${_PIP_DEFS}"))
	set(_PIP_SAVED_DEFS "${_PIP_DEFS}" CACHE STRING "pip_defs" FORCE)
	file(WRITE ${_PIP_DEFS_FILE} "// This file was generated by PIP CMake, don`t edit it!\n")
	if (NOT "x${_PIP_DEFS}" STREQUAL "x")
		file(APPEND ${_PIP_DEFS_FILE} "#ifndef ${_PIP_DEFS}\n#  define ${_PIP_DEFS}\n#endif\n")
	endif()
endif()
list(APPEND HDRS ${_PIP_DEFS_FILE})
#message("${_PIP_DEFS_CHANGED}")



# Add main library
if(APPLE)
	add_definitions(-D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE)
endif()
if ((NOT DEFINED SHSTKPROJECT) AND (DEFINED ANDROID_PLATFORM))
	include_directories(${ANDROID_SYSTEM_LIBRARY_PATH}/usr/include)
	#message("${ANDROID_SYSTEM_LIBRARY_PATH}/usr/include")
	#message("${ANDROID_NDK}/sysroot/usr/include")
endif()

if(NOT PIP_FREERTOS)
	if(WIN32)
		if(${C_COMPILER} STREQUAL "cl.exe")
		else()
			list(APPEND LIBS_MAIN ws2_32 iphlpapi psapi cfgmgr32 setupapi hid)
		endif()
	else()
		list(APPEND LIBS_MAIN dl)
		if(DEFINED ENV{QNX_HOST})
			list(APPEND LIBS_MAIN socket)
		else()
			if (NOT DEFINED ANDROID_PLATFORM)
				list(APPEND LIBS_MAIN pthread util)
				if (NOT APPLE)
					list(APPEND LIBS_MAIN rt)
				endif()
			endif()
		endif()
	endif()
endif()
set(PIP_LIBS)
if(PIP_FREERTOS)
	set(PIP_LIBS ${LIBS_MAIN})
else()
	foreach(LIB_ ${LIBS_MAIN})
		pip_find_lib(${LIB_})
	endforeach()
endif()
if(WIN32)
	add_definitions(-DPSAPI_VERSION=1)
	if(${C_COMPILER} STREQUAL "cl.exe")
		set(CMAKE_CXX_FLAGS "/O2 /Ob2 /Ot /W0 /EH-")
	endif()
else()
	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
	if (NOT DEFINED ANDROID_PLATFORM)
		set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions")
	endif()
	if(DEFINED ENV{QNX_HOST} OR PIP_FREERTOS)
		set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftemplate-depth-32")
	endif()
endif()
set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS}")

set(PCRE2_BUILD_PCRE2_8   OFF CACHE BOOL "" FORCE)
set(PCRE2_BUILD_PCRE2_16  ON  CACHE BOOL "" FORCE)
set(PCRE2_BUILD_PCRE2_32  OFF CACHE BOOL "" FORCE)
set(PCRE2_BUILD_PCRE2GREP OFF CACHE BOOL "" FORCE)
set(PCRE2_BUILD_TESTS     OFF CACHE BOOL "" FORCE)
set(PCRE2_SHOW_REPORT     OFF CACHE BOOL "" FORCE)
if (WIN32)
	set (ZLIB_ROOT "${MINGW_INCLUDE}")
endif()
add_subdirectory("3rd/pcre2" EXCLUDE_FROM_ALL)
list(APPEND LIBS_MAIN pcre2-16-static)

pip_module(main "${LIBS_MAIN}" "PIP main library" "" "${PIP_3PL_DIR}/BLAKE2;${PIP_3PL_DIR}/SipHash" "")

generate_export_header(pip)
list(APPEND HDRS "${CMAKE_CURRENT_BINARY_DIR}/pip_export.h")
foreach(_m ${PIP_SRC_MODULES})
	set_target_properties(pip PROPERTIES DEFINE_SYMBOL pip_${_m}_EXPORTS)
	generate_export_header(pip BASE_NAME "pip_${_m}")
	list(APPEND HDRS "${CMAKE_CURRENT_BINARY_DIR}/pip_${_m}_export.h")
endforeach()
set_target_properties(pip PROPERTIES DEFINE_SYMBOL pip_EXPORTS)

# Override containers minimum bytes allocation
if(NOT "x${PIP_CONTAINERS_MIN_ALLOC}" STREQUAL "x")
	target_compile_definitions(pip PRIVATE "-DPIP_CONTAINERS_MIN_ALLOC=${PIP_CONTAINERS_MIN_ALLOC}")
	message(STATUS "Attention: Override PIP_CONTAINERS_MIN_ALLOC = ${PIP_CONTAINERS_MIN_ALLOC}")
endif()
# Override containers maximum bytes for power of two expansion, may be bytes or X_KiB, or X_MiB
if(NOT "x${PIP_CONTAINERS_MAX_POT_ALLOC}" STREQUAL "x")
	target_compile_definitions(pip PRIVATE "-DPIP_CONTAINERS_MAX_POT_ALLOC=${PIP_CONTAINERS_MAX_POT_ALLOC}")
	message(STATUS "Attention: Override PIP_CONTAINERS_MAX_POT_ALLOC = ${PIP_CONTAINERS_MAX_POT_ALLOC}")
endif()


if (NOT CROSSTOOLS)
	if (NOT PIP_FREERTOS)

		if (PIP_BUILD_CONSOLE)
			pip_module(console "" "PIP console support" "" "" "")
		endif()

		if (PIP_BUILD_USB)
			pip_find_lib(usb)
			if(usb_FOUND)
				pip_module(usb "usb" "PIP usb support" "" "" "")
			endif()
		endif()


		if (PIP_BUILD_COMPRESS)
			pip_find_lib(zlib NAMES z zlib)
			if(zlib_FOUND)
				pip_module(compress "zlib" "PIP compression support" "" "" "")
			endif()
		endif()


		if (PIP_BUILD_CRYPT)
			pip_find_lib(sodium)
			if(sodium_FOUND)
				pip_module(crypt "sodium" "PIP crypt support" "" "" "")
				pip_module(client_server "pip_io_utils" "PIP client-server helper" "" "" "")
				pip_module(cloud "pip_io_utils" "PIP cloud support" "" "" "")
			endif()
		endif()


		if (PIP_BUILD_FFTW)
			# Check if PIP support fftw3 for PIFFT using in math module
			set(FFTW_LIB_NAME fftw3)
			set(FFTW_LIB_SUFFIXES "")
			if (PIP_FFTW_F)
				list(APPEND FFTW_LIB_SUFFIXES "f")
			endif()
			if (PIP_FFTW_L)
				list(APPEND FFTW_LIB_SUFFIXES "l")
			endif()
			if (PIP_FFTW_Q)
				list(APPEND FFTW_LIB_SUFFIXES "q")
			endif()
			if (NOT "${FFTW_LIB_SUFFIXES}" STREQUAL "")
				set(FFTW_LIB_SUFFIXES ";${FFTW_LIB_SUFFIXES}")
			else()
				list(APPEND FFTW_LIB_SUFFIXES "" "_")
			endif()
			set(FFTW_LIB_SUFFIXES2 "" "-3")
			set(FFTW_MSG "")
			set(FFTW_LIBS)
			set(FFTW_ABS_LIBS)
			set(CMAKE_REQUIRED_INCLUDES fftw3.h)
			foreach(FFTW_S_ IN LISTS FFTW_LIB_SUFFIXES)
				set(FFTW_BREAK false)
				foreach(FFTW_S2_ IN LISTS FFTW_LIB_SUFFIXES2)
					if(NOT FFTW_BREAK)
						set(FFTW_CLN  "${FFTW_LIB_NAME}${FFTW_S_}${FFTW_S2_}")
						set(FFTW_CLNT "${FFTW_LIB_NAME}${FFTW_S_}_threads${FFTW_S2_}")
						find_library(${FFTW_CLN}_LIBRARIES ${FFTW_CLN})
						find_library(${FFTW_CLNT}_LIBRARIES ${FFTW_CLNT})
						set(${FFTW_CLN}_FOUND FALSE)
						set(${FFTW_CLNT}_FOUND FALSE)
						if(${FFTW_CLN}_LIBRARIES)
							if (NOT "${FFTW_MSG}" STREQUAL "")
								set(FFTW_MSG "${FFTW_MSG}, ")
							endif()
							set(FFTW_MSG "${FFTW_MSG}${FFTW_CLN}")
							set(${FFTW_CLN}_FOUND TRUE)
							list(APPEND FFTW_LIBS "${FFTW_CLN}")
							list(APPEND FFTW_ABS_LIBS "${${FFTW_CLN}_LIBRARIES}")
							set(${FFTW_CLN}_CTS "${FFTW_CLN}")
							if(${FFTW_CLNT}_FLIBRARIES)
								set(${FFTW_CLNT}_FOUND TRUE)
								list(APPEND FFTW_LIBS "${FFTW_CLNT}")
								list(APPEND FFTW_ABS_LIBS "${${FFTW_CLNT}_LIBRARIES}")
								list(APPEND ${FFTW_CLN}_CTS "${FFTW_CLNT}")
							endif()
							set(CMAKE_REQUIRED_LIBRARIES ${${FFTW_CLN}_CTS})
							CHECK_FUNCTION_EXISTS(fftw${FFTW_S_}_make_planner_thread_safe ${FFTW_CLN}_TSFE)
							add_definitions(-DPIP_FFTW${FFTW_S_})
							if(${FFTW_CLN}_TSFE)
								add_definitions(-DPIP_FFTW${FFTW_S_}_THREADSAFE)
							else()
								message(STATUS "Warning: PIFFTW${FFTW_S_}::preparePlan was not threadsafe")
							endif()
						endif()
					endif()
				endforeach()
			endforeach()
			if(FFTW_LIBS)
				pip_module(fftw "${FFTW_LIBS}" "PIP FFTW support" "" "" " (${FFTW_MSG})")
			endif()
		endif()


		if (PIP_BUILD_OPENCL)
			if (NOT "x${MINGW_INCLUDE}" STREQUAL "x")
				list(APPEND CMAKE_INCLUDE_PATH "${MINGW_INCLUDE}")
			endif()
			find_package(OpenCL QUIET) #OpenCL_VERSION_STRING
			if(OpenCL_FOUND)
				set(_opencl_inc "${OpenCL_INCLUDE_DIRS}")
				if(APPLE)
					set(_opencl_inc "${OpenCL_INCLUDE_DIRS}/Headers")
				endif()
				pip_module(opencl "OpenCL" "PIP OpenCL support" "${_opencl_inc}" "" " (${OpenCL_VERSION_STRING})")
			endif()
		endif()


		if (PIP_BUILD_IO_UTILS)
			if(sodium_FOUND)
				pip_module(io_utils "pip_crypt" "PIP I/O support" "" "" " (+crypt)")
			else()
				pip_module(io_utils "" "PIP I/O support" "" "" "")
			endif()
		endif()


		if (PIP_BUILD_LUA)
			# Lua module
			set(_lua_src_dir "${PIP_3PL_DIR}/lua")
			set(_lua_src_hdr "${_lua_src_dir}/lua.hpp" "${_lua_src_dir}/lua.h" "${_lua_src_dir}/luaconf.h" "${_lua_src_dir}/lualib.h")
			pip_module(lua "" "PIP Lua support" "${_lua_src_dir};${PIP_3PL_DIR}" "${_lua_src_dir}" " (internal)")
			target_include_directories(pip_lua PUBLIC "${_lua_src_dir}")
			if (WIN32)
				target_compile_definitions(pip_lua PRIVATE LUA_BUILD_AS_DLL LUA_CORE)
			else()
				target_compile_definitions(pip_lua PRIVATE LUA_USE_POSIX)
			endif()
			list(APPEND HDR_DIRS "${PIP_3PL_DIR}/LuaBridge")
			list(APPEND HDRS ${_lua_src_hdr})
		endif()


		if (PIP_BUILD_HTTP_SERVER)
			# libmicrohttpd
			pip_find_lib(microhttpd HINTS "${MINGW_LIB}")
			if (microhttpd_FOUND)
				set(_microhttpd_add_libs microhttpd)
				if(WIN32)
					if("${C_COMPILER}" STREQUAL "cl.exe")
					else()
						list(APPEND _microhttpd_add_libs ws2_32)
					endif()
				else()
					list(APPEND _microhttpd_add_libs dl)
					find_library(tls_lib gnutls)
					if (tls_lib)
						set(gnutls_FOUND TRUE)
						set(gnutls_LIBRARIES "${tls_lib}")
						list(APPEND _microhttpd_add_libs gnutls)
					endif()
					if(DEFINED ENV{QNX_HOST})
						list(APPEND _microhttpd_add_libs socket)
					else()
						if (NOT DEFINED ANDROID_PLATFORM)
							list(APPEND _microhttpd_add_libs pthread util)
						endif()
					endif()
				endif()
				#list(APPEND microhttpd_LIBRARIES "${_microhttpd_add_libs}")
				pip_module(http_server "${_microhttpd_add_libs}" "PIP HTTP server" "" "" "")
			endif()
		endif()


		if (PIP_BUILD_HTTP_CLIENT)
			# libcurl
			pip_find_lib(curl HINTS "${MINGW_LIB}")
			if (curl_FOUND)
				pip_module(http_client curl "PIP HTTP client" "" "" "")
			endif()
		endif()


		if (PIP_BUILD_MQTT_CLIENT)
			# paho.mqtt.c

			#set(MQTT_C_OpenSSL_SUPPORT   OFF CACHE BOOL "" FORCE)
			#set(MQTT_C_MbedTLS_SUPPORT   OFF CACHE BOOL "" FORCE)
			#set(MQTT_C_BearSSL_SUPPORT   OFF CACHE BOOL "" FORCE)
			#set(MQTT_C_EXAMPLES          OFF CACHE BOOL "" FORCE)
			#set(MQTT_C_INSTALL_EXAMPLES  OFF CACHE BOOL "" FORCE)
			#set(MQTT_C_TESTS             OFF CACHE BOOL "" FORCE)
			set(PAHO_WITH_SSL             OFF CACHE BOOL "" FORCE)
			set(PAHO_WITH_LIBRESSL        OFF CACHE BOOL "" FORCE)
			set(PAHO_WITH_LIBUUID         OFF CACHE BOOL "" FORCE)
			set(PAHO_BUILD_SHARED         OFF CACHE BOOL "" FORCE)
			set(PAHO_BUILD_STATIC         ON  CACHE BOOL "" FORCE)
			set(PAHO_BUILD_DOCUMENTATION  OFF CACHE BOOL "" FORCE)
			set(PAHO_BUILD_SAMPLES        OFF CACHE BOOL "" FORCE)
			set(PAHO_BUILD_DEB_PACKAGE    OFF CACHE BOOL "" FORCE)
			set(PAHO_ENABLE_TESTING       OFF CACHE BOOL "" FORCE)
			set(PAHO_ENABLE_CPACK         OFF CACHE BOOL "" FORCE)
			set(PAHO_HIGH_PERFORMANCE     OFF CACHE BOOL "" FORCE)
			set(PAHO_USE_SELECT           OFF CACHE BOOL "" FORCE)
			set(PAHO_NO_TCP_NODELAY       OFF CACHE BOOL "" FORCE)
			add_subdirectory("3rd/paho.mqtt.c" EXCLUDE_FROM_ALL)

			pip_module(mqtt_client eclipse-paho-mqtt-c::paho-mqtt3c-static "PIP MQTT Client" "" "" " (internal)")
		endif()


		# Test program
		if(PIP_UTILS)

			#add_library(pip_plugin SHARED "test_plugin.h" "test_plugin.cpp" "ccm.h" "ccm.cpp")
			#target_link_libraries(pip_plugin pip)

			if (NOT DEFINED ANDROID_PLATFORM)
				if (PIP_MANUAL_TEST)
					if(microhttpd_FOUND AND curl_FOUND)
						add_executable(pip_test "main.cpp")
						target_link_libraries(pip_test pip pip_io_utils pip_client_server pip_http_server pip_http_client pip_mqtt_client)
						if(sodium_FOUND)
							add_executable(pip_cloud_test "main_picloud_test.cpp")
							target_link_libraries(pip_cloud_test pip_cloud)
						endif()
					endif()
				endif()
			endif()
		endif()

	else()

		if (PIP_BUILD_CRYPT)
			pip_module(crypt "" "PIP crypt support" "" "" "")
		endif()

		if (PIP_BUILD_COMPRESS)
			pip_module(compress "" "PIP compression support" "" "" "")
		endif()

		if (PIP_BUILD_IO_UTILS)
			pip_module(io_utils "pip_crypt" "PIP I/O support" "" "" " (+crypt)")
		endif()

	endif()
endif()

string(REPLACE ";" "," PIP_EXPORTS_STR "${PIP_EXPORTS}")
target_compile_definitions(pip PRIVATE "PICODE_DEFINES=\"${PIP_EXPORTS_STR}\"")


if(NOT PIP_FREERTOS)

# Auxiliary
	if (NOT CROSSTOOLS)
		add_subdirectory("utils/piterminal")
	endif()

# Utils
	add_subdirectory("utils/code_model_generator")
	add_subdirectory("utils/resources_compiler")
	add_subdirectory("utils/deploy_tool")
	add_subdirectory("utils/qt_support")
	add_subdirectory("utils/translator")
	add_subdirectory("utils/value_tree_translator")
	if(PIP_UTILS AND (NOT CROSSTOOLS))
		add_subdirectory("utils/system_calib")
		add_subdirectory("utils/udp_file_transfer")
		if(sodium_FOUND)
			add_subdirectory("utils/system_daemon")
			add_subdirectory("utils/crypt_tool")
			add_subdirectory("utils/cloud_dispatcher")
		endif()
	endif()

endif()


# Translations
set(PIP_LANG)
if (NOT CROSSTOOLS)
	# pip_translation(PIP_LANG lang/pip_ru.ts)
	# add_custom_target(pip_lang SOURCES "${PIP_LANG}")
	file(GLOB PIP_LANG "lang/*.btf")
endif()


# Install
# Check if system or local install will be used (to system install use "-DLIB=" argument of cmake)
if(NOT LOCAL)
	if(WIN32)
		if(MINGW)
			if (NOT CROSSTOOLS)
				install(FILES ${HDRS} DESTINATION ${MINGW_INCLUDE}/pip)
				if(PIP_LANG)
					install(FILES ${PIP_LANG} DESTINATION ${MINGW_INCLUDE}/../share/pip/lang)
				endif()
				if(HDR_DIRS)
					install(DIRECTORY ${HDR_DIRS} DESTINATION ${MINGW_INCLUDE}/pip)
				endif()
				install(TARGETS ${PIP_MODULES} ARCHIVE DESTINATION ${MINGW_LIB})
			endif()
			install(TARGETS ${PIP_MODULES} RUNTIME DESTINATION ${MINGW_BIN})
			find_library(STDLIB "stdc++-6" PATHS ${MINGW_BIN} NO_DEFAULT_PATH)
			find_library(STDLIB "stdc++-6")
			#message("${STDLIB}")
			if (STDLIB)
				file(COPY "${STDLIB}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/utils/code_model_generator")
				file(COPY "${STDLIB}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/utils/resources_compiler")
				file(COPY "${STDLIB}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/utils/deploy_tool")
				file(COPY "${STDLIB}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/utils/translator")
			endif()
		else()
			install(FILES ${CMAKE_CURRENT_BINARY_DIR}/pip_export.h DESTINATION include)
		endif()
	else()
		if (NOT CROSSTOOLS)
			install(FILES ${HDRS} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/pip)
			if(PIP_LANG)
				install(FILES ${PIP_LANG} DESTINATION ${CMAKE_INSTALL_PREFIX}/share/pip/lang)
			endif()
			if(HDR_DIRS)
				install(DIRECTORY ${HDR_DIRS} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/pip)
			endif()
		endif()
		install(TARGETS ${PIP_MODULES} DESTINATION ${CMAKE_INSTALL_PREFIX}/lib)
	endif()
else()
	if(NOT PIP_FREERTOS)
		if(WIN32)
			install(TARGETS ${PIP_MODULES} RUNTIME DESTINATION bin)
			install(TARGETS ${PIP_MODULES} ARCHIVE DESTINATION lib)
		else()
			install(TARGETS ${PIP_MODULES} DESTINATION lib)
		endif()
		install(FILES ${HDRS} DESTINATION include/pip)
		if(PIP_LANG)
			install(FILES ${PIP_LANG} DESTINATION share/pip/lang)
		endif()
		if(HDR_DIRS)
			install(DIRECTORY ${HDR_DIRS} DESTINATION include/pip)
		endif()
	endif()
endif()
file(GLOB CMAKES "cmake/*.cmake" "cmake/*.in")
install(FILES ${CMAKES} DESTINATION ${CMAKE_ROOT}/Modules)


shstk_is_parent_exists(_pe)
if (_pe)
	set(PIP_MODULES ${PIP_MODULES} PARENT_SCOPE)
endif()

#
# Build Documentation
#
if ((NOT PIP_FREERTOS) AND (NOT CROSSTOOLS))
	include(PIPDocumentation)
	find_package(Doxygen)
	if(DOXYGEN_FOUND)
		set(DOXY_DEFINES "${PIP_EXPORTS}")
		foreach (_m "console" "usb" "compress" "crypt" "client_server" "cloud" "fftw" "opencl" "io_utils" "lua" "http_server" "http_client" "mqtt_client")
			string(TOUPPER "${_m}" _mdef)
			list(APPEND DOXY_DEFINES "PIP_${_mdef}_EXPORT")
		endforeach()
		set(DOXY_PROJECT_NUMBER "${PIP_VERSION}")
		set(DOXY_QHP_CUST_FILTER_ATTRS "\"PIP ${PIP_VERSION}\"")
		set(DOXY_QHP_SECT_FILTER_ATTRS "\"PIP ${PIP_VERSION}\"")
		set(DOXY_EXAMPLE_PATH    "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/examples\"")
		set(DOXY_IMAGE_PATH      "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/images\"")
		set(DOXY_LOGO_PATH       "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/pip.png\"")
		set(DOXY_EXCLUDE         "\"${CMAKE_CURRENT_SOURCE_DIR}/3rd\"")
		set(DOXY_DOMAIN "${PIP_DOMAIN}.${PROJECT_NAME}.doc")
		if ("x${DOC_LANG}" STREQUAL "x")
			set(DOXY_OUTPUT_LANGUAGE English)
			set(DOXY_OUTPUT_DIR      en)
		else()
			set(DOXY_OUTPUT_LANGUAGE ${DOC_LANG})
			set(DOXY_OUTPUT_DIR      ${DOC_DIR})
		endif()
		if(DOXYGEN_DOT_EXECUTABLE)
			string(REPLACE "\\" "/" _DOT_PATH "${DOXYGEN_DOT_PATH}")
			set(DOXY_DOT_PATH    "\"${_DOT_PATH}\"")
			set(DOXY_DIA_PATH    "\"${_DOT_PATH}\"")
		endif()
		set(DOXY_INPUT)
		foreach(F ${PIP_MAIN_FOLDERS})
			list(APPEND DOXY_INPUT "\"${F}\"")
		endforeach(F)
		string(REPLACE ";" " " DOXY_INPUT "\"${CMAKE_CURRENT_SOURCE_DIR}/libs\";\"${CMAKE_CURRENT_SOURCE_DIR}/doc/pages\"")
		string(REPLACE ";" " " DOXY_INCLUDE_PATH "${PIP_INCLUDES}")
		string(REPLACE ";" " " DOXY_DEFINES "${DOXY_DEFINES}")
		add_documentation(doc doc/Doxyfile.in)
		install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc/html DESTINATION ../share/doc/pip COMPONENT doc EXCLUDE_FROM_ALL OPTIONAL)
	endif()
endif()


set(_max_len 0)
foreach(_m ${PIP_SRC_MODULES})
	string(LENGTH "${_m}" _clen)
	if (_clen GREATER _max_len)
		set(_max_len ${_clen})
	endif()
endforeach()
macro(expand_to_length _out _str _len)
	set(${_out} "${_str}")
	while(TRUE)
		string(LENGTH "${${_out}}" _clen)
		if (_clen GREATER_EQUAL ${_len})
			break()
		endif()
		string(APPEND ${_out} " ")
	endwhile()
endmacro()

list(REMOVE_ITEM LIBS_STATUS ${PIP_MODULES})
list(REMOVE_DUPLICATES LIBS_STATUS)
message("----------PIP----------")
message(" Version: ${PIP_VERSION} ")
message(" Linkage: ${PIP_LIB_TYPE_MSG}")
message(" Type   : ${CMAKE_BUILD_TYPE}")
if (NOT LOCAL)
	message(" Install: \"${CMAKE_INSTALL_PREFIX}\"")
else()
	if(NOT PIP_FREERTOS)
		message(" Install: local \"bin\", \"lib\" and \"include\"")
	endif()
endif()
message("")
message(" Options:")
message("  std::iostream: ${PIP_STD_IOSTREAM}")
message("  ICU strings  : ${PIP_ICU}")
message("  Introspection: ${PIP_INTROSPECTION}")
message("  Coverage     : ${PIP_COVERAGE}")
if(INTROSPECTION)
	message(STATUS "  Warning: Introspection reduces the performance!")
endif()
message("")
message(" Modules:")
foreach(_m ${PIP_SRC_MODULES})
	expand_to_length(_m_e "${_m}" ${_max_len})
	message("  ${_m_e}: ${PIP_MSG_${_m}}")
endforeach()
message("")
if (PIP_TESTS_LIST)
	message(" Tests:")
	foreach(_test ${PIP_TESTS_LIST})
		message("  * ${_test}")
	endforeach()
	if (TESTS_RUN)
		message("TESTS_RUN ON -> Run tests before install step")
	endif()
else()
	message(" Tests: skip (tests off)")
endif()
message("")
message(" Utilites:")
foreach(_util ${PIP_UTILS_LIST})
	message("  * ${_util}")
endforeach()
if(NOT PIP_FREERTOS)
	message("")
	message(" Using libraries:")
	foreach(LIB_ ${LIBS_STATUS})
		if (NOT TARGET ${LIB_})
			if(${LIB_}_FOUND)
				message("  ${LIB_} -> ${${LIB_}_LIBRARIES}")
			else()
				message("  ${LIB_} not found, may fail")
			endif()
		endif()
	endforeach()
endif()
message("-----------------------")
