# Notes:
#
# Author: Paul Harris, June 2012
#
# Supports: building static/shared, release/debug/etc, can also build html docs and some of the tests.
# Note that its designed for out-of-tree builds, so it will not pollute your source tree.
#
# TODO 1: Finish implementing tests. api tests are working, but the valgrind variants are not flagging problems.
#
# TODO 2: There is a check_exports script that would try and incorporate.
#
# TODO 3: Consolidate version numbers, currently the version number is written into: * cmake (here) * autotools (the configure) * source code header files. Should not be written directly into header files, autotools/cmake can do that job.
#
# Brief intro on how to use cmake:
# > mkdir build (somewhere - we do out-of-tree builds)
# > use cmake, ccmake, or cmake-gui to configure the project. for linux, you can only choose one variant: release,debug,etc... and static or shared.
# >> example:
# >> cd build
# >> ccmake -i ../path_to_jansson_dir
# >> inside, configure your options. press C until there are no lines with * next to them.
# >> note, I like to configure the 'install' path to ../install, so I get self-contained clean installs I can point other projects to.
# >> press G to 'generate' the project files.
# >> make (to build the project)
# >> make install
# >> make test (to run the tests, if you enabled them)
#
# Brief description on how it works:
# There is a small heirachy of CMakeLists.txt files which define how the project is built.
# Header file detection etc is done, and the results are written into config.h and jansson_config.h,
# which are generated from the corresponding config.h.cmake and jansson_config.h.cmake template files.
# The generated header files end up in the build directory - not in the source directory.
# The rest is down to the usual make process.
cmake_minimum_required ( VERSION 2.8 )
# required for exports? cmake_minimum_required (VERSION 2.8.6)
project ( jansson C )
# Options
OPTION ( BUILD_SHARED_LIBS "Build shared libraries." OFF )
# Set some nicer output dirs.
SET ( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${ PROJECT_BINARY_DIR } /bin )
SET ( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${ PROJECT_BINARY_DIR } /lib )
SET ( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${ PROJECT_BINARY_DIR } /lib )
# This is how I thought it should go
# set (JANSSON_VERSION "2.3.1")
# set (JANSSON_SOVERSION 2)
# This is what is required to match the same numbers as automake's
set ( JANSSON_VERSION "4.3.1" )
set ( JANSSON_SOVERSION 4 )
# for CheckFunctionKeywords
set ( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules" )
include ( CheckFunctionExists )
include ( CheckFunctionKeywords )
include ( CheckIncludeFiles )
include ( CheckTypeSize )
# Turn off Microsofts "security" warnings.
if ( MSVC )
add_definitions ( "/W3 /D_CRT_SECURE_NO_WARNINGS /wd4005 /wd4996 /nologo" )
endif ( )
# Check for the int-type includes
check_include_files ( sys/types.h HAVE_SYS_TYPES_H )
check_include_files ( inttypes.h HAVE_INTTYPES_H )
check_include_files ( stdint.h HAVE_STDINT_H )
# Check our 64 bit integer sizes
check_type_size ( __int64 __INT64 )
check_type_size ( int64_t INT64_T )
check_type_size ( "long long" LONG_LONG_INT )
# Check our 32 bit integer sizes
check_type_size ( int32_t INT32_T )
check_type_size ( __int32 __INT32 )
check_type_size ( "long" LONG_INT )
check_type_size ( "int" INT )
if ( HAVE_INT32_T )
set ( JSON_INT32 int32_t )
elseif ( HAVE___INT32 )
set ( JSON_INT32 __int32 )
elseif ( HAVE_LONG AND ( ${ LONG_INT } EQUAL 4 ) )
set ( JSON_INT32 long )
elseif ( HAVE_INT AND ( ${ INT } EQUAL 4 ) )
set ( JSON_INT32 int )
else ( )
message ( FATAL_ERROR "Could not detect a valid 32 bit integer type" )
endif ( )
# Check for ssize_t and SSIZE_T existance.
check_type_size ( ssize_t SSIZE_T )
check_type_size ( SSIZE_T UPPERCASE_SSIZE_T )
if ( NOT HAVE_SSIZE_T )
if ( HAVE_UPPERCASE_SSIZE_T )
set ( JSON_SSIZE SSIZE_T )
else ( )
set ( JSON_SSIZE int )
endif ( )
endif ( )
set ( CMAKE_EXTRA_INCLUDE_FILES "" )
# Check for all the variants of strtoll
check_function_exists ( strtoll HAVE_STRTOLL )
check_function_exists ( strtoq HAVE_STRTOQ )
check_function_exists ( _strtoi64 HAVE__STRTOI64 )
# Figure out what variant we should use
if ( HAVE_STRTOLL )
set ( JSON_STRTOINT strtoll )
elseif ( HAVE_STRTOQ )
set ( JSON_STRTOINT strtoq )
elseif ( HAVE__STRTOI64 )
set ( JSON_STRTOINT _strtoi64 )
else ( )
# fallback to strtol (32 bit)
# this will set all the required variables
set ( JSON_STRTOINT strtol )
set ( JSON_INT_T long )
set ( JSON_INTEGER_FORMAT "\" ld\ "" )
endif ( )
# if we haven't defined JSON_INT_T, then we have a 64 bit conversion function.
# detect what to use for the 64 bit type.
# Note: I will prefer long long if I can get it, as that is what the automake system aimed for.
if ( NOT DEFINED JSON_INT_T )
if ( HAVE_LONG_LONG_INT AND ( ${ LONG_LONG_INT } EQUAL 8 ) )
set ( JSON_INT_T "long long" )
elseif ( HAVE_INT64_T )
set ( JSON_INT_T int64_t )
elseif ( HAVE___INT64 )
set ( JSON_INT_T __int64 )
else ( )
message ( FATAL_ERROR "Could not detect 64 bit type, although I detected the strtoll equivalent" )
endif ( )
# Apparently, Borland BCC and MSVC wants I64d,
# Borland BCC could also accept LD
# and gcc wants ldd,
# I am not sure what cygwin will want, so I will assume I64d
if ( WIN32 ) # matches both msvc and cygwin
set ( JSON_INTEGER_FORMAT "\" I64d\ "" )
else ( )
set ( JSON_INTEGER_FORMAT "\" lld\ "" )
endif ( )
endif ( )
# If locale.h and localeconv() are available, define to 1, otherwise to 0.
check_include_files ( locale.h HAVE_LOCALE_H )
check_function_exists ( localeconv HAVE_LOCALECONV )
if ( HAVE_LOCALECONV AND HAVE_LOCALE_H )
set ( JSON_HAVE_LOCALECONV 1 )
else ( )
set ( JSON_HAVE_LOCALECONV 0 )
endif ( )
# check if we have setlocale
check_function_exists ( setlocale HAVE_SETLOCALE )
# Check what the inline keyword is.
# Note that the original JSON_INLINE was always set to just 'inline', so this goes further.
check_function_keywords ( "inline" )
check_function_keywords ( "__inline" )
check_function_keywords ( "__inline__" )
# check_function_keywords("__declspec(dllexport)")
# check_function_keywords("__declspec(dllimport)")
if ( HAVE_INLINE )
set ( JSON_INLINE inline )
elseif ( HAVE___INLINE )
set ( JSON_INLINE __inline )
elseif ( HAVE___INLINE__ )
set ( JSON_INLINE __inline__ )
else ( HAVE_INLINE )
# no inline on this platform
set ( JSON_INLINE )
endif ( HAVE_INLINE )
# Find our snprintf
check_function_exists ( snprintf HAVE_SNPRINTF )
# check_function_exists (_snprintf_s HAVE__SNPRINTF_s)
check_function_exists ( _snprintf HAVE__SNPRINTF )
if ( HAVE_SNPRINTF )
set ( JSON_SNPRINTF snprintf )
# elseif (HAVE__SNPRINTF_s)
# set (JSON_SNPRINTF _snprintf_s)
elseif ( HAVE__SNPRINTF )
set ( JSON_SNPRINTF _snprintf )
endif ( )
if ( MSVC )
set ( CMAKE_DEBUG_POSTFIX "_d" )
endif ( MSVC )
# configure the public config file
configure_file ( ${ CMAKE_CURRENT_SOURCE_DIR } /src/jansson_config.h.cmake
$ { C M A K E _ C U R R E N T _ B I N A R Y _ D I R } / i n c l u d e / j a n s s o n _ c o n f i g . h )
# Copy the jansson.h file to the public include folder
file ( COPY ${ CMAKE_CURRENT_SOURCE_DIR } /src/jansson.h
D E S T I N A T I O N $ { C M A K E _ C U R R E N T _ B I N A R Y _ D I R } / i n c l u d e / )
# configure the private config file
configure_file ( ${ CMAKE_CURRENT_SOURCE_DIR } /config.h.cmake
$ { C M A K E _ C U R R E N T _ B I N A R Y _ D I R } / p r i v a t e _ i n c l u d e / c o n f i g . h )
# and tell the source code to include it
add_definitions ( -DHAVE_CONFIG_H )
include_directories ( ${ CMAKE_CURRENT_BINARY_DIR } /include )
include_directories ( ${ CMAKE_CURRENT_BINARY_DIR } /private_include )
# Add the lib sources.
file ( GLOB C_FILES src/*.c )
if ( BUILD_SHARED_LIBS )
add_library ( jansson SHARED ${ C_FILES } jansson.def )
set_target_properties ( jansson PROPERTIES
V E R S I O N $ { J A N S S O N _ V E R S I O N }
S O V E R S I O N $ { J A N S S O N _ S O V E R S I O N } )
else ( )
add_library ( jansson ${ C_FILES } )
endif ( )
# LIBRARY for linux
# RUNTIME for windows (when building shared)
install ( TARGETS jansson
A R C H I V E D E S T I N A T I O N l i b
L I B R A R Y D E S T I N A T I O N l i b
R U N T I M E D E S T I N A T I O N b i n
)
install ( FILES ${ CMAKE_CURRENT_BINARY_DIR } /include/jansson_config.h DESTINATION include )
install ( FILES ${ CMAKE_CURRENT_SOURCE_DIR } /src/jansson.h DESTINATION include )
# For building Documentation (uses Sphinx)
OPTION ( BUILD_DOCS "Build documentation (uses python-sphinx)." OFF )
if ( BUILD_DOCS )
find_package ( Sphinx REQUIRED )
# configured documentation tools and intermediate build results
set ( BINARY_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/_build" )
# Sphinx cache with pickled ReST documents
set ( SPHINX_CACHE_DIR "${CMAKE_CURRENT_BINARY_DIR}/_doctrees" )
# HTML output directory
set ( SPHINX_HTML_DIR "${CMAKE_CURRENT_BINARY_DIR}/html" )
# CMake could be used to build the conf.py file too,
# eg it could automatically write the version of the program or change the theme.
# if(NOT DEFINED SPHINX_THEME)
# set(SPHINX_THEME default)
# endif()
#
# if(NOT DEFINED SPHINX_THEME_DIR)
# set(SPHINX_THEME_DIR)
# endif()
#
# configure_file(
# "${CMAKE_CURRENT_SOURCE_DIR}/conf.py.in"
# "${BINARY_BUILD_DIR}/conf.py"
# @ONLY)
add_custom_target ( jansson_docs ALL
$ { S P H I N X _ E X E C U T A B L E }
# -q # Enable for quiet mode
- b h t m l
- d " $ { S P H I N X _ C A C H E _ D I R } "
# -c "${BINARY_BUILD_DIR}" # enable if using cmake-generated conf.py
" $ { C M A K E _ C U R R E N T _ S O U R C E _ D I R } / d o c "
" $ { S P H I N X _ H T M L _ D I R } "
C O M M E N T " B u i l d i n g H T M L d o c u m e n t a t i o n w i t h S p h i n x " )
message ( STATUS "Documentation has been built in ${SPHINX_HTML_DIR}" )
endif ( )
OPTION ( BUILD_TESTS "Build tests ('make test' to execute tests)" OFF )
if ( BUILD_TESTS )
OPTION ( TEST_WITH_VALGRIND "Enable valgrind tests (TODO flag when something is wrong, currently will always pass)" OFF )
ENABLE_TESTING ( )
if ( TEST_WITH_VALGRIND )
# TODO: Add FindValgrind.cmake instead of having a hardcoded path.
# enable valgrind
set ( CMAKE_MEMORYCHECK_COMMAND /usr/bin/valgrind )
set ( CMAKE_MEMORYCHECK_COMMAND_OPTIONS "--leak-check=full --show-reachable=yes --track-origins=yes -q" )
set ( MEMCHECK_COMMAND "${CMAKE_MEMORYCHECK_COMMAND} ${CMAKE_MEMORYCHECK_COMMAND_OPTIONS}" )
separate_arguments ( MEMCHECK_COMMAND )
endif ( )
#
# Test suites.
#
if ( CMAKE_COMPILER_IS_GNUCC )
add_definitions ( -Wall -Wextra -Wdeclaration-after-statement -Werror )
endif ( )
set ( api_tests
t e s t _ a r r a y
t e s t _ c o p y
t e s t _ d u m p
t e s t _ d u m p _ c a l l b a c k
t e s t _ e q u a l
t e s t _ l o a d
t e s t _ l o a d b
t e s t _ n u m b e r
t e s t _ o b j e c t
t e s t _ p a c k
t e s t _ s i m p l e
t e s t _ u n p a c k )
# Doing arithmetic on void pointers is not allowed by Microsofts compiler
# such as secure_malloc and secure_free is doing, so exclude it for now.
if ( NOT MSVC )
list ( APPEND api_tests test_memory_funcs )
endif ( )
# Helper macro for building and linking a test program.
macro ( build_testprog name dir )
add_executable ( ${ name } EXCLUDE_FROM_ALL ${ dir } / ${ name } .c )
add_dependencies ( ${ name } jansson )
target_link_libraries ( ${ name } jansson )
endmacro ( build_testprog )
# Create executables and tests/valgrind tests for API tests.
foreach ( test ${ api_tests } )
build_testprog ( ${ test } ${ PROJECT_SOURCE_DIR } /test/suites/api )
add_test ( ${ test } ${ CMAKE_RUNTIME_OUTPUT_DIRECTORY } / ${ test } )
if ( TEST_WITH_VALGRIND )
add_test ( memcheck_ ${ test } ${ MEMCHECK_COMMAND } ${ CMAKE_RUNTIME_OUTPUT_DIRECTORY } / ${ test } )
endif ( )
endforeach ( )
# Test harness for the suites tests.
build_testprog ( json_process ${ PROJECT_SOURCE_DIR } /test/bin )
set ( SUITES encoding-flags valid invalid invalid-unicode )
foreach ( SUITE ${ SUITES } )
file ( GLOB TESTDIRS ${ jansson_SOURCE_DIR } /test/suites/ ${ SUITE } /* )
foreach ( TESTDIR ${ TESTDIRS } )
if ( IS_DIRECTORY ${ TESTDIR } )
get_filename_component ( TNAME ${ TESTDIR } NAME )
add_test ( ${ SUITE } __ ${ TNAME } ${ CMAKE_RUNTIME_OUTPUT_DIRECTORY } /json_process ${ TESTDIR } )
endif ( )
endforeach ( )
endforeach ( )
add_custom_target ( check COMMAND ${ CMAKE_CTEST_COMMAND }
D E P E N D S $ { a p i _ t e s t s } j s o n _ p r o c e s s )
endif ( )