From f32703a7a1990b6b7c97d14a8ef6818badd2d835 Mon Sep 17 00:00:00 2001 From: Zach Hindes Date: Wed, 29 Aug 2018 16:13:59 -0500 Subject: [PATCH 1/4] Support default __stdcall calling convention (/Gz) on Windows --- cJSON.c | 12 +++---- cJSON.h | 98 +++++++++++++++++++++++++++++++-------------------------- test.c | 2 +- 3 files changed, 60 insertions(+), 52 deletions(-) diff --git a/cJSON.c b/cJSON.c index cbdec41..5c4cf66 100644 --- a/cJSON.c +++ b/cJSON.c @@ -119,22 +119,22 @@ static int case_insensitive_strcmp(const unsigned char *string1, const unsigned typedef struct internal_hooks { - void *(*allocate)(size_t size); - void (*deallocate)(void *pointer); - void *(*reallocate)(void *pointer, size_t size); + void *(CJSON_CDECL *allocate)(size_t size); + void (CJSON_CDECL *deallocate)(void *pointer); + void *(CJSON_CDECL *reallocate)(void *pointer, size_t size); } internal_hooks; #if defined(_MSC_VER) /* work around MSVC error C2322: '...' address of dillimport '...' is not static */ -static void *internal_malloc(size_t size) +static void * CJSON_CDECL internal_malloc(size_t size) { return malloc(size); } -static void internal_free(void *pointer) +static void CJSON_CDECL internal_free(void *pointer) { free(pointer); } -static void *internal_realloc(void *pointer, size_t size) +static void * CJSON_CDECL internal_realloc(void *pointer, size_t size) { return realloc(pointer, size); } diff --git a/cJSON.h b/cJSON.h index 6e0bde9..18210c8 100644 --- a/cJSON.h +++ b/cJSON.h @@ -28,6 +28,56 @@ extern "C" { #endif +#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) +#define __WINDOWS__ +#endif + +#ifdef __WINDOWS__ + +/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options: + +CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols +CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default) +CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol + +For *nix builds that support visibility attribute, you can define similar behavior by + +setting default visibility to hidden by adding +-fvisibility=hidden (for gcc) +or +-xldscope=hidden (for sun cc) +to CFLAGS + +then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does + +*/ + +#define CJSON_CDECL __cdecl +#define CJSON_STDCALL __stdcall + +/* export symbols by default, this is necessary for copy pasting the C and header file */ +#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS) +#define CJSON_EXPORT_SYMBOLS +#endif + +#if defined(CJSON_HIDE_SYMBOLS) +#define CJSON_PUBLIC(type) type CJSON_STDCALL +#elif defined(CJSON_EXPORT_SYMBOLS) +#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL +#elif defined(CJSON_IMPORT_SYMBOLS) +#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL +#endif +#else /* !__WINDOWS__ */ +#define CJSON_CDECL +#define CJSON_STDCALL + +#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY) +#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type +#else +#define CJSON_PUBLIC(type) type +#endif +#endif + /* project version */ #define CJSON_VERSION_MAJOR 1 #define CJSON_VERSION_MINOR 7 @@ -74,55 +124,13 @@ typedef struct cJSON typedef struct cJSON_Hooks { - void *(*malloc_fn)(size_t sz); - void (*free_fn)(void *ptr); + /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */ + void *(CJSON_CDECL *malloc_fn)(size_t sz); + void (CJSON_CDECL *free_fn)(void *ptr); } cJSON_Hooks; typedef int cJSON_bool; -#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) -#define __WINDOWS__ -#endif -#ifdef __WINDOWS__ - -/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 2 define options: - -CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols -CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default) -CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol - -For *nix builds that support visibility attribute, you can define similar behavior by - -setting default visibility to hidden by adding --fvisibility=hidden (for gcc) -or --xldscope=hidden (for sun cc) -to CFLAGS - -then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does - -*/ - -/* export symbols by default, this is necessary for copy pasting the C and header file */ -#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS) -#define CJSON_EXPORT_SYMBOLS -#endif - -#if defined(CJSON_HIDE_SYMBOLS) -#define CJSON_PUBLIC(type) type __stdcall -#elif defined(CJSON_EXPORT_SYMBOLS) -#define CJSON_PUBLIC(type) __declspec(dllexport) type __stdcall -#elif defined(CJSON_IMPORT_SYMBOLS) -#define CJSON_PUBLIC(type) __declspec(dllimport) type __stdcall -#endif -#else /* !WIN32 */ -#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY) -#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type -#else -#define CJSON_PUBLIC(type) type -#endif -#endif - /* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them. * This is to prevent stack overflows. */ #ifndef CJSON_NESTING_LIMIT diff --git a/test.c b/test.c index 66154e0..986fc6e 100644 --- a/test.c +++ b/test.c @@ -256,7 +256,7 @@ static void create_objects(void) cJSON_Delete(root); } -int main(void) +int CJSON_CDECL main(void) { /* print the version */ printf("Version: %s\n", cJSON_Version()); From ad2cb5b7eabd0e4803bdb9402258f0f75c7bd507 Mon Sep 17 00:00:00 2001 From: Zach Hindes Date: Tue, 4 Sep 2018 14:25:15 -0500 Subject: [PATCH 2/4] Enable build and test on Windows --- .gitattributes | 2 ++ CMakeLists.txt | 2 ++ tests/CMakeLists.txt | 5 ++++- tests/cjson_add.c | 8 +++++++- tests/unity_setup.c | 3 +++ 5 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 .gitattributes create mode 100644 tests/unity_setup.c diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..6e5ee10 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +* text=auto +/tests/inputs/* text eol=lf \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index b347ac9..c9d2db9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,6 +54,8 @@ if (ENABLE_CUSTOM_COMPILER_FLAGS) /Za /sdl /W4 + /wd4001 + /D_CRT_SECURE_NO_WARNINGS ) endif() endif() diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 7967292..6f1688d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,5 +1,5 @@ if(ENABLE_CJSON_TEST) - add_library(unity "${CJSON_LIBRARY_TYPE}" unity/src/unity.c) + add_library(unity STATIC unity/src/unity.c) # Disable -Werror for Unity if (FLAG_SUPPORTED_Werror) @@ -72,6 +72,9 @@ if(ENABLE_CJSON_TEST) foreach(unity_test ${unity_tests}) add_executable("${unity_test}" "${unity_test}.c") + if("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC") + target_sources(${unity_test} PRIVATE unity_setup.c) + endif() target_link_libraries("${unity_test}" "${CJSON_LIB}" unity) if(MEMORYCHECK_COMMAND) add_test(NAME "${unity_test}" diff --git a/tests/cjson_add.c b/tests/cjson_add.c index 01668a9..eb9def2 100644 --- a/tests/cjson_add.c +++ b/tests/cjson_add.c @@ -34,9 +34,15 @@ static void *failing_malloc(size_t size) return NULL; } +/* work around MSVC error C2322: '...' address of dillimport '...' is not static */ +static void CJSON_CDECL normal_free(void *pointer) +{ + free(pointer); +} + static cJSON_Hooks failing_hooks = { failing_malloc, - free + normal_free }; static void cjson_add_null_should_add_null(void) diff --git a/tests/unity_setup.c b/tests/unity_setup.c new file mode 100644 index 0000000..99b6897 --- /dev/null +++ b/tests/unity_setup.c @@ -0,0 +1,3 @@ +// msvc doesn't support weak-linking, so we need to define these functions. +void setUp(void) { } +void tearDown(void) { } \ No newline at end of file From f25b8448e47360a807b4b5fae3a84092c84f1468 Mon Sep 17 00:00:00 2001 From: Zach Hindes Date: Wed, 12 Sep 2018 15:32:30 -0500 Subject: [PATCH 3/4] Support default __stdcall calling convention on tests as well --- CMakeLists.txt | 2 ++ tests/cjson_add.c | 4 ++-- tests/compare_tests.c | 2 +- tests/misc_tests.c | 4 ++-- tests/parse_array.c | 2 +- tests/parse_examples.c | 2 +- tests/parse_hex4.c | 2 +- tests/parse_number.c | 2 +- tests/parse_object.c | 2 +- tests/parse_string.c | 2 +- tests/parse_value.c | 2 +- tests/parse_with_opts.c | 2 +- tests/print_array.c | 2 +- tests/print_number.c | 2 +- tests/print_object.c | 2 +- tests/print_string.c | 2 +- tests/print_value.c | 2 +- tests/readme_examples.c | 2 +- 18 files changed, 21 insertions(+), 19 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c9d2db9..00bf771 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,8 @@ if (ENABLE_CUSTOM_COMPILER_FLAGS) -Wswitch-enum ) elseif("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC") + # Disable warning c4001 - nonstandard extension 'single line comment' was used + # Define _CRT_SECURE_NO_WARNINGS to disable deprecation warnings for "insecure" C library functions list(APPEND custom_compiler_flags /GS /Za diff --git a/tests/cjson_add.c b/tests/cjson_add.c index eb9def2..00ffc34 100644 --- a/tests/cjson_add.c +++ b/tests/cjson_add.c @@ -28,7 +28,7 @@ #include "unity/src/unity.h" #include "common.h" -static void *failing_malloc(size_t size) +static void * CJSON_CDECL failing_malloc(size_t size) { (void)size; return NULL; @@ -378,7 +378,7 @@ static void cjson_add_array_should_fail_on_allocation_failure(void) cJSON_Delete(root); } -int main(void) +int CJSON_CDECL main(void) { UNITY_BEGIN(); diff --git a/tests/compare_tests.c b/tests/compare_tests.c index 63b6d4a..307d0e8 100644 --- a/tests/compare_tests.c +++ b/tests/compare_tests.c @@ -186,7 +186,7 @@ static void cjson_compare_should_compare_objects(void) false)) } -int main(void) +int CJSON_CDECL main(void) { UNITY_BEGIN(); diff --git a/tests/misc_tests.c b/tests/misc_tests.c index a0b4f7e..f42772a 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -410,7 +410,7 @@ static void cjson_functions_shouldnt_crash_with_null_pointers(void) cJSON_Delete(item); } -static void *failing_realloc(void *pointer, size_t size) +static void * CJSON_CDECL failing_realloc(void *pointer, size_t size) { (void)size; (void)pointer; @@ -527,7 +527,7 @@ static void cjson_add_item_to_object_should_not_use_after_free_when_string_is_al cJSON_Delete(object); } -int main(void) +int CJSON_CDECL main(void) { UNITY_BEGIN(); diff --git a/tests/parse_array.c b/tests/parse_array.c index 69e0f41..dfaae29 100644 --- a/tests/parse_array.c +++ b/tests/parse_array.c @@ -152,7 +152,7 @@ static void parse_array_should_not_parse_non_arrays(void) assert_not_array("\"[]hello world!\n\""); } -int main(void) +int CJSON_CDECL main(void) { /* initialize cJSON item */ memset(item, 0, sizeof(cJSON)); diff --git a/tests/parse_examples.c b/tests/parse_examples.c index 76215bb..3aab77f 100644 --- a/tests/parse_examples.c +++ b/tests/parse_examples.c @@ -195,7 +195,7 @@ static void test12_should_not_be_parsed(void) } } -int main(void) +int CJSON_CDECL main(void) { UNITY_BEGIN(); RUN_TEST(file_test1_should_be_parsed_and_printed); diff --git a/tests/parse_hex4.c b/tests/parse_hex4.c index 7115cba..83cbe65 100644 --- a/tests/parse_hex4.c +++ b/tests/parse_hex4.c @@ -64,7 +64,7 @@ static void parse_hex4_should_parse_mixed_case(void) TEST_ASSERT_EQUAL_INT(0xBEEF, parse_hex4((const unsigned char*)"BEEF")); } -int main(void) +int CJSON_CDECL main(void) { UNITY_BEGIN(); RUN_TEST(parse_hex4_should_parse_all_combinations); diff --git a/tests/parse_number.c b/tests/parse_number.c index f499ab6..4cb72ec 100644 --- a/tests/parse_number.c +++ b/tests/parse_number.c @@ -96,7 +96,7 @@ static void parse_number_should_parse_negative_reals(void) assert_parse_number("-123e-128", 0, -123e-128); } -int main(void) +int CJSON_CDECL main(void) { /* initialize cJSON item */ memset(item, 0, sizeof(cJSON)); diff --git a/tests/parse_object.c b/tests/parse_object.c index 0985845..5f8e7cf 100644 --- a/tests/parse_object.c +++ b/tests/parse_object.c @@ -162,7 +162,7 @@ static void parse_object_should_not_parse_non_objects(void) assert_not_object("\"{}hello world!\n\""); } -int main(void) +int CJSON_CDECL main(void) { /* initialize cJSON item */ memset(item, 0, sizeof(cJSON)); diff --git a/tests/parse_string.c b/tests/parse_string.c index ceb1a89..ce1c138 100644 --- a/tests/parse_string.c +++ b/tests/parse_string.c @@ -119,7 +119,7 @@ static void parse_string_should_parse_bug_94(void) reset(item); } -int main(void) +int CJSON_CDECL main(void) { /* initialize cJSON item and error pointer */ memset(item, 0, sizeof(cJSON)); diff --git a/tests/parse_value.c b/tests/parse_value.c index 08ec3e7..6b6b095 100644 --- a/tests/parse_value.c +++ b/tests/parse_value.c @@ -96,7 +96,7 @@ static void parse_value_should_parse_object(void) reset(item); } -int main(void) +int CJSON_CDECL main(void) { /* initialize cJSON item */ memset(item, 0, sizeof(cJSON)); diff --git a/tests/parse_with_opts.c b/tests/parse_with_opts.c index 84b69cf..e390b92 100644 --- a/tests/parse_with_opts.c +++ b/tests/parse_with_opts.c @@ -97,7 +97,7 @@ static void parse_with_opts_should_parse_utf8_bom(void) cJSON_Delete(without_bom); } -int main(void) +int CJSON_CDECL main(void) { UNITY_BEGIN(); diff --git a/tests/print_array.c b/tests/print_array.c index 4bee17f..7d40f2e 100644 --- a/tests/print_array.c +++ b/tests/print_array.c @@ -87,7 +87,7 @@ static void print_array_should_print_arrays_with_multiple_elements(void) assert_print_array("[1, null, true, false, [], \"hello\", {\n\t}]", "[1,null,true,false,[],\"hello\",{}]"); } -int main(void) +int CJSON_CDECL main(void) { /* initialize cJSON item */ UNITY_BEGIN(); diff --git a/tests/print_number.c b/tests/print_number.c index 5ebb348..f2385f3 100644 --- a/tests/print_number.c +++ b/tests/print_number.c @@ -89,7 +89,7 @@ static void print_number_should_print_non_number(void) /* assert_print_number("null", -INFTY); */ } -int main(void) +int CJSON_CDECL main(void) { /* initialize cJSON item */ UNITY_BEGIN(); diff --git a/tests/print_object.c b/tests/print_object.c index 70bbb43..3ed0bfe 100644 --- a/tests/print_object.c +++ b/tests/print_object.c @@ -88,7 +88,7 @@ static void print_object_should_print_objects_with_multiple_elements(void) assert_print_object("{\n\t\"one\":\t1,\n\t\"NULL\":\tnull,\n\t\"TRUE\":\ttrue,\n\t\"FALSE\":\tfalse,\n\t\"array\":\t[],\n\t\"world\":\t\"hello\",\n\t\"object\":\t{\n\t}\n}", "{\"one\":1,\"NULL\":null,\"TRUE\":true,\"FALSE\":false,\"array\":[],\"world\":\"hello\",\"object\":{}}"); } -int main(void) +int CJSON_CDECL main(void) { /* initialize cJSON item */ UNITY_BEGIN(); diff --git a/tests/print_string.c b/tests/print_string.c index 83de1e7..e6f5b92 100644 --- a/tests/print_string.c +++ b/tests/print_string.c @@ -65,7 +65,7 @@ static void print_string_should_print_utf8(void) assert_print_string("\"ü猫慕\"", "ü猫慕"); } -int main(void) +int CJSON_CDECL main(void) { /* initialize cJSON item */ UNITY_BEGIN(); diff --git a/tests/print_value.c b/tests/print_value.c index d590823..b54db5b 100644 --- a/tests/print_value.c +++ b/tests/print_value.c @@ -90,7 +90,7 @@ static void print_value_should_print_object(void) assert_print_value("{}"); } -int main(void) +int CJSON_CDECL main(void) { /* initialize cJSON item */ UNITY_BEGIN(); diff --git a/tests/readme_examples.c b/tests/readme_examples.c index f3fa443..1ab1b13 100644 --- a/tests/readme_examples.c +++ b/tests/readme_examples.c @@ -246,7 +246,7 @@ static void supports_full_hd_should_check_for_full_hd_support(void) TEST_ASSERT_FALSE(supports_full_hd(monitor_without_hd)); } -int main(void) +int CJSON_CDECL main(void) { UNITY_BEGIN(); From d9fe34bade211088b0c8f5db4e4ac9d09cc12a92 Mon Sep 17 00:00:00 2001 From: Zach Hindes Date: Mon, 17 Sep 2018 09:10:20 -0500 Subject: [PATCH 4/4] Add newline to end of unity_setup.c --- tests/unity_setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unity_setup.c b/tests/unity_setup.c index 99b6897..1d828b0 100644 --- a/tests/unity_setup.c +++ b/tests/unity_setup.c @@ -1,3 +1,3 @@ // msvc doesn't support weak-linking, so we need to define these functions. void setUp(void) { } -void tearDown(void) { } \ No newline at end of file +void tearDown(void) { }