Make the build configuration under Bazel more correct. (#1600)

* Expose JSON_USE_EXCEPTION and JSON_HAS_INT64 as Bazel config flags with defaults that match the existing Bazel build.
Switch //:jsoncpp from using copts ro defines for JSON_USE_EXCEPTION and JSON_HAS_INT64 so that rules that depend on it get the same config.
Make src/test_lib_json/fuzz.cpp respect JSON_USE_EXCEPTION.

* #ifdef stuff that should only be used with JSON_USE_EXCEPTION.

---------

Co-authored-by: Jordan Bayles <[email protected]>
diff --git a/BUILD.bazel b/BUILD.bazel
index 6d7ac3d..2227fee 100644
--- a/BUILD.bazel
+++ b/BUILD.bazel
@@ -1,7 +1,29 @@
 licenses(["unencumbered"])  # Public Domain or MIT
 
+load("@bazel_skylib//rules:common_settings.bzl", "bool_flag")
+
 exports_files(["LICENSE"])
 
+bool_flag(
+    name = "use_exception",
+    build_setting_default = False,
+)
+
+config_setting(
+    name = "use_exception_cfg",
+    flag_values = {":use_exception": "true"},
+)
+
+bool_flag(
+    name = "has_int64",
+    build_setting_default = True,
+)
+
+config_setting(
+    name = "has_int64_cfg",
+    flag_values = {":has_int64": "true"},
+)
+
 cc_library(
     name = "jsoncpp",
     srcs = [
@@ -22,10 +44,13 @@
         "include/json/version.h",
         "include/json/writer.h",
     ],
-    copts = [
-        "-DJSON_USE_EXCEPTION=0",
-        "-DJSON_HAS_INT64",
-    ],
+    defines = select({
+        ":use_exception_cfg": ["JSON_USE_EXCEPTION=1"],
+        "//conditions:default": ["JSON_USE_EXCEPTION=0"],
+    }) + select({
+        ":has_int64_cfg": ["JSON_HAS_INT64"],
+        "//conditions:default": [],
+    }),
     includes = ["include"],
     visibility = ["//visibility:public"],
     deps = [":private"],
diff --git a/MODULE.bazel b/MODULE.bazel
index 03f192d..e60fa06 100644
--- a/MODULE.bazel
+++ b/MODULE.bazel
@@ -12,3 +12,8 @@
     version = "1.9.7",
     compatibility_level = 1,
 )
+
+bazel_dep(
+    name = "bazel_skylib",
+    version = "1.7.1",
+)
diff --git a/src/test_lib_json/fuzz.cpp b/src/test_lib_json/fuzz.cpp
index 5b75c22..3679a95 100644
--- a/src/test_lib_json/fuzz.cpp
+++ b/src/test_lib_json/fuzz.cpp
@@ -11,10 +11,6 @@
 #include <memory>
 #include <string>
 
-namespace Json {
-class Exception;
-}
-
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
   Json::CharReaderBuilder builder;
 
@@ -45,10 +41,14 @@
 
   Json::Value root;
   const auto data_str = reinterpret_cast<const char*>(data);
+#if JSON_USE_EXCEPTION
   try {
+#endif // JSON_USE_EXCEPTION
     reader->parse(data_str, data_str + size, &root, nullptr);
+#if JSON_USE_EXCEPTION
   } catch (Json::Exception const&) {
   }
+#endif // JSON_USE_EXCEPTION
   // Whether it succeeded or not doesn't matter.
   return 0;
 }
diff --git a/src/test_lib_json/jsontest.h b/src/test_lib_json/jsontest.h
index 69e3264..3652c40 100644
--- a/src/test_lib_json/jsontest.h
+++ b/src/test_lib_json/jsontest.h
@@ -228,6 +228,8 @@
                              JsonTest::ToJsonString(actual), __FILE__,         \
                              __LINE__, #expected " == " #actual)
 
+#if JSON_USE_EXCEPTION
+
 /// \brief Asserts that a given expression throws an exception
 #define JSONTEST_ASSERT_THROWS(expr)                                           \
   do {                                                                         \
@@ -242,6 +244,8 @@
                           "expected exception thrown: " #expr);                \
   } while (0)
 
+#endif // JSON_USE_EXCEPTION
+
 /// \brief Begin a fixture test case.
 #define JSONTEST_FIXTURE(FixtureType, name)                                    \
   class Test##FixtureType##name : public FixtureType {                         \
diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp
index 60f149d..e207234 100644
--- a/src/test_lib_json/main.cpp
+++ b/src/test_lib_json/main.cpp
@@ -1888,7 +1888,7 @@
   JSONTEST_ASSERT_THROWS(objVal.asBool());
   JSONTEST_ASSERT_THROWS(arrVal.asBool());
 
-#endif
+#endif // JSON_USE_EXCEPTION
 }
 
 JSONTEST_FIXTURE_LOCAL(ValueTest, offsetAccessors) {
@@ -3323,6 +3323,8 @@
 }
 
 JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithStackLimit) {
+#if JSON_USE_EXCEPTION
+
   Json::CharReaderBuilder b;
   Json::Value root;
   char const doc[] = R"({ "property" : "value" })";
@@ -3342,6 +3344,8 @@
     JSONTEST_ASSERT_THROWS(
         reader->parse(doc, doc + std::strlen(doc), &root, &errs));
   }
+
+#endif // JSON_USE_EXCEPTION
 }
 
 JSONTEST_FIXTURE_LOCAL(CharReaderTest, testOperator) {
@@ -3961,6 +3965,8 @@
 }
 
 JSONTEST_FIXTURE_LOCAL(IteratorTest, constness) {
+#if JSON_USE_EXCEPTION
+
   Json::Value const v;
   JSONTEST_ASSERT_THROWS(
       Json::Value::iterator it(v.begin())); // Compile, but throw.
@@ -3982,6 +3988,8 @@
   }
   Json::String expected = R"(" 9","10","11",)";
   JSONTEST_ASSERT_STRING_EQUAL(expected, out.str());
+
+#endif // JSON_USE_EXCEPTION
 }
 
 struct RValueTest : JsonTest::TestCase {};