Skip to content

Commit 2a62b36

Browse files
committed
Pin MSVC toolchain and add automatic min version check
This will run immediately on a process loading LiteCore into its process space.
1 parent 641301c commit 2a62b36

File tree

4 files changed

+114
-2
lines changed

4 files changed

+114
-2
lines changed

CMakeLists.txt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,15 @@ target_include_directories(
262262
${LiteCoreObjectsIncludes}
263263
)
264264

265-
add_library(LiteCore SHARED $<TARGET_OBJECTS:LiteCoreObjects>)
265+
if(MSVC)
266+
add_library(LiteCore SHARED $<TARGET_OBJECTS:LiteCoreObjects> MSVC/dllmain.c)
267+
target_include_directories(
268+
LiteCore PRIVATE
269+
C/include
270+
)
271+
else()
272+
add_library(LiteCore SHARED $<TARGET_OBJECTS:LiteCoreObjects>)
273+
endif()
266274

267275
add_library(LiteCoreStatic STATIC EXCLUDE_FROM_ALL $<TARGET_OBJECTS:LiteCoreObjects>)
268276
target_link_libraries(LiteCoreStatic PRIVATE LiteCoreObjects)

MSVC/dllmain.c

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
#pragma comment(lib, "Version.lib")
2+
3+
#include <Windows.h>
4+
#include <stdio.h>
5+
#include <stdlib.h>
6+
#include "c4Log.h"
7+
8+
typedef struct {
9+
WORD major;
10+
WORD minor;
11+
WORD build;
12+
WORD revision;
13+
} Version;
14+
15+
static int GetDllVersion(const wchar_t* path, Version* out_version) {
16+
DWORD dummy;
17+
DWORD size = GetFileVersionInfoSizeW(path, &dummy);
18+
if ( size == 0 ) { return 0; }
19+
20+
BYTE* buffer = (BYTE*)malloc(size);
21+
if ( !buffer ) { return 0; }
22+
if ( !GetFileVersionInfoW(path, 0, size, buffer) ) {
23+
c4log(kC4DefaultLog, kC4LogVerbose, "GetFileVersionInfoW failed: %lu", GetLastError());
24+
free(buffer);
25+
return 0;
26+
}
27+
28+
VS_FIXEDFILEINFO* fileInfo;
29+
UINT len = 0;
30+
if ( !VerQueryValueA(buffer, "\\", (LPVOID*)&fileInfo, &len) ) {
31+
c4log(kC4DefaultLog, kC4LogVerbose, "VerQueryValueA failed: %lu", GetLastError());
32+
free(buffer);
33+
return 0;
34+
}
35+
36+
if ( fileInfo ) {
37+
out_version->major = HIWORD(fileInfo->dwFileVersionMS);
38+
out_version->minor = LOWORD(fileInfo->dwFileVersionMS);
39+
out_version->build = HIWORD(fileInfo->dwFileVersionLS);
40+
out_version->revision = LOWORD(fileInfo->dwFileVersionLS);
41+
free(buffer);
42+
return 1;
43+
}
44+
45+
c4log(kC4DefaultLog, kC4LogVerbose, "VerQueryValueA returned NULL");
46+
free(buffer);
47+
return 0;
48+
}
49+
50+
static int CompareVersions(const Version* a, const Version* b) {
51+
if ( a->major != b->major ) return a->major < b->major ? -1 : 1;
52+
if ( a->minor != b->minor ) return a->minor < b->minor ? -1 : 1;
53+
if ( a->build != b->build ) return a->build < b->build ? -1 : 1;
54+
if ( a->revision != b->revision ) return a->revision < b->revision ? -1 : 1;
55+
return 0;
56+
}
57+
58+
void CheckCppRuntime() {
59+
HMODULE hMod = GetModuleHandleA("msvcp140.dll");
60+
if ( !hMod ) { hMod = LoadLibraryA("msvcp140d.dll"); }
61+
62+
if ( !hMod ) {
63+
c4log(kC4DefaultLog, kC4LogWarning, "msvcp140.dll not loaded yet, unable to check version...");
64+
return;
65+
}
66+
67+
wchar_t path[MAX_PATH];
68+
if ( GetModuleFileNameW(hMod, path, MAX_PATH) == 0 ) {
69+
c4log(kC4DefaultLog, kC4LogWarning, "Unable to determine msvcp140.dll filename to check version...");
70+
return;
71+
}
72+
73+
Version loaded = {0};
74+
if ( !GetDllVersion(path, &loaded) ) {
75+
c4log(kC4DefaultLog, kC4LogWarning, "Unable to get version of msvcp140.dll to check...");
76+
return;
77+
}
78+
79+
Version expected = {14, 36, 32457, 0};
80+
int cmp = CompareVersions(&loaded, &expected);
81+
if ( cmp < 0 ) {
82+
c4log(kC4DefaultLog, kC4LogWarning, "msvcp140.dll version is older than expected: %u.%u.%u.%u < %u.%u.%u.%u",
83+
loaded.major, loaded.minor, loaded.revision, loaded.build, expected.major, expected.minor,
84+
expected.revision, expected.build);
85+
c4log(kC4DefaultLog, kC4LogWarning, "This may cause instability in your application");
86+
}
87+
}
88+
89+
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
90+
switch ( ul_reason_for_call ) {
91+
case DLL_PROCESS_ATTACH:
92+
CheckCppRuntime();
93+
break;
94+
default:
95+
break;
96+
}
97+
return TRUE;
98+
}

jenkins/build_server_win.ps1

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,10 @@ function Build() {
7878
$MsArch = "x64"
7979
}
8080

81+
# This -T version controls which version of the MSVC toolchain is used.
82+
# Once it is decided for a given minor release line, it should not be changed.
8183
& "C:\Program Files\CMake\bin\cmake.exe" `
84+
-T version=14.36 `
8285
-A $MsArch `
8386
-DEDITION="$Edition" `
8487
-DCMAKE_INSTALL_PREFIX="$(Get-Location)\install" `

jenkins/jenkins_win.ps1

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@ try {
2121

2222
New-Item -Type Directory -ErrorAction Ignore couchbase-lite-core\build_cmake\x64
2323
Set-Location couchbase-lite-core\build_cmake\x64
24-
& 'C:\Program Files\CMake\bin\cmake.exe' -A x64 -DCMAKE_SYSTEM_VERSION="10.0" -DBUILD_ENTERPRISE=ON ..\..
24+
25+
# This -T version controls which version of the MSVC toolchain is used.
26+
# Once it is decided for a given minor release line, it should not be changed.
27+
& 'C:\Program Files\CMake\bin\cmake.exe' -A x64 -T version=14.36 -DCMAKE_SYSTEM_VERSION="10.0" -DBUILD_ENTERPRISE=ON ..\..
2528
if($LASTEXITCODE -ne 0) {
2629
Write-Host "Failed to run CMake!" -ForegroundColor Red
2730
exit 1

0 commit comments

Comments
 (0)