diff --git a/crates/cxx-qt-build/src/lib.rs b/crates/cxx-qt-build/src/lib.rs index 1e9f7e78c..6aa94a785 100644 --- a/crates/cxx-qt-build/src/lib.rs +++ b/crates/cxx-qt-build/src/lib.rs @@ -1033,6 +1033,8 @@ impl CxxQtBuilder { // from within main when static linking, which would result in discarding those static variables. // Use a separate cc::Build for the little amount of code that needs to be built & linked this way. let mut init_builder = cc::Build::new(); + // Ensure that Qt modules and apple framework are linked and searched correctly + qtbuild.cargo_link_libraries(&mut init_builder); let mut include_paths = qtbuild.include_paths(); include_paths.push(header_root.clone()); // TODO: Some of the code generated by qmltyperegistrar doesn't add the include_prefix to diff --git a/crates/qt-build-utils/src/lib.rs b/crates/qt-build-utils/src/lib.rs index aa1499f57..c6efff722 100644 --- a/crates/qt-build-utils/src/lib.rs +++ b/crates/qt-build-utils/src/lib.rs @@ -68,6 +68,13 @@ fn command_help_output(command: &str) -> std::io::Result { Command::new(command).args(["--help"]).output() } +/// Whether apple is the current target +fn is_apple_target() -> bool { + env::var("TARGET") + .map(|target| target.contains("apple")) + .unwrap_or_else(|_| false) +} + /// Linking executables (including tests) with Cargo that link to Qt fails to link with GNU ld.bfd, /// which is the default on most Linux distributions, so use GNU ld.gold, lld, or mold instead. /// If you are using a C++ build system such as CMake to do the final link of the executable, you do @@ -453,9 +460,20 @@ impl QtBuild { // // Note this doesn't have an adverse affect running all the time // as it appears that all rustc-link-search are added - if let Ok(target) = &target { - if target.contains("apple") { - println!("cargo::rustc-link-search=framework={lib_path}"); + // + // Note that this adds the framework path which allows for + // includes such as to be resolved correctly + if is_apple_target() { + println!("cargo::rustc-link-search=framework={lib_path}"); + + // Ensure that any framework paths are set to -F + for framework_path in self.framework_paths() { + builder.flag_if_supported(format!("-F{}", framework_path.display())); + // Also set the -rpath otherwise frameworks can not be found at runtime + println!( + "cargo::rustc-link-arg=-Wl,-rpath,{}", + framework_path.display() + ); } } @@ -471,15 +489,10 @@ impl QtBuild { }; for qt_module in &self.qt_modules { - let framework = match &target { - Ok(target) => { - if target.contains("apple") { - Path::new(&format!("{lib_path}/Qt{qt_module}.framework")).exists() - } else { - false - } - } - Err(_) => false, + let framework = if is_apple_target() { + Path::new(&format!("{lib_path}/Qt{qt_module}.framework")).exists() + } else { + false }; let (link_lib, prl_path) = if framework { @@ -522,16 +535,52 @@ impl QtBuild { } } + /// Get the framework paths for Qt. This is intended + /// to be passed to whichever tool you are using to invoke the C++ compiler. + pub fn framework_paths(&self) -> Vec { + let mut framework_paths = vec![]; + + if is_apple_target() { + // Note that this adds the framework path which allows for + // includes such as to be resolved correctly + let framework_path = self.qmake_query("QT_INSTALL_LIBS"); + framework_paths.push(framework_path); + } + + framework_paths + .iter() + .map(PathBuf::from) + // Only add paths if they exist + .filter(|path| path.exists()) + .collect() + } + /// Get the include paths for Qt, including Qt module subdirectories. This is intended /// to be passed to whichever tool you are using to invoke the C++ compiler. pub fn include_paths(&self) -> Vec { let root_path = self.qmake_query("QT_INSTALL_HEADERS"); + let lib_path = self.qmake_query("QT_INSTALL_LIBS"); let mut paths = Vec::new(); for qt_module in &self.qt_modules { + // Add the usual location for the Qt module paths.push(format!("{root_path}/Qt{qt_module}")); + + // Ensure that we add any framework's headers path + let header_path = format!("{lib_path}/Qt{qt_module}.framework/Headers"); + if is_apple_target() && Path::new(&header_path).exists() { + paths.push(header_path); + } } + + // Add the QT_INSTALL_HEADERS itself paths.push(root_path); - paths.iter().map(PathBuf::from).collect() + + paths + .iter() + .map(PathBuf::from) + // Only add paths if they exist + .filter(|path| path.exists()) + .collect() } /// Version of the detected Qt installation