aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMelody Horn <melody@boringcactus.com>2021-10-29 20:19:57 -0600
committerMelody Horn <melody@boringcactus.com>2021-10-29 20:19:57 -0600
commit847135ed1e1e7322b63b0063be8e40d706c4954f (patch)
treedd26ddf0ed7cfb4b3b0a15d83a37e513467bcc95
downloadshit-wx-sys-847135ed1e1e7322b63b0063be8e40d706c4954f.tar.gz
shit-wx-sys-847135ed1e1e7322b63b0063be8e40d706c4954f.zip
oh my god
-rw-r--r--.gitignore2
-rw-r--r--Cargo.toml10
-rw-r--r--build.rs177
-rw-r--r--examples/hello-world.rs20
-rw-r--r--src/lib.rs9
-rw-r--r--wrapper.hpp1
6 files changed, 219 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..96ef6c0
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+/target
+Cargo.lock
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..3dd46f0
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "shit-wx-sys"
+version = "0.1.0"
+edition = "2021"
+
+[build-dependencies]
+anyhow = "1.0.44"
+bindgen = { version = "0.59.1" }
+ureq = "2.3.0"
+url = "2.2.2"
diff --git a/build.rs b/build.rs
new file mode 100644
index 0000000..f22e64f
--- /dev/null
+++ b/build.rs
@@ -0,0 +1,177 @@
+use std::env;
+use std::ffi::{OsStr, OsString};
+use std::fs;
+use std::io;
+use std::path::{Path, PathBuf};
+
+use anyhow::{anyhow, ensure, Result};
+use url::Url;
+
+// there's probably a crate for this somewhere
+fn os_concat(a: impl AsRef<OsStr>, b: impl AsRef<OsStr>) -> OsString {
+ let mut result = OsString::from(&a);
+ result.push(b);
+ result
+}
+
+fn out_dir() -> PathBuf {
+ PathBuf::from(env::var_os("OUT_DIR").expect("no OUT_DIR found"))
+}
+
+fn download(url: &str) -> Result<PathBuf> {
+ let url = Url::parse(url)?;
+ let file_name = url
+ .path_segments()
+ .and_then(|x| x.last())
+ .ok_or_else(|| anyhow!("Weird URL downloaded"))?;
+ let out_path = out_dir().join(file_name);
+ if !out_path.exists() {
+ let mut body_reader = ureq::request_url("GET", &url).call()?.into_reader();
+ let mut out_file = fs::File::create(&out_path)?;
+ io::copy(&mut body_reader, &mut out_file)?;
+ }
+ Ok(out_path)
+}
+
+fn un7z(archive: PathBuf) -> Result<()> {
+ // WARNING: This code is horrifying and also bad.
+ // It should never be used by anyone.
+ // TODO port the 7zip LZMA SDK to Rust
+ use std::process::{Command, Stdio};
+ let my_7z_exe = Path::new(r"C:\Program Files\7-Zip\7z.exe");
+ ensure!(my_7z_exe.exists());
+ let output_folder = archive
+ .parent()
+ .ok_or_else(|| anyhow!("archive with no parent"))?;
+ let output_folder_arg = os_concat("-o", &output_folder);
+ let extract_result = Command::new(my_7z_exe)
+ .args(["x", "-aos"])
+ .arg(output_folder_arg)
+ .arg(&archive)
+ .stdin(Stdio::null())
+ .stdout(Stdio::null())
+ .status()?;
+ ensure!(extract_result.success());
+ Ok(())
+}
+
+fn main() -> Result<()> {
+ println!("cargo:rerun-if-changed=build.rs");
+ let target = env::var("TARGET").expect("no TARGET found");
+
+ match target.as_str() {
+ "x86_64-pc-windows-msvc" => build_x64_windows_msvc(),
+ _ => panic!("unsupported target: {}", target),
+ }
+}
+
+/*
+ <Choose>
+ <When Condition="Exists('lib\vc14x_x64_dll\wxbase31$(wxSuffix).lib')">
+ <PropertyGroup Label="UserMacros">
+ <wxUsingVersionABICompat>1</wxUsingVersionABICompat>
+ <wxUsingDll>1</wxUsingDll>
+ <wxLibOrDllDir>lib\vc14x_x64_dll</wxLibOrDllDir>
+ </PropertyGroup>
+ </When>
+
+ <When Condition="Exists('lib\vc14x_x64_lib\wxbase31$(wxSuffix).lib')">
+ <PropertyGroup Label="UserMacros">
+ <wxUsingVersionABICompat>1</wxUsingVersionABICompat>
+ <wxUsingLib>1</wxUsingLib>
+ <wxLibOrDllDir>lib\vc14x_x64_lib</wxLibOrDllDir>
+ </PropertyGroup>
+ </When>
+ </Choose>
+*/
+
+fn build_x64_windows_msvc() -> Result<()> {
+ let headers = download("https://github.com/wxWidgets/wxWidgets/releases/download/v3.1.5/wxWidgets-3.1.5-headers.7z")?;
+ un7z(headers)?;
+
+ // TODO make sure VS2015+ is actually the right thing
+ let libs = download("https://github.com/wxWidgets/wxWidgets/releases/download/v3.1.5/wxMSW-3.1.5_vc14x_x64_Dev.7z")?;
+ un7z(libs)?;
+
+ let out_dir = out_dir();
+
+ // TODO consider actually parsing wxwidgets.props at build time instead of doing it manually
+ // TODO bindgen ahead of time
+ // TODO can we really get away with this to do static linking
+ let wx_using_lib = true;
+ if wx_using_lib {
+ let dll_folder = out_dir.join("lib/vc14x_x64_dll");
+ let lib_folder = out_dir.join("lib/vc14x_x64_lib");
+ if dll_folder.exists() && !lib_folder.exists() {
+ fs::rename(dll_folder, lib_folder)?;
+ }
+ }
+ let libs_folder = out_dir.join(if wx_using_lib {
+ "lib/vc14x_x64_lib"
+ } else {
+ "lib/vc14x_x64_dll"
+ });
+ let wx_using_dll = !wx_using_lib;
+ let debug = env::var("PROFILE")? == "release";
+ let wx_suffix = if debug { "u" } else { "ud" };
+ let mut defines = vec![
+ "__WXMSW__",
+ "wxMSVC_VERSION_AUTO",
+ "wxMSVC_VERSION_ABI_COMPAT",
+ "_UNICODE",
+ ];
+ if debug {
+ defines.push("_DEBUG");
+ }
+ if wx_using_dll {
+ defines.push("WXUSINGDLL");
+ }
+
+ let mut include_dirs = vec![out_dir.join("include/msvc"), out_dir.join("include")];
+ // TODO this is only in ResourceCompile in wxwidgets.props, is that bad
+ include_dirs.push(libs_folder.join(format!("msw{}", wx_suffix)));
+ let bindings = bindgen::Builder::default()
+ .header("wrapper.hpp")
+ // pain
+ .clang_arg("-Wno-invalid-token-paste")
+ .clang_args(defines.iter().map(|x| format!("-D{}", x)))
+ // TODO don't .display()
+ .clang_args(include_dirs.iter().map(|x| format!("-I{}", x.display())))
+ .opaque_type("std::.*")
+ // pain 2: the sequel to pain
+ .blocklist_type("CharType")
+ .blocklist_type("value_type")
+ .blocklist_type("const_reference")
+ // pain 3: the shriequel to pain
+ .blocklist_type("wxBaseArray_CMPFUNC")
+ .blocklist_type("wxBaseObjectArray")
+ .blocklist_type("wxBaseObjectArray_base")
+ .blocklist_type("pointer")
+ .blocklist_type("const_pointer")
+ .blocklist_type("wxBaseObjectArrayForwxDateTimeArray")
+ .blocklist_type("wxBaseObjectArrayForwxIconArray")
+ .blocklist_type("wxBaseObjectArrayForwxStatusBarPaneArray")
+ .opaque_type("_IMAGE_TLS_DIRECTORY64")
+ // that's enough pain? maybe?
+ .generate()
+ .map_err(|_| anyhow!("failed to generate bindings"))?;
+ let out_path = out_dir.join("bindings.rs");
+ bindings.write_to_file(&out_path)?;
+
+ let win32_libs = [
+ "kernel32", "user32", "gdi32", "comdlg32", "winspool", "shell32", "shlwapi", "ole32",
+ "oleaut32", "uuid", "advapi32", "version", "comctl32", "rpcrt4", "wsock32", "wininet",
+ "winmm",
+ ];
+ for lib in win32_libs {
+ // TODO dylib or static
+ println!("cargo:rustc-link-lib={}", lib);
+ }
+ // TODO is "native=" the right thing there (or display() for that matter)
+ println!("cargo:rustc-link-search=native={}", libs_folder.display());
+
+ // TODO which libs do we actually want to link
+ println!("cargo:rustc-link-lib=static=wxbase31{}", wx_suffix);
+ println!("cargo:rustc-link-lib=static=wxmsw31{}_core", wx_suffix);
+ Ok(())
+}
diff --git a/examples/hello-world.rs b/examples/hello-world.rs
new file mode 100644
index 0000000..fb15d85
--- /dev/null
+++ b/examples/hello-world.rs
@@ -0,0 +1,20 @@
+use std::ffi::CString;
+
+use shit_wx_sys::*;
+
+fn main() {
+ unsafe {
+ let message = "It's alive!!";
+ let c_string_message = CString::new(message).unwrap();
+ let message =
+ wxString::FromAscii(c_string_message.as_ptr(), message.len().try_into().unwrap());
+ wxMessageBox(
+ (&message) as *const wxString,
+ (&message) as *const wxString,
+ (wxOK as i32) | wxGeometryCentre_wxCENTER,
+ NULL as *mut wxWindow,
+ wxDefaultCoord,
+ wxDefaultCoord,
+ );
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..dca544b
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,9 @@
+#![allow(
+ non_camel_case_types,
+ non_snake_case,
+ unaligned_references,
+ non_upper_case_globals,
+ deref_nullptr
+)]
+
+include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
diff --git a/wrapper.hpp b/wrapper.hpp
new file mode 100644
index 0000000..2c9356c
--- /dev/null
+++ b/wrapper.hpp
@@ -0,0 +1 @@
+#include <wx/wx.h>