From 3e03b078319238d87358fe9c9ba156e29072b446 Mon Sep 17 00:00:00 2001 From: Paul Harris Date: Mon, 4 Jun 2012 01:27:48 +0800 Subject: [PATCH 01/12] Add CMake build system. Added multiple CMake-related files to project. Supports building the library and the tests. See CMakeLists.txt for notes on how it works. I had to adjust 3 existing files in order to disable some configuration that should be taken care of by cmake/automake anyway. I also added jansson.def from a future jansson version, to test cmake's support for .def files (which works fine). --- CMakeLists.txt | 276 +++++++++++++++++++++++ CMakeModules/CheckFunctionKeywords.cmake | 15 ++ CMakeModules/FindSphinx.cmake | 16 ++ config.h.cmake | 22 ++ src/CMakeLists.txt | 23 ++ src/jansson.h | 2 + src/jansson_config.h.cmake | 62 +++++ src/load.c | 2 + src/strconv.c | 5 + test/suites/api/CMakeLists.txt | 31 +++ 10 files changed, 454 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 CMakeModules/CheckFunctionKeywords.cmake create mode 100644 CMakeModules/FindSphinx.cmake create mode 100644 config.h.cmake create mode 100644 src/CMakeLists.txt create mode 100644 src/jansson_config.h.cmake create mode 100644 test/suites/api/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..696b276 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,276 @@ +# 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) + +# 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) + + +# 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) + 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) +elseif (HAVE_INT32_T) + set (JSON_INT32 int32_t) +else () + message (FATAL_ERROR "Could not detect a valid 32 bit integer type") +endif () + +# Check if we have int32_t, if not then we will use long (in config.h.cmake) +check_type_size (int32_t INT32_T) + + +# 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 + ${CMAKE_CURRENT_BINARY_DIR}/include/jansson_config.h) + +# Copy the jansson.h file to the public include folder +file (COPY ${CMAKE_CURRENT_SOURCE_DIR}/src/jansson.h + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/include/) + + +# configure the private config file +configure_file (${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake + ${CMAKE_CURRENT_BINARY_DIR}/private_include/config.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_subdirectory (src) + +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 + ${SPHINX_EXECUTABLE} + # -q # Enable for quiet mode + -b html + -d "${SPHINX_CACHE_DIR}" + # -c "${BINARY_BUILD_DIR}" # enable if using cmake-generated conf.py + "${CMAKE_CURRENT_SOURCE_DIR}/doc" + "${SPHINX_HTML_DIR}" + COMMENT "Building HTML documentation with Sphinx") + + 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) + # 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 () + + add_subdirectory (test/suites/api) +endif () + diff --git a/CMakeModules/CheckFunctionKeywords.cmake b/CMakeModules/CheckFunctionKeywords.cmake new file mode 100644 index 0000000..44601fd --- /dev/null +++ b/CMakeModules/CheckFunctionKeywords.cmake @@ -0,0 +1,15 @@ +include(CheckCSourceCompiles) + +macro(check_function_keywords _wordlist) + set(${_result} "") + foreach(flag ${_wordlist}) + string(REGEX REPLACE "[-+/ ()]" "_" flagname "${flag}") + string(TOUPPER "${flagname}" flagname) + set(have_flag "HAVE_${flagname}") + check_c_source_compiles("${flag} void func(); void func() { } int main() { func(); return 0; }" ${have_flag}) + if(${have_flag} AND NOT ${_result}) + set(${_result} "${flag}") +# break() + endif(${have_flag} AND NOT ${_result}) + endforeach(flag) +endmacro(check_function_keywords) diff --git a/CMakeModules/FindSphinx.cmake b/CMakeModules/FindSphinx.cmake new file mode 100644 index 0000000..76f6e2a --- /dev/null +++ b/CMakeModules/FindSphinx.cmake @@ -0,0 +1,16 @@ +find_program(SPHINX_EXECUTABLE NAMES sphinx-build + HINTS + $ENV{SPHINX_DIR} + PATH_SUFFIXES bin + DOC "Sphinx documentation generator" +) + +include(FindPackageHandleStandardArgs) + +find_package_handle_standard_args(Sphinx DEFAULT_MSG + SPHINX_EXECUTABLE +) + +mark_as_advanced( +  SPHINX_EXECUTABLE +) diff --git a/config.h.cmake b/config.h.cmake new file mode 100644 index 0000000..c4e5a33 --- /dev/null +++ b/config.h.cmake @@ -0,0 +1,22 @@ +/* Reduced down to the defines that are actually used in the code */ + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_LOCALE_H 1 + +/* Define to 1 if you have the 'setlocale' function. */ +#cmakedefine HAVE_SETLOCALE 1 + +/* Define to the type of a signed integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +#cmakedefine HAVE_INT32_T 1 + +#ifndef HAVE_INT32_T +# define int32_t @JSON_INT32@ +#endif + +#ifndef HAVE_SNPRINTF +# define snprintf @JSON_SNPRINTF@ +#endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..8ac6bce --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,23 @@ +file (GLOB C_FILES *.c) + +if (BUILD_SHARED_LIBS) + + add_library (jansson SHARED ${C_FILES} jansson.def) + + set_target_properties (jansson PROPERTIES + VERSION ${JANSSON_VERSION} + SOVERSION ${JANSSON_SOVERSION}) + +else () + + add_library (jansson ${C_FILES}) + +endif () + +# LIBRARY for linux +# RUNTIME for windows (when building shared) +install (TARGETS jansson + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin +) diff --git a/src/jansson.h b/src/jansson.h index ec384d8..e53a301 100644 --- a/src/jansson.h +++ b/src/jansson.h @@ -52,6 +52,7 @@ typedef struct json_t { size_t refcount; } json_t; +#ifndef JANSSON_USING_CMAKE /* disabled if using cmake */ #if JSON_INTEGER_IS_LONG_LONG #ifdef _WIN32 #define JSON_INTEGER_FORMAT "I64d" @@ -63,6 +64,7 @@ typedef long long json_int_t; #define JSON_INTEGER_FORMAT "ld" typedef long json_int_t; #endif /* JSON_INTEGER_IS_LONG_LONG */ +#endif #define json_typeof(json) ((json)->type) #define json_is_object(json) (json && json_typeof(json) == JSON_OBJECT) diff --git a/src/jansson_config.h.cmake b/src/jansson_config.h.cmake new file mode 100644 index 0000000..335ccc4 --- /dev/null +++ b/src/jansson_config.h.cmake @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2010-2012 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + * + * + * This file specifies a part of the site-specific configuration for + * Jansson, namely those things that affect the public API in + * jansson.h. + * + * The CMake system will generate the jansson_config.h file and + * copy it to the build and install directories. + */ + +#ifndef JANSSON_CONFIG_H +#define JANSSON_CONFIG_H + +/* Define this so that we can disable scattered automake configuration in source files */ +#define JANSSON_USING_CMAKE + +/* Note: when using cmake, JSON_INTEGER_IS_LONG_LONG is not defined nor used, + * as we will also check for __int64 etc types. + * (the definition was used in the automake system) */ + +/* Bring in the cmake-detected defines */ +#cmakedefine HAVE_STDINT_H 1 +#cmakedefine HAVE_INTTYPES_H 1 +#cmakedefine HAVE_SYS_TYPES_H 1 + +/* Include our standard type header for the integer typedef */ + +#if defined(HAVE_STDINT_H) +# include +#elif defined(HAVE_INTTYPES_H) +# include +#elif defined(HAVE_SYS_TYPES_H) +# include +#endif + + +/* If your compiler supports the inline keyword in C, JSON_INLINE is + defined to `inline', otherwise empty. In C++, the inline is always + supported. */ +#ifdef __cplusplus +#define JSON_INLINE inline +#else +#define JSON_INLINE @JSON_INLINE@ +#endif + + +#define json_int_t @JSON_INT_T@ +#define json_strtoint @JSON_STRTOINT@ +#define JSON_INTEGER_FORMAT @JSON_INTEGER_FORMAT@ + + +/* If locale.h and localeconv() are available, define to 1, otherwise to 0. */ +#define JSON_HAVE_LOCALECONV @JSON_HAVE_LOCALECONV@ + + + +#endif diff --git a/src/load.c b/src/load.c index 16ff53d..2cc7a5f 100644 --- a/src/load.c +++ b/src/load.c @@ -446,6 +446,7 @@ out: jsonp_free(lex->value.string); } +#ifndef JANSSON_USING_CMAKE /* disabled if using cmake */ #if JSON_INTEGER_IS_LONG_LONG #ifdef _MSC_VER /* Microsoft Visual Studio */ #define json_strtoint _strtoi64 @@ -455,6 +456,7 @@ out: #else #define json_strtoint strtol #endif +#endif static int lex_scan_number(lex_t *lex, int c, json_error_t *error) { diff --git a/src/strconv.c b/src/strconv.c index caa9ab8..3e2cb7c 100644 --- a/src/strconv.c +++ b/src/strconv.c @@ -5,6 +5,11 @@ #include "jansson_private.h" #include "strbuffer.h" +/* need config.h to get the correct snprintf */ +#ifdef HAVE_CONFIG_H +#include +#endif + #if JSON_HAVE_LOCALECONV #include diff --git a/test/suites/api/CMakeLists.txt b/test/suites/api/CMakeLists.txt new file mode 100644 index 0000000..a94d59e --- /dev/null +++ b/test/suites/api/CMakeLists.txt @@ -0,0 +1,31 @@ +set (tests + test_array + test_copy + test_dump + test_dump_callback + test_equal + test_load + test_loadb + test_memory_funcs + test_number + test_object + test_pack + test_simple + test_unpack) + +foreach (test ${tests}) + add_executable (${test} ${test}.c) + target_link_libraries (${test} jansson) +endforeach() + +# batch plain tests +foreach (test ${tests}) + add_test (${test} ${CMAKE_CURRENT_BINARY_DIR}/${test}) +endforeach() + +# batch valgrind tests +if (TEST_WITH_VALGRIND) + foreach (test ${tests}) + add_test (memcheck_${test} ${MEMCHECK_COMMAND} ${CMAKE_CURRENT_BINARY_DIR}/${test}) + endforeach() +endif () From 3d5bea57148d62c313bc9519644fd6858ba79b05 Mon Sep 17 00:00:00 2001 From: Paul Harris Date: Thu, 7 Jun 2012 23:07:04 +0800 Subject: [PATCH 02/12] Fixes for cmake for MSVC2010 --- CMakeLists.txt | 6 +++--- config.h.cmake | 15 ++++++++++++++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 696b276..07aab7c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -74,14 +74,14 @@ check_type_size (__int32 __INT32) check_type_size ("long" LONG_INT) check_type_size ("int" INT) -if (HAVE___INT32) +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) -elseif (HAVE_INT32_T) - set (JSON_INT32 int32_t) else () message (FATAL_ERROR "Could not detect a valid 32 bit integer type") endif () diff --git a/config.h.cmake b/config.h.cmake index c4e5a33..6f854ec 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -1,7 +1,20 @@ /* Reduced down to the defines that are actually used in the code */ -/* Define to 1 if you have the header file. */ +/* Define to 1 if you have the (and friends) header file. */ #cmakedefine HAVE_INTTYPES_H 1 +#cmakedefine HAVE_STDINT_H 1 +#cmakedefine HAVE_SYS_TYPES_H 1 + +/* We must include this here, as in (eg) utf.h it will want to use + the integer type, which in MSVC2010 will be in stdint.h + (there is no inttypes.h in MSVC2010) */ +#if defined(HAVE_STDINT_H) +# include +#elif defined(HAVE_INTTYPES_H) +# include +#elif defined(HAVE_SYS_TYPES_H) +# include +#endif /* Define to 1 if you have the header file. */ #cmakedefine HAVE_LOCALE_H 1 From e40d52c55013cf7368b46a7d05342d70ca8904ec Mon Sep 17 00:00:00 2001 From: Joakim Soderberg Date: Wed, 27 Feb 2013 18:54:26 +0100 Subject: [PATCH 03/12] Consolidated the CMake project. - Moved everything to one CMakeLists.txt - Added support for the json_process test suites (instead of just the API tests). - Changed to use the modified json_process version that does away with the environment variables (originally written by DanielT). - Had to exclude "test_memory_funcs" on MSVC, since void pointer arithmetics are not allowed as it is done in secure_malloc and secure_free. - Had to add a check for "ssize_t". This is not available on Windows and maybe on some other platforms (used in test_pack.c) - Result from running ctest (The failure seems unrelated to CMake, it's just that the expected result is in a different order): 99% tests passed, 1 tests failed out of 121 Total Test time (real) = 1.31 sec The following tests FAILED: 24 - valid__complex-array (Failed) --- CMakeLists.txt | 116 ++++++++++++++++- config.h.cmake | 6 + src/CMakeLists.txt | 23 ---- test/bin/json_process.c | 227 ++++++++++++++++++++++----------- test/suites/api/CMakeLists.txt | 31 ----- test/suites/api/test_pack.c | 6 + 6 files changed, 273 insertions(+), 136 deletions(-) delete mode 100644 src/CMakeLists.txt delete mode 100644 test/suites/api/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 07aab7c..1a85933 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,6 +40,11 @@ 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) @@ -56,6 +61,10 @@ 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) @@ -86,9 +95,17 @@ else () message (FATAL_ERROR "Could not detect a valid 32 bit integer type") endif () -# Check if we have int32_t, if not then we will use long (in config.h.cmake) -check_type_size (int32_t INT32_T) - +# 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) @@ -207,7 +224,31 @@ add_definitions (-DHAVE_CONFIG_H) include_directories (${CMAKE_CURRENT_BINARY_DIR}/include) include_directories (${CMAKE_CURRENT_BINARY_DIR}/private_include) -add_subdirectory (src) +# 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 + VERSION ${JANSSON_VERSION} + SOVERSION ${JANSSON_SOVERSION}) + +else () + + add_library (jansson ${C_FILES}) + +endif () + +# LIBRARY for linux +# RUNTIME for windows (when building shared) +install (TARGETS jansson + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin +) + install (FILES ${CMAKE_CURRENT_BINARY_DIR}/include/jansson_config.h DESTINATION include) install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/src/jansson.h DESTINATION include) @@ -263,14 +304,75 @@ if (BUILD_TESTS) 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(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 () - add_subdirectory (test/suites/api) + # + # Test suites. + # + if (CMAKE_COMPILER_IS_GNUCC) + add_definitions(-Wall -Wextra -Wdeclaration-after-statement -Werror) + endif() + + set(api_tests + test_array + test_copy + test_dump + test_dump_callback + test_equal + test_load + test_loadb + test_number + test_object + test_pack + test_simple + test_unpack) + + # 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} + DEPENDS ${api_tests} json_process) endif () diff --git a/config.h.cmake b/config.h.cmake index 6f854ec..8347d8b 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -30,6 +30,12 @@ # define int32_t @JSON_INT32@ #endif +#cmakedefine HAVE_SSIZE_T 1 + +#ifndef HAVE_SSIZE_T +# define ssize_t @JSON_SSIZE@ +#endif + #ifndef HAVE_SNPRINTF # define snprintf @JSON_SNPRINTF@ #endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt deleted file mode 100644 index 8ac6bce..0000000 --- a/src/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -file (GLOB C_FILES *.c) - -if (BUILD_SHARED_LIBS) - - add_library (jansson SHARED ${C_FILES} jansson.def) - - set_target_properties (jansson PROPERTIES - VERSION ${JANSSON_VERSION} - SOVERSION ${JANSSON_SOVERSION}) - -else () - - add_library (jansson ${C_FILES}) - -endif () - -# LIBRARY for linux -# RUNTIME for windows (when building shared) -install (TARGETS jansson - ARCHIVE DESTINATION lib - LIBRARY DESTINATION lib - RUNTIME DESTINATION bin -) diff --git a/test/bin/json_process.c b/test/bin/json_process.c index 637dfd5..72c4833 100644 --- a/test/bin/json_process.c +++ b/test/bin/json_process.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2012 Petri Lehtinen + * Copyright (c) 2009-2013 Petri Lehtinen * * Jansson is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. @@ -15,33 +15,31 @@ #include #include -#if HAVE_LOCALE_H +#ifdef HAVE_LOCALE_H #include -#endif + #endif #if _WIN32 #include /* for _setmode() */ #include /* for _O_BINARY */ + +static const char dir_sep = '\\'; +#else +static const char dir_sep = '/'; #endif + +struct config { + int indent; + int compact; + int preserve_order; + int ensure_ascii; + int sort_keys; + int strip; +} conf; + #define l_isspace(c) ((c) == ' ' || (c) == '\n' || (c) == '\r' || (c) == '\t') -static int getenv_int(const char *name) -{ - char *value, *end; - long result; - - value = getenv(name); - if(!value) - return 0; - - result = strtol(value, &end, 10); - if(*end != '\0') - return 0; - - return (int)result; -} - /* Return a pointer to the first non-whitespace character of str. Modifies str so that all trailing whitespace characters are replaced by '\0'. */ @@ -49,102 +47,181 @@ static const char *strip(char *str) { size_t length; char *result = str; - while(*result && l_isspace(*result)) + while (*result && l_isspace(*result)) result++; length = strlen(result); - if(length == 0) + if (length == 0) return result; - while(l_isspace(result[length - 1])) + while (l_isspace(result[length - 1])) result[--length] = '\0'; return result; } + +static char *loadfile(FILE *file) +{ + long fsize, ret; + char *buf; + + fseek(file, 0, SEEK_END); + fsize = ftell(file); + fseek(file, 0, SEEK_SET); + + buf = malloc(fsize+1); + ret = fread(buf, 1, fsize, file); + if (ret != fsize) + exit(1); + buf[fsize] = '\0'; + + return buf; +} + + +static void read_conf(FILE *conffile) +{ + char *buffer, *line, *val; + + buffer = loadfile(conffile); + line = strtok(buffer, "\r\n"); + while (line) { + val = strchr(line, '='); + if (!val) { + printf("invalid configuration line\n"); + break; + } + *val++ = '\0'; + + if (!strcmp(line, "JSON_INDENT")) + conf.indent = atoi(val); + if (!strcmp(line, "JSON_COMPACT")) + conf.compact = atoi(val); + if (!strcmp(line, "JSON_ENSURE_ASCII")) + conf.ensure_ascii = atoi(val); + if (!strcmp(line, "JSON_PRESERVE_ORDER")) + conf.preserve_order = atoi(val); + if (!strcmp(line, "JSON_SORT_KEYS")) + conf.sort_keys = atoi(val); + if (!strcmp(line, "STRIP")) + conf.strip = atoi(val); + + line = strtok(NULL, "\r\n"); + } + + free(buffer); +} + + +static int cmpfile(const char *str, const char *path, const char *fname) +{ + char filename[1024], *buffer; + int ret; + FILE *file; + + sprintf(filename, "%s%c%s", path, dir_sep, fname); + file = fopen(filename, "rb"); + if (!file) { + if (conf.strip) + strcat(filename, ".strip"); + else + strcat(filename, ".normal"); + file = fopen(filename, "rb"); + } + if (!file) { + printf("Error: test result file could not be opened.\n"); + exit(1); + } + + buffer = loadfile(file); + if (strcmp(buffer, str) != 0) + ret = 1; + else + ret = 0; + free(buffer); + fclose(file); + + return ret; +} + + int main(int argc, char *argv[]) { - int indent = 0; + int ret; size_t flags = 0; - + char filename[1024], errstr[1024]; + char *buffer; + FILE *infile, *conffile; json_t *json; json_error_t error; -#if HAVE_SETLOCALE + #ifdef HAVE_SETLOCALE setlocale(LC_ALL, ""); -#endif + #endif - if(argc != 1) { - fprintf(stderr, "usage: %s\n", argv[0]); + if (argc != 2) { + fprintf(stderr, "usage: %s test_dir\n", argv[0]); + return 2; + } + + sprintf(filename, "%s%cinput", argv[1], dir_sep); + if (!(infile = fopen(filename, "rb"))) { + fprintf(stderr, "Could not open \"%s\"\n", filename); + return 2; + } + + sprintf(filename, "%s%cenv", argv[1], dir_sep); + conffile = fopen(filename, "rb"); + if (conffile) { + read_conf(conffile); + fclose(conffile); + } + + if (conf.indent < 0 || conf.indent > 255) { + fprintf(stderr, "invalid value for JSON_INDENT: %d\n", conf.indent); return 2; } -#ifdef _WIN32 - /* On Windows, set stdout and stderr to binary mode to avoid - outputting DOS line terminators */ - _setmode(_fileno(stdout), _O_BINARY); - _setmode(_fileno(stderr), _O_BINARY); -#endif + if (conf.indent) + flags |= JSON_INDENT(conf.indent); - indent = getenv_int("JSON_INDENT"); - if(indent < 0 || indent > 255) { - fprintf(stderr, "invalid value for JSON_INDENT: %d\n", indent); - return 2; - } - - if(indent > 0) - flags |= JSON_INDENT(indent); - - if(getenv_int("JSON_COMPACT") > 0) + if (conf.compact) flags |= JSON_COMPACT; - if(getenv_int("JSON_ENSURE_ASCII")) + if (conf.ensure_ascii) flags |= JSON_ENSURE_ASCII; - if(getenv_int("JSON_PRESERVE_ORDER")) + if (conf.preserve_order) flags |= JSON_PRESERVE_ORDER; - if(getenv_int("JSON_SORT_KEYS")) + if (conf.sort_keys) flags |= JSON_SORT_KEYS; - if(getenv_int("STRIP")) { + if (conf.strip) { /* Load to memory, strip leading and trailing whitespace */ - size_t size = 0, used = 0; - char *buffer = NULL; - - while(1) { - size_t count; - - size = (size == 0 ? 128 : size * 2); - buffer = realloc(buffer, size); - if(!buffer) { - fprintf(stderr, "Unable to allocate %d bytes\n", (int)size); - return 1; - } - - count = fread(buffer + used, 1, size - used, stdin); - if(count < size - used) { - buffer[used + count] = '\0'; - break; - } - used += count; - } - + buffer = loadfile(infile); json = json_loads(strip(buffer), 0, &error); free(buffer); } else - json = json_loadf(stdin, 0, &error); + json = json_loadf(infile, 0, &error); - if(!json) { - fprintf(stderr, "%d %d %d\n%s\n", + fclose(infile); + + if (!json) { + sprintf(errstr, "%d %d %d\n%s\n", error.line, error.column, error.position, error.text); - return 1; + + ret = cmpfile(errstr, argv[1], "error"); + return ret; } - json_dumpf(json, stdout, flags); + buffer = json_dumps(json, flags); + ret = cmpfile(buffer, argv[1], "output"); + free(buffer); json_decref(json); - return 0; + return ret; } diff --git a/test/suites/api/CMakeLists.txt b/test/suites/api/CMakeLists.txt deleted file mode 100644 index a94d59e..0000000 --- a/test/suites/api/CMakeLists.txt +++ /dev/null @@ -1,31 +0,0 @@ -set (tests - test_array - test_copy - test_dump - test_dump_callback - test_equal - test_load - test_loadb - test_memory_funcs - test_number - test_object - test_pack - test_simple - test_unpack) - -foreach (test ${tests}) - add_executable (${test} ${test}.c) - target_link_libraries (${test} jansson) -endforeach() - -# batch plain tests -foreach (test ${tests}) - add_test (${test} ${CMAKE_CURRENT_BINARY_DIR}/${test}) -endforeach() - -# batch valgrind tests -if (TEST_WITH_VALGRIND) - foreach (test ${tests}) - add_test (memcheck_${test} ${MEMCHECK_COMMAND} ${CMAKE_CURRENT_BINARY_DIR}/${test}) - endforeach() -endif () diff --git a/test/suites/api/test_pack.c b/test/suites/api/test_pack.c index c7e7251..44aa8aa 100644 --- a/test/suites/api/test_pack.c +++ b/test/suites/api/test_pack.c @@ -6,6 +6,12 @@ * it under the terms of the MIT license. See LICENSE for details. */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + #include #include #include From 741e6915e223d75aa12169d5fdee4e0f8e457f42 Mon Sep 17 00:00:00 2001 From: Joakim Soderberg Date: Wed, 27 Feb 2013 23:25:04 +0100 Subject: [PATCH 04/12] Always use LF as line ending so that we don't get any problems with line endings in any tests. --- test/suites/.gitattributes | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 test/suites/.gitattributes diff --git a/test/suites/.gitattributes b/test/suites/.gitattributes new file mode 100644 index 0000000..68d8861 --- /dev/null +++ b/test/suites/.gitattributes @@ -0,0 +1,2 @@ +api/ text=auto +* text eol=lf \ No newline at end of file From 52a807272760920533ee2db81b4ae009bb0a6e5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20So=CC=88derberg?= Date: Wed, 27 Feb 2013 23:37:35 +0100 Subject: [PATCH 05/12] Rename the CMakeModules directory to simply cmake. This is more consistent with the other directories in the project. --- {CMakeModules => cmake}/CheckFunctionKeywords.cmake | 0 {CMakeModules => cmake}/FindSphinx.cmake | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename {CMakeModules => cmake}/CheckFunctionKeywords.cmake (100%) rename {CMakeModules => cmake}/FindSphinx.cmake (100%) diff --git a/CMakeModules/CheckFunctionKeywords.cmake b/cmake/CheckFunctionKeywords.cmake similarity index 100% rename from CMakeModules/CheckFunctionKeywords.cmake rename to cmake/CheckFunctionKeywords.cmake diff --git a/CMakeModules/FindSphinx.cmake b/cmake/FindSphinx.cmake similarity index 100% rename from CMakeModules/FindSphinx.cmake rename to cmake/FindSphinx.cmake From 344d2b00ea274f5df806556c8c276c1c4c47b088 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20So=CC=88derberg?= Date: Wed, 27 Feb 2013 23:38:17 +0100 Subject: [PATCH 06/12] Fix incorrect cast to ssize_t. gcc 4.2.1 warns about a possible incorrect cast to ssize_t when comparing against refcount, which is of type size_t. signed vs unsigned comparison. Sinc warnings are treated as errors (as in the autoconf project) this would cause a compile error. --- test/suites/api/test_pack.c | 1 - 1 file changed, 1 deletion(-) diff --git a/test/suites/api/test_pack.c b/test/suites/api/test_pack.c index 44aa8aa..61c7409 100644 --- a/test/suites/api/test_pack.c +++ b/test/suites/api/test_pack.c @@ -26,7 +26,6 @@ static void run_tests() /* * Simple, valid json_pack cases */ - /* true */ value = json_pack("b", 1); if(!json_is_true(value)) From 81ce1270481b2fe1dea3d0f8a48265d40df97f24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20So=CC=88derberg?= Date: Thu, 28 Feb 2013 00:16:32 +0100 Subject: [PATCH 07/12] Compile tests by default. - Encourage actually using the unit tests by compiling them by default. Set the WITHOUT_TESTS variable to build without instead... - Changed comments to keep within 80 characters. - Don't have a hard coded path for valgrind, simply assuem it's in the path instead (an OSX ports install puts it in /opt/local/bin for instance). - Fixed building the shared lib. --- CMakeLists.txt | 86 ++++++++++++++++++++++++++++---------------------- config.h.cmake | 4 +++ 2 files changed, 52 insertions(+), 38 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1a85933..e9a3bd8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,34 +1,47 @@ # Notes: # # Author: Paul Harris, June 2012 +# Additions: Joakim Soderberg, Febuary 2013 # -# 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. +# 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 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. +# 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. +# > 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. +# >> 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. +# 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. @@ -54,7 +67,7 @@ set (JANSSON_VERSION "4.3.1") set (JANSSON_SOVERSION 4) # for CheckFunctionKeywords -set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules") +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") include (CheckFunctionExists) include (CheckFunctionKeywords) @@ -174,8 +187,6 @@ check_function_exists (setlocale HAVE_SETLOCALE) 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) @@ -190,13 +201,10 @@ 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 () @@ -229,7 +237,7 @@ file (GLOB C_FILES src/*.c) if (BUILD_SHARED_LIBS) - add_library (jansson SHARED ${C_FILES} jansson.def) + add_library (jansson SHARED ${C_FILES} src/jansson.def) set_target_properties (jansson PROPERTIES VERSION ${JANSSON_VERSION} @@ -249,9 +257,10 @@ install (TARGETS jansson RUNTIME DESTINATION bin ) - -install (FILES ${CMAKE_CURRENT_BINARY_DIR}/include/jansson_config.h DESTINATION include) -install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/src/jansson.h DESTINATION include) +install (FILES + ${CMAKE_CURRENT_BINARY_DIR}/include/jansson_config.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/jansson.h + DESTINATION include) # For building Documentation (uses Sphinx) OPTION (BUILD_DOCS "Build documentation (uses python-sphinx)." OFF) @@ -296,10 +305,10 @@ if (BUILD_DOCS) endif () -OPTION (BUILD_TESTS "Build tests ('make test' to execute tests)" OFF) +OPTION (WITHOUT_TESTS "Don't 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) +if (NOT WITHOUT_TESTS) + OPTION (TEST_WITH_VALGRIND "Enable valgrind tests." OFF) ENABLE_TESTING() @@ -307,10 +316,12 @@ if (BUILD_TESTS) # 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(CMAKE_MEMORYCHECK_COMMAND 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}") + set(MEMCHECK_COMMAND + "${CMAKE_MEMORYCHECK_COMMAND} ${CMAKE_MEMORYCHECK_COMMAND_OPTIONS}") separate_arguments(MEMCHECK_COMMAND) endif () @@ -319,7 +330,7 @@ if (BUILD_TESTS) # if (CMAKE_COMPILER_IS_GNUCC) add_definitions(-Wall -Wextra -Wdeclaration-after-statement -Werror) - endif() + endif () set(api_tests test_array @@ -343,7 +354,7 @@ if (BUILD_TESTS) # Helper macro for building and linking a test program. macro(build_testprog name dir) - add_executable(${name} EXCLUDE_FROM_ALL ${dir}/${name}.c) + add_executable(${name} ${dir}/${name}.c) add_dependencies(${name} jansson) target_link_libraries(${name} jansson) endmacro(build_testprog) @@ -354,9 +365,10 @@ if (BUILD_TESTS) 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() + 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) @@ -367,12 +379,10 @@ if (BUILD_TESTS) 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() + add_test(${SUITE}__${TNAME} + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/json_process ${TESTDIR}) + endif () + endforeach () endforeach () - - add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} - DEPENDS ${api_tests} json_process) endif () diff --git a/config.h.cmake b/config.h.cmake index 8347d8b..bc81178 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -36,6 +36,10 @@ # define ssize_t @JSON_SSIZE@ #endif +#cmakedefine HAVE_SNPRINTF 1 + #ifndef HAVE_SNPRINTF # define snprintf @JSON_SNPRINTF@ #endif + +#cmakedefine HAVE_VSNPRINTF From 7214a222c746f6d2389e9320660b05cb405b9232 Mon Sep 17 00:00:00 2001 From: Joakim Soderberg Date: Wed, 6 Mar 2013 13:13:51 +0100 Subject: [PATCH 08/12] Skip using a debug postfix with visual studio. The output dir is different anyway, and this just makes it more complicated to build projects that link to this, because they need different link rules based on the build type. --- CMakeLists.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e9a3bd8..02073be 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -209,10 +209,6 @@ 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 ${CMAKE_CURRENT_BINARY_DIR}/include/jansson_config.h) From 33b0855b2729c47177504ba698b7aea1012cd672 Mon Sep 17 00:00:00 2001 From: Joakim Soderberg Date: Thu, 7 Mar 2013 16:27:41 +0100 Subject: [PATCH 09/12] Get rid of type warning on MSVC. We should use json_int_t instead of int, since this can be different depending on platform. Also MSVC warns that this can cause "loss of information" since it's converting long long to int. --- test/suites/api/test_number.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/suites/api/test_number.c b/test/suites/api/test_number.c index c256598..e789fe6 100644 --- a/test/suites/api/test_number.c +++ b/test/suites/api/test_number.c @@ -12,7 +12,7 @@ static void run_tests() { json_t *integer, *real; - int i; + json_int_t i; double d; integer = json_integer(5); From 650707fcccdafd4ce09b62c6aab4990b5c8dd710 Mon Sep 17 00:00:00 2001 From: Joakim Soderberg Date: Thu, 7 Mar 2013 18:38:47 +0100 Subject: [PATCH 10/12] Moved *config.h.cmake to the cmake directory. --- CMakeLists.txt | 4 ++-- config.h.cmake => cmake/config.h.cmake | 0 {src => cmake}/jansson_config.h.cmake | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename config.h.cmake => cmake/config.h.cmake (100%) rename {src => cmake}/jansson_config.h.cmake (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 02073be..439df79 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -210,7 +210,7 @@ elseif (HAVE__SNPRINTF) endif () # configure the public config file -configure_file (${CMAKE_CURRENT_SOURCE_DIR}/src/jansson_config.h.cmake +configure_file (${CMAKE_CURRENT_SOURCE_DIR}/cmake/jansson_config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/include/jansson_config.h) # Copy the jansson.h file to the public include folder @@ -219,7 +219,7 @@ file (COPY ${CMAKE_CURRENT_SOURCE_DIR}/src/jansson.h # configure the private config file -configure_file (${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake +configure_file (${CMAKE_CURRENT_SOURCE_DIR}/cmake/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/private_include/config.h) # and tell the source code to include it diff --git a/config.h.cmake b/cmake/config.h.cmake similarity index 100% rename from config.h.cmake rename to cmake/config.h.cmake diff --git a/src/jansson_config.h.cmake b/cmake/jansson_config.h.cmake similarity index 100% rename from src/jansson_config.h.cmake rename to cmake/jansson_config.h.cmake From b1b4f307d5e2ff294ecee2ee0a3f67f0dea28c19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20So=CC=88derberg?= Date: Wed, 13 Mar 2013 00:09:08 +0100 Subject: [PATCH 11/12] Add back the old ENV variabe approach to json_process. Enable using the old envrionment variable passing of settings for json_process so that the current autoconf test suite scripts can run nicely. json_process now takes an optional command line parameter --env which causes it to use the old method of reading the settings from environment variables instead of directly from the "env" file. Also added a --strip command line option, this will be used to run the stripped tests with CMake as well. --- test/bin/json_process.c | 151 +++++++++++++++++++++++++--- test/suites/encoding-flags/run | 2 +- test/suites/invalid-unicode/run | 2 +- test/suites/invalid/run | 2 +- test/suites/valid/complex-array/env | 1 + test/suites/valid/run | 2 +- 6 files changed, 141 insertions(+), 19 deletions(-) create mode 100644 test/suites/valid/complex-array/env diff --git a/test/bin/json_process.c b/test/bin/json_process.c index 72c4833..168d057 100644 --- a/test/bin/json_process.c +++ b/test/bin/json_process.c @@ -36,6 +36,7 @@ struct config { int ensure_ascii; int sort_keys; int strip; + int use_env; } conf; #define l_isspace(c) ((c) == ' ' || (c) == '\n' || (c) == '\r' || (c) == '\t') @@ -145,8 +146,7 @@ static int cmpfile(const char *str, const char *path, const char *fname) return ret; } - -int main(int argc, char *argv[]) +int use_conf(int argc, char **argv, char *test_path) { int ret; size_t flags = 0; @@ -156,22 +156,13 @@ int main(int argc, char *argv[]) json_t *json; json_error_t error; - #ifdef HAVE_SETLOCALE - setlocale(LC_ALL, ""); - #endif - - if (argc != 2) { - fprintf(stderr, "usage: %s test_dir\n", argv[0]); - return 2; - } - - sprintf(filename, "%s%cinput", argv[1], dir_sep); + sprintf(filename, "%s%cinput", test_path, dir_sep); if (!(infile = fopen(filename, "rb"))) { fprintf(stderr, "Could not open \"%s\"\n", filename); return 2; } - sprintf(filename, "%s%cenv", argv[1], dir_sep); + sprintf(filename, "%s%cenv", test_path, dir_sep); conffile = fopen(filename, "rb"); if (conffile) { read_conf(conffile); @@ -214,14 +205,144 @@ int main(int argc, char *argv[]) error.line, error.column, error.position, error.text); - ret = cmpfile(errstr, argv[1], "error"); + ret = cmpfile(errstr, test_path, "error"); return ret; } buffer = json_dumps(json, flags); - ret = cmpfile(buffer, argv[1], "output"); + ret = cmpfile(buffer, test_path, "output"); free(buffer); json_decref(json); return ret; } + +static int getenv_int(const char *name) +{ + char *value, *end; + long result; + + value = getenv(name); + if(!value) + return 0; + + result = strtol(value, &end, 10); + if(*end != '\0') + return 0; + + return (int)result; +} + +int use_env(int argc, char **argv) +{ + int indent; + size_t flags = 0; + json_t *json; + json_error_t error; + + #ifdef _WIN32 + /* On Windows, set stdout and stderr to binary mode to avoid + outputting DOS line terminators */ + _setmode(_fileno(stdout), _O_BINARY); + _setmode(_fileno(stderr), _O_BINARY); + #endif + + indent = getenv_int("JSON_INDENT"); + if(indent < 0 || indent > 255) { + fprintf(stderr, "invalid value for JSON_INDENT: %d\n", indent); + return 2; + } + + if(indent > 0) + flags |= JSON_INDENT(indent); + + if(getenv_int("JSON_COMPACT") > 0) + flags |= JSON_COMPACT; + + if(getenv_int("JSON_ENSURE_ASCII")) + flags |= JSON_ENSURE_ASCII; + + if(getenv_int("JSON_PRESERVE_ORDER")) + flags |= JSON_PRESERVE_ORDER; + + if(getenv_int("JSON_SORT_KEYS")) + flags |= JSON_SORT_KEYS; + + if(getenv_int("STRIP")) { + /* Load to memory, strip leading and trailing whitespace */ + size_t size = 0, used = 0; + char *buffer = NULL; + + while(1) { + int count; + + size = (size == 0 ? 128 : size * 2); + buffer = realloc(buffer, size); + if(!buffer) { + fprintf(stderr, "Unable to allocate %d bytes\n", (int)size); + return 1; + } + + count = fread(buffer + used, 1, size - used, stdin); + if(count < size - used) { + buffer[used + count] = '\0'; + break; + } + used += count; + } + + json = json_loads(strip(buffer), 0, &error); + free(buffer); + } + else + json = json_loadf(stdin, 0, &error); + + if(!json) { + fprintf(stderr, "%d %d %d\n%s\n", + error.line, error.column, + error.position, error.text); + return 1; + } + + json_dumpf(json, stdout, flags); + + return 0; +} + +int main(int argc, char *argv[]) +{ + int i; + char *test_path = NULL; + + #ifdef HAVE_SETLOCALE + setlocale(LC_ALL, ""); + #endif + + if (argc < 2) { + goto usage; + } + + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "--strip")) + conf.strip = 1; + else if (!strcmp(argv[i], "--env")) + conf.use_env = 1; + else + test_path = argv[i]; + } + + if (conf.use_env) + return use_env(argc, argv); + else + { + if (!test_path) + goto usage; + + return use_conf(argc, argv, test_path); + } + +usage: + fprintf(stderr, "argc =%d\n", argc); + fprintf(stderr, "usage: %s [--strip] [--env] test_dir\n", argv[0]); + return 2; +} diff --git a/test/suites/encoding-flags/run b/test/suites/encoding-flags/run index c49d259..6a7d755 100755 --- a/test/suites/encoding-flags/run +++ b/test/suites/encoding-flags/run @@ -14,7 +14,7 @@ run_test() { if [ -f $test_path/env ]; then . $test_path/env fi - $json_process <$test_path/input >$test_log/stdout 2>$test_log/stderr + $json_process --env <$test_path/input >$test_log/stdout 2>$test_log/stderr ) valgrind_check $test_log/stderr || return 1 cmp -s $test_path/output $test_log/stdout diff --git a/test/suites/invalid-unicode/run b/test/suites/invalid-unicode/run index 0565584..fe63262 100755 --- a/test/suites/invalid-unicode/run +++ b/test/suites/invalid-unicode/run @@ -10,7 +10,7 @@ is_test() { } run_test() { - $json_process <$test_path/input >$test_log/stdout 2>$test_log/stderr + $json_process --env <$test_path/input >$test_log/stdout 2>$test_log/stderr valgrind_check $test_log/stderr || return 1 cmp -s $test_path/error $test_log/stderr } diff --git a/test/suites/invalid/run b/test/suites/invalid/run index d15eba3..0ff5381 100755 --- a/test/suites/invalid/run +++ b/test/suites/invalid/run @@ -20,7 +20,7 @@ do_run() { strip=1 fi - STRIP=$strip $json_process \ + STRIP=$strip $json_process --env \ <$test_path/input >$test_log/stdout$s 2>$test_log/stderr$s valgrind_check $test_log/stderr$s || return 1 diff --git a/test/suites/valid/complex-array/env b/test/suites/valid/complex-array/env new file mode 100644 index 0000000..bd89eff --- /dev/null +++ b/test/suites/valid/complex-array/env @@ -0,0 +1 @@ +JSON_SORT_KEYS=1 \ No newline at end of file diff --git a/test/suites/valid/run b/test/suites/valid/run index 170760b..679eb1a 100755 --- a/test/suites/valid/run +++ b/test/suites/valid/run @@ -19,7 +19,7 @@ do_run() { strip=0 [ "$variant" = "strip" ] && strip=1 - STRIP=$strip $json_process \ + STRIP=$strip $json_process --env \ <$test_path/input >$test_log/stdout$s 2>$test_log/stderr$s valgrind_check $test_log/stderr$s || return 1 From 59bc1f42e45aa9bfd255c6002b0659e26c16e23f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20So=CC=88derberg?= Date: Wed, 13 Mar 2013 00:15:37 +0100 Subject: [PATCH 12/12] Got rid of some warnings for unused variables. --- test/bin/json_process.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/bin/json_process.c b/test/bin/json_process.c index 168d057..15eec5a 100644 --- a/test/bin/json_process.c +++ b/test/bin/json_process.c @@ -146,7 +146,7 @@ static int cmpfile(const char *str, const char *path, const char *fname) return ret; } -int use_conf(int argc, char **argv, char *test_path) +int use_conf(char *test_path) { int ret; size_t flags = 0; @@ -233,7 +233,7 @@ static int getenv_int(const char *name) return (int)result; } -int use_env(int argc, char **argv) +int use_env() { int indent; size_t flags = 0; @@ -274,7 +274,7 @@ int use_env(int argc, char **argv) char *buffer = NULL; while(1) { - int count; + size_t count; size = (size == 0 ? 128 : size * 2); buffer = realloc(buffer, size); @@ -330,15 +330,15 @@ int main(int argc, char *argv[]) else test_path = argv[i]; } - + if (conf.use_env) - return use_env(argc, argv); + return use_env(); else { if (!test_path) goto usage; - return use_conf(argc, argv, test_path); + return use_conf(test_path); } usage: