feat: Generate platform-specific shared library boilerplate in source files and improve code formatting.
All checks were successful
Rust Cross-Compile and Release / build_and_release (push) Successful in 3m8s

This commit is contained in:
Yakumo Hokori
2026-01-18 01:20:44 +08:00
parent 8b2c3ffe53
commit 3575497448

View File

@@ -1,4 +1,4 @@
use anyhow::{anyhow, Context, Result}; use anyhow::{Context, Result, anyhow};
use clap::{Parser, ValueEnum}; use clap::{Parser, ValueEnum};
use inquire::{Confirm, Select, Text}; use inquire::{Confirm, Select, Text};
use regex::Regex; use regex::Regex;
@@ -85,7 +85,11 @@ fn generate_cmakelists(
) -> String { ) -> String {
let mut lines = vec![ let mut lines = vec![
"cmake_minimum_required(VERSION 3.20)".to_string(), "cmake_minimum_required(VERSION 3.20)".to_string(),
format!("project({} LANGUAGES {})", project_name, get_lang_cmake(lang)), format!(
"project({} LANGUAGES {})",
project_name,
get_lang_cmake(lang)
),
"".to_string(), "".to_string(),
]; ];
@@ -110,24 +114,27 @@ fn generate_cmakelists(
let ext = get_lang_ext(lang); let ext = get_lang_ext(lang);
match project_type { match project_type {
ProjectType::Exe => { ProjectType::Exe => {
lines.push(format!( lines.push(format!("add_executable({} src/main.{})", project_name, ext,));
"add_executable({} src/main.{})",
project_name, ext,
));
} }
ProjectType::StaticLib => { ProjectType::StaticLib => {
lines.push(format!( lines.push(format!(
"add_library({} STATIC src/main.{})", "add_library({} STATIC src/main.{})",
project_name, ext, project_name, ext,
)); ));
lines.push(format!("target_include_directories({} PUBLIC include)", project_name)); lines.push(format!(
"target_include_directories({} PUBLIC include)",
project_name
));
} }
ProjectType::SharedLib => { ProjectType::SharedLib => {
lines.push(format!( lines.push(format!(
"add_library({} SHARED src/main.{})", "add_library({} SHARED src/main.{})",
project_name, ext, project_name, ext,
)); ));
lines.push(format!("target_include_directories({} PUBLIC include)", project_name)); lines.push(format!(
"target_include_directories({} PUBLIC include)",
project_name
));
lines.push(format!( lines.push(format!(
"target_compile_definitions({} PUBLIC {}_EXPORTS)", "target_compile_definitions({} PUBLIC {}_EXPORTS)",
project_name, project_name,
@@ -137,23 +144,67 @@ fn generate_cmakelists(
} }
// 添加导出设置(仅库类型) // 添加导出设置(仅库类型)
if matches!(project_type, ProjectType::StaticLib | ProjectType::SharedLib) { if matches!(
project_type,
ProjectType::StaticLib | ProjectType::SharedLib
) {
lines.push("".to_string()); lines.push("".to_string());
lines.push("# Export targets".to_string()); lines.push("# Export targets".to_string());
lines.push("include(GNUInstallDirs)".to_string()); lines.push("include(GNUInstallDirs)".to_string());
lines.push(format!( lines.push(format!("install(TARGETS {} DESTINATION lib)", project_name));
"install(TARGETS {} DESTINATION lib)", lines.push("install(DIRECTORY include/ DESTINATION include)".to_string());
project_name
));
lines.push(
"install(DIRECTORY include/ DESTINATION include)".to_string(),
);
} }
lines.join("\n") lines.join("\n")
} }
fn generate_source_file(lang: &Lang) -> String { fn generate_source_file(lang: &Lang, project_type: &ProjectType) -> String {
match project_type {
ProjectType::SharedLib => {
match lang {
Lang::C => {
r#"#ifdef _WIN32
#include <windows.h>
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
#else
// Non-Windows platforms
void __attribute__((constructor)) lib_init(void) {}
void __attribute__((destructor)) lib_fini(void) {}
#endif"#
.to_string()
}
Lang::Cpp => {
r#"#include <windows.h>
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}"#
.to_string()
}
}
}
_ => {
match lang { match lang {
Lang::C => { Lang::C => {
"#include <stdio.h>\n\nint main() {\n printf(\"Hello, World!\\n\");\n return 0;\n}" "#include <stdio.h>\n\nint main() {\n printf(\"Hello, World!\\n\");\n return 0;\n}"
@@ -165,6 +216,8 @@ fn generate_source_file(lang: &Lang) -> String {
} }
} }
} }
}
}
fn sanitize_folder_name(name: &str) -> String { fn sanitize_folder_name(name: &str) -> String {
let re = Regex::new(r"[^a-zA-Z0-9_-]").unwrap(); let re = Regex::new(r"[^a-zA-Z0-9_-]").unwrap();
@@ -257,7 +310,10 @@ fn create_project(
// 创建目录结构 // 创建目录结构
fs::create_dir_all(output_dir.join("src"))?; fs::create_dir_all(output_dir.join("src"))?;
if matches!(project_type, ProjectType::StaticLib | ProjectType::SharedLib) { if matches!(
project_type,
ProjectType::StaticLib | ProjectType::SharedLib
) {
fs::create_dir_all(output_dir.join("include"))?; fs::create_dir_all(output_dir.join("include"))?;
} }
@@ -272,12 +328,15 @@ fn create_project(
let ext = get_lang_ext(lang); let ext = get_lang_ext(lang);
fs::write( fs::write(
output_dir.join("src").join(format!("main.{}", ext)), output_dir.join("src").join(format!("main.{}", ext)),
generate_source_file(lang), generate_source_file(lang, project_type),
) )
.with_context(|| "写入源文件失败")?; .with_context(|| "写入源文件失败")?;
// 为库类型创建 README.md // 为库类型创建 README.md
if matches!(project_type, ProjectType::StaticLib | ProjectType::SharedLib) { if matches!(
project_type,
ProjectType::StaticLib | ProjectType::SharedLib
) {
let readme_content = format!( let readme_content = format!(
"# {}\n\nA CMake library project.\n\n## Build\n\n```bash\nmkdir build && cd build\ncmake ..\nmake\n```\n\n## Install\n\n```bash\ncmake --install .\n```\n", "# {}\n\nA CMake library project.\n\n## Build\n\n```bash\nmkdir build && cd build\ncmake ..\nmake\n```\n\n## Install\n\n```bash\ncmake --install .\n```\n",
project_name project_name
@@ -306,7 +365,14 @@ fn main() -> Result<()> {
let (name, lang, project_type, cxx_standard) = interactive_mode()?; let (name, lang, project_type, cxx_standard) = interactive_mode()?;
let folder_name = sanitize_folder_name(&name); let folder_name = sanitize_folder_name(&name);
let output_path = Path::new(".").join(&folder_name); let output_path = Path::new(".").join(&folder_name);
create_project(&name, &lang, &project_type, &cxx_standard, &output_path, args.force)?; create_project(
&name,
&lang,
&project_type,
&cxx_standard,
&output_path,
args.force,
)?;
return Ok(()); return Ok(());
} }
@@ -323,7 +389,14 @@ fn main() -> Result<()> {
Path::new(".").join(&folder_name) Path::new(".").join(&folder_name)
}; };
create_project(&name, &lang, &project_type, &cxx_standard, &output_path, args.force)?; create_project(
&name,
&lang,
&project_type,
&cxx_standard,
&output_path,
args.force,
)?;
Ok(()) Ok(())
} }