diff --git a/CMakeLists.txt b/CMakeLists.txt index b4d97943fb..72fec4e545 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -308,7 +308,16 @@ if(BUILD_ENTERPRISE) endif() if(LITECORE_BUILD_SHARED) - add_library(LiteCore SHARED $) + if(MSVC) + add_library(LiteCore SHARED $ MSVC/dllmain.c) + target_include_directories( + LiteCore PRIVATE + C/include + ) + else() + add_library(LiteCore SHARED $) + endif() + target_include_directories( LiteCore INTERFACE C/include diff --git a/MSVC/dllmain.c b/MSVC/dllmain.c new file mode 100644 index 0000000000..37720a13dd --- /dev/null +++ b/MSVC/dllmain.c @@ -0,0 +1,98 @@ +#pragma comment(lib, "Version.lib") + +#include +#include +#include +#include "c4Log.h" + +typedef struct { + WORD major; + WORD minor; + WORD build; + WORD revision; +} Version; + +static int GetDllVersion(const wchar_t* path, Version* out_version) { + DWORD dummy; + DWORD size = GetFileVersionInfoSizeW(path, &dummy); + if ( size == 0 ) { return 0; } + + BYTE* buffer = (BYTE*)malloc(size); + if ( !buffer ) { return 0; } + if ( !GetFileVersionInfoW(path, 0, size, buffer) ) { + c4log(kC4DefaultLog, kC4LogVerbose, "GetFileVersionInfoW failed: %lu", GetLastError()); + free(buffer); + return 0; + } + + VS_FIXEDFILEINFO* fileInfo; + UINT len = 0; + if ( !VerQueryValueA(buffer, "\\", (LPVOID*)&fileInfo, &len) ) { + c4log(kC4DefaultLog, kC4LogVerbose, "VerQueryValueA failed: %lu", GetLastError()); + free(buffer); + return 0; + } + + if ( fileInfo ) { + out_version->major = HIWORD(fileInfo->dwFileVersionMS); + out_version->minor = LOWORD(fileInfo->dwFileVersionMS); + out_version->build = HIWORD(fileInfo->dwFileVersionLS); + out_version->revision = LOWORD(fileInfo->dwFileVersionLS); + free(buffer); + return 1; + } + + c4log(kC4DefaultLog, kC4LogVerbose, "VerQueryValueA returned NULL"); + free(buffer); + return 0; +} + +static int CompareVersions(const Version* a, const Version* b) { + if ( a->major != b->major ) return a->major < b->major ? -1 : 1; + if ( a->minor != b->minor ) return a->minor < b->minor ? -1 : 1; + if ( a->build != b->build ) return a->build < b->build ? -1 : 1; + if ( a->revision != b->revision ) return a->revision < b->revision ? -1 : 1; + return 0; +} + +void CheckCppRuntime() { + HMODULE hMod = GetModuleHandleA("msvcp140.dll"); + if ( !hMod ) { hMod = LoadLibraryA("msvcp140d.dll"); } + + if ( !hMod ) { + c4log(kC4DefaultLog, kC4LogWarning, "msvcp140.dll not loaded yet, unable to check version..."); + return; + } + + wchar_t path[MAX_PATH]; + if ( GetModuleFileNameW(hMod, path, MAX_PATH) == 0 ) { + c4log(kC4DefaultLog, kC4LogWarning, "Unable to determine msvcp140.dll filename to check version..."); + return; + } + + Version loaded = {0}; + if ( !GetDllVersion(path, &loaded) ) { + c4log(kC4DefaultLog, kC4LogWarning, "Unable to get version of msvcp140.dll to check..."); + return; + } + + Version expected = {14, 36, 32457, 0}; + int cmp = CompareVersions(&loaded, &expected); + if ( cmp < 0 ) { + c4log(kC4DefaultLog, kC4LogWarning, "msvcp140.dll version is older than expected: %u.%u.%u.%u < %u.%u.%u.%u", + loaded.major, loaded.minor, loaded.revision, loaded.build, expected.major, expected.minor, + expected.revision, expected.build); + c4log(kC4DefaultLog, kC4LogWarning, "This may cause instability in your application"); + } +} + +BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { + switch ( ul_reason_for_call ) { + case DLL_PROCESS_ATTACH: + CheckCppRuntime(); + break; + default: + break; + } + return TRUE; +} \ No newline at end of file diff --git a/cmake/platform_win.cmake b/cmake/platform_win.cmake index 3a024bd436..b55284fceb 100644 --- a/cmake/platform_win.cmake +++ b/cmake/platform_win.cmake @@ -26,8 +26,10 @@ function(set_litecore_source) endfunction() function(setup_globals) - set(CMAKE_C_FLAGS_MINSIZEREL "/MD /O1 /Ob1 /DNDEBUG /Zi /GL" CACHE INTERNAL "") - set(CMAKE_CXX_FLAGS_MINSIZEREL "/MD /O1 /Ob1 /DNDEBUG /Zi /GL" CACHE INTERNAL "") + add_compile_options(/MP) + add_link_options(/CGTHREADS:8) + set(CMAKE_C_FLAGS_MINSIZEREL "/MD /O1 /Ob1 /DNDEBUG /Zi /GL /MP" CACHE INTERNAL "") + set(CMAKE_CXX_FLAGS_MINSIZEREL "/MD /O1 /Ob1 /DNDEBUG /Zi /GL /MP" CACHE INTERNAL "") set(CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL "/INCREMENTAL:NO /LTCG:incremental /debug" CACHE INTERNAL "") set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "/INCREMENTAL:NO /LTCG:incremental /debug" CACHE INTERNAL "") set(CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL "/LTCG:incremental" CACHE INTERNAL "") diff --git a/jenkins/build_server_win.ps1 b/jenkins/build_server_win.ps1 index 6b769181fd..c4b70f82aa 100644 --- a/jenkins/build_server_win.ps1 +++ b/jenkins/build_server_win.ps1 @@ -84,7 +84,10 @@ function Build() { $build_enterprise = "OFF" } + # This -T version controls which version of the MSVC toolchain is used. + # Once it is decided for a given minor release line, it should not be changed. & "C:\Program Files\CMake\bin\cmake.exe" ` + -T version=14.36.17.6 ` -A $MsArch ` -DBUILD_ENTERPRISE=$build_enterprise ` -DCMAKE_INSTALL_PREFIX="$(Get-Location)\install" ` diff --git a/jenkins/jenkins_win.ps1 b/jenkins/jenkins_win.ps1 index c416a0d1c3..32004bdcb8 100644 --- a/jenkins/jenkins_win.ps1 +++ b/jenkins/jenkins_win.ps1 @@ -21,13 +21,16 @@ try { New-Item -Type Directory -ErrorAction Ignore couchbase-lite-core\build_cmake\x64 Set-Location couchbase-lite-core\build_cmake\x64 - & 'C:\Program Files\CMake\bin\cmake.exe' -A x64 -DCMAKE_SYSTEM_VERSION="10.0" -DBUILD_ENTERPRISE=ON ..\.. + + # This -T version controls which version of the MSVC toolchain is used. + # Once it is decided for a given minor release line, it should not be changed. + & 'C:\Program Files\CMake\bin\cmake.exe' -T version=14.36.17.6 -DCMAKE_SYSTEM_VERSION="10.0" -DBUILD_ENTERPRISE=ON ..\.. if($LASTEXITCODE -ne 0) { Write-Host "Failed to run CMake!" -ForegroundColor Red exit 1 } - & 'C:\Program Files\CMake\bin\cmake.exe' --build . --parallel 8 + & 'C:\Program Files\CMake\bin\cmake.exe' --build . --parallel $env:NUMBER_OF_PROCESSORS if($LASTEXITCODE -ne 0) { Write-Host "Failed to build!" -ForegroundColor Red exit 1