From b0eaef3dbec85b2d50db6c250ce3def2a913cc00 Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Thu, 17 Jun 2021 10:07:15 -0400 Subject: [PATCH] Switch to dev-time rather than build-time cbindgen Following up on #788, my no-network workaround seemed to work OK, but then I ran into problems with `cargo metadata` wanting to create a Cargo.lock file in a read-only filesystem. I don't see any way to prevent the cbindgen build.rs invocation from triggering this. But ... we can just use cbindgen as a standalone tool and save the generated headers in the repo. I liked the idea of doing things on-the-fly in build.rs, but I can't think of any reason that we *have* to, and the dev-time approach is faster and simpler, and it turns out that it also solves out docs.rs problems. So it's a pretty clear decision. Also, I don't expect these generated headers to vary often. But I documented how to regenerate them in their respective crate READMEs. --- Cargo.lock | 24 -- crates/bridge_core/Cargo.toml | 1 - crates/bridge_core/README.md | 12 + crates/bridge_core/build.rs | 82 +---- crates/bridge_core/cbindgen.toml | 20 + .../support/tectonic_bridge_core_generated.h | 341 ++++++++++++++++++ crates/bridge_flate/Cargo.toml | 2 - crates/bridge_flate/README.md | 12 + crates/bridge_flate/build.rs | 41 +-- crates/bridge_flate/cbindgen.toml | 7 + .../include/tectonic_bridge_flate.h | 105 ++++++ crates/engine_bibtex/Cargo.toml | 1 - crates/engine_bibtex/README.md | 12 + crates/engine_bibtex/bibtex/bibtex_bindings.h | 33 ++ crates/engine_bibtex/build.rs | 47 +-- crates/engine_bibtex/cbindgen.toml | 10 + crates/engine_xdvipdfmx/Cargo.toml | 1 - crates/engine_xdvipdfmx/README.md | 12 + crates/engine_xdvipdfmx/build.rs | 48 +-- crates/engine_xdvipdfmx/cbindgen.toml | 10 + .../xdvipdfmx/xdvipdfmx_bindings.h | 29 ++ crates/engine_xetex/Cargo.toml | 1 - crates/engine_xetex/README.md | 12 + crates/engine_xetex/build.rs | 48 +-- crates/engine_xetex/cbindgen.toml | 10 + crates/engine_xetex/src/lib.rs | 3 + crates/engine_xetex/xetex/xetex-ini.c | 2 +- crates/engine_xetex/xetex/xetex_bindings.h | 36 ++ 28 files changed, 689 insertions(+), 273 deletions(-) create mode 100644 crates/bridge_core/cbindgen.toml create mode 100644 crates/bridge_core/support/tectonic_bridge_core_generated.h create mode 100644 crates/bridge_flate/cbindgen.toml create mode 100644 crates/bridge_flate/include/tectonic_bridge_flate.h create mode 100644 crates/engine_bibtex/bibtex/bibtex_bindings.h create mode 100644 crates/engine_bibtex/cbindgen.toml create mode 100644 crates/engine_xdvipdfmx/cbindgen.toml create mode 100644 crates/engine_xdvipdfmx/xdvipdfmx/xdvipdfmx_bindings.h create mode 100644 crates/engine_xetex/cbindgen.toml create mode 100644 crates/engine_xetex/xetex/xetex_bindings.h diff --git a/Cargo.lock b/Cargo.lock index cbc349075f..ad96ac154c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -187,25 +187,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" -[[package]] -name = "cbindgen" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9344318b9c787667b95cd2c5124f5eaf2bde35e959dd01ea04fc5b234c542c11" -dependencies = [ - "clap", - "heck", - "indexmap", - "log", - "proc-macro2", - "quote", - "serde", - "serde_json", - "syn", - "tempfile", - "toml", -] - [[package]] name = "cc" version = "1.0.68" @@ -2146,7 +2127,6 @@ dependencies = [ name = "tectonic_bridge_core" version = "0.0.0-dev.0" dependencies = [ - "cbindgen", "cc", "flate2", "lazy_static", @@ -2161,7 +2141,6 @@ dependencies = [ name = "tectonic_bridge_flate" version = "0.0.0-dev.0" dependencies = [ - "cbindgen", "flate2", "libc", ] @@ -2238,7 +2217,6 @@ dependencies = [ name = "tectonic_engine_bibtex" version = "0.0.0-dev.0" dependencies = [ - "cbindgen", "cc", "libc", "tectonic_bridge_core", @@ -2249,7 +2227,6 @@ dependencies = [ name = "tectonic_engine_xdvipdfmx" version = "0.0.0-dev.0" dependencies = [ - "cbindgen", "cc", "libc", "tectonic_bridge_core", @@ -2261,7 +2238,6 @@ dependencies = [ name = "tectonic_engine_xetex" version = "0.0.0-dev.0" dependencies = [ - "cbindgen", "cc", "libc", "tectonic_bridge_core", diff --git a/crates/bridge_core/Cargo.toml b/crates/bridge_core/Cargo.toml index 0744c5b65b..94264664cc 100644 --- a/crates/bridge_core/Cargo.toml +++ b/crates/bridge_core/Cargo.toml @@ -28,7 +28,6 @@ tectonic_io_base = { path = "../io_base", version = "0.0.0-dev.0" } tectonic_status_base = { path = "../status_base", version = "0.0.0-dev.0" } [build-dependencies] -cbindgen = "^0.16" cc = "^1.0.66" [package.metadata.internal_dep_versions] diff --git a/crates/bridge_core/README.md b/crates/bridge_core/README.md index 06dbc3f3c1..cb511e48e5 100644 --- a/crates/bridge_core/README.md +++ b/crates/bridge_core/README.md @@ -31,3 +31,15 @@ use tectonic_bridge_core; This crate does not currently provide any [Cargo features][features]. [features]: https://doc.rust-lang.org/cargo/reference/features.html + + +## Updating the generated header + +This crate exposes Rust functions to C/C++ code using a header file created by +[cbindgen]. To update the header, run: + +[cbindgen]: https://github.com/eqrion/cbindgen/ + +```sh +cbindgen --output support/tectonic_bridge_core_generated.h +``` diff --git a/crates/bridge_core/build.rs b/crates/bridge_core/build.rs index cb88150007..6ba5b4b81f 100644 --- a/crates/bridge_core/build.rs +++ b/crates/bridge_core/build.rs @@ -4,87 +4,25 @@ use std::{env, path::PathBuf}; fn main() { - let outdir = env::var("OUT_DIR").unwrap(); + let manifest_dir: PathBuf = env::var("CARGO_MANIFEST_DIR").unwrap().into(); - // Cargo exposes this as the environment variable DEP_XXX_INCLUDE, where XXX - // is the "links" setting in Cargo.toml. This is the key element that allows - // us to have a network of crates containing both C/C++ and Rust code that - // all interlink. - println!("cargo:include={}", outdir); - - // cbindgen to generate the C header from our Rust code. - - let mut gen_header_path: PathBuf = outdir.clone().into(); - gen_header_path.push("tectonic_bridge_core_generated.h"); - - println!("cargo:rerun-if-changed=src/lib.rs"); - - let mut config = cbindgen::Config { - cpp_compat: true, - ..Default::default() - }; - config.enumeration.prefix_with_name = true; - - let mut manifest_dir: PathBuf = env::var("CARGO_MANIFEST_DIR").unwrap().into(); - - // 2021 June: work around https://github.com/tectonic-typesetting/tectonic/issues/788 - if env::var_os("DOCS_RS").is_some() { - env::set_var("CARGO_NET_OFFLINE", "true"); - } - - cbindgen::Builder::new() - .with_config(config) - .with_crate(&manifest_dir) - .with_language(cbindgen::Language::C) - .with_include_guard("TECTONIC_BRIDGE_CORE_GENERATED_H") - .with_style(cbindgen::Style::Type) - .with_after_include( - " -typedef struct ttbc_input_handle_t ttbc_input_handle_t; -typedef struct ttbc_output_handle_t ttbc_output_handle_t; - -typedef ttbc_input_handle_t *rust_input_handle_t; -typedef ttbc_output_handle_t *rust_output_handle_t;", - ) - .rename_item("CoreBridgeState", "ttbc_state_t") - .rename_item("Diagnostic", "ttbc_diagnostic_t") - .rename_item("FileFormat", "ttbc_file_format") - .rename_item("InputHandle", "ttbc_input_handle_t") - .rename_item("OutputHandle", "ttbc_output_handle_t") - .generate() - .expect("Unable to generate bindings") - .write_to_file(&gen_header_path); - - // Copy the static header file for C preprocessing convenience. - - let mut main_header_src = manifest_dir.clone(); + let mut main_header_src = manifest_dir; main_header_src.push("support"); - main_header_src.push("tectonic_bridge_core.h"); - - let mut main_header_dest = PathBuf::from(outdir.clone()); - main_header_dest.push("tectonic_bridge_core.h"); - - std::fs::copy(&main_header_src, &main_header_dest).expect("failed to copy main header"); - - println!("cargo:rerun-if-changed=support/tectonic_bridge_core.h"); - - // Now that we have that, we can compile our C support code. let mut build = cc::Build::new(); build .warnings(true) .file("support/support.c") - .include(&outdir) + .include(&main_header_src) .compile("libtectonic_bridge_core.a"); println!("cargo:rerun-if-changed=support/support.c"); + println!("cargo:rerun-if-changed=support/tectonic_bridge_core.h"); + println!("cargo:rerun-if-changed=support/tectonic_bridge_core_generated.h"); - // Workaround so that we can `cargo package` this crate. Cf - // https://github.com/eqrion/cbindgen/issues/560 . cbindgen calls `cargo - // metadata` which creates a new Cargo.lock file when building this crate as - // part of its packaging process. This isn't noticed in regular builds since - // they occur in a workspace context. Lame but effective solution: - // unconditionally blow away the file. - manifest_dir.push("Cargo.lock"); - let _ignored = std::fs::remove_file(&manifest_dir); + // Cargo exposes this as the environment variable DEP_XXX_INCLUDE, where XXX + // is the "links" setting in Cargo.toml. This is the key element that allows + // us to have a network of crates containing both C/C++ and Rust code that + // all interlink. + println!("cargo:include={}", main_header_src.display()); } diff --git a/crates/bridge_core/cbindgen.toml b/crates/bridge_core/cbindgen.toml new file mode 100644 index 0000000000..a8d0d8fee4 --- /dev/null +++ b/crates/bridge_core/cbindgen.toml @@ -0,0 +1,20 @@ +language = "C" +cpp_compat = true +style = "type" +include_guard = "TECTONIC_BRIDGE_CORE_GENERATED_H" +after_includes = """ +typedef struct ttbc_input_handle_t ttbc_input_handle_t; +typedef struct ttbc_output_handle_t ttbc_output_handle_t; +typedef ttbc_input_handle_t *rust_input_handle_t; +typedef ttbc_output_handle_t *rust_output_handle_t; +""" + +[enum] +prefix_with_name = true + +[export.rename] +"CoreBridgeState" = "ttbc_state_t" +"Diagnostic" = "ttbc_diagnostic_t" +"FileFormat" = "ttbc_file_format" +"InputHandle" = "ttbc_input_handle_t" +"OutputHandle" = "ttbc_output_handle_t" \ No newline at end of file diff --git a/crates/bridge_core/support/tectonic_bridge_core_generated.h b/crates/bridge_core/support/tectonic_bridge_core_generated.h new file mode 100644 index 0000000000..b059be84dd --- /dev/null +++ b/crates/bridge_core/support/tectonic_bridge_core_generated.h @@ -0,0 +1,341 @@ +#ifndef TECTONIC_BRIDGE_CORE_GENERATED_H +#define TECTONIC_BRIDGE_CORE_GENERATED_H + +#include +#include +#include +#include +typedef struct ttbc_input_handle_t ttbc_input_handle_t; +typedef struct ttbc_output_handle_t ttbc_output_handle_t; +typedef ttbc_input_handle_t *rust_input_handle_t; +typedef ttbc_output_handle_t *rust_output_handle_t; + + +/** + * Different types of files that can be opened by TeX engines + * + * This enumeration is used to guess filename extensions to try when looking + * for a file to open. + * + */ +typedef enum { + /** + * An Adobe Font Metrics file. + */ + TTBC_FILE_FORMAT_AFM = 4, + /** + * A BibTeX bibliography data file. + */ + TTBC_FILE_FORMAT_BIB = 6, + /** + * A BibTeX style file. + */ + TTBC_FILE_FORMAT_BST = 7, + /** + * A character map data file. + */ + TTBC_FILE_FORMAT_CMAP = 45, + /** + * A configuration file. + */ + TTBC_FILE_FORMAT_CNF = 8, + /** + * An encoding data file. + */ + TTBC_FILE_FORMAT_ENC = 44, + /** + * A TeX "format" file. + */ + TTBC_FILE_FORMAT_FORMAT = 10, + /** + * A font-map file. + */ + TTBC_FILE_FORMAT_FONT_MAP = 11, + /** + * A miscellaneous font file. + */ + TTBC_FILE_FORMAT_MISC_FONTS = 41, + /** + * An OFM font metrics file. + */ + TTBC_FILE_FORMAT_OFM = 20, + /** + * An OpenType font file. + */ + TTBC_FILE_FORMAT_OPEN_TYPE = 47, + /** + * An OVF file. + */ + TTBC_FILE_FORMAT_OVF = 23, + /** + * An image file. + */ + TTBC_FILE_FORMAT_PICT = 25, + /** + * A PK font file. + */ + TTBC_FILE_FORMAT_PK = 1, + /** + * A general program data file. + */ + TTBC_FILE_FORMAT_PROGRAM_DATA = 39, + /** + * An SFD file. + */ + TTBC_FILE_FORMAT_SFD = 46, + /** + * The Tectonic primary input file. + */ + TTBC_FILE_FORMAT_TECTONIC_PRIMARY = 59, + /** + * A TeX language file. + */ + TTBC_FILE_FORMAT_TEX = 26, + /** + * A TeX PostScript header file. + */ + TTBC_FILE_FORMAT_TEX_PS_HEADER = 30, + /** + * A TeX Font Metrics file. + */ + TTBC_FILE_FORMAT_TFM = 3, + /** + * A TrueType font file. + */ + TTBC_FILE_FORMAT_TRUE_TYPE = 36, + /** + * A Type1 font file. + */ + TTBC_FILE_FORMAT_TYPE1 = 32, + /** + * A Virtual Font file. + */ + TTBC_FILE_FORMAT_VF = 33, +} ttbc_file_format; + +/** + * The CoreBridgeState structure is a handle to Rust state that can be used by + * C/C++ engine code to perform basic I/O functions. + * + * Code that invokes a Tectonic C/C++ engine should pass a pointer to one of + * these state structures into the C/C++ layer. It is essential that lifetimes + * be properly managed across the Rust/C boundary. + */ +typedef struct ttbc_state_t ttbc_state_t; + +/** + * A buffer for diagnostic messages. Rust code does not need to use this type. + * + * This type has to be public so that it can be exposed in the C/C++ headers, + * but it doesn't provide any useful functionality on the Rust side. + */ +typedef struct ttbc_diagnostic_t ttbc_diagnostic_t; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +extern const char *_ttbc_get_error_message(void); + +/** + * Issue a warning. + * + * # Safety + * + * This function is unsafe because it accepts a raw C string. + */ +void ttbc_issue_warning(ttbc_state_t *es, const char *text); + +/** + * Issue an error. + * + * # Safety + * + * This function is unsafe because it accepts a raw C string. + */ +void ttbc_issue_error(ttbc_state_t *es, const char *text); + +/** + * Calculate the MD5 digest of a Tectonic file. + * + * # Safety + * + * This function is unsafe because it dereferences raw pointers from C. + */ +int ttbc_get_file_md5(ttbc_state_t *es, const char *path, uint8_t *digest); + +/** + * Calculate the MD5 digest of a block of binary data. + * + * This actually doesn't rely on the state and isn't really I/O, but we also + * have a get-file-MD5 routine so it's convenient to have this here. + * + * # Safety + * + * This function is unsafe because it dereferences raw pointers from C. + */ +int ttbc_get_data_md5(const uint8_t *data, size_t len, uint8_t *digest); + +/** + * Open a Tectonic file for output. + * + * # Safety + * + * This function is unsafe because it accepts a raw C string. + */ +ttbc_output_handle_t *ttbc_output_open(ttbc_state_t *es, const char *name, int is_gz); + +/** + * Open the general user output stream as a Tectonic output file. + */ +ttbc_output_handle_t *ttbc_output_open_stdout(ttbc_state_t *es); + +/** + * Write a single character to a Tectonic output file. + */ +int ttbc_output_putc(ttbc_state_t *es, ttbc_output_handle_t *handle, int c); + +/** + * Write data to a Tectonic output file. + * + * # Safety + * + * This function is unsafe because it dereferences raw C pointers. + */ +size_t ttbc_output_write(ttbc_state_t *es, + ttbc_output_handle_t *handle, + const uint8_t *data, + size_t len); + +/** + * Flush pending writes to a Tectonic output file. + */ +int ttbc_output_flush(ttbc_state_t *es, ttbc_output_handle_t *handle); + +/** + * Close a Tectonic output file. + */ +int ttbc_output_close(ttbc_state_t *es, ttbc_output_handle_t *handle); + +/** + * Open a Tectonic file for input. + * + * # Safety + * + * This function is unsafe because it accepts a raw C string. + */ +ttbc_input_handle_t *ttbc_input_open(ttbc_state_t *es, + const char *name, + ttbc_file_format format, + int is_gz); + +/** + * Open the "primary input" file. + */ +ttbc_input_handle_t *ttbc_input_open_primary(ttbc_state_t *es); + +/** + * Get the filesystem path of the most-recently-opened input file. + * + * This function is needed by SyncTeX, because its output file should contain + * absolute filesystem paths to the input source files. In principle this + * functionality could be implemented in a few different ways, but the approach + * used here is the most backward-compatible. This function will fill in the + * caller's buffer with the filesystem path associated with the most + * recently-opened input file, including a terminating NUL, if possible. + * + * It returns 0 if no such path is known, -1 if the path cannot be expressed + * UTF-8, -2 if the destination buffer is not big enough, or the number of + * bytes written into the buffer (including a terminating NUL) otherwise. + * + * # Safety + * + * This function is unsafe because it dereferences raw C pointers. + */ +ssize_t ttbc_get_last_input_abspath(ttbc_state_t *es, uint8_t *buffer, size_t len); + +/** + * Get the size of a Tectonic input file. + */ +size_t ttbc_input_get_size(ttbc_state_t *es, ttbc_input_handle_t *handle); + +/** + * Get the modification time of a Tectonic input file. + */ +time_t ttbc_input_get_mtime(ttbc_state_t *es, ttbc_input_handle_t *handle); + +/** + * Seek in a Tectonic input stream. + * + * # Safety + * + * This function is unsafe because it dereferences raw pointers from C. + */ +size_t ttbc_input_seek(ttbc_state_t *es, + ttbc_input_handle_t *handle, + ssize_t offset, + int whence, + int *internal_error); + +/** + * Get a single character from a Tectonic input file. + */ +int ttbc_input_getc(ttbc_state_t *es, ttbc_input_handle_t *handle); + +/** + * Put back a character that was obtained from a `getc` call. + */ +int ttbc_input_ungetc(ttbc_state_t *es, ttbc_input_handle_t *handle, int ch); + +/** + * Read data from a Tectonic input handle + * + * # Safety + * + * This function is unsafe because it dereferences raw C pointers. + */ +ssize_t ttbc_input_read(ttbc_state_t *es, ttbc_input_handle_t *handle, uint8_t *data, size_t len); + +/** + * Close a Tectonic input file. + */ +int ttbc_input_close(ttbc_state_t *es, ttbc_input_handle_t *handle); + +/** + * Create a new diagnostic that will be reported as a warning. + */ +ttbc_diagnostic_t *ttbc_diag_begin_warning(void); + +/** + * Create a new diagnostic that will be reported as an error. + */ +ttbc_diagnostic_t *ttbc_diag_begin_error(void); + +/** + * Append text to a diagnostic. + * + * # Safety + * + * This function is unsafe because it accepts a raw C string. + */ +void ttbc_diag_append(ttbc_diagnostic_t *diag, const char *text); + +/** + * "Finish" a diagnostic: report it to the driver and free the diagnostic object. + */ +void ttbc_diag_finish(ttbc_state_t *es, ttbc_diagnostic_t *diag); + +/** + * Run a shell command + * + * # Safety + * + * This function is unsafe because it dereferences raw pointers from C and accepts a raw C string. + */ +int ttbc_shell_escape(ttbc_state_t *es, const uint16_t *cmd, size_t len); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif /* TECTONIC_BRIDGE_CORE_GENERATED_H */ diff --git a/crates/bridge_flate/Cargo.toml b/crates/bridge_flate/Cargo.toml index d53d2e6521..b5c1971e36 100644 --- a/crates/bridge_flate/Cargo.toml +++ b/crates/bridge_flate/Cargo.toml @@ -22,5 +22,3 @@ links = "tectonic_bridge_flate" flate2 = { version = "^1.0", default-features = false, features = ["zlib"] } libc = "^0.2" -[build-dependencies] -cbindgen = "^0.16" diff --git a/crates/bridge_flate/README.md b/crates/bridge_flate/README.md index ee994678ef..b606864060 100644 --- a/crates/bridge_flate/README.md +++ b/crates/bridge_flate/README.md @@ -37,3 +37,15 @@ libz here as well. Once the linking framework is built up, it will become possible to allow for more flexibility in this area. [features]: https://doc.rust-lang.org/cargo/reference/features.html + + +## Updating the generated header + +This crate exposes Rust functions to C/C++ code using a header file created by +[cbindgen]. To update the header, run: + +[cbindgen]: https://github.com/eqrion/cbindgen/ + +```sh +cbindgen --output include/tectonic_bridge_flate.h +``` diff --git a/crates/bridge_flate/build.rs b/crates/bridge_flate/build.rs index ee5c40fdfe..d22aef820e 100644 --- a/crates/bridge_flate/build.rs +++ b/crates/bridge_flate/build.rs @@ -4,45 +4,14 @@ use std::{env, path::PathBuf}; fn main() { - let outdir = env::var("OUT_DIR").unwrap(); + let manifest_dir: PathBuf = env::var("CARGO_MANIFEST_DIR").unwrap().into(); + + let mut include_dir = manifest_dir; + include_dir.push("include"); // Cargo exposes this as the environment variable DEP_XXX_INCLUDE, where XXX // is the "links" setting in Cargo.toml. This is the key element that allows // us to have a network of crates containing both C/C++ and Rust code that // all interlink. - println!("cargo:include={}", outdir); - - let mut header_path: PathBuf = outdir.into(); - header_path.push("tectonic_bridge_flate.h"); - - let mut config = cbindgen::Config { - cpp_compat: true, - ..Default::default() - }; - config.enumeration.prefix_with_name = true; - - let mut manifest_dir: PathBuf = env::var("CARGO_MANIFEST_DIR").unwrap().into(); - - // 2021 June: work around https://github.com/tectonic-typesetting/tectonic/issues/788 - if env::var_os("DOCS_RS").is_some() { - env::set_var("CARGO_NET_OFFLINE", "true"); - } - - cbindgen::Builder::new() - .with_config(config) - .with_crate(&manifest_dir) - .with_language(cbindgen::Language::C) - .with_include_guard("TECTONIC_BRIDGE_FLATE_H") - .generate() - .expect("Unable to generate bindings") - .write_to_file(&header_path); - - // Workaround so that we can `cargo package` this crate. Cf - // https://github.com/eqrion/cbindgen/issues/560 . cbindgen calls `cargo - // metadata` which creates a new Cargo.lock file when building this crate as - // part of its packaging process. This isn't noticed in regular builds since - // they occur in a workspace context. Lame but effective solution: - // unconditionally blow away the file. - manifest_dir.push("Cargo.lock"); - let _ignored = std::fs::remove_file(&manifest_dir); + println!("cargo:include={}", include_dir.display()); } diff --git a/crates/bridge_flate/cbindgen.toml b/crates/bridge_flate/cbindgen.toml new file mode 100644 index 0000000000..48f1bc0f45 --- /dev/null +++ b/crates/bridge_flate/cbindgen.toml @@ -0,0 +1,7 @@ +language = "C" +cpp_compat = true +style = "type" +include_guard = "TECTONIC_BRIDGE_FLATE_H" + +[enum] +prefix_with_name = true diff --git a/crates/bridge_flate/include/tectonic_bridge_flate.h b/crates/bridge_flate/include/tectonic_bridge_flate.h new file mode 100644 index 0000000000..0b2b40c2c6 --- /dev/null +++ b/crates/bridge_flate/include/tectonic_bridge_flate.h @@ -0,0 +1,105 @@ +#ifndef TECTONIC_BRIDGE_FLATE_H +#define TECTONIC_BRIDGE_FLATE_H + +#include +#include +#include +#include + +/** + * Outcomes of (de)flate operations. + */ +typedef enum { + /** + * The operation succeeded. + */ + FlateResult_Success = 0, + /** + * The operation succeeded and encountered the end of the input. + */ + FlateResult_StreamEnd = 1, + /** + * The operation failed because a buffer was not big enough or full enough. + */ + FlateResult_BufError = -1, + /** + * The operation failed due to an error other than the ones enumerated + * here. + */ + FlateResult_OtherError = -2, +} FlateResult; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** + * Compress a block of data. This function maps fairly directly onto the + * `Compress::compress` function provided by `flate2`. + * + * Returns nonzero on error. + * + * # Safety + * + * This is a C API function, so it is unsafe. + */ +FlateResult tectonic_flate_compress(uint8_t *output_ptr, + uint64_t *output_len, + const uint8_t *input_ptr, + uint64_t input_len, + uint32_t compression_level); + +/** + * Deompress a block of data. This function maps fairly directly onto the + * `Decompress::decompress` function provided by `flate2`. + * + * Returns nonzero on error. + * + * # Safety + * + * This is a C API function, so it is unsafe. + */ +FlateResult tectonic_flate_decompress(uint8_t *output_ptr, + uint64_t *output_len, + const uint8_t *input_ptr, + uint64_t input_len); + +/** + * Allocate a new DEFLATE decompressor. + * + * # Safety + * + * This is a C API function, so it is unsafe. + */ +void *tectonic_flate_new_decompressor(const uint8_t *input_ptr, uint64_t input_len); + +/** + * Decompress some DEFLATEd data. + * + * After calling this function, the `input_len` parameter is rewritten with the + * total number of bytes of compressed data that have been read. The + * `output_len` parameter is rewritten with the total number of bytes of + * decompressed data that have been written. + * + * Returns nonzero on error. + * + * # Safety + * + * This is a C API function, so it is unsafe. + */ +int tectonic_flate_decompress_chunk(void *handle, uint8_t *output_ptr, uint64_t *output_len); + +/** + * Deallocate a DEFLATE decompressor. + * + * # Safety + * + * This is a C API function, so it is unsafe. + */ +void tectonic_flate_free_decompressor(void *handle); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif /* TECTONIC_BRIDGE_FLATE_H */ diff --git a/crates/engine_bibtex/Cargo.toml b/crates/engine_bibtex/Cargo.toml index 452f2bc8bf..bcfbcb536f 100644 --- a/crates/engine_bibtex/Cargo.toml +++ b/crates/engine_bibtex/Cargo.toml @@ -24,7 +24,6 @@ tectonic_bridge_core = { path = "../bridge_core", version = "0.0.0-dev.0" } tectonic_errors = { path = "../errors", version = "0.0.0-dev.0" } [build-dependencies] -cbindgen = "^0.16" cc = "^1.0.66" [package.metadata.internal_dep_versions] diff --git a/crates/engine_bibtex/README.md b/crates/engine_bibtex/README.md index 1503d441d6..ffb8872b7a 100644 --- a/crates/engine_bibtex/README.md +++ b/crates/engine_bibtex/README.md @@ -17,3 +17,15 @@ project](https://tectonic-typesetting.github.io/en-US/). It provides the This crate does not currently provides any [Cargo features][features]. [features]: https://doc.rust-lang.org/cargo/reference/features.html + + +## Updating the generated header + +This crate exposes Rust functions to C/C++ code using a header file created by +[cbindgen]. To update the header, run: + +[cbindgen]: https://github.com/eqrion/cbindgen/ + +```sh +cbindgen --output bibtex/bibtex_bindings.h +``` diff --git a/crates/engine_bibtex/bibtex/bibtex_bindings.h b/crates/engine_bibtex/bibtex/bibtex_bindings.h new file mode 100644 index 0000000000..d32533e762 --- /dev/null +++ b/crates/engine_bibtex/bibtex/bibtex_bindings.h @@ -0,0 +1,33 @@ +#ifndef BIBTEX_BINDINGS_H +#define BIBTEX_BINDINGS_H + +#include +#include +#include +#include + +typedef enum { + HISTORY_SPOTLESS = 0, + HISTORY_WARNING_ISSUED = 1, + HISTORY_ERROR_ISSUED = 2, + HISTORY_FATAL_ERROR = 3, + HISTORY_ABORTED = 4, +} History; + +typedef struct { + int min_crossrefs; +} BibtexConfig; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +extern History tt_engine_bibtex_main(ttbc_state_t *api, + const BibtexConfig *cfg, + const char *aux_name); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif /* BIBTEX_BINDINGS_H */ diff --git a/crates/engine_bibtex/build.rs b/crates/engine_bibtex/build.rs index 07f91721a2..3c41352152 100644 --- a/crates/engine_bibtex/build.rs +++ b/crates/engine_bibtex/build.rs @@ -5,56 +5,19 @@ use std::{env, path::PathBuf}; fn main() { let bc_include_dir = env::var("DEP_TECTONIC_BRIDGE_CORE_INCLUDE").unwrap(); - let out_dir = env::var("OUT_DIR").unwrap(); - let mut manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); - // 2021 June: work around https://github.com/tectonic-typesetting/tectonic/issues/788 - if env::var_os("DOCS_RS").is_some() { - env::set_var("CARGO_NET_OFFLINE", "true"); - } - - // cbindgen to generate the C header from our Rust code. - - let mut gen_header_path: PathBuf = out_dir.clone().into(); - gen_header_path.push("bibtex_bindings.h"); - - println!("cargo:rerun-if-changed=src/lib.rs"); - - let mut config = cbindgen::Config { - cpp_compat: true, - ..Default::default() - }; - config.enumeration.prefix_with_name = true; - - cbindgen::Builder::new() - .with_config(config) - .with_crate(&manifest_dir) - .with_language(cbindgen::Language::C) - .with_include_guard("BIBTEX_BINDINGS_H") - .with_style(cbindgen::Style::Type) - .rename_item("CoreBridgeState", "ttbc_state_t") // unfortunately we need to propagate this rename - .generate() - .expect("Unable to generate bindings") - .write_to_file(&gen_header_path); - - // Now we can compile the C code + let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); + let mut bt_include_dir = manifest_dir; + bt_include_dir.push("bibtex"); let mut build = cc::Build::new(); build .warnings(true) .file("bibtex/bibtex.c") + .include(&bt_include_dir) .include(&bc_include_dir) - .include(&out_dir) .compile("libtectonic_engine_bibtex.a"); println!("cargo:rerun-if-changed=bibtex/bibtex.c"); - - // Workaround so that we can `cargo package` this crate. Cf - // https://github.com/eqrion/cbindgen/issues/560 . cbindgen calls `cargo - // metadata` which creates a new Cargo.lock file when building this crate as - // part of its packaging process. This isn't noticed in regular builds since - // they occur in a workspace context. Lame but effective solution: - // unconditionally blow away the file. - manifest_dir.push("Cargo.lock"); - let _ignored = std::fs::remove_file(&manifest_dir); + println!("cargo:rerun-if-changed=bibtex/bibtex_bindings.h"); } diff --git a/crates/engine_bibtex/cbindgen.toml b/crates/engine_bibtex/cbindgen.toml new file mode 100644 index 0000000000..46eab4e633 --- /dev/null +++ b/crates/engine_bibtex/cbindgen.toml @@ -0,0 +1,10 @@ +language = "C" +cpp_compat = true +style = "type" +include_guard = "BIBTEX_BINDINGS_H" + +[export.rename] +"CoreBridgeState" = "ttbc_state_t" + +[enum] +prefix_with_name = true diff --git a/crates/engine_xdvipdfmx/Cargo.toml b/crates/engine_xdvipdfmx/Cargo.toml index 4828bd3d34..8cb147b9d8 100644 --- a/crates/engine_xdvipdfmx/Cargo.toml +++ b/crates/engine_xdvipdfmx/Cargo.toml @@ -25,7 +25,6 @@ tectonic_errors = { path = "../errors", version = "0.0.0-dev.0" } tectonic_pdf_io = { path = "../pdf_io", version = "0.0.0-dev.0" } [build-dependencies] -cbindgen = "^0.16" cc = "^1.0.66" [package.metadata.internal_dep_versions] diff --git a/crates/engine_xdvipdfmx/README.md b/crates/engine_xdvipdfmx/README.md index 594628b6a2..6f4ffc4a1a 100644 --- a/crates/engine_xdvipdfmx/README.md +++ b/crates/engine_xdvipdfmx/README.md @@ -17,3 +17,15 @@ project](https://tectonic-typesetting.github.io/en-US/). It provides This crate does not currently provides any [Cargo features][features]. [features]: https://doc.rust-lang.org/cargo/reference/features.html + + +## Updating the generated header + +This crate exposes Rust functions to C/C++ code using a header file created by +[cbindgen]. To update the header, run: + +[cbindgen]: https://github.com/eqrion/cbindgen/ + +```sh +cbindgen --output xdvipdfmx/xdvipdfmx_bindings.h +``` diff --git a/crates/engine_xdvipdfmx/build.rs b/crates/engine_xdvipdfmx/build.rs index 9b6c8ca185..5b73ca7d4f 100644 --- a/crates/engine_xdvipdfmx/build.rs +++ b/crates/engine_xdvipdfmx/build.rs @@ -1,51 +1,17 @@ // Copyright 2021 the Tectonic Project // Licensed under the MIT License. -use std::{env, path::PathBuf}; +use std::env; fn main() { let bc_include_dir = env::var("DEP_TECTONIC_BRIDGE_CORE_INCLUDE").unwrap(); let pi_include_path = env::var("DEP_TECTONIC_PDF_IO_INCLUDE_PATH").unwrap(); - let out_dir = env::var("OUT_DIR").unwrap(); - let mut manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); - - // 2021 June: work around https://github.com/tectonic-typesetting/tectonic/issues/788 - if env::var_os("DOCS_RS").is_some() { - env::set_var("CARGO_NET_OFFLINE", "true"); - } - - // cbindgen to generate the C header from our Rust code. - - let mut gen_header_path: PathBuf = out_dir.clone().into(); - gen_header_path.push("xdvipdfmx_bindings.h"); - - println!("cargo:rerun-if-changed=src/lib.rs"); - - let mut config = cbindgen::Config { - cpp_compat: true, - ..Default::default() - }; - config.enumeration.prefix_with_name = true; - - cbindgen::Builder::new() - .with_config(config) - .with_crate(&manifest_dir) - .with_language(cbindgen::Language::C) - .with_include_guard("XDVIPDFMX_BINDINGS_H") - .with_style(cbindgen::Style::Type) - .rename_item("CoreBridgeState", "ttbc_state_t") // unfortunately we need to propagate this rename - .generate() - .expect("Unable to generate bindings") - .write_to_file(&gen_header_path); - - // Now we can compile the C code let mut build = cc::Build::new(); build .warnings(true) .file("xdvipdfmx/dvipdfmx.c") - .include(&bc_include_dir) - .include(&out_dir); + .include(&bc_include_dir); for item in pi_include_path.split(';') { build.include(item); @@ -54,13 +20,5 @@ fn main() { build.compile("libtectonic_engine_xdvipdfmx.a"); println!("cargo:rerun-if-changed=xdvipdfmx/dvipdfmx.c"); - - // Workaround so that we can `cargo package` this crate. Cf - // https://github.com/eqrion/cbindgen/issues/560 . cbindgen calls `cargo - // metadata` which creates a new Cargo.lock file when building this crate as - // part of its packaging process. This isn't noticed in regular builds since - // they occur in a workspace context. Lame but effective solution: - // unconditionally blow away the file. - manifest_dir.push("Cargo.lock"); - let _ignored = std::fs::remove_file(&manifest_dir); + println!("cargo:rerun-if-changed=xdvipdfmx/dvipdfmx_bindings.h"); } diff --git a/crates/engine_xdvipdfmx/cbindgen.toml b/crates/engine_xdvipdfmx/cbindgen.toml new file mode 100644 index 0000000000..272e27833f --- /dev/null +++ b/crates/engine_xdvipdfmx/cbindgen.toml @@ -0,0 +1,10 @@ +language = "C" +cpp_compat = true +style = "type" +include_guard = "XDVIPDFMX_BINDINGS_H" + +[export.rename] +"CoreBridgeState" = "ttbc_state_t" + +[enum] +prefix_with_name = true diff --git a/crates/engine_xdvipdfmx/xdvipdfmx/xdvipdfmx_bindings.h b/crates/engine_xdvipdfmx/xdvipdfmx/xdvipdfmx_bindings.h new file mode 100644 index 0000000000..01ef083a77 --- /dev/null +++ b/crates/engine_xdvipdfmx/xdvipdfmx/xdvipdfmx_bindings.h @@ -0,0 +1,29 @@ +#ifndef XDVIPDFMX_BINDINGS_H +#define XDVIPDFMX_BINDINGS_H + +#include +#include +#include +#include + +typedef struct { + const char *paperspec; + unsigned char enable_compression; + unsigned char deterministic_tags; + time_t build_date; +} XdvipdfmxConfig; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +extern int tt_engine_xdvipdfmx_main(ttbc_state_t *api, + const XdvipdfmxConfig *cfg, + const char *dviname, + const char *pdfname); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif /* XDVIPDFMX_BINDINGS_H */ diff --git a/crates/engine_xetex/Cargo.toml b/crates/engine_xetex/Cargo.toml index d3af347bbf..b035597b0a 100644 --- a/crates/engine_xetex/Cargo.toml +++ b/crates/engine_xetex/Cargo.toml @@ -29,7 +29,6 @@ tectonic_pdf_io = { path = "../pdf_io", version = "0.0.0-dev.0" } tectonic_xetex_layout = { path = "../xetex_layout", version = "0.0.0-dev.0" } [build-dependencies] -cbindgen = "^0.16" cc = "^1.0.66" tectonic_cfg_support = { path = "../cfg_support", version = "0.0.0-dev.0" } diff --git a/crates/engine_xetex/README.md b/crates/engine_xetex/README.md index faf677d86b..90dd69f79e 100644 --- a/crates/engine_xetex/README.md +++ b/crates/engine_xetex/README.md @@ -20,3 +20,15 @@ This crate provides the following [Cargo features][features]: - **`external-harfbuzz`**: activates the same-named feature in the `tectonic_bridge_harfbuzz` dependency. + + +## Updating the generated header + +This crate exposes Rust functions to C/C++ code using a header file created by +[cbindgen]. To update the header, run: + +[cbindgen]: https://github.com/eqrion/cbindgen/ + +```sh +cbindgen --output xetex/xetex_bindings.h +``` diff --git a/crates/engine_xetex/build.rs b/crates/engine_xetex/build.rs index 87f5290985..992b3511c1 100644 --- a/crates/engine_xetex/build.rs +++ b/crates/engine_xetex/build.rs @@ -6,43 +6,6 @@ use tectonic_cfg_support::*; fn main() { let target = env::var("TARGET").unwrap(); - let out_dir = env::var("OUT_DIR").unwrap(); - let mut manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); - - // 2021 June: work around https://github.com/tectonic-typesetting/tectonic/issues/788 - if env::var_os("DOCS_RS").is_some() { - env::set_var("CARGO_NET_OFFLINE", "true"); - } - - // cbindgen to generate the C header from our Rust code. - - let mut gen_header_path: PathBuf = out_dir.clone().into(); - gen_header_path.push("core-bindgen.h"); - - println!("cargo:rerun-if-changed=src/lib.rs"); - - let mut config = cbindgen::Config { - cpp_compat: true, - ..Default::default() - }; - config.enumeration.prefix_with_name = true; - - cbindgen::Builder::new() - .with_config(config) - .with_crate(&manifest_dir) - .with_language(cbindgen::Language::C) - .with_include_guard("TECTONIC_ENGINE_XETEX_BINDGEN_H") - .with_style(cbindgen::Style::Type) - .rename_item("CoreBridgeState", "ttbc_state_t") // unfortunately we need to propagate this rename - .generate() - .expect("Unable to generate bindings") - .write_to_file(&gen_header_path); - - // Re-export $TARGET during the build so that our executable tests know - // what environment variable CARGO_TARGET_@TARGET@_RUNNER to check when - // they want to spawn off executables. - - println!("cargo:rustc-env=TARGET={}", target); // Include paths exported by our internal dependencies. @@ -89,7 +52,7 @@ fn main() { profile_config(&mut c_cfg); profile_config(&mut cxx_cfg); - for p in &[&out_dir, ".", &core_include_dir, &flate_include_dir] { + for p in &[".", &core_include_dir, &flate_include_dir] { c_cfg.include(p); cxx_cfg.include(p); } @@ -160,15 +123,6 @@ fn main() { let file = file.unwrap(); println!("cargo:rerun-if-changed={}", file.path().display()); } - - // Workaround so that we can `cargo package` this crate. Cf - // https://github.com/eqrion/cbindgen/issues/560 . cbindgen calls `cargo - // metadata` which creates a new Cargo.lock file when building this crate as - // part of its packaging process. This isn't noticed in regular builds since - // they occur in a workspace context. Lame but effective solution: - // unconditionally blow away the file. - manifest_dir.push("Cargo.lock"); - let _ignored = std::fs::remove_file(&manifest_dir); } const C_FLAGS: &[&str] = &[ diff --git a/crates/engine_xetex/cbindgen.toml b/crates/engine_xetex/cbindgen.toml new file mode 100644 index 0000000000..61fa905efa --- /dev/null +++ b/crates/engine_xetex/cbindgen.toml @@ -0,0 +1,10 @@ +language = "C" +cpp_compat = true +style = "type" +include_guard = "TECTONIC_ENGINE_XETEX_BINDGEN_H" + +[export.rename] +"CoreBridgeState" = "ttbc_state_t" + +[enum] +prefix_with_name = true diff --git a/crates/engine_xetex/src/lib.rs b/crates/engine_xetex/src/lib.rs index 4df939cc8f..e010c3026b 100644 --- a/crates/engine_xetex/src/lib.rs +++ b/crates/engine_xetex/src/lib.rs @@ -32,6 +32,9 @@ use tectonic_errors::prelude::*; /// should munge this serial number in the filename, or something along those /// lines, to make sure that when the engine is updated you don’t attempt to /// reuse old files. +// +// DEVELOPER NOTE: if you change this, rerun cbindgen! This value is exported +// into the C/C++ code as a #define. pub const FORMAT_SERIAL: u32 = 30; /// A possible outcome from a (Xe)TeX engine invocation. diff --git a/crates/engine_xetex/xetex/xetex-ini.c b/crates/engine_xetex/xetex/xetex-ini.c index 3039e27965..bf1cd74a40 100644 --- a/crates/engine_xetex/xetex/xetex-ini.c +++ b/crates/engine_xetex/xetex/xetex-ini.c @@ -7,7 +7,7 @@ #include "xetex-xetexd.h" #include "xetex-synctex.h" #include "dpx-pdfobj.h" /* pdf_files_{init,close} */ -#include "core-bindgen.h" /* FORMAT_SERIAL */ +#include "xetex_bindings.h" /* FORMAT_SERIAL */ /* All the following variables are declared in xetex-xetexd.h */ bool shell_escape_enabled = false; diff --git a/crates/engine_xetex/xetex/xetex_bindings.h b/crates/engine_xetex/xetex/xetex_bindings.h new file mode 100644 index 0000000000..fae3e2cc07 --- /dev/null +++ b/crates/engine_xetex/xetex/xetex_bindings.h @@ -0,0 +1,36 @@ +#ifndef TECTONIC_ENGINE_XETEX_BINDGEN_H +#define TECTONIC_ENGINE_XETEX_BINDGEN_H + +#include +#include +#include +#include + +/** + * A serial number describing the detailed binary layout of the TeX “format + * files” used by this crate. This number will occasionally increment, + * indicating that the format file structure has changed. There is no provision + * for partial forwards or backwards compatibility: if the number changes, you + * need to regenerate your format files. If you’re generating format files, you + * should munge this serial number in the filename, or something along those + * lines, to make sure that when the engine is updated you don’t attempt to + * reuse old files. + */ +#define FORMAT_SERIAL 30 + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +extern int tt_xetex_set_int_variable(const char *var_name, int value); + +extern int tt_engine_xetex_main(ttbc_state_t *api, + const char *dump_name, + const char *input_file_name, + time_t build_date); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif /* TECTONIC_ENGINE_XETEX_BINDGEN_H */