commit 65e17fc55b82da833653f0bff36c8b664bbcc46c Author: Sebastian Hugentobler Date: Wed May 1 16:21:07 2024 +0200 bare bones calibre db reading diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4075fb2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +target +result diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..573c35f --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,208 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" + +[[package]] +name = "calibre-db" +version = "0.1.0" +dependencies = [ + "rusqlite", + "thiserror", +] + +[[package]] +name = "cc" +version = "1.0.96" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "065a29261d53ba54260972629f9ca6bffa69bac13cd1fed61420f7fa68b9f8bd" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "allocator-api2", +] + +[[package]] +name = "hashlink" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "692eaaf7f7607518dd3cef090f1474b61edc5301d8012f09579920df68b725ee" +dependencies = [ + "hashbrown", +] + +[[package]] +name = "libsqlite3-sys" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c10584274047cb335c23d3e61bcef8e323adae7c5c8c760540f73610177fc3f" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "proc-macro2" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rusqlite" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b838eba278d213a8beaf485bd313fd580ca4505a00d5871caeb1457c55322cae" +dependencies = [ + "bitflags", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "smallvec", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "syn" +version = "2.0.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..75f6141 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,5 @@ +[workspace] +resolver = "2" +members = [ + "calibre-db", +] diff --git a/calibre-db/Cargo.toml b/calibre-db/Cargo.toml new file mode 100644 index 0000000..5aea1bd --- /dev/null +++ b/calibre-db/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "calibre-db" +version = "0.1.0" +edition = "2021" + +[dependencies] +rusqlite = { version = "0.31.0", features = ["bundled"] } +thiserror = "1.0.59" diff --git a/calibre-db/src/calibre.rs b/calibre-db/src/calibre.rs new file mode 100644 index 0000000..b136c48 --- /dev/null +++ b/calibre-db/src/calibre.rs @@ -0,0 +1,94 @@ +use rusqlite::Connection; + +use crate::data::{author::Author, book::Book, error::DataStoreError, pagination::SortOrder}; + +pub struct Calibre { + conn: Connection, +} + +impl Calibre { + pub fn load(url: &str) -> Result { + let conn = Connection::open(url)?; + Ok(Self { conn }) + } + + pub fn books( + &self, + limit: u64, + cursor: Option<&str>, + sort_order: SortOrder, + ) -> Result, DataStoreError> { + Book::books(&self.conn, limit, cursor, sort_order) + } + + pub fn authors( + &self, + limit: u64, + cursor: Option<&str>, + sort_order: SortOrder, + ) -> Result, DataStoreError> { + Author::authors(&self.conn, limit, cursor, sort_order) + } + + pub fn author_books( + &self, + author_id: u64, + limit: u64, + cursor: Option<&str>, + sort_order: SortOrder, + ) -> Result, DataStoreError> { + Book::author_books(&self.conn, author_id, limit, cursor, sort_order) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn books() { + let c = Calibre::load("./testdata/metadata.db").unwrap(); + let books = c.books(10, None, SortOrder::ASC).unwrap(); + assert_eq!(books.len(), 4); + } + + #[test] + fn authors() { + let c = Calibre::load("./testdata/metadata.db").unwrap(); + let authors = c.authors(10, None, SortOrder::ASC).unwrap(); + assert_eq!(authors.len(), 3); + } + + #[test] + fn author_books() { + let c = Calibre::load("./testdata/metadata.db").unwrap(); + let books = c.author_books(1, 10, None, SortOrder::ASC).unwrap(); + assert_eq!(books.len(), 2); + } + + #[test] + fn pagination() { + let c = Calibre::load("./testdata/metadata.db").unwrap(); + let authors = c.authors(1, None, SortOrder::ASC).unwrap(); + assert_eq!(authors.len(), 1); + assert_eq!(authors[0].name, "Kevin R. Grazier"); + + let authors = c + .authors(1, Some(&authors[0].sort), SortOrder::ASC) + .unwrap(); + assert_eq!(authors.len(), 1); + assert_eq!(authors[0].name, "Terry Pratchett"); + + let authors = c + .authors(1, Some(&authors[0].sort), SortOrder::ASC) + .unwrap(); + assert_eq!(authors.len(), 1); + assert_eq!(authors[0].name, "Edward Noyes Westcott"); + + let authors = c + .authors(1, Some(&authors[0].sort), SortOrder::DESC) + .unwrap(); + assert_eq!(authors.len(), 1); + assert_eq!(authors[0].name, "Terry Pratchett"); + } +} diff --git a/calibre-db/src/data/author.rs b/calibre-db/src/data/author.rs new file mode 100644 index 0000000..106133d --- /dev/null +++ b/calibre-db/src/data/author.rs @@ -0,0 +1,38 @@ +use rusqlite::{Connection, Row}; + +use super::{ + error::DataStoreError, + pagination::{Pagination, SortOrder}, +}; + +#[derive(Debug)] +pub struct Author { + pub id: i32, + pub name: String, + pub sort: String, +} + +impl Author { + fn from_row(row: &Row<'_>) -> Result { + Ok(Self { + id: row.get(0)?, + name: row.get(1)?, + sort: row.get(2)?, + }) + } + + pub fn authors( + conn: &Connection, + limit: u64, + cursor: Option<&str>, + sort_order: SortOrder, + ) -> Result, DataStoreError> { + let pagination = Pagination::new("sort", cursor, limit, sort_order); + pagination.paginate( + conn, + "SELECT id, name, sort FROM authors", + &[], + Self::from_row, + ) + } +} diff --git a/calibre-db/src/data/book.rs b/calibre-db/src/data/book.rs new file mode 100644 index 0000000..91449c0 --- /dev/null +++ b/calibre-db/src/data/book.rs @@ -0,0 +1,56 @@ +use rusqlite::{Connection, Row}; + +use super::{ + error::DataStoreError, + pagination::{Pagination, SortOrder}, +}; + +#[derive(Debug)] +pub struct Book { + pub id: i32, + pub title: String, + pub sort: String, +} + +impl Book { + fn from_row(row: &Row<'_>) -> Result { + Ok(Self { + id: row.get(0)?, + title: row.get(1)?, + sort: row.get(2)?, + }) + } + + pub fn books( + conn: &Connection, + limit: u64, + cursor: Option<&str>, + sort_order: SortOrder, + ) -> Result, DataStoreError> { + let pagination = Pagination::new("sort", cursor, limit, sort_order); + pagination.paginate( + conn, + "SELECT id, title, sort FROM books", + &[], + Self::from_row, + ) + } + + pub fn author_books( + conn: &Connection, + author_id: u64, + limit: u64, + cursor: Option<&str>, + sort_order: SortOrder, + ) -> Result, DataStoreError> { + let pagination = Pagination::new("books.sort", cursor, limit, sort_order); + pagination.paginate( + conn, + "SELECT books.id, books.title, books.sort FROM books \ + INNER JOIN books_authors_link ON books.id = books_authors_link.book \ + WHERE books_authors_link.author = (:author_id) AND", + &[(":author_id", &author_id)], + Self::from_row, + ) + } +} diff --git a/calibre-db/src/data/error.rs b/calibre-db/src/data/error.rs new file mode 100644 index 0000000..8a2c803 --- /dev/null +++ b/calibre-db/src/data/error.rs @@ -0,0 +1,7 @@ +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum DataStoreError { + #[error("sqlite error")] + SqliteError(#[from] rusqlite::Error), +} diff --git a/calibre-db/src/data/pagination.rs b/calibre-db/src/data/pagination.rs new file mode 100644 index 0000000..6c7c90d --- /dev/null +++ b/calibre-db/src/data/pagination.rs @@ -0,0 +1,72 @@ +use rusqlite::{Connection, Row, ToSql}; + +use super::error::DataStoreError; + +#[derive(Debug, PartialEq)] +pub enum SortOrder { + ASC, + DESC, +} + +pub struct Pagination<'a> { + pub sort_col: &'a str, + pub limit: u64, + pub cursor: Option<&'a str>, + pub sort_order: SortOrder, +} + +impl<'a> Pagination<'a> { + pub fn new( + sort_col: &'a str, + cursor: Option<&'a str>, + limit: u64, + sort_order: SortOrder, + ) -> Self { + Self { + sort_col, + limit, + cursor, + sort_order, + } + } + + pub fn paginate( + &self, + conn: &Connection, + statement: &str, + params: &[(&str, &dyn ToSql)], + processor: F, + ) -> Result, DataStoreError> + where + F: FnMut(&Row<'_>) -> Result, + { + let cursor = self.cursor.unwrap_or(""); + let comparison = if self.sort_order == SortOrder::ASC { + ">" + } else { + "<" + }; + let where_sql = if statement.ends_with("AND") { + "" + } else { + "WHERE" + }; + + let sort_col = self.sort_col; + let sort_order = &self.sort_order; + // DANGER: vulnerable to SQL injection if statement or sort_col variable is influenced by user input + let mut stmt = conn.prepare(&format!( + "{statement} {where_sql} {sort_col} {comparison} (:cursor) ORDER BY {sort_col} {sort_order:?} LIMIT (:limit)" + ))?; + let params = [ + &[ + (":cursor", &cursor as &dyn ToSql), + (":limit", &self.limit as &dyn ToSql), + ], + params, + ] + .concat(); + let iter = stmt.query_map(params.as_slice(), processor)?; + Ok(iter.filter_map(Result::ok).collect()) + } +} diff --git a/calibre-db/src/lib.rs b/calibre-db/src/lib.rs new file mode 100644 index 0000000..2a70732 --- /dev/null +++ b/calibre-db/src/lib.rs @@ -0,0 +1,7 @@ +pub mod calibre; +pub mod data { + pub mod author; + pub mod book; + pub mod error; + pub mod pagination; +} diff --git a/calibre-db/testdata/metadata.db b/calibre-db/testdata/metadata.db new file mode 100644 index 0000000..ef1842b Binary files /dev/null and b/calibre-db/testdata/metadata.db differ diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..b3f9457 --- /dev/null +++ b/flake.lock @@ -0,0 +1,145 @@ +{ + "nodes": { + "fenix": { + "inputs": { + "nixpkgs": "nixpkgs", + "rust-analyzer-src": "rust-analyzer-src" + }, + "locked": { + "lastModified": 1714544767, + "narHash": "sha256-kF1bX+YFMedf1g0PAJYwGUkzh22JmULtj8Rm4IXAQKs=", + "owner": "nix-community", + "repo": "fenix", + "rev": "73124e1356bde9411b163d636b39fe4804b7ca45", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "fenix", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "naersk": { + "inputs": { + "nixpkgs": "nixpkgs_2" + }, + "locked": { + "lastModified": 1713520724, + "narHash": "sha256-CO8MmVDmqZX2FovL75pu5BvwhW+Vugc7Q6ze7Hj8heI=", + "owner": "nix-community", + "repo": "naersk", + "rev": "c5037590290c6c7dae2e42e7da1e247e54ed2d49", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "naersk", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1714253743, + "narHash": "sha256-mdTQw2XlariysyScCv2tTE45QSU9v/ezLcHJ22f0Nxc=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "58a1abdbae3217ca6b702f03d3b35125d88a2994", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 0, + "narHash": "sha256-mdTQw2XlariysyScCv2tTE45QSU9v/ezLcHJ22f0Nxc=", + "path": "/nix/store/801l7gvdz7yaibhjsxqx82sc7zkakjbq-source", + "type": "path" + }, + "original": { + "id": "nixpkgs", + "type": "indirect" + } + }, + "nixpkgs_3": { + "locked": { + "lastModified": 1714253743, + "narHash": "sha256-mdTQw2XlariysyScCv2tTE45QSU9v/ezLcHJ22f0Nxc=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "58a1abdbae3217ca6b702f03d3b35125d88a2994", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "fenix": "fenix", + "flake-utils": "flake-utils", + "naersk": "naersk", + "nixpkgs": "nixpkgs_3" + } + }, + "rust-analyzer-src": { + "flake": false, + "locked": { + "lastModified": 1714501997, + "narHash": "sha256-g31zfxwUFzkPgX0Q8sZLcrqGmOxwjEZ/iqJjNx4fEGo=", + "owner": "rust-lang", + "repo": "rust-analyzer", + "rev": "49e502b277a8126a9ad10c802d1aaa3ef1a280ef", + "type": "github" + }, + "original": { + "owner": "rust-lang", + "ref": "nightly", + "repo": "rust-analyzer", + "type": "github" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..d9f544f --- /dev/null +++ b/flake.nix @@ -0,0 +1,148 @@ +{ + description = "rusty-cops project"; + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + naersk.url = "github:nix-community/naersk"; + fenix.url = "github:nix-community/fenix"; + }; + + outputs = + { + self, + nixpkgs, + naersk, + fenix, + flake-utils, + ... + }: + let + buildTargets = { + "x86_64-linux" = { + crossSystemConfig = "x86_64-unknown-linux-musl"; + rustTarget = "x86_64-unknown-linux-musl"; + }; + + "i686-linux" = { + crossSystemConfig = "i686-unknown-linux-musl"; + rustTarget = "i686-unknown-linux-musl"; + }; + + "aarch64-linux" = { + crossSystemConfig = "aarch64-unknown-linux-musl"; + rustTarget = "aarch64-unknown-linux-musl"; + }; + + "armv6l-linux" = { + crossSystemConfig = "armv6l-unknown-linux-musleabihf"; + rustTarget = "arm-unknown-linux-musleabihf"; + }; + }; + + eachSystem = + supportedSystems: callback: + builtins.foldl' (overall: system: overall // { ${system} = callback system; }) { } supportedSystems; + + eachCrossSystem = + supportedSystems: callback: + eachSystem supportedSystems ( + buildSystem: + builtins.foldl' ( + inner: targetSystem: inner // { "cross-${targetSystem}" = callback buildSystem targetSystem; } + ) { default = callback buildSystem buildSystem; } supportedSystems + ); + + mkPkgs = + buildSystem: targetSystem: + import nixpkgs ( + { + system = buildSystem; + } + // ( + if targetSystem == null then + { } + else + { crossSystem.config = buildTargets.${targetSystem}.crossSystemConfig; } + ) + ); + in + flake-utils.lib.eachDefaultSystem ( + system: + let + pkgs = import nixpkgs { inherit system; }; + rust = fenix.packages.${system}.stable; + in + with pkgs; + { + devShells.default = mkShell { + buildInputs = [ + mosquitto + rust.toolchain + rust-analyzer + sea-orm-cli + ]; + }; + } + ) + // { + packages = eachCrossSystem (builtins.attrNames buildTargets) ( + buildSystem: targetSystem: + let + pkgs = mkPkgs buildSystem null; + pkgsCross = mkPkgs buildSystem targetSystem; + rustTarget = buildTargets.${targetSystem}.rustTarget; + + fenixPkgs = fenix.packages.${buildSystem}; + + mkToolchain = fenixPkgs: fenixPkgs.stable; + + toolchain = fenixPkgs.combine [ + (mkToolchain fenixPkgs).rustc + (mkToolchain fenixPkgs).cargo + (mkToolchain fenixPkgs.targets.${rustTarget}).rust-std + ]; + + buildPackageAttrs = + if builtins.hasAttr "makeBuildPackageAttrs" buildTargets.${targetSystem} then + buildTargets.${targetSystem}.makeBuildPackageAttrs pkgsCross + else + { }; + + naersk-lib = pkgs.callPackage naersk { + cargo = toolchain; + rustc = toolchain; + }; + in + naersk-lib.buildPackage ( + buildPackageAttrs + // rec { + src = ./.; + strictDeps = true; + doCheck = false; + + OPENSSL_STATIC = "1"; + OPENSSL_LIB_DIR = "${pkgsCross.pkgsStatic.openssl.out}/lib"; + OPENSSL_INCLUDE_DIR = "${pkgsCross.pkgsStatic.openssl.dev}/include"; + + # Required because ring crate is special. This also seems to have + # fixed some issues with the x86_64-windows cross-compile :shrug: + TARGET_CC = "${pkgsCross.stdenv.cc}/bin/${pkgsCross.stdenv.cc.targetPrefix}cc"; + + CARGO_BUILD_TARGET = rustTarget; + CARGO_BUILD_RUSTFLAGS = [ + "-C" + "target-feature=+crt-static" + + # -latomic is required to build openssl-sys for armv6l-linux, but + # it doesn't seem to hurt any other builds. + # "-C" + # "link-args=-static -latomic" + + "-C" + "linker=${TARGET_CC}" + ]; + } + ) + ); + }; +}