Skip to content

Commit adb1544

Browse files
committed
build: try with forced types and configuration on msvc
1 parent 96080bd commit adb1544

File tree

5 files changed

+225
-19
lines changed

5 files changed

+225
-19
lines changed

build.rs

Lines changed: 214 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,38 @@ use std::path::PathBuf;
4141
use std::process::Command;
4242
use fs_extra::dir;
4343

44+
// Custom callback to handle MSVC type mapping issues
45+
#[derive(Debug)]
46+
struct MSVCTypeCallback;
47+
48+
impl bindgen::callbacks::ParseCallbacks for MSVCTypeCallback {
49+
fn int_macro(&self, name: &str, value: i64) -> Option<bindgen::callbacks::IntKind> {
50+
// Force unsigned macros and values to use u32 on MSVC
51+
if name.contains("UINT")
52+
|| name.ends_with("_U")
53+
|| (value >= 0 && name.contains("UNSIGNED"))
54+
{
55+
Some(bindgen::callbacks::IntKind::U32)
56+
} else {
57+
None
58+
}
59+
}
60+
61+
fn item_name(&self, item_info: bindgen::callbacks::ItemInfo<'_>) -> Option<String> {
62+
// Handle specific type mappings if needed
63+
match item_info.name {
64+
"c_uint" => Some("u32".to_string()),
65+
"c_ulong" => Some("u32".to_string()),
66+
_ => None,
67+
}
68+
}
69+
70+
// Chain with CargoCallbacks
71+
fn include_file(&self, filename: &str) {
72+
bindgen::CargoCallbacks::new().include_file(filename);
73+
}
74+
}
75+
4476
#[cfg(feature = "community")]
4577
static CBL_INCLUDE_DIR: &str = "libcblite_community/include";
4678
#[cfg(feature = "enterprise")]
@@ -103,6 +135,139 @@ enum OperatingSystem {
103135
IOs,
104136
}
105137

138+
fn find_msvc_paths() -> Result<(Option<String>, Option<String>), Box<dyn Error>> {
139+
// Try to find MSVC installation paths automatically
140+
let mut msvc_include = None;
141+
let mut ucrt_include = None;
142+
143+
// Method 1: Use environment variables from Rust/Cargo build (preferred method)
144+
if let Ok(include_path) = env::var("INCLUDE") {
145+
// Parse the INCLUDE environment variable that MSVC sets
146+
for path in include_path.split(';') {
147+
let path = path.trim();
148+
if !path.is_empty() {
149+
if path.contains("VC\\Tools\\MSVC") && path.ends_with("include") {
150+
msvc_include = Some(path.to_string());
151+
} else if path.contains("Windows Kits") && path.ends_with("ucrt") {
152+
ucrt_include = Some(path.to_string());
153+
}
154+
}
155+
}
156+
}
157+
158+
// Method 2: Try using vswhere.exe if available and no env vars found
159+
if msvc_include.is_none()
160+
&& let Ok(output) = Command::new("vswhere.exe")
161+
.args([
162+
"-latest",
163+
"-products",
164+
"*",
165+
"-requires",
166+
"Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
167+
"-property",
168+
"installationPath",
169+
])
170+
.output()
171+
&& output.status.success()
172+
{
173+
let vs_path = String::from_utf8_lossy(&output.stdout).trim().to_string();
174+
if !vs_path.is_empty() {
175+
// Try to find the MSVC version
176+
let vc_tools_path = format!("{}\\VC\\Tools\\MSVC", vs_path);
177+
if let Ok(entries) = fs::read_dir(&vc_tools_path) {
178+
let mut versions = Vec::new();
179+
for entry in entries.flatten() {
180+
if entry.file_type().map(|t| t.is_dir()).unwrap_or(false) {
181+
let version_path = entry.path();
182+
let include_path = version_path.join("include");
183+
if include_path.exists() {
184+
let version = entry.file_name().to_string_lossy().to_string();
185+
versions.push((version, include_path.to_string_lossy().to_string()));
186+
}
187+
}
188+
}
189+
// Sort versions and take the latest
190+
versions.sort_by(|a, b| b.0.cmp(&a.0));
191+
if let Some((_, path)) = versions.first() {
192+
msvc_include = Some(path.clone());
193+
}
194+
}
195+
}
196+
}
197+
198+
// Method 3: Check common Visual Studio locations
199+
if msvc_include.is_none() {
200+
let common_vs_paths = [
201+
"C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Tools\\MSVC",
202+
"C:\\Program Files\\Microsoft Visual Studio\\2022\\Professional\\VC\\Tools\\MSVC",
203+
"C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Tools\\MSVC",
204+
"C:\\Program Files\\Microsoft Visual Studio\\2019\\Enterprise\\VC\\Tools\\MSVC",
205+
"C:\\Program Files\\Microsoft Visual Studio\\2019\\Professional\\VC\\Tools\\MSVC",
206+
"C:\\Program Files\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC",
207+
];
208+
209+
for vs_path in &common_vs_paths {
210+
if let Ok(entries) = fs::read_dir(vs_path) {
211+
let mut versions = Vec::new();
212+
for entry in entries.flatten() {
213+
if entry.file_type().map(|t| t.is_dir()).unwrap_or(false) {
214+
let version_path = entry.path();
215+
let include_path = version_path.join("include");
216+
if include_path.exists() {
217+
let version = entry.file_name().to_string_lossy().to_string();
218+
versions.push((version, include_path.to_string_lossy().to_string()));
219+
}
220+
}
221+
}
222+
// Sort versions and take the latest
223+
versions.sort_by(|a, b| b.0.cmp(&a.0));
224+
if let Some((_, path)) = versions.first() {
225+
msvc_include = Some(path.clone());
226+
break;
227+
}
228+
}
229+
}
230+
}
231+
232+
// Method 4: Try to find Windows SDK UCRT if not found via env vars
233+
if ucrt_include.is_none() {
234+
let sdk_paths = [
235+
"C:\\Program Files (x86)\\Windows Kits\\10\\Include",
236+
"C:\\Program Files\\Windows Kits\\10\\Include",
237+
];
238+
239+
for sdk_path in &sdk_paths {
240+
if let Ok(entries) = fs::read_dir(sdk_path) {
241+
// Find the latest version
242+
let mut versions = Vec::new();
243+
for entry in entries.flatten() {
244+
if entry.file_type().map(|t| t.is_dir()).unwrap_or(false) {
245+
let name = entry.file_name();
246+
let name_str = name.to_string_lossy();
247+
if name_str.starts_with("10.") {
248+
let ucrt_path = entry.path().join("ucrt");
249+
if ucrt_path.exists() {
250+
versions.push((
251+
name_str.to_string(),
252+
ucrt_path.to_string_lossy().to_string(),
253+
));
254+
}
255+
}
256+
}
257+
}
258+
// Sort versions and take the latest
259+
versions.sort_by(|a, b| b.0.cmp(&a.0));
260+
if let Some((_, path)) = versions.first() {
261+
ucrt_include = Some(path.clone());
262+
break;
263+
}
264+
}
265+
}
266+
}
267+
268+
Ok((msvc_include, ucrt_include))
269+
}
270+
106271
fn is_target(target: OperatingSystem) -> Result<bool, Box<dyn Error>> {
107272
let target_os = env::var("CARGO_CFG_TARGET_OS")?;
108273
Ok(match target {
@@ -172,12 +337,39 @@ fn generate_bindings() -> Result<(), Box<dyn Error>> {
172337
.clang_arg(format!("--target={}", "x86_64-pc-windows-gnu"));
173338
}
174339

175-
bindings = bindings
176-
.clang_arg("-IC:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Tools\\MSVC\\14.40.33807\\include".to_string())
177-
.clang_arg("-IC:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.17763.0\\ucrt");
340+
// Special handling for MSVC targets to fix unsigned type generation
341+
if is_target(OperatingSystem::Windows)? {
342+
// Try to auto-detect MSVC paths
343+
let (msvc_include, ucrt_include) = find_msvc_paths()?;
344+
345+
if let Some(msvc_path) = msvc_include {
346+
bindings = bindings.clang_arg(format!("-I{}", msvc_path));
347+
} else {
348+
eprintln!("Warning: Could not auto-detect MSVC include path, using fallback");
349+
bindings = bindings.clang_arg("-IC:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Tools\\MSVC\\14.40.33807\\include");
350+
}
351+
352+
if let Some(ucrt_path) = ucrt_include {
353+
bindings = bindings.clang_arg(format!("-I{}", ucrt_path));
354+
} else {
355+
eprintln!("Warning: Could not auto-detect Windows SDK UCRT path, using fallback");
356+
bindings = bindings.clang_arg(
357+
"-IC:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.17763.0\\ucrt",
358+
);
359+
}
360+
361+
bindings = bindings
362+
// Force unsigned types on MSVC
363+
.clang_arg("-DUINT32=unsigned int")
364+
.clang_arg("-DULONG=unsigned long")
365+
// Ensure proper type detection
366+
.clang_arg("-D_WIN32_WINNT=0x0601")
367+
.blocklist_type("c_uint")
368+
.blocklist_type("c_ulong");
369+
}
178370

179371
let out_dir = env::var("OUT_DIR")?;
180-
bindings
372+
let mut final_bindings = bindings
181373
.allowlist_type("CBL.*")
182374
.allowlist_type("FL.*")
183375
.allowlist_var("k?CBL.*")
@@ -186,7 +378,24 @@ fn generate_bindings() -> Result<(), Box<dyn Error>> {
186378
.allowlist_function("_?FL.*")
187379
.no_copy("FLSliceResult")
188380
.size_t_is_usize(true)
189-
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
381+
// Fix for MSVC: Force unsigned types to be generated as u32 instead of i32
382+
.default_enum_style(bindgen::EnumVariation::Consts)
383+
// Force constants to be generated as const u32 instead of complex enums
384+
.translate_enum_integer_types(true);
385+
386+
// Add MSVC-specific type fixes
387+
if is_target(OperatingSystem::Windows)? {
388+
final_bindings = final_bindings
389+
.raw_line("#[allow(non_camel_case_types)]")
390+
.raw_line("pub type c_uint = u32;")
391+
.raw_line("pub type c_ulong = u32;")
392+
.raw_line("pub type DWORD = u32;")
393+
.raw_line("pub type UINT = u32;")
394+
.raw_line("pub type ULONG = u32;");
395+
}
396+
397+
final_bindings
398+
.parse_callbacks(Box::new(MSVCTypeCallback))
190399
.generate()
191400
.expect("Unable to generate bindings")
192401
.write_to_file(PathBuf::from(out_dir).join("bindings.rs"))

src/error.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ impl Error {
212212
}
213213

214214
pub(crate) fn as_cbl_error(&self) -> CBLError {
215-
let domain: i32;
215+
let domain: u32;
216216
let code: i32;
217217
match &self.code {
218218
ErrorCode::CouchbaseLite(e) => {
@@ -278,7 +278,7 @@ impl fmt::Display for Error {
278278

279279
impl ErrorCode {
280280
fn new(err: &CBLError) -> Self {
281-
match i32::from(err.domain) {
281+
match u32::from(err.domain) {
282282
kCBLDomain => CouchbaseLiteError::from_i32(err.code)
283283
.map_or(Self::untranslatable(), Self::CouchbaseLite),
284284
kCBLNetworkDomain => {

src/fleece.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ impl Fleece {
7171
pub fn parse(data: &[u8], trust: Trust) -> Result<Self> {
7272
unsafe {
7373
let copied = FLSlice_Copy(from_bytes(data).get_ref());
74-
let doc = FLDoc_FromResultData(copied, trust as i32, ptr::null_mut(), NULL_SLICE);
74+
let doc = FLDoc_FromResultData(copied, trust as u32, ptr::null_mut(), NULL_SLICE);
7575
if doc.is_null() {
7676
return Err(Error::fleece_error(FLError_kFLInvalidData));
7777
}

src/fleece_mutable.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ impl MutableArray {
8080
pub fn from_array_(array: &Array, flags: CopyFlags) -> Self {
8181
unsafe {
8282
Self {
83-
cbl_ref: FLArray_MutableCopy(array.get_ref(), flags as i32),
83+
cbl_ref: FLArray_MutableCopy(array.get_ref(), flags as u32),
8484
}
8585
}
8686
}
@@ -274,7 +274,7 @@ impl MutableDict {
274274
pub fn from_dict_(dict: &Dict, flags: CopyFlags) -> Self {
275275
unsafe {
276276
Self {
277-
cbl_ref: FLDict_MutableCopy(dict.get_ref(), flags as i32),
277+
cbl_ref: FLDict_MutableCopy(dict.get_ref(), flags as u32),
278278
}
279279
}
280280
}

src/replicator.rs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ pub enum ReplicatorType {
170170

171171
impl From<CBLReplicatorType> for ReplicatorType {
172172
fn from(repl_type: CBLReplicatorType) -> Self {
173-
match i32::from(repl_type) {
173+
match u32::from(repl_type) {
174174
kCBLReplicatorTypePushAndPull => Self::PushAndPull,
175175
kCBLReplicatorTypePush => Self::Push,
176176
kCBLReplicatorTypePull => Self::Pull,
@@ -197,7 +197,7 @@ pub enum ProxyType {
197197

198198
impl From<CBLProxyType> for ProxyType {
199199
fn from(proxy_type: CBLProxyType) -> Self {
200-
match i32::from(proxy_type) {
200+
match u32::from(proxy_type) {
201201
kCBLProxyHTTP => Self::HTTP,
202202
kCBLProxyHTTPS => Self::HTTPS,
203203
_ => unreachable!(),
@@ -297,10 +297,7 @@ unsafe extern "C" fn c_replication_pull_filter(
297297
}
298298
}
299299
fn read_document_flags(flags: CBLDocumentFlags) -> (bool, bool) {
300-
(
301-
flags & DELETED as u32 != 0,
302-
flags & ACCESS_REMOVED as u32 != 0,
303-
)
300+
(flags & DELETED != 0, flags & ACCESS_REMOVED != 0)
304301
}
305302

306303
/** Conflict-resolution callback for use in replications. This callback will be invoked
@@ -1088,7 +1085,7 @@ pub enum ReplicatorActivityLevel {
10881085

10891086
impl From<u8> for ReplicatorActivityLevel {
10901087
fn from(level: u8) -> Self {
1091-
match i32::from(level) {
1088+
match u32::from(level) {
10921089
kCBLReplicatorStopped => Self::Stopped,
10931090
kCBLReplicatorOffline => Self::Offline,
10941091
kCBLReplicatorConnecting => Self::Connecting,
@@ -1181,8 +1178,8 @@ unsafe extern "C" fn c_replicator_document_change_listener(
11811178
}
11821179

11831180
/** Flags describing a replicated document. */
1184-
pub static DELETED: i32 = kCBLDocumentFlagsDeleted;
1185-
pub static ACCESS_REMOVED: i32 = kCBLDocumentFlagsAccessRemoved;
1181+
pub static DELETED: u32 = kCBLDocumentFlagsDeleted;
1182+
pub static ACCESS_REMOVED: u32 = kCBLDocumentFlagsAccessRemoved;
11861183

11871184
/** Information about a document that's been pushed or pulled. */
11881185
pub struct ReplicatedDocument {

0 commit comments

Comments
 (0)