Skip to content

Commit

Permalink
Set the rpath to Qt for Rust binaries
Browse files Browse the repository at this point in the history
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 for
the MCU build (such as the linker script).

cc #566
  • Loading branch information
tronical committed Jan 5, 2022
1 parent 2401eea commit 0776518
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 4 deletions.
20 changes: 20 additions & 0 deletions api/sixtyfps-rs/sixtyfps-build/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,5 +269,25 @@ pub fn compile_with_config(
println!("cargo:rerun-if-env-changed=SIXTYFPS_STYLE");

println!("cargo:rustc-env=SIXTYFPS_INCLUDE_GENERATED={}", output_file_path.display());

apply_linker_flags();

Ok(())
}

// Backends such as Qt or the MCU might need special link flags. We don't want to require users to have to
// deal with those, so propagate them here.
fn apply_linker_flags() {
// Same logic as in sixtyfps-rendering-backend-default's build script to get the path
if let Some(path) = std::env::var_os("OUT_DIR").and_then(|path| {
Some(Path::new(&path).parent()?.parent()?.join("SIXTYFPS_BACKEND_LINK_FLAGS.txt"))
}) {
// unfortunately, if for some reason the file is changed, it is changed after cargo decide to re-run
// this build script or not. So that means one will need two build to settle the right thing.
println!("cargo:rerun-if-changed={}", path.display());

if let Ok(mut link_flags_file) = std::fs::File::open(path) {
std::io::copy(&mut link_flags_file, &mut std::io::stdout()).ok();
}
}
}
27 changes: 24 additions & 3 deletions sixtyfps_runtime/rendering_backends/default/build.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright © SixtyFPS GmbH <info@sixtyfps.io>
// SPDX-License-Identifier: (GPL-3.0-only OR LicenseRef-SixtyFPS-commercial)

use std::fmt::Write;
use std::path::Path;

fn main() {
Expand Down Expand Up @@ -28,8 +29,28 @@ fn main() {
// out_dir is something like
// <target_dir>/build/sixtyfps-rendering-backend-default-1fe5c4ab61eb0584/out
// and we want to write to a common directory, so write in the build/ dir
let target_path =
let style_target_path =
Path::new(&out_dir).parent().unwrap().parent().unwrap().join("SIXTYFPS_DEFAULT_STYLE.txt");
std::fs::write(target_path, if has_native_style { b"native\n" as &[u8] } else { b"fluent\n" })
.unwrap();
std::fs::write(
style_target_path,
if has_native_style { b"native\n" as &[u8] } else { b"fluent\n" },
)
.unwrap();

let mut link_flags = String::new();

for backend in ["GL", "QT"] {
let link_args_var = format!("DEP_SIXTYFPS_RENDERING_BACKEND_{}_LINK_ARG", backend);
if let Ok(var) = std::env::var(link_args_var) {
write!(&mut link_flags, "cargo:rustc-link-arg={}\n", var).unwrap();
}
}

let link_flags_target_path = std::path::Path::new(&out_dir)
.parent()
.unwrap()
.parent()
.unwrap()
.join("SIXTYFPS_BACKEND_LINK_FLAGS.txt");
std::fs::write(link_flags_target_path, link_flags).unwrap();
}
14 changes: 13 additions & 1 deletion sixtyfps_runtime/rendering_backends/qt/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,11 @@ fn main() {
// Ref: https://docs.microsoft.com/en-us/cpp/build/reference/utf-8-set-source-and-executable-character-sets-to-utf-8
config.flag_if_supported("/utf-8");

let qt_library_path = std::env::var("DEP_QT_LIBRARY_PATH").unwrap();

if cfg!(target_os = "macos") {
config.flag("-F");
config.flag(&std::env::var("DEP_QT_LIBRARY_PATH").unwrap());
config.flag(&qt_library_path);
}
config.include(std::env::var("DEP_QT_INCLUDE_PATH").unwrap()).build("lib.rs");

Expand All @@ -58,4 +60,14 @@ fn main() {
println!("cargo:rerun-if-changed=qt_widgets/tabwidget.rs");
println!("cargo:rerun-if-changed=lib.rs");
println!("cargo:SUPPORTS_NATIVE_STYLE=1");

// 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).
// 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
// can write it to a file for use by sixtyfps-build.
// For C++ apps that's not an issue because we create a cdylib, qttypes emits `rustc-cdylib-link-arg` and that *is* propagated.
// 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
// backend might/will.
if std::env::var("CARGO_CFG_TARGET_FAMILY").as_ref().map(|s| s.as_ref()) == Ok("unix") {
println!("cargo:LINK_ARG=-Wl,-rpath,{}", &qt_library_path)
}
}

0 comments on commit 0776518

Please sign in to comment.