Skip to content

Commit bc8fd2f

Browse files
committed
Set the rpath to Qt for Rust binaries
For C++ apps we apply rpath to the cdylib implicitly via qttypes, but link flags for rust binaries are not transitively propagated but require explicit opt-in by the top-level crate. However we want that convenience, to avoid Rust apps having to deal with Qt backend specific code in their build.rs. Therefore we use the _DEP mechanism to get the qt library path from the qttypes crate, forward it to the default backend crate and write it into a generic file in the qt backend's build.rs, which is then picked up by sixtyfps-build. In the future, we'll use the same mechanism to propagate link flags and extend the linker serach path for the MCU build (such as the linker script). cc #566
1 parent 8160235 commit bc8fd2f

File tree

3 files changed

+67
-4
lines changed

3 files changed

+67
-4
lines changed

api/sixtyfps-rs/sixtyfps-build/lib.rs

+20
Original file line numberDiff line numberDiff line change
@@ -269,5 +269,25 @@ pub fn compile_with_config(
269269
println!("cargo:rerun-if-env-changed=SIXTYFPS_STYLE");
270270

271271
println!("cargo:rustc-env=SIXTYFPS_INCLUDE_GENERATED={}", output_file_path.display());
272+
273+
apply_linker_flags();
274+
272275
Ok(())
273276
}
277+
278+
// Backends such as Qt or the MCU might need special link flags. We don't want to require users to have to
279+
// deal with those, so propagate them here.
280+
fn apply_linker_flags() {
281+
// Same logic as in sixtyfps-rendering-backend-default's build script to get the path
282+
if let Some(path) = std::env::var_os("OUT_DIR").and_then(|path| {
283+
Some(Path::new(&path).parent()?.parent()?.join("SIXTYFPS_BACKEND_LINK_FLAGS.txt"))
284+
}) {
285+
// unfortunately, if for some reason the file is changed, it is changed after cargo decide to re-run
286+
// this build script or not. So that means one will need two build to settle the right thing.
287+
println!("cargo:rerun-if-changed={}", path.display());
288+
289+
if let Ok(mut link_flags_file) = std::fs::File::open(path) {
290+
std::io::copy(&mut link_flags_file, &mut std::io::stdout()).ok();
291+
}
292+
}
293+
}

sixtyfps_runtime/rendering_backends/default/build.rs

+34-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright © SixtyFPS GmbH <[email protected]>
22
// SPDX-License-Identifier: (GPL-3.0-only OR LicenseRef-SixtyFPS-commercial)
33

4+
use std::fmt::Write;
45
use std::path::Path;
56

67
fn main() {
@@ -28,8 +29,38 @@ fn main() {
2829
// out_dir is something like
2930
// <target_dir>/build/sixtyfps-rendering-backend-default-1fe5c4ab61eb0584/out
3031
// and we want to write to a common directory, so write in the build/ dir
31-
let target_path =
32+
let style_target_path =
3233
Path::new(&out_dir).parent().unwrap().parent().unwrap().join("SIXTYFPS_DEFAULT_STYLE.txt");
33-
std::fs::write(target_path, if has_native_style { b"native\n" as &[u8] } else { b"fluent\n" })
34-
.unwrap();
34+
std::fs::write(
35+
style_target_path,
36+
if has_native_style { b"native\n" as &[u8] } else { b"fluent\n" },
37+
)
38+
.unwrap();
39+
40+
let mut link_flags = String::new();
41+
42+
for backend in ["GL", "QT"] {
43+
if let Ok(args) =
44+
std::env::var(format!("DEP_SIXTYFPS_RENDERING_BACKEND_{}_LINK_ARGS", backend))
45+
{
46+
for arg in args.split('|') {
47+
write!(&mut link_flags, "cargo:rustc-link-arg={}\n", arg).unwrap();
48+
}
49+
}
50+
if let Ok(args) =
51+
std::env::var(format!("DEP_SIXTYFPS_RENDERING_BACKEND_{}_LINK_SEARCH_PATHS", backend))
52+
{
53+
for arg in args.split('|') {
54+
write!(&mut link_flags, "cargo:rustc-link-search={}\n", arg).unwrap();
55+
}
56+
}
57+
}
58+
59+
let link_flags_target_path = std::path::Path::new(&out_dir)
60+
.parent()
61+
.unwrap()
62+
.parent()
63+
.unwrap()
64+
.join("SIXTYFPS_BACKEND_LINK_FLAGS.txt");
65+
std::fs::write(link_flags_target_path, link_flags).unwrap();
3566
}

sixtyfps_runtime/rendering_backends/qt/build.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,11 @@ fn main() {
3838
// Ref: https://docs.microsoft.com/en-us/cpp/build/reference/utf-8-set-source-and-executable-character-sets-to-utf-8
3939
config.flag_if_supported("/utf-8");
4040

41+
let qt_library_path = std::env::var("DEP_QT_LIBRARY_PATH").unwrap();
42+
4143
if cfg!(target_os = "macos") {
4244
config.flag("-F");
43-
config.flag(&std::env::var("DEP_QT_LIBRARY_PATH").unwrap());
45+
config.flag(&qt_library_path);
4446
}
4547
config.include(std::env::var("DEP_QT_INCLUDE_PATH").unwrap()).build("lib.rs");
4648

@@ -58,4 +60,14 @@ fn main() {
5860
println!("cargo:rerun-if-changed=qt_widgets/tabwidget.rs");
5961
println!("cargo:rerun-if-changed=lib.rs");
6062
println!("cargo:SUPPORTS_NATIVE_STYLE=1");
63+
64+
// Cargo doesn't support implicit transitive link flags for crates (https://github.com/rust-lang/cargo/issues/9554 | https://github.com/rust-lang/cargo/issues/9562 | https://github.com/sixtyfpsui/sixtyfps/issues/566).
65+
// Instead of requiring Rust apps to have Qt backend specific code, propagate the needed rpath link options via a DEP_ variable to the default backend, which
66+
// can write it to a file for use by sixtyfps-build.
67+
// For C++ apps that's not an issue because we create a cdylib, qttypes emits `rustc-cdylib-link-arg` and that *is* propagated.
68+
// This also means that the Qt backend cannot be combined with another backend that also writes to this file. The GL backend doesn't, but the MCU
69+
// backend might/will.
70+
if std::env::var("CARGO_CFG_TARGET_FAMILY").as_ref().map(|s| s.as_ref()) == Ok("unix") {
71+
println!("cargo:LINK_ARGS=-Wl,-rpath,{}", &qt_library_path)
72+
}
6173
}

0 commit comments

Comments
 (0)