2
2
// Copyright 2016-2020 the Tectonic Project
3
3
// Licensed under the MIT License.
4
4
5
- /// The Tectonic build script. Not only do we have internal C/C++ code, we
6
- /// also depend on several external C/C++ libraries, so there's a lot to do
7
- /// here. It would be great to streamline things.
8
- use std:: {
9
- env,
10
- path:: { Path , PathBuf } ,
11
- } ;
12
- use tectonic_cfg_support:: * ;
13
-
14
- #[ cfg( not( target_os = "macos" ) ) ]
15
- const PKGCONFIG_LIBS : & str =
16
- "fontconfig harfbuzz >= 1.4 harfbuzz-icu icu-uc freetype2 graphite2 libpng" ;
17
-
18
- // No fontconfig on MacOS:
19
- #[ cfg( target_os = "macos" ) ]
20
- const PKGCONFIG_LIBS : & str = "harfbuzz >= 1.4 harfbuzz-icu icu-uc freetype2 graphite2 libpng" ;
21
-
22
- /// Build-script state when using pkg-config as the backend.
23
- #[ derive( Debug ) ]
24
- struct PkgConfigState {
25
- libs : pkg_config:: Library ,
26
- }
27
-
28
- // Need a way to check that the vcpkg harfbuzz port has graphite2 and icu options enabled.
29
- #[ cfg( not( target_os = "macos" ) ) ]
30
- const VCPKG_LIBS : & [ & str ] = & [ "fontconfig" , "harfbuzz" , "freetype" , "graphite2" ] ;
31
-
32
- #[ cfg( target_os = "macos" ) ]
33
- const VCPKG_LIBS : & [ & str ] = & [ "harfbuzz" , "freetype" , "graphite2" ] ;
34
-
35
- /// Build-script state when using vcpkg as the backend.
36
- #[ derive( Clone , Debug ) ]
37
- struct VcPkgState {
38
- include_paths : Vec < PathBuf > ,
39
- }
40
-
41
- /// State for discovering and managing our dependencies, which may vary
42
- /// depending on the framework that we're using to discover them.
43
- ///
44
- /// The basic gameplan is that we probe our dependencies to check that they're
45
- /// available and pull out the C/C++ include directories; then we emit info
46
- /// for building our C/C++ libraries; then we emit info for our dependencies.
47
- /// Building stuff pretty much always requires some level of hackery, though,
48
- /// so we don't try to be purist about the details.
49
- #[ derive( Debug ) ]
50
- enum DepState {
51
- /// pkg-config
52
- PkgConfig ( PkgConfigState ) ,
53
-
54
- /// vcpkg
55
- VcPkg ( VcPkgState ) ,
56
- }
57
-
58
- impl DepState {
59
- /// Probe for our dependent libraries using pkg-config.
60
- fn new_pkg_config ( ) -> Self {
61
- let statik = env:: var ( "TECTONIC_PKGCONFIG_FORCE_SEMI_STATIC" ) . is_ok ( ) ;
62
-
63
- let libs = pkg_config:: Config :: new ( )
64
- . cargo_metadata ( false )
65
- . statik ( statik)
66
- . probe ( PKGCONFIG_LIBS )
67
- . unwrap ( ) ;
68
- DepState :: PkgConfig ( PkgConfigState { libs } )
69
- }
5
+ //! The Tectonic build script. Not only do we have internal C/C++ code, we
6
+ //! also depend on several external C/C++ libraries, so there's a lot to do
7
+ //! here. It would be great to streamline things.
70
8
71
- /// Probe for our dependent libraries using vcpkg.
72
- fn new_vcpkg ( ) -> Self {
73
- let mut include_paths = vec ! [ ] ;
9
+ use std :: { env , path :: PathBuf } ;
10
+ use tectonic_cfg_support :: * ;
11
+ use tectonic_dep_support :: { Backend , Configuration , Dependency , Spec } ;
74
12
75
- for dep in VCPKG_LIBS {
76
- let library = vcpkg:: Config :: new ( )
77
- . cargo_metadata ( false )
78
- . find_package ( dep)
79
- . unwrap_or_else ( |e| panic ! ( "failed to load package {} from vcpkg: {}" , dep, e) ) ;
80
- include_paths. extend ( library. include_paths . iter ( ) . cloned ( ) ) ;
81
- }
13
+ struct TectonicRestSpec ;
82
14
83
- DepState :: VcPkg ( VcPkgState { include_paths } )
15
+ impl Spec for TectonicRestSpec {
16
+ #[ cfg( not( target_os = "macos" ) ) ]
17
+ fn get_pkgconfig_spec ( & self ) -> & str {
18
+ "fontconfig harfbuzz >= 1.4 harfbuzz-icu icu-uc freetype2 libpng"
84
19
}
85
20
86
- /// Invoke a callback for each C/C++ include directory injected by our
87
- /// dependencies.
88
- fn foreach_include_path < F > ( & self , mut f : F )
89
- where
90
- F : FnMut ( & Path ) ,
91
- {
92
- match self {
93
- DepState :: PkgConfig ( ref s) => {
94
- for p in & s. libs . include_paths {
95
- f ( p) ;
96
- }
97
- }
98
-
99
- DepState :: VcPkg ( ref s) => {
100
- for p in & s. include_paths {
101
- f ( p) ;
102
- }
103
- }
104
- }
21
+ // No fontconfig on macOS.
22
+ #[ cfg( target_os = "macos" ) ]
23
+ fn get_pkgconfig_spec ( & self ) -> & str {
24
+ "harfbuzz >= 1.4 harfbuzz-icu icu-uc freetype2 libpng"
105
25
}
106
26
107
- /// This function is called after we've emitted the cargo compilation info
108
- /// for our own libraries. Now we can emit any special information
109
- /// relating to our dependencies, which may depend on the dep-finding
110
- /// backend or the target.
111
- fn emit_late_extras ( & self , target : & str ) {
112
- match self {
113
- DepState :: PkgConfig ( ref state) => {
114
- if env:: var ( "TECTONIC_PKGCONFIG_FORCE_SEMI_STATIC" ) . is_ok ( ) {
115
- // pkg-config will prevent "system libraries" from being
116
- // linked statically even when PKG_CONFIG_ALL_STATIC=1,
117
- // but its definition of a system library isn't always
118
- // perfect. For Debian cross builds, we'd like to make
119
- // binaries that are dynamically linked with things like
120
- // libc and libm but not libharfbuzz, etc. In this mode we
121
- // override pkg-config's logic by emitting the metadata
122
- // ourselves.
123
- for link_path in & state. libs . link_paths {
124
- println ! ( "cargo:rustc-link-search=native={}" , link_path. display( ) ) ;
125
- }
126
-
127
- for fw_path in & state. libs . framework_paths {
128
- println ! ( "cargo:rustc-link-search=framework={}" , fw_path. display( ) ) ;
129
- }
130
-
131
- for libbase in & state. libs . libs {
132
- let do_static = match libbase. as_ref ( ) {
133
- "c" | "m" | "dl" | "pthread" => false ,
134
- _ => {
135
- // Frustratingly, graphite2 seems to have
136
- // issues with static builds; e.g. static
137
- // graphite2 is not available on Debian. So
138
- // let's jump through the hoops of testing
139
- // whether the static archive seems findable.
140
- let libname = format ! ( "lib{}.a" , libbase) ;
141
- state
142
- . libs
143
- . link_paths
144
- . iter ( )
145
- . any ( |d| d. join ( & libname) . exists ( ) )
146
- }
147
- } ;
148
-
149
- let mode = if do_static { "static=" } else { "" } ;
150
- println ! ( "cargo:rustc-link-lib={}{}" , mode, libbase) ;
151
- }
152
-
153
- for fw in & state. libs . frameworks {
154
- println ! ( "cargo:rustc-link-lib=framework={}" , fw) ;
155
- }
156
- } else {
157
- // Just let pkg-config do its thing.
158
- pkg_config:: Config :: new ( )
159
- . cargo_metadata ( true )
160
- . probe ( PKGCONFIG_LIBS )
161
- . unwrap ( ) ;
162
- }
163
- }
164
-
165
- DepState :: VcPkg ( _) => {
166
- for dep in VCPKG_LIBS {
167
- vcpkg:: find_package ( dep) . unwrap_or_else ( |e| {
168
- panic ! ( "failed to load package {} from vcpkg: {}" , dep, e)
169
- } ) ;
170
- }
171
- if target. contains ( "-linux-" ) {
172
- // add icudata to the end of the list of libs as vcpkg-rs
173
- // does not order individual libraries as a single pass
174
- // linker requires.
175
- println ! ( "cargo:rustc-link-lib=icudata" ) ;
176
- }
177
- }
178
- }
27
+ // Would be nice to have a way to check that the vcpkg harfbuzz port has
28
+ // graphite2 and icu options enabled.
29
+ #[ cfg( not( target_os = "macos" ) ) ]
30
+ fn get_vcpkg_spec ( & self ) -> & [ & str ] {
31
+ & [ "fontconfig" , "harfbuzz" , "freetype" ]
179
32
}
180
- }
181
33
182
- /// The default dependency-finding backend is pkg-config.
183
- impl Default for DepState {
184
- fn default ( ) -> Self {
185
- DepState :: new_pkg_config ( )
34
+ #[ cfg( target_os = "macos" ) ]
35
+ fn get_vcpkg_spec ( & self ) -> & [ & str ] {
36
+ & [ "harfbuzz" , "freetype" ]
186
37
}
187
38
}
188
39
@@ -193,6 +44,7 @@ fn main() {
193
44
// Generate bindings for the C/C++ code to interface with backend Rust code.
194
45
// As a heuristic we trigger rebuilds on changes to src/engines/mod.rs since
195
46
// most of `core-bindgen.h` comes from this file.
47
+
196
48
let mut cbindgen_header_path: PathBuf = env:: var ( "OUT_DIR" ) . unwrap ( ) . into ( ) ;
197
49
cbindgen_header_path. push ( "core-bindgen.h" ) ;
198
50
@@ -208,28 +60,19 @@ fn main() {
208
60
209
61
println ! ( "cargo:rustc-env=TARGET={}" , target) ;
210
62
211
- // OK, how are we finding our dependencies?
63
+ // Find our dependencies that aren't provided by any bridge or -sys crates.
212
64
213
- println ! ( "cargo:rerun-if-env-changed=TECTONIC_DEP_BACKEND" ) ;
214
- println ! ( "cargo:rerun-if-env-changed=TECTONIC_PKGCONFIG_FORCE_SEMI_STATIC" ) ;
215
-
216
- let dep_state = if let Ok ( dep_backend_str) = env:: var ( "TECTONIC_DEP_BACKEND" ) {
217
- match dep_backend_str. as_ref ( ) {
218
- "pkg-config" => DepState :: new_pkg_config ( ) ,
219
- "vcpkg" => DepState :: new_vcpkg ( ) ,
220
- "default" => DepState :: default ( ) ,
221
- other => panic ! ( "unrecognized TECTONIC_DEP_BACKEND setting {:?}" , other) ,
222
- }
223
- } else {
224
- DepState :: default ( )
225
- } ;
65
+ let dep_cfg = Configuration :: default ( ) ;
66
+ let dep = Dependency :: probe ( TectonicRestSpec , & dep_cfg) ;
226
67
227
68
// Include paths exported by our internal dependencies.
228
69
229
70
let flate_include_dir = env:: var ( "DEP_TECTONIC_BRIDGE_FLATE_INCLUDE" ) . unwrap ( ) ;
71
+ let graphite2_include_dir = env:: var ( "DEP_GRAPHITE2_INCLUDE" ) . unwrap ( ) ;
230
72
231
- // Actually I'm not 100% sure that I can't compile the C and C++ code
232
- // into one library, but who cares?
73
+ // Specify the C/C++ support libraries. Actually I'm not 100% sure that I
74
+ // can't compile the C and C++ code into one library, but it's no a big deal
75
+ // -- it all gets linked together in the end.
233
76
234
77
let mut ccfg = cc:: Build :: new ( ) ;
235
78
let mut cppcfg = cc:: Build :: new ( ) ;
@@ -280,6 +123,7 @@ fn main() {
280
123
// compiler to include frame pointers. We whitelist platforms that are
281
124
// known to be able to profile *without* frame pointers: currently, only
282
125
// Linux/x86_64.
126
+
283
127
let profile_target_requires_frame_pointer: bool =
284
128
target_cfg ! ( not( all( target_os = "linux" , target_arch = "x86_64" ) ) ) ;
285
129
@@ -387,6 +231,7 @@ fn main() {
387
231
. file ( "tectonic/xetex-xetex0.c" )
388
232
. include ( env:: var ( "OUT_DIR" ) . unwrap ( ) )
389
233
. include ( "." )
234
+ . include ( & graphite2_include_dir)
390
235
. include ( & flate_include_dir) ;
391
236
392
237
let cppflags = [
@@ -437,9 +282,10 @@ fn main() {
437
282
. file ( "tectonic/xetex-XeTeXOTMath.cpp" )
438
283
. include ( env:: var ( "OUT_DIR" ) . unwrap ( ) )
439
284
. include ( "." )
285
+ . include ( & graphite2_include_dir)
440
286
. include ( & flate_include_dir) ;
441
287
442
- dep_state . foreach_include_path ( |p| {
288
+ dep . foreach_include_path ( |p| {
443
289
ccfg. include ( p) ;
444
290
cppcfg. include ( p) ;
445
291
} ) ;
@@ -488,7 +334,17 @@ fn main() {
488
334
ccfg. compile ( "libtectonic_c.a" ) ;
489
335
cppcfg. compile ( "libtectonic_cpp.a" ) ;
490
336
491
- dep_state. emit_late_extras ( & target) ;
337
+ dep. emit ( ) ;
338
+
339
+ // vcpkg-rs is not guaranteed to emit libraries in the order required by a
340
+ // single-pass linker, so we might need to make sure that's done right.
341
+
342
+ if dep_cfg. backend == Backend :: Vcpkg && target. contains ( "-linux-" ) {
343
+ // add icudata to the end of the list of libs as vcpkg-rs
344
+ // does not order individual libraries as a single pass
345
+ // linker requires.
346
+ println ! ( "cargo:rustc-link-lib=icudata" ) ;
347
+ }
492
348
493
349
// Tell cargo to rerun build.rs only if files in the tectonic/ directory have changed.
494
350
for file in PathBuf :: from ( "tectonic" ) . read_dir ( ) . unwrap ( ) {
0 commit comments