build.rs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. // Copyright 2019-2023 Tauri Programme within The Commons Conservancy
  2. // SPDX-License-Identifier: Apache-2.0
  3. // SPDX-License-Identifier: MIT
  4. use heck::AsShoutySnakeCase;
  5. use heck::AsSnakeCase;
  6. use heck::ToSnakeCase;
  7. use once_cell::sync::OnceCell;
  8. use std::{path::Path, sync::Mutex};
  9. static CHECKED_FEATURES: OnceCell<Mutex<Vec<String>>> = OnceCell::new();
  10. // checks if the given Cargo feature is enabled.
  11. fn has_feature(feature: &str) -> bool {
  12. CHECKED_FEATURES
  13. .get_or_init(Default::default)
  14. .lock()
  15. .unwrap()
  16. .push(feature.to_string());
  17. // when a feature is enabled, Cargo sets the `CARGO_FEATURE_<name>` env var to 1
  18. // https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts
  19. std::env::var(format!("CARGO_FEATURE_{}", AsShoutySnakeCase(feature)))
  20. .map(|x| x == "1")
  21. .unwrap_or(false)
  22. }
  23. // creates a cfg alias if `has_feature` is true.
  24. // `alias` must be a snake case string.
  25. fn alias(alias: &str, has_feature: bool) {
  26. println!("cargo:rustc-check-cfg=cfg({alias})");
  27. if has_feature {
  28. println!("cargo:rustc-cfg={alias}");
  29. }
  30. }
  31. fn main() {
  32. alias("custom_protocol", has_feature("custom-protocol"));
  33. alias("dev", !has_feature("custom-protocol"));
  34. alias("updater", has_feature("updater"));
  35. let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap();
  36. let mobile = target_os == "ios" || target_os == "android";
  37. alias("desktop", !mobile);
  38. alias("mobile", mobile);
  39. let api_all = has_feature("api-all");
  40. alias("api_all", api_all);
  41. alias_module(
  42. "fs",
  43. &[
  44. "read-file",
  45. "write-file",
  46. "read-dir",
  47. "copy-file",
  48. "create-dir",
  49. "remove-dir",
  50. "remove-file",
  51. "rename-file",
  52. "exists",
  53. ],
  54. api_all,
  55. );
  56. alias_module(
  57. "window",
  58. &[
  59. "create",
  60. "center",
  61. "request-user-attention",
  62. "set-resizable",
  63. "set-maximizable",
  64. "set-minimizable",
  65. "set-closable",
  66. "set-title",
  67. "maximize",
  68. "unmaximize",
  69. "minimize",
  70. "unminimize",
  71. "show",
  72. "hide",
  73. "close",
  74. "set-decorations",
  75. "set-always-on-top",
  76. "set-content-protected",
  77. "set-size",
  78. "set-min-size",
  79. "set-max-size",
  80. "set-position",
  81. "set-fullscreen",
  82. "set-focus",
  83. "set-icon",
  84. "set-skip-taskbar",
  85. "set-cursor-grab",
  86. "set-cursor-visible",
  87. "set-cursor-icon",
  88. "set-cursor-position",
  89. "set-ignore-cursor-events",
  90. "start-dragging",
  91. "print",
  92. ],
  93. api_all,
  94. );
  95. alias_module("shell", &["execute", "sidecar", "open"], api_all);
  96. // helper for the command module macro
  97. let shell_script = has_feature("shell-execute") || has_feature("shell-sidecar");
  98. alias("shell_script", shell_script);
  99. alias("shell_scope", has_feature("shell-open-api") || shell_script);
  100. if !mobile {
  101. alias_module(
  102. "dialog",
  103. &["open", "save", "message", "ask", "confirm"],
  104. api_all,
  105. );
  106. }
  107. alias_module("http", &["request"], api_all);
  108. alias("cli", has_feature("cli"));
  109. if !mobile {
  110. alias_module("notification", &[], api_all);
  111. alias_module("global-shortcut", &[], api_all);
  112. }
  113. alias_module("os", &[], api_all);
  114. alias_module("path", &[], api_all);
  115. alias_module("protocol", &["asset"], api_all);
  116. alias_module("process", &["relaunch", "exit"], api_all);
  117. alias_module("clipboard", &["write-text", "read-text"], api_all);
  118. alias_module("app", &["show", "hide"], api_all);
  119. let checked_features_out_path =
  120. Path::new(&std::env::var("OUT_DIR").unwrap()).join("checked_features");
  121. std::fs::write(
  122. checked_features_out_path,
  123. CHECKED_FEATURES.get().unwrap().lock().unwrap().join(","),
  124. )
  125. .expect("failed to write checked_features file");
  126. // workaround needed to prevent `STATUS_ENTRYPOINT_NOT_FOUND` error
  127. // see https://github.com/tauri-apps/tauri/pull/4383#issuecomment-1212221864
  128. let target_os = std::env::var("CARGO_CFG_TARGET_OS");
  129. let target_env = std::env::var("CARGO_CFG_TARGET_ENV");
  130. let is_tauri_workspace = std::env::var("__TAURI_WORKSPACE__").map_or(false, |v| v == "true");
  131. if is_tauri_workspace
  132. && Ok("windows") == target_os.as_deref()
  133. && Ok("msvc") == target_env.as_deref()
  134. {
  135. add_manifest();
  136. }
  137. }
  138. // create aliases for the given module with its apis.
  139. // each api is translated into a feature flag in the format of `<module>-<api>`
  140. // and aliased as `<module_snake_case>_<api_snake_case>`.
  141. //
  142. // The `<module>-all` feature is also aliased to `<module>_all`.
  143. //
  144. // If any of the features is enabled, the `<module_snake_case>_any` alias is created.
  145. //
  146. // Note that both `module` and `apis` strings must be written in kebab case.
  147. fn alias_module(module: &str, apis: &[&str], api_all: bool) {
  148. let all_feature_name = format!("{module}-all");
  149. let all = has_feature(&all_feature_name) || api_all;
  150. alias(&all_feature_name.to_snake_case(), all);
  151. let mut any = all;
  152. for api in apis {
  153. let has = has_feature(&format!("{module}-{api}")) || all;
  154. alias(
  155. &format!("{}_{}", AsSnakeCase(module), AsSnakeCase(api)),
  156. has,
  157. );
  158. any = any || has;
  159. }
  160. alias(&format!("{}_any", AsSnakeCase(module)), any);
  161. }
  162. fn add_manifest() {
  163. static WINDOWS_MANIFEST_FILE: &str = "window-app-manifest.xml";
  164. let manifest = std::env::current_dir()
  165. .unwrap()
  166. .join("../tauri-build/src")
  167. .join(WINDOWS_MANIFEST_FILE);
  168. println!("cargo:rerun-if-changed={}", manifest.display());
  169. // Embed the Windows application manifest file.
  170. println!("cargo:rustc-link-arg=/MANIFEST:EMBED");
  171. println!(
  172. "cargo:rustc-link-arg=/MANIFESTINPUT:{}",
  173. manifest.to_str().unwrap()
  174. );
  175. // Turn linker warnings into errors.
  176. println!("cargo:rustc-link-arg=/WX");
  177. }