1use std::marker::PhantomData;
6use std::path::{Path, PathBuf};
7use std::process::Command;
8
9pub struct StatusSetProjectDir;
11
12pub struct StatusSetConfigPreset;
14
15pub struct StatusSetLibraryName;
17
18pub struct StatusConfig;
20
21pub struct StatusBuild;
23
24#[derive(Debug)]
26pub struct CMakePresetBuilder<S> {
27 output_dir: PathBuf,
28 project_dir: PathBuf,
29 config_preset: String,
30 library_name: String,
31 _phantom: PhantomData<S>,
32}
33
34impl CMakePresetBuilder<StatusSetProjectDir> {
35 pub fn new() -> CMakePresetBuilder<StatusSetProjectDir> {
37 CMakePresetBuilder {
38 output_dir: std::env::var("OUT_DIR")
39 .unwrap_or_else(|_| ".".to_string())
40 .into(),
41 project_dir: PathBuf::new(),
42 config_preset: "".to_string(),
43 library_name: "".to_string(),
44 _phantom: PhantomData,
45 }
46 }
47
48 pub fn set_project_dir<P: AsRef<Path>>(
53 self,
54 project_dir: P,
55 ) -> CMakePresetBuilder<StatusSetConfigPreset> {
56 if !project_dir.as_ref().exists() {
57 panic!(
58 "Project directory:{:?} does not exist",
59 project_dir.as_ref()
60 );
61 } else if !project_dir.as_ref().is_dir() {
62 panic!(
63 "Project directory:{:?} is not a directory",
64 project_dir.as_ref()
65 );
66 }
67
68 println!(
69 "cargo:rerun-if-changed={}/",
70 project_dir.as_ref().to_str().unwrap()
71 );
72 CMakePresetBuilder {
73 output_dir: self.output_dir,
74 project_dir: project_dir.as_ref().to_path_buf(),
75 config_preset: self.config_preset,
76 library_name: self.library_name,
77 _phantom: PhantomData,
78 }
79 }
80}
81
82impl CMakePresetBuilder<StatusSetConfigPreset> {
83 pub fn set_config_preset(
87 self,
88 preset_name: impl AsRef<str>,
89 ) -> CMakePresetBuilder<StatusSetLibraryName> {
90 CMakePresetBuilder {
91 output_dir: self.output_dir,
92 project_dir: self.project_dir,
93 config_preset: preset_name.as_ref().into(),
94 library_name: self.library_name,
95 _phantom: PhantomData,
96 }
97 }
98}
99
100impl CMakePresetBuilder<StatusSetLibraryName> {
101 pub fn set_library_name(
105 self,
106 library_name: impl AsRef<str>,
107 ) -> CMakePresetBuilder<StatusConfig> {
108 println!(
109 "cargo:rustc-link-search=native={}",
110 self.output_dir.to_str().unwrap()
111 );
112 println!("cargo:rustc-link-lib=static={}", library_name.as_ref());
113 CMakePresetBuilder {
114 output_dir: self.output_dir,
115 project_dir: self.project_dir,
116 config_preset: self.config_preset,
117 library_name: library_name.as_ref().to_string(),
118 _phantom: PhantomData,
119 }
120 }
121}
122
123impl CMakePresetBuilder<StatusConfig> {
124 pub fn config(self) -> CMakePresetBuilder<StatusBuild> {
126 let output_dir = std::env::var("OUT_DIR").unwrap_or_else(|_| ".".to_string());
127
128 if !self.project_dir.exists() {
129 panic!("Project directory does not exist: {:?}", self.project_dir);
130 }
131
132 let output = Command::new("cmake")
133 .arg("--preset")
134 .arg(&self.config_preset)
135 .arg("-B")
136 .arg(&output_dir)
137 .current_dir(&self.project_dir)
138 .output()
139 .unwrap();
140
141 if !output.status.success() {
142 panic!(
143 "CMake configure failed: {}",
144 String::from_utf8_lossy(&output.stderr)
145 );
146 }
147
148 CMakePresetBuilder {
149 output_dir: self.output_dir,
150 project_dir: self.project_dir,
151 config_preset: self.config_preset,
152 library_name: self.library_name,
153 _phantom: PhantomData,
154 }
155 }
156}
157
158impl CMakePresetBuilder<StatusBuild> {
159 pub fn build(self) {
161 let output = Command::new("cmake")
162 .arg("--build")
163 .arg(&self.output_dir)
164 .arg("--parallel")
165 .current_dir(&self.project_dir)
166 .output()
167 .unwrap();
168
169 if !output.status.success() {
170 panic!(
171 "CMake build failed: {}",
172 String::from_utf8_lossy(&output.stdout)
173 );
174 }
175 }
176}