|
3 | 3 | // |
4 | 4 | // SPDX-License-Identifier: MIT OR Apache-2.0 |
5 | 5 |
|
6 | | -use quote::ToTokens; |
7 | | -use serde::{Deserialize, Serialize}; |
8 | | -use std::{fs::File, io::Write, path::PathBuf}; |
9 | | - |
10 | | -/// Representation of a generated CXX header, source, and name |
11 | | -#[derive(Serialize, Deserialize)] |
12 | | -struct GeneratedType { |
13 | | - header: String, |
14 | | - name: String, |
15 | | - source: String, |
16 | | -} |
17 | | - |
18 | | -/// Generate a CXX header, source, name for a given Rust file |
19 | | -fn gen_cxx_sources(folder: &str, file_stem: &str) -> GeneratedType { |
20 | | - // Read the rust source files |
21 | | - let path = format!("{}/{}.rs", folder, file_stem); |
22 | | - println!("cargo:rerun-if-changed={}", path); |
23 | | - let content = std::fs::read_to_string(path).expect("Could not read Rust file"); |
24 | | - let file = syn::parse_file(&content).unwrap(); |
25 | | - |
26 | | - // Generate the CXX header and cc for the file |
27 | | - let opt = cxx_gen::Opt::default(); |
28 | | - let generated = cxx_gen::generate_header_and_cc(file.into_token_stream(), &opt) |
29 | | - .expect("Could not generate C++ from Rust file"); |
30 | | - |
31 | | - GeneratedType { |
32 | | - header: String::from_utf8(generated.header).unwrap(), |
33 | | - name: format!("{}_cxx", file_stem), |
34 | | - source: String::from_utf8(generated.implementation).unwrap(), |
35 | | - } |
36 | | -} |
37 | | - |
38 | | -/// Write generates types to a given file as JSON |
39 | | -fn write_cxx_sources(gen: &Vec<GeneratedType>, path: &str) { |
40 | | - let file = std::fs::File::create(path).expect("Could not create generated file"); |
41 | | - serde_json::to_writer(file, &gen).unwrap(); |
42 | | -} |
43 | | - |
44 | | -fn create_and_write_file(path: &impl AsRef<std::path::Path>, file_contents: &str) { |
45 | | - let path = path.as_ref(); |
46 | | - File::create(&path) |
47 | | - .unwrap_or_else(|_| panic!("Could not create file {}", path.display())) |
48 | | - .write_all(file_contents.as_bytes()) |
49 | | - .unwrap_or_else(|_| panic!("Could not write file {}", path.display())); |
50 | | -} |
| 6 | +use std::env; |
51 | 7 |
|
52 | 8 | fn main() { |
53 | | - // Read the cargo folder and out folder |
54 | | - let mut dir_manifest = std::env::var("CARGO_MANIFEST_DIR").expect("Could not get manifest dir"); |
55 | | - if cfg!(windows) { |
56 | | - dir_manifest = dir_manifest.replace('\\', "/"); |
| 9 | + let qt_modules = vec!["Core", "Gui"] |
| 10 | + .iter() |
| 11 | + .map(|m| String::from(*m)) |
| 12 | + .collect(); |
| 13 | + let qtbuild = qt_build::QtBuild::new(qt_modules).expect("Could not find Qt installation"); |
| 14 | + qtbuild.cargo_link_libraries(); |
| 15 | + |
| 16 | + let bridge_files = [ |
| 17 | + "src/types/qcolor.rs", |
| 18 | + "src/types/qdate.rs", |
| 19 | + "src/types/qdatetime.rs", |
| 20 | + "src/types/qpoint.rs", |
| 21 | + "src/types/qpointf.rs", |
| 22 | + "src/types/qrect.rs", |
| 23 | + "src/types/qrectf.rs", |
| 24 | + "src/types/qsize.rs", |
| 25 | + "src/types/qsizef.rs", |
| 26 | + "src/types/qstring.rs", |
| 27 | + "src/types/qtime.rs", |
| 28 | + "src/types/qurl.rs", |
| 29 | + "src/types/qvariant.rs", |
| 30 | + "src/types/update_requester.rs", |
| 31 | + ]; |
| 32 | + for bridge_file in bridge_files { |
| 33 | + println!("cargo:rerun-if-changed={}", bridge_file); |
57 | 34 | } |
58 | | - println!("cargo:rerun-if-env-changed=CARGO_MANIFEST_DIR"); |
59 | 35 |
|
60 | | - let mut dir_out = std::env::var("OUT_DIR").expect("Could not get out dir"); |
61 | | - if cfg!(windows) { |
62 | | - dir_out = dir_out.replace('\\', "/"); |
| 36 | + for include_path in qtbuild.include_paths() { |
| 37 | + cxx_build::CFG |
| 38 | + .exported_header_dirs |
| 39 | + .push(include_path.as_path()); |
63 | 40 | } |
64 | | - println!("cargo:rerun-if-env-changed=OUT_DIR"); |
65 | | - |
66 | | - // Prepare cxx-qt-lib dir we'll write to |
67 | | - let path = format!("{}/cxx-qt-lib", dir_out); |
68 | | - std::fs::create_dir_all(&path).expect("Could not create cxx-qt-lib dir"); |
69 | 41 |
|
70 | | - // Read the types directory for CXX objects |
71 | | - let types_dir = format!("{}/src/types/", dir_manifest); |
72 | | - // If any of the files in this directory change, then we need to re-run |
73 | | - println!("cargo:rerun-if-changed={}", types_dir); |
74 | | - |
75 | | - let mut generated = vec![]; |
76 | | - |
77 | | - for entry in std::fs::read_dir(&types_dir).expect("Could not open types folder") { |
78 | | - let path = entry.expect("Could not open file").path(); |
79 | | - let file_stem = path |
80 | | - .file_stem() |
81 | | - .expect("Could not find file name") |
82 | | - .to_str() |
83 | | - .expect("Could not convert to unicode"); |
84 | | - |
85 | | - // Check we are a file and not the mod.rs |
86 | | - if path.is_file() && file_stem != "mod" { |
87 | | - generated.push(gen_cxx_sources(&types_dir, file_stem)); |
88 | | - } |
| 42 | + let mut builder = cxx_build::bridges(&bridge_files); |
| 43 | + for cpp_file in ["src/qt_types.cpp"] { |
| 44 | + builder.file(cpp_file); |
| 45 | + println!("cargo:rerun-if-changed={}", cpp_file); |
89 | 46 | } |
90 | | - |
91 | | - // Write the generated sources to a qt_types_cxx.json file |
92 | | - write_cxx_sources(&generated, &format!("{}/qt_types_cxx.json", path)); |
93 | | - |
94 | | - // Write the generated sources to CXX_QT_LIB_OUT_DIR if set |
95 | | - println!("cargo:rerun-if-env-changed=CXX_QT_LIB_OUT_DIR"); |
96 | | - if let Ok(env_var) = std::env::var("CXX_QT_LIB_OUT_DIR") { |
97 | | - let directory = PathBuf::from(env_var); |
98 | | - if !directory.is_dir() { |
99 | | - panic!( |
100 | | - "CXX_QT_LIB_OUT_DIR {} is not a directory", |
101 | | - directory.display() |
102 | | - ); |
103 | | - } |
104 | | - |
105 | | - let include_directory_path = PathBuf::from(format!("{}/include", &directory.display())); |
106 | | - std::fs::create_dir_all(&include_directory_path) |
107 | | - .expect("Could not create CXX_QT_LIB_OUT_DIR include dir"); |
108 | | - let source_directory_path = PathBuf::from(format!("{}/src", &directory.display())); |
109 | | - std::fs::create_dir_all(&source_directory_path) |
110 | | - .expect("Could not create CXX_QT_LIB_OUT_DIR source dir"); |
111 | | - |
112 | | - std::fs::copy( |
113 | | - format!("{}/include/qt_types.h", dir_manifest), |
114 | | - format!("{}/qt_types.h", include_directory_path.display()), |
115 | | - ) |
116 | | - .expect("Could not copy qt_types.h to CXX_QT_LIB_OUT_DIR"); |
| 47 | + // MSVC |
| 48 | + builder.flag_if_supported("/std:c++17"); |
| 49 | + builder.flag_if_supported("/Zc:__cplusplus"); |
| 50 | + // GCC + Clang |
| 51 | + builder.flag_if_supported("-std=c++17"); |
| 52 | + builder.compile("cxx-qt-lib"); |
| 53 | + |
| 54 | + // Copy qt_types.h so CMake can include it. |
| 55 | + // By design, CARGO_TARGET_DIR is not set by cargo when running build scripts. |
| 56 | + // Copying the header is only needed for making the header available to a C++ |
| 57 | + // build system, in which case CARGO_TARGET_DIR will be set by |
| 58 | + // the C++ build system. |
| 59 | + if let Ok(target_dir) = env::var("CARGO_TARGET_DIR") { |
| 60 | + let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); |
| 61 | + std::fs::create_dir_all(&format!("{}/cxxbridge/cxx-qt-lib/include", target_dir)).unwrap(); |
117 | 62 | std::fs::copy( |
118 | | - format!("{}/src/qt_types.cpp", dir_manifest), |
119 | | - format!("{}/qt_types.cpp", source_directory_path.display()), |
| 63 | + &format!("{}/include/qt_types.h", manifest_dir), |
| 64 | + &format!("{}/cxxbridge/cxx-qt-lib/include/qt_types.h", target_dir), |
120 | 65 | ) |
121 | | - .expect("Could not copy qt_types.cpp to CXX_QT_LIB_OUT_DIR"); |
122 | | - |
123 | | - create_and_write_file( |
124 | | - &format!("{}/cxx.h", include_directory_path.display()), |
125 | | - cxx_gen::HEADER, |
126 | | - ); |
127 | | - |
128 | | - for class in generated { |
129 | | - create_and_write_file( |
130 | | - &format!("{}/{}.h", include_directory_path.display(), class.name), |
131 | | - &class.header, |
132 | | - ); |
133 | | - |
134 | | - create_and_write_file( |
135 | | - &format!("{}/{}.cpp", source_directory_path.display(), class.name), |
136 | | - &class.source, |
137 | | - ); |
138 | | - } |
| 66 | + .unwrap(); |
139 | 67 | } |
140 | 68 | } |
0 commit comments