22// Copyright 2016-2020 the Tectonic Project
33// Licensed under the MIT License.
44
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.
708
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 } ;
7412
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 ;
8214
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"
8419 }
8520
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"
10525 }
10626
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" ]
17932 }
180- }
18133
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" ]
18637 }
18738}
18839
@@ -193,6 +44,7 @@ fn main() {
19344 // Generate bindings for the C/C++ code to interface with backend Rust code.
19445 // As a heuristic we trigger rebuilds on changes to src/engines/mod.rs since
19546 // most of `core-bindgen.h` comes from this file.
47+
19648 let mut cbindgen_header_path: PathBuf = env:: var ( "OUT_DIR" ) . unwrap ( ) . into ( ) ;
19749 cbindgen_header_path. push ( "core-bindgen.h" ) ;
19850
@@ -208,28 +60,19 @@ fn main() {
20860
20961 println ! ( "cargo:rustc-env=TARGET={}" , target) ;
21062
211- // OK, how are we finding our dependencies?
63+ // Find our dependencies that aren't provided by any bridge or -sys crates.
21264
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) ;
22667
22768 // Include paths exported by our internal dependencies.
22869
22970 let flate_include_dir = env:: var ( "DEP_TECTONIC_BRIDGE_FLATE_INCLUDE" ) . unwrap ( ) ;
71+ let graphite2_include_dir = env:: var ( "DEP_GRAPHITE2_INCLUDE" ) . unwrap ( ) ;
23072
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.
23376
23477 let mut ccfg = cc:: Build :: new ( ) ;
23578 let mut cppcfg = cc:: Build :: new ( ) ;
@@ -280,6 +123,7 @@ fn main() {
280123 // compiler to include frame pointers. We whitelist platforms that are
281124 // known to be able to profile *without* frame pointers: currently, only
282125 // Linux/x86_64.
126+
283127 let profile_target_requires_frame_pointer: bool =
284128 target_cfg ! ( not( all( target_os = "linux" , target_arch = "x86_64" ) ) ) ;
285129
@@ -387,6 +231,7 @@ fn main() {
387231 . file ( "tectonic/xetex-xetex0.c" )
388232 . include ( env:: var ( "OUT_DIR" ) . unwrap ( ) )
389233 . include ( "." )
234+ . include ( & graphite2_include_dir)
390235 . include ( & flate_include_dir) ;
391236
392237 let cppflags = [
@@ -437,9 +282,10 @@ fn main() {
437282 . file ( "tectonic/xetex-XeTeXOTMath.cpp" )
438283 . include ( env:: var ( "OUT_DIR" ) . unwrap ( ) )
439284 . include ( "." )
285+ . include ( & graphite2_include_dir)
440286 . include ( & flate_include_dir) ;
441287
442- dep_state . foreach_include_path ( |p| {
288+ dep . foreach_include_path ( |p| {
443289 ccfg. include ( p) ;
444290 cppcfg. include ( p) ;
445291 } ) ;
@@ -488,7 +334,17 @@ fn main() {
488334 ccfg. compile ( "libtectonic_c.a" ) ;
489335 cppcfg. compile ( "libtectonic_cpp.a" ) ;
490336
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+ }
492348
493349 // Tell cargo to rerun build.rs only if files in the tectonic/ directory have changed.
494350 for file in PathBuf :: from ( "tectonic" ) . read_dir ( ) . unwrap ( ) {
0 commit comments