forked from ajrcarey/pdfium-render
-
Notifications
You must be signed in to change notification settings - Fork 0
/
build.rs
189 lines (154 loc) · 6.69 KB
/
build.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
// Copyright 2021, pdfium-sys Developers
// Copyright 2022 - 2024, pdfium-render Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
#[cfg(feature = "bindings")]
extern crate bindgen;
#[cfg(feature = "bindings")]
use {
bindgen::BindgenError,
std::env::var,
std::ffi::OsStr,
std::fs::{read_dir, write},
std::path::PathBuf,
};
#[derive(Debug)]
enum BuildError {
#[cfg(feature = "bindings")]
#[allow(dead_code)]
IoError(std::io::Error),
#[cfg(feature = "bindings")]
#[allow(dead_code)]
BindgenError(BindgenError),
#[cfg(feature = "bindings")]
#[allow(dead_code)]
PathConversionError(PathBuf),
}
#[cfg(feature = "bindings")]
impl From<std::io::Error> for BuildError {
fn from(item: std::io::Error) -> Self {
BuildError::IoError(item)
}
}
#[cfg(feature = "bindings")]
impl From<BindgenError> for BuildError {
fn from(item: BindgenError) -> Self {
BuildError::BindgenError(item)
}
}
fn main() -> Result<(), BuildError> {
#[cfg(feature = "bindings")]
build_bindings()?;
#[cfg(feature = "static")]
statically_link_pdfium();
Ok(())
}
#[cfg(feature = "bindings")]
fn build_bindings() -> Result<(), BuildError> {
// AJRC - 3-Jan-22 - modified from the pdfium-sys version to removing explicit linking to
// a system-provided pdfium. We still want the bindings generated by rust-bindgen,
// since they provide various constants that are useful, but we will load functions
// dynamically at runtime using libloading.
// AJRC - 13-Jan-22 - docs.rs runs cargo doc in a read-only sandbox, so we can't
// generate bindings. Skip bindings generation entirely if the DOCS_RS environment
// variable is set, as per https://docs.rs/about/builds#detecting-docsrs.
// AJRC - 22-Jan-22 - expanded bindings generation to cover all Pdfium modules, not
// just the viewing and rendering functionality defined in fpdfview.h.
// AJRC - 5-Aug-24 - expanded bindings generation to cover multiple versions of the Pdfium API.
// Consumers can use crate feature flags to select a specific API version to use.
for release in read_dir("include/")? {
let release = release?.path();
if release.is_dir() {
build_bindings_for_one_pdfium_release(
release
.file_name()
.ok_or(BuildError::PathConversionError(release.clone()))?
.to_str()
.ok_or(BuildError::PathConversionError(release.clone()))?,
)?;
}
}
Ok(())
}
#[cfg(feature = "bindings")]
fn build_bindings_for_one_pdfium_release(release: &str) -> Result<(), BuildError> {
if var("DOCS_RS").is_err() {
// The DOCS_RS environment variable is _not_ set. Proceed with bindgen.
// Generate an import wrapper telling bindgen which header files to use as input sources.
let header_file_extension = OsStr::new("h");
let wrapper_file_name = OsStr::new("rust-import-wrapper.h");
let mut included_header_files = Vec::new();
for header in read_dir(format!("include/{}/", release))? {
let header = header?.path();
if header.is_file()
&& header.file_name().is_some()
&& header.extension() == Some(header_file_extension)
&& header.file_name() != Some(wrapper_file_name)
{
// Include this header file in the list of input sources.
let header_file_name = header
.file_name()
.ok_or(BuildError::PathConversionError(header.clone()))?
.to_str()
.ok_or(BuildError::PathConversionError(header.clone()))?
.to_owned();
included_header_files.push(header_file_name);
}
}
let wrapper = included_header_files
.iter()
.map(|file_name| format!("#include \"{}\"", file_name))
.collect::<Vec<_>>()
.join("\n");
write(
format!("include/{}/rust-import-wrapper.h", release),
wrapper,
)?;
let bindings = bindgen::Builder::default()
// The input header we would like to generate bindings for.
.header(format!("include/{}/rust-import-wrapper.h", release))
.size_t_is_usize(true) // There are esoteric architectures where size_t != usize. See:
// https://github.com/rust-lang/rust-bindgen/issues/1671
// Long term, the solution is for Bindgen to switch to converting size_t to
// std::os::raw::c_size_t instead of usize, but c_size_t is not yet stabilized.
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new())) // Tell cargo to invalidate
// the built crate whenever any of the included header files change.
.clang_args(
// Try to keep original C++ comments for docs.
[
"-fretain-comments-from-system-headers",
"-fparse-all-comments",
]
.iter(),
)
.generate_comments(true)
.generate()?;
// Write the bindings to src/bindgen.rs.
let out_path = PathBuf::from("src");
bindings.write_to_file(out_path.join(format!("bindgen/{}.rs", release)))?;
}
Ok(())
}
#[cfg(feature = "static")]
fn statically_link_pdfium() {
if let Ok(path) = std::env::var("PDFIUM_STATIC_LIB_PATH") {
// Instruct cargo to statically link the given library during the build.
println!("cargo:rustc-link-lib=static=pdfium");
println!("cargo:rustc-link-search=native={}", path);
// Optionally instruct cargo to link to a C++ standard library during the build.
// TODO: AJRC - 30-Sep-22 - for now, we dynamically link to the selected standard library,
// but ultimately we want to use a link type of "static:-bundle" once the feature is stabilized
// (currently it is available only in nightly builds of Rust).
#[cfg(feature = "libstdc++")]
println!("cargo:rustc-link-lib=dylib=stdc++");
#[cfg(feature = "libc++")]
println!("cargo:rustc-link-lib=dylib=c++");
} else if let Ok(path) = std::env::var("PDFIUM_DYNAMIC_LIB_PATH") {
// Instruct cargo to dynamically link the given library during the build.
println!("cargo:rustc-link-lib=dylib=pdfium");
println!("cargo:rustc-link-search=native={}", path);
}
}