fix typos from #28614
[tor.git] / src / rust / build.rs
blob5626b35f751f1de5f7e2e086468c4dd157582e27
1 //! Build script for Rust modules in Tor.
2 //!
3 //! We need to use this because some of our Rust tests need to use some
4 //! of our C modules, which need to link some external libraries.
5 //!
6 //! This script works by looking at a "config.rust" file generated by our
7 //! configure script, and then building a set of options for cargo to pass to
8 //! the compiler.
10 use std::collections::HashMap;
11 use std::env;
12 use std::fs::File;
13 use std::io;
14 use std::io::prelude::*;
15 use std::path::PathBuf;
17 /// Wrapper around a key-value map.
18 struct Config(HashMap<String, String>);
20 /// Locate a config.rust file generated by autoconf, starting in the OUT_DIR
21 /// location provided by cargo and recursing up the directory tree.  Note that
22 /// we need to look in the OUT_DIR, since autoconf will place generated files
23 /// in the build directory.
24 fn find_cfg() -> io::Result<String> {
25     let mut path = PathBuf::from(env::var("OUT_DIR").unwrap());
26     loop {
27         path.push("config.rust");
28         if path.exists() {
29             return Ok(path.to_str().unwrap().to_owned());
30         }
31         path.pop(); // remove config.rust
32         if !path.pop() {
33             // can't remove last part of directory
34             return Err(io::Error::new(io::ErrorKind::NotFound, "No config.rust"));
35         }
36     }
39 impl Config {
40     /// Find the config.rust file and try to parse it.
41     ///
42     /// The file format is a series of lines of the form KEY=VAL, with
43     /// any blank lines and lines starting with # ignored.
44     fn load() -> io::Result<Config> {
45         let path = find_cfg()?;
46         let f = File::open(&path)?;
47         let reader = io::BufReader::new(f);
48         let mut map = HashMap::new();
49         for line in reader.lines() {
50             let s = line?;
51             if s.trim().starts_with("#") || s.trim() == "" {
52                 continue;
53             }
54             let idx = match s.find("=") {
55                 None => {
56                     return Err(io::Error::new(io::ErrorKind::InvalidData, "missing ="));
57                 }
58                 Some(x) => x,
59             };
60             let (var, eq_val) = s.split_at(idx);
61             let val = &eq_val[1..];
62             map.insert(var.to_owned(), val.to_owned());
63         }
64         Ok(Config(map))
65     }
67     /// Return a reference to the value whose key is 'key'.
68     ///
69     /// Panics if 'key' is not found in the configuration.
70     fn get(&self, key: &str) -> &str {
71         self.0.get(key).unwrap()
72     }
74     /// Add a dependency on a static C library that is part of Tor, by name.
75     fn component(&self, s: &str) {
76         println!("cargo:rustc-link-lib=static={}", s);
77     }
79     /// Add a dependency on a native library that is not part of Tor, by name.
80     fn dependency(&self, s: &str) {
81         println!("cargo:rustc-link-lib={}", s);
82     }
84     /// Add a link path, relative to Tor's build directory.
85     fn link_relpath(&self, s: &str) {
86         let builddir = self.get("BUILDDIR");
87         println!("cargo:rustc-link-search=native={}/{}", builddir, s);
88     }
90     /// Add an absolute link path.
91     fn link_path(&self, s: &str) {
92         println!("cargo:rustc-link-search=native={}", s);
93     }
95     /// Parse the CFLAGS in s, looking for -l and -L items, and adding
96     /// rust configuration as appropriate.
97     fn from_cflags(&self, s: &str) {
98         let mut next_is_lib = false;
99         let mut next_is_path = false;
100         for ent in self.get(s).split_whitespace() {
101             if next_is_lib {
102                 self.dependency(ent);
103                 next_is_lib = false;
104             } else if next_is_path {
105                 self.link_path(ent);
106                 next_is_path = false;
107             } else if ent == "-l" {
108                 next_is_lib = true;
109             } else if ent == "-L" {
110                 next_is_path = true;
111             } else if ent.starts_with("-L") {
112                 self.link_path(&ent[2..]);
113             } else if ent.starts_with("-l") {
114                 self.dependency(&ent[2..]);
115             }
116         }
117     }
120 pub fn main() {
121     let cfg = Config::load().unwrap();
122     let package = env::var("CARGO_PKG_NAME").unwrap();
124     match package.as_ref() {
125         "crypto" => {
126             // Right now, I'm having a separate configuration for each Rust
127             // package, since I'm hoping we can trim them down.  Once we have a
128             // second Rust package that needs to use this build script, let's
129             // extract some of this stuff into a module.
130             //
131             // This is a ridiculous amount of code to be pulling in just
132             // to test our crypto library: modularity would be our
133             // friend here.
134             cfg.from_cflags("TOR_LDFLAGS_zlib");
135             cfg.from_cflags("TOR_LDFLAGS_openssl");
136             cfg.from_cflags("TOR_LDFLAGS_libevent");
138             cfg.link_relpath("src/lib");
139             cfg.link_relpath("src/ext/keccak-tiny");
140             cfg.link_relpath("src/ext/ed25519/ref10");
141             cfg.link_relpath("src/ext/ed25519/donna");
142             cfg.link_relpath("src/trunnel");
144             // Note that we can't pull in "libtor-testing", or else we
145             // will have dependencies on all the other rust packages that
146             // tor uses.  We must be careful with factoring and dependencies
147             // moving forward!
148             cfg.component("tor-crypt-ops-testing");
149             cfg.component("tor-sandbox-testing");
150             cfg.component("tor-encoding-testing");
151             cfg.component("tor-fs-testing");
152             cfg.component("tor-net-testing");
153             cfg.component("tor-buf-testing");
154             cfg.component("tor-time-testing");
155             cfg.component("tor-thread-testing");
156             cfg.component("tor-memarea-testing");
157             cfg.component("tor-log-testing");
158             cfg.component("tor-lock-testing");
159             cfg.component("tor-fdio-testing");
160             cfg.component("tor-container-testing");
161             cfg.component("tor-smartlist-core-testing");
162             cfg.component("tor-string-testing");
163             cfg.component("tor-malloc");
164             cfg.component("tor-wallclock");
165             cfg.component("tor-err-testing");
166             cfg.component("tor-version-testing");
167             cfg.component("tor-intmath-testing");
168             cfg.component("tor-ctime-testing");
169             cfg.component("curve25519_donna");
170             cfg.component("keccak-tiny");
171             cfg.component("ed25519_ref10");
172             cfg.component("ed25519_donna");
173             cfg.component("or-trunnel-testing");
175             cfg.from_cflags("TOR_ZLIB_LIBS");
176             cfg.from_cflags("TOR_LIB_MATH");
177             cfg.from_cflags("NSS_LIBS");
178             cfg.from_cflags("TOR_OPENSSL_LIBS");
179             cfg.from_cflags("TOR_LIBEVENT_LIBS");
180             cfg.from_cflags("TOR_LIB_WS32");
181             cfg.from_cflags("TOR_LIB_GDI");
182             cfg.from_cflags("TOR_LIB_USERENV");
183             cfg.from_cflags("CURVE25519_LIBS");
184             cfg.from_cflags("TOR_LZMA_LIBS");
185             cfg.from_cflags("TOR_ZSTD_LIBS");
186             cfg.from_cflags("LIBS");
187         }
188         _ => {
189             panic!("No configuration in build.rs for package {}", package);
190         }
191     }