2 Commits
v1.1.0 ... main

Author SHA1 Message Date
Yakumo Hokori
3575497448 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
2026-01-18 01:20:44 +08:00
Yakumo Hokori
8b2c3ffe53 add cxx26 support
All checks were successful
Rust Cross-Compile and Release / build_and_release (push) Successful in 2m59s
2026-01-16 14:57:16 +08:00

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;
@@ -30,6 +30,8 @@ enum CxxStandard {
Cxx20, Cxx20,
#[value(name = "23")] #[value(name = "23")]
Cxx23, Cxx23,
#[value(name = "26")]
Cxx26,
} }
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
@@ -83,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(),
]; ];
@@ -95,6 +101,7 @@ fn generate_cmakelists(
Some(CxxStandard::Cxx17) => "17", Some(CxxStandard::Cxx17) => "17",
Some(CxxStandard::Cxx20) => "20", Some(CxxStandard::Cxx20) => "20",
Some(CxxStandard::Cxx23) => "23", Some(CxxStandard::Cxx23) => "23",
Some(CxxStandard::Cxx26) => "26",
None => "17", None => "17",
}; };
lines.push(format!("set(CMAKE_CXX_STANDARD {})", standard)); lines.push(format!("set(CMAKE_CXX_STANDARD {})", standard));
@@ -107,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,
@@ -134,31 +144,77 @@ 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 lang { match project_type {
Lang::C => { ProjectType::SharedLib => {
"#include <stdio.h>\n\nint main() {\n printf(\"Hello, World!\\n\");\n return 0;\n}" match lang {
.to_string() 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()
}
}
} }
Lang::Cpp => { _ => {
"#include <iostream>\n\nint main() {\n std::cout << \"Hello, World!\" << std::endl;\n return 0;\n}" match lang {
.to_string() Lang::C => {
"#include <stdio.h>\n\nint main() {\n printf(\"Hello, World!\\n\");\n return 0;\n}"
.to_string()
}
Lang::Cpp => {
"#include <iostream>\n\nint main() {\n std::cout << \"Hello, World!\" << std::endl;\n return 0;\n}"
.to_string()
}
}
} }
} }
} }
@@ -211,14 +267,15 @@ fn interactive_mode() -> Result<(String, Lang, ProjectType, Option<CxxStandard>)
}; };
let cxx_standard = if matches!(lang, Lang::Cpp) { let cxx_standard = if matches!(lang, Lang::Cpp) {
let standard_choices = vec!["11", "14", "17", "20", "23"]; let standard_choices = vec!["11", "14", "17", "20", "23", "26"];
let standard_raw = Select::new("请选择C++标准版本:", standard_choices).prompt()?; let standard_raw = Select::new("请选择C++标准版本:", standard_choices).prompt()?;
Some(match standard_raw { Some(match standard_raw {
"11" => CxxStandard::Cxx11, "11" => CxxStandard::Cxx11,
"14" => CxxStandard::Cxx14, "14" => CxxStandard::Cxx14,
"17" => CxxStandard::Cxx17, "17" => CxxStandard::Cxx17,
"20" => CxxStandard::Cxx20, "20" => CxxStandard::Cxx20,
_ => CxxStandard::Cxx23, "23" => CxxStandard::Cxx23,
_ => CxxStandard::Cxx26,
}) })
} else { } else {
None None
@@ -253,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"))?;
} }
@@ -268,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
@@ -302,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(());
} }
@@ -319,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(())
} }