Win32 C++ builds of Avro-C ***************************** April 2, 2012 These instructions describe some of the changes required to allow Avro-C to compile under the Microsoft Visual C++ 2008 compiler, as well as some limitations of the Windows build. Status of the Windows Build: **************************** The Windows build of Avro-C compiles under Microsoft Visual C++ 2008. You can use C-Make to create the solution file (AvroC.sln) for the build. The solution file contains projects for the build as well as projects for the tests. All the tests are run and pass when the project RUN_TESTS is built from within MS Visual C++ 2008. Limitations of Windows Build: ****************************** 1. The Windows build of Avro-C is compiled using Microsoft's C++ compiler and not Microsoft's C compiler. This is done using the /TP flag in the MSVC++ compiler. This flag is automatically set using CMakeLists.txt The reason to compile Win32 under C++ instead of C is that there are lots of places where variables are declared after statements, the Microsoft C compiler does not support declarations after statements. It is possible, that if all the declarations after statements were removed, that Avro-C would compile under Microsoft's C compiler also. I have not tried this. 2. The shared library, i.e. DLL, for avro has not been built. There are instructions on how to build DLLs using CMake at http://www.cmake.org/Wiki/BuildingWinDLL 3. Currently avropipe.c and avromod.c do not compile under Windows. In order for them to compile we would have to either port getopt() to Windows, or remove their dependency on getopt(). 4. Windows cannot run version.sh to generate the version number. Currently, LIBAVRO_VERSION is hard coded to "22:0:0" for the Windows build, in the top level CMakeLists.txt. 5. Found two bugs related to improper return values under error conditions in Avro. These bugs were marked with #warnings in the code. Instructions for Maintenance ***************************** 1. Instructions to check name mangling in Visual C++: In a DOS prompt go to "C:\Program Files(x86)\Microsoft Visual Studio 9.0\VC\" Run the program vcvarsall.bat . This will set up environment variables. Now go to the avro_c\build_win32\src\Debug\ directory. Run the command dumpbin /ALL avro.lib > tmp.txt View tmp.txt in your favorite editor. This will allow you to see which names are mangled and which names are not mangled. Every header file should start with #ifndef HEADER_FILE_NAME_H #define HEADER_FILE_NAME_H #ifdef __cplusplus extern "C" { #define CLOSE_EXTERN } #else #define CLOSE_EXTERN #endif and end with CLOSE_EXTERN #endif /* HEADER_FILE_NAME_H */ This will ensure that all exported (public) functions are mangled using C name mangling instead of C++ name mangling. 2. All file I/O operations should have "b" for binary in the fopen statements. Otherwise Windows will replace LF with CRLF in binary data. 3. Windows does not allow writing to a file with exclusive access using the mode "wbx". Use the non-exclusive mode "wb" instead. 4. If the hashtable from st.c is used, the functions in the struct st_hash_type should be cast to HASH_FUNCTION_CAST. 5. Do not use "%zu" to print size_t. Use '"%" PRIsz' without the single quotes, instead. 6. MS Visual C++ 2008 does not properly expand variadic preprocessor macros by default. It is possible to "trick" MSVC++ to properly expand variadic preprocessor macros by using an extra (dummy) preprocessor macro, whose only purpose is to properly expand its input. This method is described here: http://stackoverflow.com/questions/2575864/the-problem-about-different-treatment-to-va-args-when-using-vs-2008-and-gcc See the solution described by monkeyman. This method is used in the macro expand_args(...) in test_avro_values.c. 7. Web site describing how to debug macro expansion in Visual C++: http://fneep.fiffa.net/?p=66 8. Sometimes it is necessary to declare a struct at the top of a file and define it at the bottom of a file. An example is AVRO_DATUM_VALUE_CLASS in src/datum_value.c. A C++ compiler will complain that the struct is defined twice. To avoid this, declare the struct with the modifier "extern" at the top of the file, and then define it at the bottom of the file. Note that it cannot be defined as "static" because Win32 does not like an extern struct mapping to a static struct. 9. Use __FUNCTION__ instead of __func__ for generating the function name. 10. All variables need to be explicitly cast when calling functions with differing function signatures 11. All pointers need to be explicitly cast when assigning to other pointers of a different type. 12. Do not perform pointer arithmetic on void * pointers. Cast the pointers to char * before performing pointer arithmetic. 13. The executable names of any examples and tests need to be set explicitly to include the "Debug/" directory in the path, and the ".exe" ending. See the CMakeLists.txt in the examples and the tests directory to see how this is done. 14. Do not include the headers inttypes.h or unistd.h or stdint.h. Instead include avro/platform.h in your C files. 15. Do not include dirent.h in your tests. When _WIN32 is defined include msdirent.h. See example in test_avro_schema.c. 16. If _WIN32 is defined, define snprintf() to_snprintf(), which MS Visual C++ recognizes. 17. MSVC++ does not recognize strtoll(). Define it to _strtoi64() instead. 18. Old-style C function declarations are not allowed in C++. See the changes in st.c and st.h -- which were converted to new-style function declarations. 19. Structures cannot be initialized using the .element notation for Win32. For example if we have a struct test_t: typedef struct { int a; int b; } test_t; Then we can initialize the struct using the syntax: test_t t1 = { 0, 0 }; But we cannot use the syntax: test_t t2 = { .a = 0, . b = 0 }; because Win32 does not support it.