Skip to content

cxx-qt-build: ensure that we set framework path for inner cc builds #970

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions crates/cxx-qt-build/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
75 changes: 62 additions & 13 deletions crates/qt-build-utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,13 @@ fn command_help_output(command: &str) -> std::io::Result<std::process::Output> {
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
Expand Down Expand Up @@ -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 <QtCore/QObject> 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()
);
}
}

Expand All @@ -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 {
Expand Down Expand Up @@ -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<PathBuf> {
let mut framework_paths = vec![];

if is_apple_target() {
// Note that this adds the framework path which allows for
// includes such as <QtCore/QObject> 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<PathBuf> {
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
Expand Down
Loading