aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.toml2
-rw-r--r--build.rs21
-rw-r--r--src/lib.rs33
3 files changed, 56 insertions, 0 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 53943d1..d4f9960 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -10,7 +10,9 @@ categories = ["external-ffi-bindings"]
links = "tcl"
[dependencies]
+flate2 = "1.0.20"
libc = "0.2.94"
+tar = "0.4.33"
[build-dependencies]
bindgen = "0.58.1"
diff --git a/build.rs b/build.rs
index acbf264..8baa99f 100644
--- a/build.rs
+++ b/build.rs
@@ -199,6 +199,7 @@ fn main() {
generate_bindings(target.as_str(), host.as_str(), include_paths.as_slice());
link_tcl(target_os);
+ compress_stdlib(tcl_lib_path.join("tcl8.6"));
println!("cargo:rerun-if-changed=build.rs");
}
@@ -250,6 +251,26 @@ fn generate_bindings(target: &str, host: &str, headers_paths: &[String]) {
.expect("Couldn't write bindings!");
}
+fn compress_stdlib(stdlib_root: PathBuf) {
+ let out_dir = env::var("OUT_DIR").unwrap();
+ let tcl_stdlib_archive_path = Path::new(&out_dir).join("stdlib.tar.gz");
+ let writer = flate2::write::GzEncoder::new(
+ fs::File::create(tcl_stdlib_archive_path).unwrap(),
+ flate2::Compression::best(),
+ );
+ let mut ar = tar::Builder::new(writer);
+
+ for child in stdlib_root.read_dir().unwrap() {
+ let child = child.unwrap();
+ if child.path().is_dir() {
+ ar.append_dir_all(child.file_name(), child.path()).unwrap();
+ } else {
+ ar.append_path_with_name(child.path(), child.file_name())
+ .unwrap();
+ }
+ }
+}
+
fn get_os_from_triple(triple: &str) -> Option<&str> {
triple.splitn(3, "-").nth(2)
}
diff --git a/src/lib.rs b/src/lib.rs
index d403fbc..a1dfc93 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -4,6 +4,38 @@
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
+mod stdlib {
+ use std::env::current_exe;
+ use std::io;
+ use std::path::{Path, PathBuf};
+
+ const STDLIB_DATA: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/stdlib.tar.gz"));
+
+ /// Guess where tcl will look for the standard library (from the directory containing the current executable, ../lib/tcl8.6/).
+ pub fn guess_expected_stdlib_target() -> PathBuf {
+ let exe = current_exe().unwrap();
+ let exe_parent = exe.parent().unwrap();
+ let exe_parent_parent = exe_parent.parent().unwrap();
+ let exe_parent_parent_lib = exe_parent_parent.join("lib");
+ let expected_stdlib_path = exe_parent_parent_lib.join("tcl8.6");
+ expected_stdlib_path
+ }
+
+ /// Extract the built-in standard library to the given path, ignoring if already exists.
+ pub fn extract_stdlib_to(target: impl AsRef<Path>) -> io::Result<()> {
+ let reader = flate2::read::GzDecoder::new(STDLIB_DATA);
+ let mut ar = tar::Archive::new(reader);
+ ar.set_overwrite(false);
+ let result = ar.unpack(target);
+ match result {
+ Err(e) if e.kind() == io::ErrorKind::AlreadyExists => Ok(()),
+ x => x,
+ }
+ }
+}
+
+pub use stdlib::*;
+
#[cfg(test)]
mod tests {
use super::*;
@@ -12,6 +44,7 @@ mod tests {
#[test]
fn two_plus_two() {
unsafe {
+ extract_stdlib_to(guess_expected_stdlib_target()).unwrap();
let interp = Tcl_CreateInterp();
let init_status = Tcl_Init(interp);
if init_status == TCL_ERROR as i32 {