bind_builder/
lib.rs

1//! Build dependency for downloading, building and linking native libraries.
2//!
3//! This crate expands on `cc` and `cmake` to provide a more streamlined way of distributing crates
4//! that depend on both static and shared libraries.
5//!
6
7use std::fs;
8use std::ops::Add;
9use std::path::Path;
10use crate::commands::{add_library_search_path, link_shared_library, link_static_library};
11use crate::types::local_library::LocalLibrary;
12use crate::variables::{platform, Platform, shared_library_extension, static_library_extension, target_directory};
13
14pub mod types;
15
16pub (crate) mod variables;
17pub (crate) mod commands;
18
19const LIBRARY_NAME_PREFIX: &str = "lib";
20
21fn get_static_library_name(library_name: &str) -> String {
22    // Omit the prefix for Windows since there is no convention for library names.
23    if platform() == Platform::Windows {
24        return library_name.to_string()
25            .add(static_library_extension());
26    }
27
28    LIBRARY_NAME_PREFIX.to_string()
29        .add(library_name)
30        .add(static_library_extension())
31}
32
33fn get_shared_library_name(library_name: &str) -> String  {
34    // Omit the prefix for Windows since there is no convention for library names.
35    if platform() == Platform::Windows {
36        return library_name.to_string()
37            .add(shared_library_extension());
38    }
39
40    LIBRARY_NAME_PREFIX.to_string()
41        .add(library_name)
42        .add(shared_library_extension())
43}
44
45fn copy_shared_object(
46    target_directory: &Path,
47    library_path: &Path,
48) {
49    if !target_directory.exists() {
50        fs::create_dir_all(target_directory)
51            .expect("Could not create target directory.");
52    }
53
54    if !library_path.exists() {
55        panic!("Could not find shared object: {:?}", library_path);
56    }
57
58    fs::copy(
59        library_path,
60        target_directory.join(library_path.file_name().unwrap())
61    ).expect("Could not copy shared object.");
62}
63
64/// Trait for integrating a `LocalLibrary` into `cc::Build`.
65pub trait BindBuild {
66
67    /// Binds a `LocalLibrary` to the `cc::Build` instance.
68    fn bind_library(
69        &mut self,
70        library: LocalLibrary
71    ) -> &mut cc::Build;
72}
73
74impl BindBuild for cc::Build {
75
76    fn bind_library(
77        &mut self,
78        library: LocalLibrary
79    ) -> &mut cc::Build {
80
81        // Remove duplicates and invalid entries
82        let mut include_directories = library
83            .get_include_directories()
84            .clone();
85
86        include_directories.dedup();
87        include_directories.retain(|x| x.is_dir());
88
89        self.includes(include_directories);
90
91        let mut library_directories = library
92            .get_library_directories()
93            .clone();
94
95        library_directories.dedup();
96        library_directories.retain(|x| x.is_dir());
97
98        for library_directory in library_directories.iter() {
99            add_library_search_path(library_directory.as_path())
100        }
101
102        let mut link_targets = library
103            .get_link_targets()
104            .clone();
105
106        link_targets.dedup();
107
108        let target_directory = target_directory();
109
110        // Always prefer static libraries over shared libraries
111        for library in link_targets.iter() {
112            for library_directory in library_directories.iter() {
113                let static_library_path = library_directory
114                    .join(get_static_library_name(library));
115
116                let shared_library_path = library_directory
117                    .join(get_shared_library_name(library));
118
119                if static_library_path.exists() {
120                    link_static_library(library);
121                } else if shared_library_path.exists() {
122                    // Copy shared object to target directory
123                    copy_shared_object(
124                        target_directory.as_path(),
125                        shared_library_path.as_path()
126                    );
127                    link_shared_library(library);
128                }
129            }
130        }
131
132        // Link against any system libraries.
133        let mut system_link_targets = library
134            .get_system_link_targets()
135            .clone();
136
137        system_link_targets.dedup();
138
139        for library in system_link_targets.iter() {
140            link_shared_library(library);
141        }
142
143        self
144    }
145}