JSON-C implements a reference counting object model that allows you to easily
construct JSON objects in C, output them as JSON formatted strings and parse
JSON formatted strings back into the C representation of JSON objects.
It aims to conform to RFC 8259.
Skip down to Using json-c
or check out the API docs,
if you already have json-c installed and ready to use.
If you believe you’ve discovered a bug, report it at
(https://github.com/json-c/json-c/issues). Please be sure to include
the version of json-c you’re using, the OS you’re running on, and any
other relevant details. Fully reproducible test cases and/or patches
to fix problems are greatly appreciated.
Fixes for bugs, or small new features can be directly submitted as a
pull request. For major new
features or large changes of any kind, please first start a discussion
on the forums.
Building on Unix with git, gcc and cmake
If you already have json-c installed, see Linking to libjson-c
for how to build and link your program against it.
$ git clone https://github.com/json-c/json-c.git
$ mkdir json-c-build
$ cd json-c-build
$ cmake ../json-c # See CMake section below for custom arguments
Note: it’s also possible to put your build directory inside the json-c
source directory, or even not use a separate build directory at all, but
certain things might not work quite right (notably, make distcheck)
Then:
$ make
$ make test
$ make USE_VALGRIND=0 test # optionally skip using valgrind
$ sudo make install # it could be necessary to execute make install
Generating documentation with Doxygen:
The library documentation can be generated directly from the source code using Doxygen tool:
# in build directory
make doc
google-chrome doc/html/index.html
CMake Options
The json-c library is built with CMake,
which can take a few options.
Variable
Type
Description
CMAKE_INSTALL_PREFIX
String
The install location.
CMAKE_BUILD_TYPE
String
Defaults to “debug”.
BUILD_SHARED_LIBS
Bool
The default build generates a dynamic (dll/so) library. Set this to OFF to create a static library only.
BUILD_STATIC_LIBS
Bool
The default build generates a static (lib/a) library. Set this to OFF to create a shared library only.
DISABLE_STATIC_FPIC
Bool
The default builds position independent code. Set this to OFF to create a shared library only.
DISABLE_BSYMBOLIC
Bool
Disable use of -Bsymbolic-functions.
DISABLE_THREAD_LOCAL_STORAGE
Bool
Disable use of Thread-Local Storage (HAVE___THREAD).
DISABLE_WERROR
Bool
Disable use of -Werror.
DISABLE_EXTRA_LIBS
Bool
Disable use of extra libraries, libbsd
DISABLE_JSON_POINTER
Bool
Omit json_pointer support from the build.
ENABLE_RDRAND
Bool
Enable RDRAND Hardware RNG Hash Seed.
ENABLE_THREADING
Bool
Enable partial threading support.
OVERRIDE_GET_RANDOM_SEED
String
A block of code to use instead of the default implementation of json_c_get_random_seed(), e.g. on embedded platforms where not even the fallback to time() works. Must be a single line.
Pass these options as -D on CMake’s command-line.
# build a static library only
cmake -DBUILD_SHARED_LIBS=OFF ..
Building with partial threading support
Although json-c does not support fully multi-threaded access to
object trees, it has some code to help make its use in threaded programs
a bit safer. Currently, this is limited to using atomic operations for
json_object_get() and json_object_put().
Since this may have a performance impact, of at least 3x slower
according to https://stackoverflow.com/a/11609063, it is disabled by
default. You may turn it on by adjusting your cmake command with:
-DENABLE_THREADING=ON
Separately, the default hash function used for object field keys,
lh_char_hash, uses a compare-and-swap operation to ensure the random
seed is only generated once. Because this is a one-time operation, it
is always compiled in when the compare-and-swap operation is available.
cmake-configure wrapper script
For those familiar with the old autoconf/autogen.sh/configure method,
there is a cmake-configure wrapper script to ease the transition to cmake.
mkdir build
cd build
../cmake-configure --prefix=/some/install/path
make
By default, if valgrind is available running tests uses it.
That can slow the tests down considerably, so to disable it use:
export USE_VALGRIND=0
To run tests a separate build directory is recommended:
mkdir build-test
cd build-test
# VALGRIND=1 causes -DVALGRIND=1 to be passed when compiling code
# which uses slightly slower, but valgrind-safe code.
VALGRIND=1 cmake ..
make
make test
# By default, if valgrind is available running tests uses it.
make USE_VALGRIND=0 test # optionally skip using valgrind
If a test fails, check Testing/Temporary/LastTest.log,
tests/testSubDir/${testname}/${testname}.vg.out, and other similar files.
If there is insufficient output try:
VERBOSE=1 CTEST_OUTPUT_ON_FAILURE=1 make test
or
JSONC_TEST_TRACE=1 make test
and check the log files again.
Building on Unix and Windows with vcpkg
You can download and install JSON-C using the vcpkg dependency manager:
The JSON-C port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please create an issue or pull request on the vcpkg repository.
Building for Commodore Amiga is supported for both Motorola 68k (AmigaOS 3) and PowerPC (AmigaOS 4) architectures. MorphOS on compatible PowerPC hardware is also supported. You can set up a cross compiler locally, however it is much easier to use the already preconfigured Amiga development environment within a Docker container.
Included below are instructions for building for specific individual systems, as well as how to build for all Amiga variants.
Install Docker on your machine if you don’t already have it. You can download Docker Desktop for Windows/macOS/Linux here.
To build for Motorola 68k Amiga:
mkdir build
docker run --rm \
-v ${PWD}:/work \
-e USER=$( id -u ) -e GROUP=$( id -g ) \
-it sacredbanana/amiga-compiler:m68k-amigaos bash
cd build
cmake -DM68K_CRT=newlib ..
make
libjson-c.a will get created in the build directory.
You can change newlib to nix20, nix13, ixemul or clib2 if you would like to build the library suited for libnix or clib2 instead. Newlib is default.
By default the m68k build uses -fbaserel. You can select a different base-relative mode with -DM68K_BASEREL=:
You can also set the target CPU with -DM68K_CPU=. This is passed to the compiler as -m<cpu> (for example 68020 becomes -m68020). If omitted, the compiler default is used.
A note on base-relative addressing (-fbaserel, i.e. M68K_BASEREL=baserel)
on m68k: a base-relative library keeps its globals at an offset from a4, and
a4 is established once by the program’s startup code. Such a library is only
safe inside a program that is itself base-relative and that declares every
function the OS can call back into (BOOPSI/MUI dispatchers, struct Hook
entries, interrupt servers) with __saveds, so a4 is re-established on entry.
Without that, a hook entered from the OS runs with a foreign a4 and every
a4-relative access made by this library – or by libnix’s malloc – reads
from a wrong address.
Conversely, a library built without-fbaserel and compiled at -O1 or above
may allocate a4 as a scratch register. That is harmless in a program that is
also non-base-relative, but it corrupts the base pointer of a base-relative one.
In short: match M68K_BASEREL to the consuming program, and if that program is
base-relative make sure its OS callbacks are __saveds.
To build for PowerPC Amiga:
mkdir build
docker run --rm \
-v ${PWD}:/work \
-e USER=$( id -u ) -e GROUP=$( id -g ) \
-it sacredbanana/amiga-compiler:ppc-amigaos bash
cd build
cmake ..
make
libjson-c.a will get created in the build directory.
Select the C runtime with -DPPC_CRT=: newlib (default), clib2 or clib4.
Anything other than newlib is passed to the compiler as -mcrt=<value>.
cmake -DPPC_CRT=clib4 ..
To build for PowerPC MorphOS:
mkdir build
docker run --rm \
-v ${PWD}:/work \
-e USER=$( id -u ) -e GROUP=$( id -g ) \
-it sacredbanana/amiga-compiler:ppc-morphos bash
cd build
cmake -DNOIXEMUL=1 ..
make
If you are making an application that absolutely requires ixemul, then remove the -DNOIXEMUL=1.
libjson-c.a will get created in the build directory.
Two further options apply to MorphOS:
-DMORPHOS_CLIB= selects default (ixemul) or libnix (passed as
-mclib=libnix). That is the same multilib -noixemul selects, and is the
self-contained ABI – an ixemul build needs ixemul.library on the target.
Two scripts in the amiga/ directory build the whole matrix across all three
systems, so you do not have to drive the container by hand.
amiga/build-amiga-sdk.sh [OS ...] — builds every variant and installs
libjson-c.a plus the json-c/ headers into an SDK tree. The location comes
from $AMIGA_SDK (default /opt/amiga); either a <target>/ or an
AmigaSDK-gcc-style amigaos3/sdk/<target>/ layout is accepted, and an OS
whose subdirectory is absent is skipped rather than failing.
amiga/package-amiga.sh [OS ...] — builds the same matrix into a staging tree and
produces dist/json-c.lha for distribution.
Both default to AmigaOS3 AmigaOS4 MorphOS, and both take the variant list
from the same table in amiga/build-amiga-sdk.sh, so they cannot disagree. 22
libraries are built in total: 15 for AmigaOS 3 (newlib, libnix and clib2, each
across the five multilib slots), 3 for AmigaOS 4 (newlib, clib2, clib4) and 4
for MorphOS (ixemul and native, each with and without -mbaserel32).
Which of them actually link is a separate question from whether they build,
and was checked by compiling a program against each one:
target
links
AmigaOS 3, libnix
all 5 slots
AmigaOS 3, clib2
lib/libm020/ and lib/libb32/libm020/ only
AmigaOS 3, newlib
none – the m68k newlib tree has no gettimeofday()
AmigaOS 4
all 3 (newlib, clib2, clib4)
MorphOS
all 4 slots
The clib2 failures are inside clib2 itself: its 68000 multilib provides no
strtoll/strtoull, and 16-bit -fbaserel overflows with truncated to fit:
DREL16 once json-c’s data is added – -fbaserel32 has no 64 KB limit. Link
with -ljson-c -lm after your own objects, and add -lunix for clib2.
The archive is a single json-c/ directory at the root, with the readme and
one directory per system, each following the compiler’s own layout so it can
be copied straight over an SDK:
json-c/json-c.readme
json-c/AmigaOS3/{include,lib,...}/ plus libnix/ and clib2/ subtrees
json-c/AmigaOS4/{include,lib,lib/clib2,lib/clib4}/
json-c/MorphOS/{include,lib,lib/libb32,lib/libnix}/
Note that m68k and PPC lay their C runtimes out differently, and the variant
table follows each. On m68k a runtime is a separate tree (libnix/, clib2/),
each with its own include/ and lib/. On PPC a runtime is a multilib slot
beneath a single shared lib/: -mcrt=clib4 searches <target>/lib/clib4/
and takes headers from <target>/include/. This was read off
-print-search-dirs rather than assumed, because installing to the wrong one
produces a library the compiler silently never finds.
Linking to libjson-c
If your system has pkgconfig,
then you can just add this to your makefile:
The primary type in json-c is json_object. It describes a reference counted
tree of json objects which are created by either parsing text with a
json_tokener (i.e. json_tokener_parse_ex()), or by creating
(with json_object_new_object(), json_object_new_int(), etc…) and adding
(with json_object_object_add(), json_object_array_add(), etc…) them
individually.
Typically, every object in the tree will have one reference, from its parent.
When you are done with the tree of objects, you call json_object_put() on just
the root object to free it, which recurses down through any child objects
calling json_object_put() on each one of those in turn.
You can get a reference to a single child
(json_object_object_get() or json_object_array_get_idx())
and use that object as long as its parent is valid. If you need a child object to live longer than its parent, you can
increment the child’s refcount (json_object_get()) to allow it to survive
the parent being freed or it being removed from its parent
(json_object_object_del() or json_object_array_del_idx())
When parsing text, the json_tokener object is independent from the json_object
that it returns. It can be allocated (json_tokener_new())
used one or multiple times (json_tokener_parse_ex(), and
freed (json_tokener_free()) while the json_object objects live on.
A json_object tree can be serialized back into a string with
json_object_to_json_string_ext(). The string that is returned
is only valid until the next “to_json_string” call on that same object.
Also, it is freed when the json_object is freed.
\mainpage
json-c
vcpkgJSON-C - A JSON implementation in C
JSON-C implements a reference counting object model that allows you to easily construct JSON objects in C, output them as JSON formatted strings and parse JSON formatted strings back into the C representation of JSON objects. It aims to conform to RFC 8259.
Skip down to Using json-c or check out the API docs, if you already have json-c installed and ready to use.
Home page for json-c: https://github.com/json-c/json-c/wiki
Getting Help
If you have questions about using json-c, please start a thread on our forums at: https://groups.google.com/forum/#!forum/json-c
If you believe you’ve discovered a bug, report it at (https://github.com/json-c/json-c/issues). Please be sure to include the version of json-c you’re using, the OS you’re running on, and any other relevant details. Fully reproducible test cases and/or patches to fix problems are greatly appreciated.
Fixes for bugs, or small new features can be directly submitted as a pull request. For major new features or large changes of any kind, please first start a discussion on the forums.
Building on Unix with
git,gccandcmakeIf you already have json-c installed, see Linking to
libjson-cfor how to build and link your program against it.Build Status
Test Status
Prerequisites:
gcc,clang, or another C compilercmake>=2.8,>=3.16recommended,cmake=>3.1for testsTo generate docs you’ll also need:
doxygen>=1.8.13If you are on a relatively modern system, you’ll likely be able to install the prerequisites using your OS’s packaging system.
Install using apt (e.g. Ubuntu 16.04.2 LTS)
Build instructions:
json-cGitHub repo: https://github.com/json-c/json-cNote: it’s also possible to put your build directory inside the json-c source directory, or even not use a separate build directory at all, but certain things might not work quite right (notably,
make distcheck)Then:
Generating documentation with Doxygen:
The library documentation can be generated directly from the source code using Doxygen tool:
CMake Options
The json-c library is built with CMake, which can take a few options.
Pass these options as
-Don CMake’s command-line.Building with partial threading support
Although json-c does not support fully multi-threaded access to object trees, it has some code to help make its use in threaded programs a bit safer. Currently, this is limited to using atomic operations for json_object_get() and json_object_put().
Since this may have a performance impact, of at least 3x slower according to https://stackoverflow.com/a/11609063, it is disabled by default. You may turn it on by adjusting your cmake command with: -DENABLE_THREADING=ON
Separately, the default hash function used for object field keys, lh_char_hash, uses a compare-and-swap operation to ensure the random seed is only generated once. Because this is a one-time operation, it is always compiled in when the compare-and-swap operation is available.
cmake-configure wrapper script
For those familiar with the old autoconf/autogen.sh/configure method, there is a
cmake-configurewrapper script to ease the transition to cmake.cmake-configure can take a few options.
Testing:
By default, if valgrind is available running tests uses it. That can slow the tests down considerably, so to disable it use:
To run tests a separate build directory is recommended:
If a test fails, check
Testing/Temporary/LastTest.log,tests/testSubDir/${testname}/${testname}.vg.out, and other similar files. If there is insufficient output try:or
and check the log files again.
Building on Unix and Windows with
vcpkgYou can download and install JSON-C using the vcpkg dependency manager:
The JSON-C port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please create an issue or pull request on the vcpkg repository.
Building for Android
Building on Android is now particularly well supported, but there have been some reports of success using https://developer.android.com/ndk/guides/cmake
Building for Commodore Amiga or MorphOS
Building for Commodore Amiga is supported for both Motorola 68k (AmigaOS 3) and PowerPC (AmigaOS 4) architectures. MorphOS on compatible PowerPC hardware is also supported. You can set up a cross compiler locally, however it is much easier to use the already preconfigured Amiga development environment within a Docker container.
Included below are instructions for building for specific individual systems, as well as how to build for all Amiga variants.
Install Docker on your machine if you don’t already have it. You can download Docker Desktop for Windows/macOS/Linux here.
To build for Motorola 68k Amiga:
libjson-c.a will get created in the build directory.
You can change newlib to nix20, nix13, ixemul or clib2 if you would like to build the library suited for libnix or clib2 instead. Newlib is default.
By default the m68k build uses
-fbaserel. You can select a different base-relative mode with-DM68K_BASEREL=:baserel(default) —-fbaserelbaserel32—-fbaserel32off— no base-relative flagYou can also set the target CPU with
-DM68K_CPU=. This is passed to the compiler as-m<cpu>(for example68020becomes-m68020). If omitted, the compiler default is used.A note on base-relative addressing (
-fbaserel, i.e.M68K_BASEREL=baserel) on m68k: a base-relative library keeps its globals at an offset froma4, anda4is established once by the program’s startup code. Such a library is only safe inside a program that is itself base-relative and that declares every function the OS can call back into (BOOPSI/MUI dispatchers,struct Hookentries, interrupt servers) with__saveds, soa4is re-established on entry. Without that, a hook entered from the OS runs with a foreigna4and everya4-relative access made by this library – or by libnix’smalloc– reads from a wrong address.Conversely, a library built without
-fbasereland compiled at-O1or above may allocatea4as a scratch register. That is harmless in a program that is also non-base-relative, but it corrupts the base pointer of a base-relative one.In short: match
M68K_BASERELto the consuming program, and if that program is base-relative make sure its OS callbacks are__saveds.To build for PowerPC Amiga:
libjson-c.a will get created in the build directory.
Select the C runtime with
-DPPC_CRT=:newlib(default),clib2orclib4. Anything other thannewlibis passed to the compiler as-mcrt=<value>.To build for PowerPC MorphOS:
If you are making an application that absolutely requires ixemul, then remove the
-DNOIXEMUL=1.libjson-c.a will get created in the build directory.
Two further options apply to MorphOS:
-DMORPHOS_CLIB=selectsdefault(ixemul) orlibnix(passed as-mclib=libnix). That is the same multilib-noixemulselects, and is the self-contained ABI – an ixemul build needsixemul.libraryon the target.-DMORPHOS_BASEREL32=ONadds-mbaserel32.Building and packaging every variant
Two scripts in the
amiga/directory build the whole matrix across all three systems, so you do not have to drive the container by hand.amiga/build-amiga-sdk.sh [OS ...]— builds every variant and installslibjson-c.aplus thejson-c/headers into an SDK tree. The location comes from$AMIGA_SDK(default/opt/amiga); either a<target>/or an AmigaSDK-gcc-styleamigaos3/sdk/<target>/layout is accepted, and an OS whose subdirectory is absent is skipped rather than failing.amiga/package-amiga.sh [OS ...]— builds the same matrix into a staging tree and producesdist/json-c.lhafor distribution.Both default to
AmigaOS3 AmigaOS4 MorphOS, and both take the variant list from the same table inamiga/build-amiga-sdk.sh, so they cannot disagree. 22 libraries are built in total: 15 for AmigaOS 3 (newlib, libnix and clib2, each across the five multilib slots), 3 for AmigaOS 4 (newlib, clib2, clib4) and 4 for MorphOS (ixemul and native, each with and without-mbaserel32).Which of them actually link is a separate question from whether they build, and was checked by compiling a program against each one:
lib/libm020/andlib/libb32/libm020/onlygettimeofday()The clib2 failures are inside clib2 itself: its 68000 multilib provides no
strtoll/strtoull, and 16-bit-fbasereloverflows with truncated to fit: DREL16 once json-c’s data is added –-fbaserel32has no 64 KB limit. Link with-ljson-c -lmafter your own objects, and add-lunixfor clib2.The archive is a single
json-c/directory at the root, with the readme and one directory per system, each following the compiler’s own layout so it can be copied straight over an SDK:Note that m68k and PPC lay their C runtimes out differently, and the variant table follows each. On m68k a runtime is a separate tree (
libnix/,clib2/), each with its owninclude/andlib/. On PPC a runtime is a multilib slot beneath a single sharedlib/:-mcrt=clib4searches<target>/lib/clib4/and takes headers from<target>/include/. This was read off-print-search-dirsrather than assumed, because installing to the wrong one produces a library the compiler silently never finds.Linking to
libjson-cIf your system has
pkgconfig, then you can just add this to yourmakefile:Without
pkgconfig, you might do something like this:If your project uses cmake:
Using json-c
To use json-c you can either include json.h, or preferably, one of the following more specific header files:
json_object_object_foreach()in json_object.h)For a full list of headers see files.html
The primary type in json-c is json_object. It describes a reference counted tree of json objects which are created by either parsing text with a json_tokener (i.e.
json_tokener_parse_ex()), or by creating (withjson_object_new_object(),json_object_new_int(), etc…) and adding (withjson_object_object_add(),json_object_array_add(), etc…) them individually. Typically, every object in the tree will have one reference, from its parent. When you are done with the tree of objects, you call json_object_put() on just the root object to free it, which recurses down through any child objects calling json_object_put() on each one of those in turn.You can get a reference to a single child (
json_object_object_get()orjson_object_array_get_idx()) and use that object as long as its parent is valid.If you need a child object to live longer than its parent, you can increment the child’s refcount (
json_object_get()) to allow it to survive the parent being freed or it being removed from its parent (json_object_object_del()orjson_object_array_del_idx())When parsing text, the json_tokener object is independent from the json_object that it returns. It can be allocated (
json_tokener_new()) used one or multiple times (json_tokener_parse_ex(), and freed (json_tokener_free()) while the json_object objects live on.A json_object tree can be serialized back into a string with
json_object_to_json_string_ext(). The string that is returned is only valid until the next “to_json_string” call on that same object. Also, it is freed when the json_object is freed.