blob: b7a6897a29312a39cdb9b435b69d7fe6b095749d [file] [log] [blame]
extern crate cc;
extern crate wayland_scanner;
use rayon::prelude::*;
use std::env;
use std::fs::File;
use std::io::ErrorKind;
use std::io::Write;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;
use wayland_scanner::*;
fn run_bindgen(header: &str, output: &str) {
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
let sysroot = env::var("SYSROOT").unwrap_or("/".to_string());
let status = Command::new("bindgen")
.args(&["-o", out_path.join(output).to_str().unwrap()])
.arg("--no-doc-comments")
.arg("--no-layout-tests")
.args(&["--new-type-alias", "wl_fixed_t"])
.args(&["--default-enum-style", "rust_non_exhaustive"])
.args(&["--bitfield-enum", "weston_keyboard_modifier"])
.args(&["--bitfield-enum", "weston_activate_flag"])
.args(&["--bitfield-enum", "wl_event_mask"])
.args(&["--no-copy", "shell_surface"])
.arg(header)
.arg("--")
.arg(format!("--sysroot={}", sysroot))
.arg("-I./wayland-server")
.arg("-I/usr/include/pixman-1")
.arg("-I./weston/include")
.arg("-I./bindgen/block")
.status()
.unwrap();
assert!(status.success())
}
struct ConfigHeader {
contents: String,
}
impl ConfigHeader {
fn new() -> ConfigHeader {
ConfigHeader {
contents: "/* automatically generated header */\n\n".to_string(),
}
}
fn define(&mut self, name: &str, value: impl std::fmt::Display) -> &mut Self {
self.contents
.push_str(&format!("#define {} {}\n", name, value.to_string()));
self
}
fn define_escaped(&mut self, name: &str, value: impl std::fmt::Display) -> &mut Self {
self.define(name, format!("\"{}\"", value));
self
}
fn build(&self, path: &str, name: &str) {
File::create(format!("{}/{}", path, name))
.unwrap()
.write(self.contents.as_bytes())
.unwrap();
}
}
fn generate_header_files(config: &Config) {
#[cfg(feature = "wayland-backend")]
{
ConfigHeader::new()
.define("HAVE_ACCEPT4", 1)
.define("HAVE_MEMFD_CREATE", 1)
.define_escaped("LIBWESTON_MODULEDIR", "/dev/null")
.define_escaped("DATADIR", &config.data_dir)
.define("_GNU_SOURCE", 1)
.define("_ALL_SOURCE", 1)
.define("MAJOR_IN_SYSMACROS", 1)
.build(&config.out_path, "config.h");
}
#[cfg(feature = "drm-backend")]
{
// TODO: some DRM GBM config might not be compatible with older version.
ConfigHeader::new()
.define("HAVE_ACCEPT4", 1)
.define("BUILD_DRM_COMPOSITOR", 1)
.define("BUILD_DRM_GBM", 1)
.define("HAVE_GBM_MODIFIERS", 1)
.define("HAVE_GBM_FD_IMPORT", 1)
.define("ENABLE_EGL", 1)
.define("HAVE_MEMFD_CREATE", 1)
.define_escaped("LIBWESTON_MODULEDIR", "/usr/lib64/libweston-9")
.define_escaped("DATADIR", &config.data_dir)
.define("_GNU_SOURCE", 1)
.define("_ALL_SOURCE", 1)
.define("MAJOR_IN_SYSMACROS", 1)
.build(&config.out_path, "config.h");
}
ConfigHeader::new()
.define("BUILD_ID", "c001bead")
.build(&config.out_path, "git-version.h");
std::fs::create_dir(format!("{}/libweston", config.out_path))
.or_else(|e| {
if e.kind() == ErrorKind::AlreadyExists {
Ok(())
} else {
Err(e)
}
})
.unwrap();
ConfigHeader::new()
.define("WESTON_VERSION_MAJOR", 9)
.define("WESTON_VERSION_MINOR", 0)
.define("WESTON_VERSION_MICRO", 0)
.define_escaped("WESTON_VERSION", "9.0.0")
.build(&config.out_path, "libweston/version.h");
}
fn generate_rust_protocol_code(config: &Config) {
let protocols = [
"wayland",
"xdg-shell",
"weston-screenshooter",
"linux-dmabuf-unstable-v1",
"croscomp",
"alpha-compositing-unstable-v1",
"aura-shell",
"cursor-shapes-unstable-v1",
"gaming-input-unstable-v2",
"keyboard-configuration-unstable-v1",
"keyboard-extension-unstable-v1",
"pointer-gestures-unstable-v1",
"remote-shell-unstable-v1",
"secure-output-unstable-v1",
"stylus-tools-unstable-v1",
"stylus-unstable-v2",
"vsync-feedback-unstable-v1",
];
let out_dir = Path::new(&config.out_path);
protocols.par_iter().for_each(|e| {
let spec = Path::new("protocol").join(e).with_extension("xml");
let out = out_dir.join(e).with_extension("rs");
println!("cargo:rerun-if-changed={}", spec.to_str().unwrap());
generate_code_with_destructor_events(spec, out, Side::Server, &[("wl_callback", "done")]);
});
}
fn generate_protocol_code(config: &Config) -> Vec<String> {
let wp = "/usr/share/wayland-protocols";
let stable = ["viewporter", "presentation-time", "xdg-shell"];
let unstable = [
("input-method", 1),
("input-timestamps", 1),
("linux-dmabuf", 1),
("linux-explicit-synchronization", 1),
("xdg-output", 1),
("relative-pointer", 1),
("pointer-constraints", 1),
("fullscreen-shell", 1),
];
let internal = [
"wayland",
"weston-content-protection",
"weston-touch-calibration",
"weston-debug",
"weston-direct-display",
"text-cursor-position",
];
let protocols = stable
.iter()
.map(|name| {
(
format!("{}/stable/{}/{}.xml", wp, name, name),
format!("{}/{}", config.out_path, name),
)
})
.chain(unstable.iter().map(|(name, version)| {
(
format!(
"{}/unstable/{}/{}-unstable-v{}.xml",
wp, name, name, version
),
format!("{}/{}-unstable-v{}", config.out_path, name, version),
)
}))
.chain(internal.iter().map(|name| {
(
format!("protocol/{}.xml", name),
format!("{}/{}", config.out_path, name),
)
}));
fn generate(xml: &str, output: &str) -> String {
for (t, suffix) in [
("client-header", "client-protocol.h"),
("server-header", "server-protocol.h"),
("private-code", "protocol.c"),
] {
let output_file = format!("{}-{}", output, suffix);
Command::new("wayland-scanner")
.args([t, &xml, &output_file])
.status()
.unwrap();
}
format!("{}-protocol.c", output)
}
protocols
.map(|(xml, output)| generate(&xml, &output))
.collect()
}
struct Files {
files: Vec<String>,
}
impl Files {
fn new() -> Files {
Files { files: Vec::new() }
}
fn subdir<A: std::fmt::Display>(&mut self, prefix: &str, iter: impl IntoIterator<Item = A>) {
self.files
.extend(iter.into_iter().map(|f| format!("{}/{}", prefix, f)));
}
fn metadata(&self) {
for f in &self.files {
println!("cargo:rerun-if-changed={}", f);
}
}
}
fn build_libweston(config: &Config) {
generate_header_files(&config);
let protocol_c_files = generate_protocol_code(&config);
let mut builder = cc::Build::new();
let mut files = Files::new();
let mut deps = vec!["libdrm", "pixman-1", "xkbcommon", "libffi", "libpng"];
files.subdir(
"weston/libweston",
[
"animation.c",
"bindings.c",
"clipboard.c",
"compositor.c",
"content-protection.c",
"data-device.c",
"input.c",
"linux-dmabuf.c",
"linux-explicit-synchronization.c",
"linux-sync-file.c",
"log.c",
"noop-renderer.c",
"pixel-formats.c",
"pixman-renderer.c",
"plugin-registry.c",
"screenshooter.c",
"timeline.c",
"touch-calibration.c",
"weston-log-wayland.c",
"weston-log-file.c",
"weston-log-flight-rec.c",
"weston-log.c",
"weston-direct-display.c",
"zoom.c",
],
);
files.subdir(
"weston/shared",
[
"file-util.c",
"image-loader.c",
"matrix.c",
"os-compatibility.c",
],
);
// Internal wayland-server
files.subdir(
"wayland-server",
[
"wayland-server.c",
"wayland-shm.c",
"event-loop.c",
"connection.c",
"wayland-os.c",
"wayland-util.c",
],
);
#[cfg(feature = "wayland-backend")]
{
files.subdir("weston/libweston/backend-wayland", ["wayland.c"]);
files.subdir("weston/shared", ["frame.c", "cairo-util.c"]);
deps.extend(["wayland-client", "wayland-cursor", "cairo"])
}
#[cfg(feature = "drm-backend")]
{
files.subdir(
"weston/libweston/backend-drm",
&[
"drm.c",
"drm-gbm.c",
"fb.c",
"modes.c",
"kms.c",
"state-helpers.c",
"state-propose.c",
"libbacklight.c",
],
);
files.subdir(
"weston/libweston",
&[
"launcher-direct.c",
"launcher-util.c",
"launcher-weston-launch.c",
"libinput-device.c",
"libinput-seat.c",
"vertex-clipping.c",
],
);
files.subdir(
"weston/libweston/renderer-gl",
&["egl-glue.c", "gl-renderer.c"],
);
deps.extend(["libinput", "libevdev", "libudev", "gbm", "egl", "glesv2"]);
}
files.metadata();
builder
.cargo_metadata(false)
.files(files.files)
.files(protocol_c_files)
.extra_warnings(false)
.flag("-std=gnu99")
.include("weston/include")
.include("weston/libweston")
.include("weston")
.include(&config.out_path);
// builder.compile() normally prints these, but we need to list
// them now so that croscomp-libweston will appear before the
// pkg-config shared libraries on the link line.
println!("cargo:rustc-link-lib=static=croscomp-libweston");
println!("cargo:rustc-link-search=native={}", config.out_path);
for d in deps {
let lib = pkg_config::probe_library(d).unwrap();
lib.include_paths.iter().for_each(|item| {
builder.include(&item);
});
// TODO: fix ebuild and includes instead of loop above
//builder.includes(&lib.include_paths);
}
builder.compile("croscomp-libweston");
}
struct Config {
out_path: String,
data_dir: String,
}
fn main() {
let config = Config {
out_path: env::var("OUT_DIR").unwrap(),
data_dir: "/usr/share".to_string(),
};
build_libweston(&config);
run_bindgen("/usr/include/linux/input.h", "input.rs");
run_bindgen("./weston/croscomp_weston.h", "croscomp_weston.rs");
generate_rust_protocol_code(&config);
}