1cmake_minimum_required(VERSION 3.1.0)
2if(NOT CMAKE_BUILD_TYPE)
3	set(CMAKE_BUILD_TYPE "Release" CACHE STRING "")
4endif()
5
6#Common options
7option( BUNDLED_IRIS "Build iris library bundled" ON )
8option( ONLY_PLUGINS "Build psi-plus plugins only" OFF )
9option( USE_HUNSPELL "Build psi-plus with hunspell spellcheck" ON )
10option( USE_ENCHANT "Build psi-plus with enchant spellcheck" OFF )
11option( USE_QT5 "Use Qt5 to build psi-plus" ON )
12option( ENABLE_PLUGINS "Enable plugins" OFF )
13option( ENABLE_WEBKIT "Enable webkit support" ON )
14option( USE_WEBENGINE "Use WebEngine support instead of Webkit" OFF )
15option( USE_CCACHE "Use ccache utility if found" ON )
16option( VERBOSE_PROGRAM_NAME "Verbose output binary name" OFF ) #Experimental
17#Windows or MXE only
18option( USE_MXE "Use MXE cross-compilation" OFF )
19option( ENABLE_PORTABLE "Create portable version of Psi+ in win32" OFF)
20option( PRODUCTION "Build production version" OFF )
21#Iris options
22option( USE_QJDNS "Use qjdns/jdns library. Disabled by default for Qt5" OFF )
23option( SEPARATE_QJDNS "Build qjdns as separate lib" OFF )
24
25
26set( IS_PSIPLUS ON CACHE BOOL "Build Psi+ client")
27
28if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/widgets/psiwindowheader.cpp")
29	message(STATUS "Psi+ features - FOUND")
30	set(IS_PSIPLUS ON)
31	project(psi-plus)
32else()
33	message(STATUS "Psi+ features - NOT FOUND")
34	set(IS_PSIPLUS OFF)
35	project(psi)
36endif()
37
38set(GLOBAL_DEPENDS_DEBUG_MODE ON)
39
40set( CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules" )
41
42set( ENABLE_SQL OFF CACHE BOOL "Enable SQL history support")
43
44if(ENABLE_WEBKIT)
45	add_definitions(
46		-DWEBKIT
47	)
48	if(USE_QT5)
49		find_package( Qt5Core REQUIRED )
50		find_package( Qt5 COMPONENTS WebEngine QUIET )
51		if(${Qt5Core_VERSION} VERSION_GREATER 5.6.0)
52			if( Qt5WebEngine_FOUND )
53				set( USE_WEBENGINE ON )
54				add_definitions(
55					-DWEBENGINE=1
56				)
57				message(STATUS "QtWebEngine - enabled")
58			else()
59				set( USE_WEBENGINE OFF )
60			endif()
61		endif()
62	endif()
63	message(STATUS "Webkit - enabled")
64endif()
65
66
67if(EXISTS "${PROJECT_SOURCE_DIR}/src/historyimp.cpp")
68	message(STATUS "SQL history - enabled")
69	set(ENABLE_SQL ON)
70else()
71	set(ENABLE_SQL OFF)
72endif()
73
74if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug" OR ("${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo"))
75	set(ISDEBUG ON)
76endif()
77
78if(WIN32)
79	if(MSVC)
80		set(BUILD_ARCH "win64" CACHE STRING "CPU architecture win32/win64")
81		set(SDK_PATH "e:/build/msvc2015-root" CACHE STRING "Path to SDK")
82	else()
83		set(BUILD_ARCH "i386" CACHE STRING "CPU architecture i386/x86_64")
84		set(SDK_PATH "e:/build/psisdk" CACHE STRING "Path to SDK")
85		set(SDK_SUFFIX ${BUILD_ARCH})
86		#temporary Qt5
87		if(USE_QT5)
88			set(SDK_PATH "${SDK_PATH}/Qt5")
89			set(SDK_SUFFIX "")
90		endif()
91		set(LIBGCRYPT_SDK "libgcrypt")
92		set(LIBGPGERROR_SDK "libgpg-error")
93	endif()
94	#autodetect 64bit architecture
95	if(CMAKE_SIZEOF_VOID_P MATCHES "8")
96		if(MSVC)
97			set(BUILD_ARCH "win64")
98		else()
99			set(BUILD_ARCH "x86_64")
100		endif()
101	endif()
102	message(STATUS "Detecting build architecture: ${BUILD_ARCH} detected")
103	if(EXISTS "${SDK_PATH}")
104		if(MSVC)
105			set(QCA_DIR "${SDK_PATH}/" CACHE STRING "Path to QCA")
106			set(IDN_ROOT "${SDK_PATH}/" CACHE STRING "Path to IDN library")
107			set(HUNSPELL_ROOT "${SDK_PATH}/" CACHE STRING "Path to hunspell library")
108			set(LIBGCRYPT_ROOT "${SDK_PATH}/" CACHE STRING "Path to libgcrypt library")
109			set(LIBGPGERROR_ROOT "${SDK_PATH}/" CACHE STRING "Path to libgpg-error library")
110			set(LIBOTR_ROOT "${SDK_PATH}/" CACHE STRING "Path to libotr library")
111			set(LIBTIDY_ROOT "${SDK_PATH}/" CACHE STRING "Path to libtidy library")
112			set(ZLIB_ROOT "${SDK_PATH}/" CACHE STRING "Path to zlib")
113		else()
114			set(QCA_DIR "${SDK_PATH}/qca/${SDK_SUFFIX}/" CACHE STRING "Path to QCA")
115			set(IDN_ROOT "${SDK_PATH}/libidn/${SDK_SUFFIX}/" CACHE STRING "Path to IDN library")
116			set(HUNSPELL_ROOT "${SDK_PATH}/hunspell/${SDK_SUFFIX}/" CACHE STRING "Path to hunspell library")
117			set(LIBGCRYPT_ROOT "${SDK_PATH}/${LIBGCRYPT_SDK}/${SDK_SUFFIX}/" CACHE STRING "Path to libgcrypt library")
118			set(LIBGPGERROR_ROOT "${SDK_PATH}/${LIBGPGERROR_SDK}/${SDK_SUFFIX}/" CACHE STRING "Path to libgpg-error library")
119			set(LIBOTR_ROOT "${SDK_PATH}/libotr/${SDK_SUFFIX}/" CACHE STRING "Path to libotr library")
120			set(LIBTIDY_ROOT "${SDK_PATH}/libtidy/${SDK_SUFFIX}/" CACHE STRING "Path to libtidy library")
121			set(QJSON_ROOT "${SDK_PATH}/qjson/${SDK_SUFFIX}" CACHE STRING "Path to qjson library")
122			set(ZLIB_ROOT "${SDK_PATH}/zlib/${SDK_SUFFIX}/" CACHE STRING "Path to zlib")
123			set(QJDNS_DIR "${SDK_PATH}/qjdns/${SDK_SUFFIX}/" CACHE STRING "Path to qjdns")
124			set(GST_SDK "${SDK_PATH}/gstbundle/${SDK_SUFFIX}/" CACHE STRING "Path to gstreamer SDK")
125			set(PSIMEDIA_DIR "${SDK_PATH}/psimedia/${SDK_SUFFIX}/" CACHE STRING "Path to psimedia plugin")
126		endif()
127	else()
128		message(WARNING "Psi SDK not found at ${SDK_PATH}. Please set SDK_PATH variable or add Psi dependencies to PATH system environmet variable")
129	endif()
130	set(PLUGINS_PATH "/plugins" CACHE STRING "Install suffix for plugins")
131endif()
132
133set(VER_FILE ${PROJECT_SOURCE_DIR}/version)
134if(EXISTS "${VER_FILE}")
135	message(STATUS "Found Psi version file: ${VER_FILE}")
136	file(STRINGS "${VER_FILE}" VER_LINES)
137	if(IS_PSIPLUS)
138		string(REGEX MATCHALL "^([0-9]+\\.[0-9]+\\.[0-9]+)+.+Psi:([a-fA-F0-9]+)+.+Psi\\+:([a-fA-F0-9]+)+" VER_LINE_A ${VER_LINES})
139		if(${CMAKE_MATCH_COUNT} EQUAL 3)
140			if(CMAKE_MATCH_1)
141				set(APP_VERSION ${CMAKE_MATCH_1})
142			endif()
143			if(CMAKE_MATCH_2)
144				set(PSI_REVISION ${CMAKE_MATCH_2})
145			endif()
146			if(CMAKE_MATCH_3)
147				set(PSI_PLUS_REVISION ${CMAKE_MATCH_3})
148			endif()
149		endif()
150		if(APP_VERSION)
151			message(STATUS "Psi version found: ${APP_VERSION}")
152		elseif(NOT APP_VERSION AND (NOT PSI_VERSION) )
153			message(WARNING "Psi+ version not found! 1.0-dev version will be set")
154			set(APP_VERSION "1.0")
155		endif()
156		if(PSI_REVISION)
157			message(STATUS "Psi revision found: ${PSI_REVISION}")
158		endif()
159		if(PSI_PLUS_REVISION)
160			message(STATUS "Psi+ revision found: ${PSI_PLUS_REVISION}")
161		endif()
162	else()
163		string(REGEX MATCH "^[0-9]+\\.[0-9]+" VER_LINE ${VER_LINES})
164		if (VER_LINE)
165			set(APP_VERSION ${VER_LINE})
166			message(STATUS "Psi version found: ${VER_LINE}")
167		elseif( NOT PSI_VERSION )
168			message(WARNING "Psi version not found! 1.0-dev version will be set")
169			set(APP_VERSION "1.0")
170		endif()
171	endif()
172endif()
173
174if( IS_PSIPLUS AND ( APP_VERSION AND ( PSI_REVISION AND PSI_PLUS_REVISION ) ) )
175	set(PSIPLUS_VERSION_OBTAINED ON)
176elseif( NOT IS_PSIPLUS AND APP_VERSION )
177	set(PSI_VERSION_OBTAINED ON)
178endif()
179
180# Define LINUX on Linux like as WIN32 on Windows and APPLE on Mac OS X
181if(UNIX AND NOT APPLE)
182	set(LINUX ON)
183	add_definitions(
184		-DHAVE_X11
185		-DHAVE_FREEDESKTOP
186		-DAPP_PREFIX=${CMAKE_INSTALL_PREFIX}
187		-DAPP_BIN_NAME=${PROJECT_NAME}
188	)
189endif()
190
191#Detect MXE cross-compilation
192if( (CMAKE_CROSSCOMPILING) AND (DEFINED MSYS) )
193	message(STATUS "MXE environment detected")
194	set(USE_MXE ON)
195endif()
196
197# Qt dependencies make building very slow
198# Track only .h files
199include_regular_expression("^.*\\.h$")
200
201# Put executable in build root dir
202set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/psi" )
203
204if(APPLE)
205	# Force Qt5 build on Mac OS X. Qt4 is not supported
206	set(USE_QT5 ON)
207	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-overloaded-virtual")
208else()
209# Enable all warnings
210	if(NOT MSVC)
211		set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Wextra")
212		set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra")
213	else()
214		set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
215		if(NOT ISDEBUG)
216			set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /LTCG")
217			set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /LTCG")
218		endif()
219		add_definitions(-DNOMINMAX)
220	endif()
221endif()
222
223message(STATUS "CXX flags: ${CMAKE_CXX_FLAGS}")
224message(STATUS "C flags: ${CMAKE_C_FLAGS}")
225
226if(ISDEBUG)
227	set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0")
228	set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0")
229	if(MSVC)
230		set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /INCREMENT:NO /MANIFEST:NO")
231		set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /INCREMENT:NO /MANIFEST:NO")
232		set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
233	endif()
234	message(STATUS "CXX debug flags: ${CMAKE_CXX_FLAGS_DEBUG}")
235	message(STATUS "C debug flags: ${CMAKE_C_FLAGS_DEBUG}")
236endif()
237
238if(USE_QT5)
239	option( QT4_BUILD "Build with Qt4 support" OFF )
240else()
241	set( USE_QT5 OFF)
242	option( QT4_BUILD "Build with Qt4 support" ON )
243endif()
244
245if(NOT WIN32 AND PRODUCTION)
246	message(WARNING "PRODUCTION flag only for Windows OS")
247	set(PRODUCTION OFF)
248endif()
249
250if(NOT WIN32 AND ENABLE_PORTABLE)
251	message(WARNING "Portable version creation possible only for Windows OS")
252	set(ENABLE_PORTABLE OFF)
253elseif(WIN32 AND ENABLE_PORTABLE)
254	set(PRODUCTION ON)
255endif()
256
257# Copy a list of files from one directory to another. Only full paths.
258function(copy SOURCE DEST TARGET)
259	if(EXISTS ${SOURCE})
260		set(OUT_TARGET_FILE "${CMAKE_BINARY_DIR}/${TARGET}.cmake")
261
262		string(REGEX REPLACE "\\\\+" "/" DEST "${DEST}")
263		string(REGEX REPLACE "\\\\+" "/" SOURCE "${SOURCE}")
264
265		if(NOT TARGET ${TARGET})
266			file(REMOVE "${OUT_TARGET_FILE}")
267			add_custom_target(${TARGET} COMMAND ${CMAKE_COMMAND} -P "${OUT_TARGET_FILE}")
268		endif()
269
270		if(IS_DIRECTORY ${SOURCE})
271			# copy directory
272			file(GLOB_RECURSE FILES "${SOURCE}/*")
273			get_filename_component(SOURCE_DIR_NAME ${SOURCE} NAME)
274
275			foreach(FILE ${FILES})
276				file(RELATIVE_PATH REL_PATH ${SOURCE} ${FILE})
277				set(REL_PATH "${SOURCE_DIR_NAME}/${REL_PATH}")
278				get_filename_component(REL_PATH ${REL_PATH} DIRECTORY)
279				set(DESTIN "${DEST}/${REL_PATH}")
280
281				string(REGEX REPLACE "/+" "/" DESTIN ${DESTIN})
282				string(REGEX REPLACE "/+" "/" FILE ${FILE})
283
284				file(APPEND
285					"${OUT_TARGET_FILE}"
286					"file(INSTALL \"${FILE}\" DESTINATION \"${DESTIN}\" USE_SOURCE_PERMISSIONS)\n")
287			endforeach()
288		else()
289			string(REPLACE "//" "/" DEST ${DEST})
290			if(DEST MATCHES "/$")
291				set(DIR "${DEST}")
292				string(REGEX REPLACE "^(.+)/$" "\\1" DIR ${DIR})
293			else()
294				# need to copy and rename
295				get_filename_component(DIR ${DEST} DIRECTORY)
296				get_filename_component(FILENAME ${DEST} NAME)
297				get_filename_component(SOURCE_FILENAME ${SOURCE} NAME)
298			endif()
299			file(APPEND
300				"${OUT_TARGET_FILE}"
301				"file(INSTALL \"${SOURCE}\" DESTINATION \"${DIR}\" USE_SOURCE_PERMISSIONS)\n")
302			if(DEFINED FILENAME)
303				file(APPEND
304					"${OUT_TARGET_FILE}"
305					"file(RENAME \"${DIR}/${SOURCE_FILENAME}\" \"${DIR}/${FILENAME}\")\n")
306			endif()
307		endif()
308	endif()
309endfunction()
310
311if(USE_MXE)
312	set(USE_CCACHE OFF)
313endif()
314
315if(USE_CCACHE)
316	# Configure CCache if available
317	find_program(CCACHE_PATH ccache DOC "Path to ccache")
318	if(CCACHE_PATH)
319		message(STATUS "Found ccache at ${CCACHE_PATH}")
320		set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${CCACHE_PATH})
321		set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ${CCACHE_PATH})
322	endif()
323endif()
324
325
326if(NOT ONLY_PLUGINS)
327	if( USE_WEBENGINE )
328		add_subdirectory( 3rdparty )
329	endif()
330	if( ${BUNDLED_IRIS} )
331		add_subdirectory( iris )
332	else( ${BUNDLED_IRIS} )
333		find_package( Iris REQUIRED )
334		include_directories(${Iris_INCLUDE_DIR})
335	endif( ${BUNDLED_IRIS} )
336	set( iris_LIB iris )
337
338	add_subdirectory(src)
339else()
340	set(ENABLE_PLUGINS ON)
341	add_subdirectory(src/plugins)
342endif()
343