From 13ee2306c34ae25a6376fc5de0811e39225306f5 Mon Sep 17 00:00:00 2001 From: MeyerFabian Date: Mon, 20 Jul 2020 17:04:11 +0200 Subject: [PATCH 1/3] build/clang-cl-windows --- CMakeLists.txt | 6 +++- code/AssetLib/M3D/m3d.h | 4 +-- code/AssetLib/Step/STEPFile.h | 8 ++--- code/CMakeLists.txt | 1 - .../gtest/include/gtest/internal/gtest-port.h | 14 +++++++++ contrib/gtest/src/gtest-port.cc | 3 +- .../rapidjson/include/rapidjson/document.h | 2 +- .../rapidjson/include/rapidjson/encodings.h | 4 +-- .../include/rapidjson/internal/meta.h | 4 +-- contrib/rapidjson/include/rapidjson/reader.h | 4 +-- contrib/rapidjson/include/rapidjson/writer.h | 6 ++-- contrib/unzip/ioapi.c | 15 +++++----- contrib/unzip/ioapi.h | 2 +- contrib/unzip/unzip.c | 1 - contrib/zip/src/miniz.h | 6 ++-- include/assimp/Compiler/poppack1.h | 2 +- include/assimp/Compiler/pushpack1.h | 2 +- test/unit/UnitTestFileGenerator.h | 30 +++++++++---------- test/unit/utColladaImportExport.cpp | 1 - 19 files changed, 65 insertions(+), 50 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 23725381d..ecf1de619 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -257,7 +257,11 @@ IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT CMAKE_COMPILER_IS_MINGW) SET(LIBSTDC++_LIBRARIES -lstdc++) ELSEIF(MSVC) # enable multi-core compilation with MSVC - ADD_COMPILE_OPTIONS(/MP /bigobj /W4 /WX ) + IF( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" ) # clang-cl + ADD_COMPILE_OPTIONS(/bigobj /W4 /WX ) + ELSE() # msvc + ADD_COMPILE_OPTIONS(/MP /bigobj /W4 /WX) + ENDIF() # disable "elements of array '' will be default initialized" warning on MSVC2013 IF(MSVC12) ADD_COMPILE_OPTIONS(/wd4351) diff --git a/code/AssetLib/M3D/m3d.h b/code/AssetLib/M3D/m3d.h index 5ab3d16de..e0d456c3c 100644 --- a/code/AssetLib/M3D/m3d.h +++ b/code/AssetLib/M3D/m3d.h @@ -84,7 +84,7 @@ typedef uint16_t M3D_INDEX; #ifndef M3D_BONEMAXLEVEL #define M3D_BONEMAXLEVEL 8 #endif -#ifndef _MSC_VER +#if !defined(_MSC_VER) || defined(__clang__) #ifndef _inline #define _inline __inline__ #endif @@ -101,7 +101,7 @@ typedef uint16_t M3D_INDEX; #define _register #endif -#if _MSC_VER > 1920 +#if _MSC_VER > 1920 && !defined(__clang__) # pragma warning(push) # pragma warning(disable : 4100 4127 4189 4505 4244 4403 4701 4703) # if (_MSC_VER > 1800 ) diff --git a/code/AssetLib/Step/STEPFile.h b/code/AssetLib/Step/STEPFile.h index 72648e462..1ef5d65c4 100644 --- a/code/AssetLib/Step/STEPFile.h +++ b/code/AssetLib/Step/STEPFile.h @@ -130,8 +130,8 @@ namespace STEP { * coupled with a line number. */ // ------------------------------------------------------------------------------- struct SyntaxError : DeadlyImportError { - enum { - LINE_NOT_SPECIFIED = 0xffffffffffffffffLL + enum : uint64_t { + LINE_NOT_SPECIFIED = 0xfffffffffffffffLL }; SyntaxError(const std::string &s, uint64_t line = LINE_NOT_SPECIFIED); @@ -143,8 +143,8 @@ struct SyntaxError : DeadlyImportError { * It is typically coupled with both an entity id and a line number.*/ // ------------------------------------------------------------------------------- struct TypeError : DeadlyImportError { - enum { - ENTITY_NOT_SPECIFIED = 0xffffffffffffffffLL, + enum : uint64_t { + ENTITY_NOT_SPECIFIED = 0xffffffffffffffffUL, ENTITY_NOT_SPECIFIED_32 = 0x00000000ffffffff }; diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index bb43449e1..2ba893281 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -45,7 +45,6 @@ # cmake_minimum_required( VERSION 3.0 ) SET( HEADER_PATH ../include/assimp ) - if(NOT ANDROID AND ASSIMP_ANDROID_JNIIOSYSTEM) message(WARNING "Requesting Android JNI I/O-System in non-Android toolchain. Resetting ASSIMP_ANDROID_JNIIOSYSTEM to OFF.") set(ASSIMP_ANDROID_JNIIOSYSTEM OFF) diff --git a/contrib/gtest/include/gtest/internal/gtest-port.h b/contrib/gtest/include/gtest/internal/gtest-port.h index 0094ed507..f66d9cd32 100644 --- a/contrib/gtest/include/gtest/internal/gtest-port.h +++ b/contrib/gtest/include/gtest/internal/gtest-port.h @@ -312,10 +312,22 @@ __pragma(warning(disable: warnings)) # define GTEST_DISABLE_MSC_WARNINGS_POP_() \ __pragma(warning(pop)) +# if defined(__clang__) +# define GTEST_DISABLE_CLANG_DEPRECATED_WARNINGS_PUSH_() \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") +# define GTEST_DISABLE_CLANG_WARNINGS_POP_() \ + _Pragma("clang diagnostic pop") +# else +# define GTEST_DISABLE_CLANG_DEPRECATED_WARNINGS_PUSH_() +# define GTEST_DISABLE_CLANG_WARNINGS_POP_() +# endif #else // Older versions of MSVC don't have __pragma. # define GTEST_DISABLE_MSC_WARNINGS_PUSH_(warnings) # define GTEST_DISABLE_MSC_WARNINGS_POP_() +# define GTEST_DISABLE_CLANG_DEPRECATED_WARNINGS_PUSH_() +# define GTEST_DISABLE_CLANG_WARNINGS_POP_() #endif #ifndef GTEST_LANG_CXX11 @@ -2352,6 +2364,7 @@ inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); } // Functions deprecated by MSVC 8.0. GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996 /* deprecated function */) +GTEST_DISABLE_CLANG_DEPRECATED_WARNINGS_PUSH_() inline const char* StrNCpy(char* dest, const char* src, size_t n) { return strncpy(dest, src, n); @@ -2399,6 +2412,7 @@ inline const char* GetEnv(const char* name) { #endif } +GTEST_DISABLE_CLANG_WARNINGS_POP_() GTEST_DISABLE_MSC_WARNINGS_POP_() #if GTEST_OS_WINDOWS_MOBILE diff --git a/contrib/gtest/src/gtest-port.cc b/contrib/gtest/src/gtest-port.cc index e5bf3dd2b..e04aa9a57 100644 --- a/contrib/gtest/src/gtest-port.cc +++ b/contrib/gtest/src/gtest-port.cc @@ -926,7 +926,7 @@ GTestLog::~GTestLog() { // Disable Microsoft deprecation warnings for POSIX functions called from // this class (creat, dup, dup2, and close) GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996) - +GTEST_DISABLE_CLANG_DEPRECATED_WARNINGS_PUSH_() #if GTEST_HAS_STREAM_REDIRECTION // Object that captures an output stream (stdout/stderr). @@ -1010,6 +1010,7 @@ class CapturedStream { }; GTEST_DISABLE_MSC_WARNINGS_POP_() +GTEST_DISABLE_CLANG_WARNINGS_POP_() static CapturedStream* g_captured_stderr = NULL; static CapturedStream* g_captured_stdout = NULL; diff --git a/contrib/rapidjson/include/rapidjson/document.h b/contrib/rapidjson/include/rapidjson/document.h index 473d846e3..17df30725 100644 --- a/contrib/rapidjson/include/rapidjson/document.h +++ b/contrib/rapidjson/include/rapidjson/document.h @@ -31,7 +31,7 @@ #include RAPIDJSON_DIAG_PUSH -#ifdef _MSC_VER +#if defined(_MSC_VER) && !(__clang__) RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible loss of data #endif diff --git a/contrib/rapidjson/include/rapidjson/encodings.h b/contrib/rapidjson/include/rapidjson/encodings.h index 0df1c3435..de4d9d216 100644 --- a/contrib/rapidjson/include/rapidjson/encodings.h +++ b/contrib/rapidjson/include/rapidjson/encodings.h @@ -17,7 +17,7 @@ #include "rapidjson.h" -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__clang__) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data RAPIDJSON_DIAG_OFF(4702) // unreachable code @@ -709,7 +709,7 @@ struct Transcoder { RAPIDJSON_NAMESPACE_END -#if defined(__GNUC__) || defined(_MSC_VER) +#if defined(__GNUC__) || (defined(_MSC_VER) && !defined(__clang__)) RAPIDJSON_DIAG_POP #endif diff --git a/contrib/rapidjson/include/rapidjson/internal/meta.h b/contrib/rapidjson/include/rapidjson/internal/meta.h index 5a9aaa428..bcbfc7709 100644 --- a/contrib/rapidjson/include/rapidjson/internal/meta.h +++ b/contrib/rapidjson/include/rapidjson/internal/meta.h @@ -21,7 +21,7 @@ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #endif -#if defined(_MSC_VER) +#if defined(_MSC_VER) && !defined(__clang__) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(6334) #endif @@ -174,7 +174,7 @@ template struct RemoveSfinaeTag { typedef T Type; RAPIDJSON_NAMESPACE_END //@endcond -#if defined(__GNUC__) || defined(_MSC_VER) +#if defined(__GNUC__) || (defined(_MSC_VER) && !defined(__clang__)) RAPIDJSON_DIAG_POP #endif diff --git a/contrib/rapidjson/include/rapidjson/reader.h b/contrib/rapidjson/include/rapidjson/reader.h index 120c31115..4b172e953 100644 --- a/contrib/rapidjson/include/rapidjson/reader.h +++ b/contrib/rapidjson/include/rapidjson/reader.h @@ -37,7 +37,7 @@ #include #endif -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__clang__) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant RAPIDJSON_DIAG_OFF(4702) // unreachable code @@ -2214,7 +2214,7 @@ RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_POP #endif -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__clang__) RAPIDJSON_DIAG_POP #endif diff --git a/contrib/rapidjson/include/rapidjson/writer.h b/contrib/rapidjson/include/rapidjson/writer.h index e610ebb60..53d1a5d7f 100644 --- a/contrib/rapidjson/include/rapidjson/writer.h +++ b/contrib/rapidjson/include/rapidjson/writer.h @@ -36,7 +36,7 @@ #include #endif -#ifdef _MSC_VER +#if defined (_MSC_VER) && !defined(__clang__) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant #endif @@ -700,11 +700,11 @@ inline bool Writer::ScanWriteUnescapedString(StringStream& is, siz RAPIDJSON_NAMESPACE_END -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__clang__) RAPIDJSON_DIAG_POP #endif -#ifdef __clang__ +#if defined(__clang__) RAPIDJSON_DIAG_POP #endif diff --git a/contrib/unzip/ioapi.c b/contrib/unzip/ioapi.c index e1ef46088..0f1bf4f21 100644 --- a/contrib/unzip/ioapi.c +++ b/contrib/unzip/ioapi.c @@ -1,11 +1,3 @@ -/* ioapi.c -- IO base function header for compress/uncompress .zip - files using zlib + zip or unzip API - - Version 1.01e, February 12th, 2005 - - Copyright (C) 1998-2005 Gilles Vollant -*/ - #include #include #include @@ -16,6 +8,10 @@ #ifdef _WIN32 # pragma warning(push) # pragma warning(disable : 4131 4100) +# ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wunused-parameter" +# endif #endif // _WIN32 /* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ @@ -181,4 +177,7 @@ void fill_fopen_filefunc (pzlib_filefunc_def) #ifdef _WIN32 # pragma warning(pop) +# ifdef __clang__ +# pragma clang diagnostic pop +# endif #endif // _WIN32 diff --git a/contrib/unzip/ioapi.h b/contrib/unzip/ioapi.h index 7d457baab..63ec641bf 100644 --- a/contrib/unzip/ioapi.h +++ b/contrib/unzip/ioapi.h @@ -24,7 +24,7 @@ #ifndef ZCALLBACK -#if (defined(WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) +#if (defined(_WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) #define ZCALLBACK CALLBACK #else #define ZCALLBACK diff --git a/contrib/unzip/unzip.c b/contrib/unzip/unzip.c index 3937f821e..7bac01df0 100644 --- a/contrib/unzip/unzip.c +++ b/contrib/unzip/unzip.c @@ -1554,7 +1554,6 @@ extern int ZEXPORT unzGetGlobalComment (file, szComment, uSizeBuf) char *szComment; uLong uSizeBuf; { - int err=UNZ_OK; unz_s* s; uLong uReadThis ; if (file==NULL) diff --git a/contrib/zip/src/miniz.h b/contrib/zip/src/miniz.h index 07f7b2de2..7570ae929 100644 --- a/contrib/zip/src/miniz.h +++ b/contrib/zip/src/miniz.h @@ -5361,7 +5361,7 @@ mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, } else { // Temporarily allocate a read buffer. read_buf_size = MZ_MIN(file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__clang__) if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) #else @@ -5454,7 +5454,7 @@ void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size; -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__clang__) if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) #else if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) @@ -5560,7 +5560,7 @@ mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) { // The file is stored or the caller has requested the compressed data. if (pZip->m_pState->m_pMem) { -#ifdef _MSC_VER +#if defined (_MSC_VER) && !defined(__clang__) if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > 0xFFFFFFFF)) #else diff --git a/include/assimp/Compiler/poppack1.h b/include/assimp/Compiler/poppack1.h index e033bc147..a8e9a3c7e 100644 --- a/include/assimp/Compiler/poppack1.h +++ b/include/assimp/Compiler/poppack1.h @@ -14,7 +14,7 @@ #endif // reset packing to the original value -#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__) +#if (defined(_MSC_VER) && !defined(__clang__)) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__) # pragma pack( pop ) #endif #undef PACK_STRUCT diff --git a/include/assimp/Compiler/pushpack1.h b/include/assimp/Compiler/pushpack1.h index 4c9fbb857..2a5e2dfe6 100644 --- a/include/assimp/Compiler/pushpack1.h +++ b/include/assimp/Compiler/pushpack1.h @@ -22,7 +22,7 @@ # error poppack1.h must be included after pushpack1.h #endif -#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__) +#if (defined(_MSC_VER) && !defined(__clang__)) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__) # pragma pack(push,1) # define PACK_STRUCT #elif defined( __GNUC__ ) || defined(__clang__) diff --git a/test/unit/UnitTestFileGenerator.h b/test/unit/UnitTestFileGenerator.h index 91d69357f..2166c6939 100644 --- a/test/unit/UnitTestFileGenerator.h +++ b/test/unit/UnitTestFileGenerator.h @@ -44,21 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -#if defined(__GNUC__) || defined(__clang__) -#define TMP_PATH "/tmp/" -inline FILE* MakeTmpFile(char* tmplate) -{ - auto fd = mkstemp(tmplate); - EXPECT_NE(-1, fd); - if(fd == -1) - { - return nullptr; - } - auto fs = fdopen(fd, "w+"); - EXPECT_NE(nullptr, fs); - return fs; -} -#elif defined(_MSC_VER) +#if defined(_MSC_VER) #include #define TMP_PATH "./" inline FILE* MakeTmpFile(char* tmplate) @@ -73,4 +59,18 @@ inline FILE* MakeTmpFile(char* tmplate) EXPECT_NE(fs, nullptr); return fs; } +#elif defined(__GNUC__) || defined(__clang__) +#define TMP_PATH "/tmp/" +inline FILE* MakeTmpFile(char* tmplate) +{ + auto fd = mkstemp(tmplate); + EXPECT_NE(-1, fd); + if(fd == -1) + { + return nullptr; + } + auto fs = fdopen(fd, "w+"); + EXPECT_NE(nullptr, fs); + return fs; +} #endif diff --git a/test/unit/utColladaImportExport.cpp b/test/unit/utColladaImportExport.cpp index 451c8e235..100ca548a 100644 --- a/test/unit/utColladaImportExport.cpp +++ b/test/unit/utColladaImportExport.cpp @@ -157,7 +157,6 @@ public: static inline void CheckNodeIdNames(IdNameMap &nodeIdMap, IdNameMap &nodeNameMap, const aiNode *parent, size_t index) { IdNameString namePair = GetItemIdName(parent, index); - const auto result = nodeNameMap.insert(namePair); IdNameString idPair = GetColladaIdName(parent, index); ReportDuplicate(nodeIdMap, idPair, typeid(aiNode).name()); From a19e4e41129589c2ca1e09a476ae57874462d685 Mon Sep 17 00:00:00 2001 From: MeyerFabian Date: Mon, 20 Jul 2020 18:28:50 +0200 Subject: [PATCH 2/3] Make clang with msvc abi work. --- code/AssetLib/Blender/BlenderTessellator.cpp | 8 +++++++- code/CMakeLists.txt | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/code/AssetLib/Blender/BlenderTessellator.cpp b/code/AssetLib/Blender/BlenderTessellator.cpp index 3c1cd6ea8..3366d56c5 100644 --- a/code/AssetLib/Blender/BlenderTessellator.cpp +++ b/code/AssetLib/Blender/BlenderTessellator.cpp @@ -386,7 +386,14 @@ void BlenderTessellatorP2T::ReferencePoints( std::vector< Blender::PointP2T >& p // ------------------------------------------------------------------------------------------------ inline PointP2T& BlenderTessellatorP2T::GetActualPointStructure( p2t::Point& point ) const { +#if defined __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Winvalid-offsetof" +#endif // __clang__ unsigned int pointOffset = offsetof( PointP2T, point2D ); +#if defined __clang__ +# pragma clang diagnostic pop +#endif PointP2T& pointStruct = *reinterpret_cast< PointP2T* >( reinterpret_cast< char* >( &point ) - pointOffset ); if ( pointStruct.magic != static_cast( BLEND_TESS_MAGIC ) ) { @@ -394,7 +401,6 @@ inline PointP2T& BlenderTessellatorP2T::GetActualPointStructure( p2t::Point& poi } return pointStruct; } - // ------------------------------------------------------------------------------------------------ void BlenderTessellatorP2T::MakeFacesFromTriangles( std::vector< p2t::Triangle* >& triangles ) const { diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 2ba893281..23cfba4ff 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -1065,7 +1065,7 @@ endif() ADD_DEFINITIONS( -DASSIMP_BUILD_DLL_EXPORT ) -if ( MSVC ) +IF( MSVC OR "${CMAKE_CXX_SIMULATE_ID}" MATCHES "MSVC") # clang with MSVC ABI ADD_DEFINITIONS( -D_SCL_SECURE_NO_WARNINGS ) ADD_DEFINITIONS( -D_CRT_SECURE_NO_WARNINGS ) endif () From 51e592123add5da3359f37465b3e28b73852e678 Mon Sep 17 00:00:00 2001 From: MeyerFabian Date: Mon, 20 Jul 2020 18:42:57 +0200 Subject: [PATCH 3/3] Fix two deletions. --- code/CMakeLists.txt | 1 + contrib/unzip/ioapi.c | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 23cfba4ff..7ccc6439f 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -45,6 +45,7 @@ # cmake_minimum_required( VERSION 3.0 ) SET( HEADER_PATH ../include/assimp ) + if(NOT ANDROID AND ASSIMP_ANDROID_JNIIOSYSTEM) message(WARNING "Requesting Android JNI I/O-System in non-Android toolchain. Resetting ASSIMP_ANDROID_JNIIOSYSTEM to OFF.") set(ASSIMP_ANDROID_JNIIOSYSTEM OFF) diff --git a/contrib/unzip/ioapi.c b/contrib/unzip/ioapi.c index 0f1bf4f21..5e0497f9e 100644 --- a/contrib/unzip/ioapi.c +++ b/contrib/unzip/ioapi.c @@ -1,3 +1,11 @@ +/* ioapi.c -- IO base function header for compress/uncompress .zip + files using zlib + zip or unzip API + + Version 1.01e, February 12th, 2005 + + Copyright (C) 1998-2005 Gilles Vollant +*/ + #include #include #include