From 72852cd8fe4d3dc23a0e341a88cbbb2a8bf7de09 Mon Sep 17 00:00:00 2001 From: Andrew Hayzen Date: Wed, 5 Jun 2024 08:22:51 +0100 Subject: [PATCH 1/4] cxx-qt-build: ensure that we set framework path for inner cc builds Closes #885 --- crates/cxx-qt-build/src/lib.rs | 19 ++++++++++++++-- crates/qt-build-utils/src/lib.rs | 37 +++++++++++++++++++++++++++++++- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/crates/cxx-qt-build/src/lib.rs b/crates/cxx-qt-build/src/lib.rs index 1e9f7e78c..3af8720ee 100644 --- a/crates/cxx-qt-build/src/lib.rs +++ b/crates/cxx-qt-build/src/lib.rs @@ -647,10 +647,15 @@ impl CxxQtBuilder { builder: &mut cc::Build, include_paths: &[impl AsRef], defines: &[(String, Option)], + qtbuild: &qt_build_utils::QtBuild, ) { // Note, ensure our settings stay in sync across cxx-qt and cxx-qt-lib builder.cpp(true); builder.std("c++17"); + // MacOS needs the framework path + for framework_path in qtbuild.framework_paths() { + builder.flag_if_supported(format!("-F{}", framework_path.display())); + } // MSVC builder.flag_if_supported("/Zc:__cplusplus"); builder.flag_if_supported("/permissive-"); @@ -1044,9 +1049,19 @@ impl CxxQtBuilder { let compile_definitions = dependencies::all_compile_definitions(self.public_interface.as_ref(), &dependencies); - Self::setup_cc_builder(&mut self.cc_builder, &include_paths, &compile_definitions); + Self::setup_cc_builder( + &mut self.cc_builder, + &include_paths, + &compile_definitions, + &qtbuild, + ); - Self::setup_cc_builder(&mut init_builder, &include_paths, &compile_definitions); + Self::setup_cc_builder( + &mut init_builder, + &include_paths, + &compile_definitions, + &qtbuild, + ); // Note: From now on the init_builder is correctly configured. // When building object files with this builder, we always need to copy it first. // So remove `mut` to ensure that we can't accidentally change the configuration or add diff --git a/crates/qt-build-utils/src/lib.rs b/crates/qt-build-utils/src/lib.rs index aa1499f57..7f872929e 100644 --- a/crates/qt-build-utils/src/lib.rs +++ b/crates/qt-build-utils/src/lib.rs @@ -453,6 +453,9 @@ impl QtBuild { // // Note this doesn't have an adverse affect running all the time // as it appears that all rustc-link-search are added + // + // Note that this adds the framework path which allows for + // includes such as to be resolved correctly if let Ok(target) = &target { if target.contains("apple") { println!("cargo::rustc-link-search=framework={lib_path}"); @@ -522,16 +525,48 @@ 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![]; + + let target = env::var("TARGET"); + if let Ok(target) = &target { + if target.contains("apple") { + // 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 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}")); } + + // 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 From 575a253c1d9fd96dc554cfbdbcfc1d535132e6d7 Mon Sep 17 00:00:00 2001 From: Andrew Hayzen Date: Tue, 15 Oct 2024 15:09:36 +0100 Subject: [PATCH 2/4] qt-build-utils: load a framework headers dir if there is one --- crates/qt-build-utils/src/lib.rs | 46 +++++++++++++++++--------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/crates/qt-build-utils/src/lib.rs b/crates/qt-build-utils/src/lib.rs index 7f872929e..8e97effb5 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 @@ -456,10 +463,8 @@ impl QtBuild { // // Note that this adds the framework path which allows for // includes such as to be resolved correctly - if let Ok(target) = &target { - if target.contains("apple") { - println!("cargo::rustc-link-search=framework={lib_path}"); - } + if is_apple_target() { + println!("cargo::rustc-link-search=framework={lib_path}"); } let prefix = match &target { @@ -474,15 +479,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 { @@ -530,14 +530,11 @@ impl QtBuild { pub fn framework_paths(&self) -> Vec { let mut framework_paths = vec![]; - let target = env::var("TARGET"); - if let Ok(target) = &target { - if target.contains("apple") { - // 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); - } + 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 @@ -552,10 +549,17 @@ impl QtBuild { /// 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 From e70922011c068a9c0d8270b4f29e7bade2bc2d71 Mon Sep 17 00:00:00 2001 From: Andrew Hayzen Date: Tue, 15 Oct 2024 16:10:17 +0100 Subject: [PATCH 3/4] build: set -F framework path in qt-build-utils always --- crates/cxx-qt-build/src/lib.rs | 21 ++++----------------- crates/qt-build-utils/src/lib.rs | 5 +++++ 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/crates/cxx-qt-build/src/lib.rs b/crates/cxx-qt-build/src/lib.rs index 3af8720ee..6aa94a785 100644 --- a/crates/cxx-qt-build/src/lib.rs +++ b/crates/cxx-qt-build/src/lib.rs @@ -647,15 +647,10 @@ impl CxxQtBuilder { builder: &mut cc::Build, include_paths: &[impl AsRef], defines: &[(String, Option)], - qtbuild: &qt_build_utils::QtBuild, ) { // Note, ensure our settings stay in sync across cxx-qt and cxx-qt-lib builder.cpp(true); builder.std("c++17"); - // MacOS needs the framework path - for framework_path in qtbuild.framework_paths() { - builder.flag_if_supported(format!("-F{}", framework_path.display())); - } // MSVC builder.flag_if_supported("/Zc:__cplusplus"); builder.flag_if_supported("/permissive-"); @@ -1038,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 @@ -1049,19 +1046,9 @@ impl CxxQtBuilder { let compile_definitions = dependencies::all_compile_definitions(self.public_interface.as_ref(), &dependencies); - Self::setup_cc_builder( - &mut self.cc_builder, - &include_paths, - &compile_definitions, - &qtbuild, - ); + Self::setup_cc_builder(&mut self.cc_builder, &include_paths, &compile_definitions); - Self::setup_cc_builder( - &mut init_builder, - &include_paths, - &compile_definitions, - &qtbuild, - ); + Self::setup_cc_builder(&mut init_builder, &include_paths, &compile_definitions); // Note: From now on the init_builder is correctly configured. // When building object files with this builder, we always need to copy it first. // So remove `mut` to ensure that we can't accidentally change the configuration or add diff --git a/crates/qt-build-utils/src/lib.rs b/crates/qt-build-utils/src/lib.rs index 8e97effb5..c03e58ff3 100644 --- a/crates/qt-build-utils/src/lib.rs +++ b/crates/qt-build-utils/src/lib.rs @@ -465,6 +465,11 @@ impl QtBuild { // 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())); + } } let prefix = match &target { From fa5030289e70ae2e86c5eda6455e4e7cd6856594 Mon Sep 17 00:00:00 2001 From: Andrew Hayzen Date: Wed, 16 Oct 2024 12:17:18 +0100 Subject: [PATCH 4/4] qt-build-utils: set the rpath to the framework path on macOS Otherwise the @rpath cannot be found at runtime --- crates/qt-build-utils/src/lib.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/crates/qt-build-utils/src/lib.rs b/crates/qt-build-utils/src/lib.rs index c03e58ff3..c6efff722 100644 --- a/crates/qt-build-utils/src/lib.rs +++ b/crates/qt-build-utils/src/lib.rs @@ -469,6 +469,11 @@ impl QtBuild { // 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() + ); } }