1# - Find jsoncpp - Overarching find module
2# This is a over-arching find module to find older jsoncpp versions and those sadly built
3# without JSONCPP_WITH_CMAKE_PACKAGE=ON, as well as those built with the cmake config file.
4# It also wraps the different versions of the module.
5#
6# On CMake 3.0 and newer:
7#  JsonCpp::JsonCpp - Imported target (possibly an interface/alias) to use:
8#  if anything is populated, this is. If both shared and static are found, then
9#  this will be the static version on DLL platforms and shared on non-DLL platforms.
10#  JsonCpp::JsonCppShared - Imported target (possibly an interface/alias) for a
11#  shared library version.
12#  JsonCpp::JsonCppStatic - Imported target (possibly an interface/alias) for a
13#  static library version.
14#
15# On all CMake versions: (Note that on CMake 2.8.10 and earlier, you may need to use JSONCPP_INCLUDE_DIRS)
16#  JSONCPP_LIBRARY - wraps JsonCpp::JsonCpp or equiv.
17#  JSONCPP_LIBRARY_IS_SHARED - if we know for sure JSONCPP_LIBRARY is shared, this is true-ish. We try to "un-set" it if we don't know one way or another.
18#  JSONCPP_LIBRARY_SHARED - wraps JsonCpp::JsonCppShared or equiv.
19#  JSONCPP_LIBRARY_STATIC - wraps JsonCpp::JsonCppStatic or equiv.
20#  JSONCPP_INCLUDE_DIRS - Include directories - should (generally?) not needed if you require CMake 2.8.11+ since it handles target include directories.
21#
22#  JSONCPP_FOUND - True if JsonCpp was found.
23#
24# Original Author:
25# 2016 Ryan Pavlik <ryan.pavlik@gmail.com>
26# Incorporates work from the module contributed to VRPN under the same license:
27# 2011 Philippe Crassous (ENSAM ParisTech / Institut Image) p.crassous _at_ free.fr
28#
29# Copyright Philippe Crassous 2011.
30# Copyright Sensics, Inc. 2016.
31# Distributed under the Boost Software License, Version 1.0.
32# (See accompanying file LICENSE_1_0.txt or copy at
33# http://www.boost.org/LICENSE_1_0.txt)
34
35set(__jsoncpp_have_namespaced_targets OFF)
36set(__jsoncpp_have_interface_support OFF)
37if(NOT ("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 3.0))
38	set(__jsoncpp_have_namespaced_targets ON)
39	set(__jsoncpp_have_interface_support ON)
40elseif(("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" EQUAL 2.8) AND "${CMAKE_PATCH_VERSION}" GREATER 10)
41	set(__jsoncpp_have_interface_support ON)
42endif()
43
44# sets __jsoncpp_have_jsoncpplib based on whether or not we have a real imported jsoncpp_lib target.
45macro(_jsoncpp_check_for_real_jsoncpplib)
46	set(__jsoncpp_have_jsoncpplib FALSE)
47	if(TARGET jsoncpp_lib)
48		get_property(__jsoncpp_lib_type TARGET jsoncpp_lib PROPERTY TYPE)
49		#message(STATUS "__jsoncpp_lib_type ${__jsoncpp_lib_type}")
50		# We make interface libraries. If an actual config module made it, it would be an imported library.
51		if(NOT __jsoncpp_lib_type STREQUAL "INTERFACE_LIBRARY")
52			#message("have jsoncpp_lib and we didn't invent it ourselves")
53			set(__jsoncpp_have_jsoncpplib TRUE)
54		endif()
55	endif()
56endmacro()
57
58include(FindPackageHandleStandardArgs)
59# Ensure that if this is TRUE later, it's because we set it.
60set(JSONCPP_FOUND FALSE)
61
62# See if we find a CMake config file - there is no harm in calling this more than once,
63# and we need to call it at least once every CMake invocation to create the original
64# imported targets, since those don't stick around like cache variables.
65find_package(jsoncpp QUIET NO_MODULE)
66
67if(jsoncpp_FOUND)
68	# Build a string to help us figure out when to invalidate our cache variables.
69	# start with where we found jsoncpp
70	set(__jsoncpp_info_string "[${jsoncpp_DIR}]")
71
72	# part of the string to indicate if we found a real jsoncpp_lib (and what kind)
73	_jsoncpp_check_for_real_jsoncpplib()
74	if(__jsoncpp_have_jsoncpplib)
75		list(APPEND __jsoncpp_info_string "[${__jsoncpp_lib_type}]")
76	else()
77		list(APPEND __jsoncpp_info_string "[]")
78	endif()
79	# part of the string to indicate if we found jsoncpp_lib_static
80	if(TARGET jsoncpp_lib_static)
81		list(APPEND __jsoncpp_info_string "[T]")
82	else()
83		list(APPEND __jsoncpp_info_string "[]")
84	endif()
85endif()
86
87
88# If we found something, and it's not the exact same as what we've found before...
89# NOTE: The contents of this "if" block update only (internal) cache variables!
90# (since this will only get run the first CMake pass that finds jsoncpp or that finds a different/updated install)
91if(jsoncpp_FOUND AND NOT __jsoncpp_info_string STREQUAL "${JSONCPP_CACHED_JSONCPP_DIR_DETAILS}")
92	#message("Updating jsoncpp cache variables! ${__jsoncpp_info_string}")
93	set(JSONCPP_CACHED_JSONCPP_DIR_DETAILS "${__jsoncpp_info_string}" CACHE INTERNAL "" FORCE)
94	unset(JSONCPP_IMPORTED_LIBRARY_SHARED)
95	unset(JSONCPP_IMPORTED_LIBRARY_STATIC)
96	unset(JSONCPP_IMPORTED_LIBRARY)
97	unset(JSONCPP_IMPORTED_INCLUDE_DIRS)
98	unset(JSONCPP_IMPORTED_LIBRARY_IS_SHARED)
99
100	# if(__jsoncpp_have_jsoncpplib) is equivalent to if(TARGET jsoncpp_lib) except it excludes our
101	# "invented" jsoncpp_lib interface targets, made for convenience purposes after this block.
102
103	if(__jsoncpp_have_jsoncpplib AND TARGET jsoncpp_lib_static)
104
105		# A veritable cache of riches - we have both shared and static!
106		set(JSONCPP_IMPORTED_LIBRARY_SHARED jsoncpp_lib CACHE INTERNAL "" FORCE)
107		set(JSONCPP_IMPORTED_LIBRARY_STATIC jsoncpp_lib_static CACHE INTERNAL "" FORCE)
108		if(WIN32 OR CYGWIN OR MINGW)
109			# DLL platforms: static library should be default
110			set(JSONCPP_IMPORTED_LIBRARY ${JSONCPP_IMPORTED_LIBRARY_STATIC} CACHE INTERNAL "" FORCE)
111			set(JSONCPP_IMPORTED_LIBRARY_IS_SHARED FALSE CACHE INTERNAL "" FORCE)
112		else()
113			# Other platforms - might require PIC to be linked into shared libraries, so safest to prefer shared.
114			set(JSONCPP_IMPORTED_LIBRARY ${JSONCPP_IMPORTED_LIBRARY_SHARED} CACHE INTERNAL "" FORCE)
115			set(JSONCPP_IMPORTED_LIBRARY_IS_SHARED TRUE CACHE INTERNAL "" FORCE)
116		endif()
117
118	elseif(TARGET jsoncpp_lib_static)
119		# Well, only one variant, but we know for sure that it's static.
120		set(JSONCPP_IMPORTED_LIBRARY_STATIC jsoncpp_lib_static CACHE INTERNAL "" FORCE)
121		set(JSONCPP_IMPORTED_LIBRARY jsoncpp_lib_static CACHE INTERNAL "" FORCE)
122		set(JSONCPP_IMPORTED_LIBRARY_IS_SHARED FALSE CACHE INTERNAL "" FORCE)
123
124	elseif(__jsoncpp_have_jsoncpplib AND __jsoncpp_lib_type STREQUAL "STATIC_LIBRARY")
125		# We were able to figure out the mystery library is static!
126		set(JSONCPP_IMPORTED_LIBRARY_STATIC jsoncpp_lib CACHE INTERNAL "" FORCE)
127		set(JSONCPP_IMPORTED_LIBRARY jsoncpp_lib CACHE INTERNAL "" FORCE)
128		set(JSONCPP_IMPORTED_LIBRARY_IS_SHARED FALSE CACHE INTERNAL "" FORCE)
129
130	elseif(__jsoncpp_have_jsoncpplib AND __jsoncpp_lib_type STREQUAL "SHARED_LIBRARY")
131		# We were able to figure out the mystery library is shared!
132		set(JSONCPP_IMPORTED_LIBRARY_SHARED jsoncpp_lib CACHE INTERNAL "" FORCE)
133		set(JSONCPP_IMPORTED_LIBRARY jsoncpp_lib CACHE INTERNAL "" FORCE)
134		set(JSONCPP_IMPORTED_LIBRARY_IS_SHARED TRUE CACHE INTERNAL "" FORCE)
135
136	elseif(__jsoncpp_have_jsoncpplib)
137		# One variant, and we have no idea if this is just an old version or if
138		# this is shared based on the target name alone. Hmm.
139		set(JSONCPP_IMPORTED_LIBRARY jsoncpp_lib CACHE INTERNAL "" FORCE)
140	endif()
141
142	# Now, we need include directories. Can't just limit this to old CMakes, since
143	# new CMakes might be used to build projects designed to support older ones.
144	if(__jsoncpp_have_jsoncpplib)
145		get_property(__jsoncpp_interface_include_dirs TARGET jsoncpp_lib PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
146		if(__jsoncpp_interface_include_dirs)
147			set(JSONCPP_IMPORTED_INCLUDE_DIRS "${__jsoncpp_interface_include_dirs}" CACHE INTERNAL "" FORCE)
148		endif()
149	endif()
150	if(TARGET jsoncpp_lib_static AND NOT JSONCPP_IMPORTED_INCLUDE_DIRS)
151		get_property(__jsoncpp_interface_include_dirs TARGET jsoncpp_lib_static PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
152		if(__jsoncpp_interface_include_dirs)
153			set(JSONCPP_IMPORTED_INCLUDE_DIRS "${__jsoncpp_interface_include_dirs}" CACHE INTERNAL "" FORCE)
154		endif()
155	endif()
156endif()
157
158# As a convenience...
159if(TARGET jsoncpp_lib_static AND NOT TARGET jsoncpp_lib)
160	add_library(jsoncpp_lib INTERFACE)
161	target_link_libraries(jsoncpp_lib INTERFACE jsoncpp_lib_static)
162endif()
163
164if(JSONCPP_IMPORTED_LIBRARY)
165	if(NOT JSONCPP_IMPORTED_INCLUDE_DIRS)
166		# OK, so we couldn't get it from the target... maybe we can figure it out from jsoncpp_DIR.
167
168		# take off the jsoncpp component
169		get_filename_component(__jsoncpp_import_root "${jsoncpp_DIR}/.." ABSOLUTE)
170		set(__jsoncpp_hints "${__jsoncpp_import_root}")
171		# take off the cmake component
172		get_filename_component(__jsoncpp_import_root "${__jsoncpp_import_root}/.." ABSOLUTE)
173		list(APPEND __jsoncpp_hints "${__jsoncpp_import_root}")
174		# take off the lib component
175		get_filename_component(__jsoncpp_import_root "${__jsoncpp_import_root}/.." ABSOLUTE)
176		list(APPEND __jsoncpp_hints "${__jsoncpp_import_root}")
177		# take off one more component in case of multiarch lib
178		get_filename_component(__jsoncpp_import_root "${__jsoncpp_import_root}/.." ABSOLUTE)
179		list(APPEND __jsoncpp_hints "${__jsoncpp_import_root}")
180
181		# Now, search.
182		find_path(JsonCpp_INCLUDE_DIR
183			NAMES
184			json/json.h
185			PATH_SUFFIXES include jsoncpp include/jsoncpp
186			HINTS ${__jsoncpp_hints})
187		if(JsonCpp_INCLUDE_DIR)
188			mark_as_advanced(JsonCpp_INCLUDE_DIR)
189			# Note - this does not set it in the cache, in case we find it better at some point in the future!
190			set(JSONCPP_IMPORTED_INCLUDE_DIRS ${JsonCpp_INCLUDE_DIR})
191		endif()
192	endif()
193
194	find_package_handle_standard_args(JsonCpp
195		DEFAULT_MSG
196		jsoncpp_DIR
197		JSONCPP_IMPORTED_LIBRARY
198		JSONCPP_IMPORTED_INCLUDE_DIRS)
199endif()
200
201if(JSONCPP_FOUND)
202	# Create any missing namespaced targets from the config module.
203	if(__jsoncpp_have_namespaced_targets)
204		if(JSONCPP_IMPORTED_LIBRARY AND NOT TARGET JsonCpp::JsonCpp)
205			add_library(JsonCpp::JsonCpp INTERFACE IMPORTED)
206			set_target_properties(JsonCpp::JsonCpp PROPERTIES
207				INTERFACE_INCLUDE_DIRECTORIES "${JSONCPP_IMPORTED_INCLUDE_DIRS}"
208				INTERFACE_LINK_LIBRARIES "${JSONCPP_IMPORTED_LIBRARY}")
209		endif()
210
211		if(JSONCPP_IMPORTED_LIBRARY_SHARED AND NOT TARGET JsonCpp::JsonCppShared)
212			add_library(JsonCpp::JsonCppShared INTERFACE IMPORTED)
213			set_target_properties(JsonCpp::JsonCppShared PROPERTIES
214				INTERFACE_INCLUDE_DIRECTORIES "${JSONCPP_IMPORTED_INCLUDE_DIRS}"
215				INTERFACE_LINK_LIBRARIES "${JSONCPP_IMPORTED_LIBRARY_SHARED}")
216		endif()
217
218		if(JSONCPP_IMPORTED_LIBRARY_STATIC AND NOT TARGET JsonCpp::JsonCppStatic)
219			add_library(JsonCpp::JsonCppStatic INTERFACE IMPORTED)
220			set_target_properties(JsonCpp::JsonCppStatic PROPERTIES
221				INTERFACE_INCLUDE_DIRECTORIES "${JSONCPP_IMPORTED_INCLUDE_DIRS}"
222				INTERFACE_LINK_LIBRARIES "${JSONCPP_IMPORTED_LIBRARY_STATIC}")
223		endif()
224
225		# Hide the stuff we didn't, and no longer, need.
226		if(NOT JsonCpp_LIBRARY)
227			unset(JsonCpp_LIBRARY CACHE)
228		endif()
229		if(NOT JsonCpp_INCLUDE_DIR)
230			unset(JsonCpp_INCLUDE_DIR CACHE)
231		endif()
232	endif()
233
234	set(JSONCPP_LIBRARY ${JSONCPP_IMPORTED_LIBRARY})
235	set(JSONCPP_INCLUDE_DIRS ${JSONCPP_IMPORTED_INCLUDE_DIRS})
236	if(DEFINED JSONCPP_IMPORTED_LIBRARY_IS_SHARED)
237		set(JSONCPP_LIBRARY_IS_SHARED ${JSONCPP_IMPORTED_LIBRARY_IS_SHARED})
238	else()
239		unset(JSONCPP_LIBRARY_IS_SHARED)
240	endif()
241
242	if(JSONCPP_IMPORTED_LIBRARY_SHARED)
243		set(JSONCPP_LIBRARY_SHARED ${JSONCPP_IMPORTED_LIBRARY_SHARED})
244	endif()
245
246	if(JSONCPP_IMPORTED_LIBRARY_STATIC)
247		set(JSONCPP_LIBRARY_STATIC ${JSONCPP_IMPORTED_LIBRARY_STATIC})
248	endif()
249endif()
250
251# Still nothing after looking for the config file: must go "old-school"
252if(NOT JSONCPP_FOUND)
253	# Invoke pkgconfig for hints
254	find_package(PkgConfig QUIET)
255	set(_JSONCPP_INCLUDE_HINTS)
256	set(_JSONCPP_LIB_HINTS)
257	if(PKG_CONFIG_FOUND)
258		pkg_search_module(_JSONCPP_PC QUIET jsoncpp)
259		if(_JSONCPP_PC_INCLUDE_DIRS)
260			set(_JSONCPP_INCLUDE_HINTS ${_JSONCPP_PC_INCLUDE_DIRS})
261		endif()
262		if(_JSONCPP_PC_LIBRARY_DIRS)
263			set(_JSONCPP_LIB_HINTS ${_JSONCPP_PC_LIBRARY_DIRS})
264		endif()
265		if(_JSONCPP_PC_LIBRARIES)
266			set(_JSONCPP_LIB_NAMES ${_JSONCPP_PC_LIBRARIES})
267		endif()
268	endif()
269
270	if(NOT _JSONCPP_LIB_NAMES)
271		# OK, if pkg-config wasn't able to give us a library name suggestion, then we may
272		# have to resort to some intense old logic.
273		set(_JSONCPP_LIB_NAMES jsoncpp)
274		set(_JSONCPP_PATHSUFFIXES)
275
276		if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
277			list(APPEND _JSONCPP_PATHSUFFIXES
278				linux-gcc) # bit of a generalization but close...
279		endif()
280		if(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_SYSTEM_NAME STREQUAL "Linux")
281			list(APPEND
282				_JSONCPP_LIB_NAMES
283				json_linux-gcc-${CMAKE_CXX_COMPILER_VERSION}_libmt
284				json_linux-gcc_libmt)
285			list(APPEND _JSONCPP_PATHSUFFIXES
286				linux-gcc-${CMAKE_CXX_COMPILER_VERSION})
287
288		elseif(MSVC)
289			if(MSVC_VERSION EQUAL 1200)
290				list(APPEND _JSONCPP_LIB_NAMES json_vc6_libmt)
291				list(APPEND _JSONCPP_PATHSUFFIXES msvc6)
292			elseif(MSVC_VERSION EQUAL 1300)
293				list(APPEND _JSONCPP_LIB_NAMES json_vc7_libmt)
294				list(APPEND _JSONCPP_PATHSUFFIXES msvc7)
295			elseif(MSVC_VERSION EQUAL 1310)
296				list(APPEND _JSONCPP_LIB_NAMES json_vc71_libmt)
297				list(APPEND _JSONCPP_PATHSUFFIXES msvc71)
298			elseif(MSVC_VERSION EQUAL 1400)
299				list(APPEND _JSONCPP_LIB_NAMES json_vc8_libmt)
300				list(APPEND _JSONCPP_PATHSUFFIXES msvc80)
301			elseif(MSVC_VERSION EQUAL 1500)
302				list(APPEND _JSONCPP_LIB_NAMES json_vc9_libmt)
303				list(APPEND _JSONCPP_PATHSUFFIXES msvc90)
304			elseif(MSVC_VERSION EQUAL 1600)
305				list(APPEND _JSONCPP_LIB_NAMES json_vc10_libmt)
306				list(APPEND _JSONCPP_PATHSUFFIXES msvc10 msvc100)
307			endif()
308
309		elseif(MINGW)
310			list(APPEND _JSONCPP_LIB_NAMES
311				json_mingw_libmt)
312			list(APPEND _JSONCPP_PATHSUFFIXES mingw)
313
314		else()
315			list(APPEND _JSONCPP_LIB_NAMES
316				json_suncc_libmt
317				json_vacpp_libmt)
318		endif()
319	endif() # end of old logic
320
321	# Actually go looking.
322	find_path(JsonCpp_INCLUDE_DIR
323		NAMES
324		json/json.h
325		PATH_SUFFIXES jsoncpp
326		HINTS ${_JSONCPP_INCLUDE_HINTS})
327	find_library(JsonCpp_LIBRARY
328		NAMES
329		${_JSONCPP_LIB_NAMES}
330		PATHS libs
331		PATH_SUFFIXES ${_JSONCPP_PATHSUFFIXES}
332		HINTS ${_JSONCPP_LIB_HINTS})
333
334	find_package_handle_standard_args(JsonCpp
335		DEFAULT_MSG
336		JsonCpp_INCLUDE_DIR
337		JsonCpp_LIBRARY)
338
339	if(JSONCPP_FOUND)
340		# We already know that the target doesn't exist, let's make it.
341		# TODO don't know why we get errors like:
342		# error: 'JsonCpp::JsonCpp-NOTFOUND', needed by 'bin/osvr_json_to_c', missing and no known rule to make it
343		# when we do the imported target commented out below. So, instead, we make an interface
344		# target with an alias. Hmm.
345
346		#add_library(JsonCpp::JsonCpp UNKNOWN IMPORTED)
347		#set_target_properties(JsonCpp::JsonCpp PROPERTIES
348		#	IMPORTED_LOCATION "${JsonCpp_LIBRARY}"
349		#	INTERFACE_INCLUDE_DIRECTORIES "${JsonCpp_INCLUDE_DIR}"
350		#	IMPORTED_LINK_INTERFACE_LANGUAGES "CXX")
351
352		set(JSONCPP_LIBRARY "${JsonCpp_LIBRARY}")
353		set(JSONCPP_INCLUDE_DIRS "${JsonCpp_INCLUDE_DIR}")
354		unset(JSONCPP_LIBRARY_IS_SHARED)
355
356		if(__jsoncpp_have_interface_support AND NOT TARGET jsoncpp_interface)
357			add_library(jsoncpp_interface INTERFACE)
358			set_target_properties(jsoncpp_interface PROPERTIES
359				INTERFACE_LINK_LIBRARIES "${JsonCpp_LIBRARY}"
360				INTERFACE_INCLUDE_DIRECTORIES "${JsonCpp_INCLUDE_DIR}")
361		endif()
362		if(__jsoncpp_have_namespaced_targets)
363			if(NOT TARGET JsonCpp::JsonCpp)
364				add_library(JsonCpp::JsonCpp ALIAS jsoncpp_interface)
365			endif()
366		endif()
367	endif()
368endif()
369
370if(JSONCPP_FOUND)
371	mark_as_advanced(jsoncpp_DIR JsonCpp_INCLUDE_DIR JsonCpp_LIBRARY)
372endif()
373