Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3575497448 | ||
|
|
8b2c3ffe53 |
125
src/main.rs
125
src/main.rs
@@ -1,4 +1,4 @@
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use anyhow::{Context, Result, anyhow};
|
||||
use clap::{Parser, ValueEnum};
|
||||
use inquire::{Confirm, Select, Text};
|
||||
use regex::Regex;
|
||||
@@ -30,6 +30,8 @@ enum CxxStandard {
|
||||
Cxx20,
|
||||
#[value(name = "23")]
|
||||
Cxx23,
|
||||
#[value(name = "26")]
|
||||
Cxx26,
|
||||
}
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
@@ -83,7 +85,11 @@ fn generate_cmakelists(
|
||||
) -> String {
|
||||
let mut lines = vec![
|
||||
"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(),
|
||||
];
|
||||
|
||||
@@ -95,6 +101,7 @@ fn generate_cmakelists(
|
||||
Some(CxxStandard::Cxx17) => "17",
|
||||
Some(CxxStandard::Cxx20) => "20",
|
||||
Some(CxxStandard::Cxx23) => "23",
|
||||
Some(CxxStandard::Cxx26) => "26",
|
||||
None => "17",
|
||||
};
|
||||
lines.push(format!("set(CMAKE_CXX_STANDARD {})", standard));
|
||||
@@ -107,24 +114,27 @@ fn generate_cmakelists(
|
||||
let ext = get_lang_ext(lang);
|
||||
match project_type {
|
||||
ProjectType::Exe => {
|
||||
lines.push(format!(
|
||||
"add_executable({} src/main.{})",
|
||||
project_name, ext,
|
||||
));
|
||||
lines.push(format!("add_executable({} src/main.{})", project_name, ext,));
|
||||
}
|
||||
ProjectType::StaticLib => {
|
||||
lines.push(format!(
|
||||
"add_library({} STATIC src/main.{})",
|
||||
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 => {
|
||||
lines.push(format!(
|
||||
"add_library({} SHARED src/main.{})",
|
||||
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!(
|
||||
"target_compile_definitions({} PUBLIC {}_EXPORTS)",
|
||||
project_name,
|
||||
@@ -134,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("# Export targets".to_string());
|
||||
lines.push("include(GNUInstallDirs)".to_string());
|
||||
lines.push(format!(
|
||||
"install(TARGETS {} DESTINATION lib)",
|
||||
project_name
|
||||
));
|
||||
lines.push(
|
||||
"install(DIRECTORY include/ DESTINATION include)".to_string(),
|
||||
);
|
||||
lines.push(format!("install(TARGETS {} DESTINATION lib)", project_name));
|
||||
lines.push("install(DIRECTORY include/ DESTINATION include)".to_string());
|
||||
}
|
||||
|
||||
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 {
|
||||
Lang::C => {
|
||||
"#include <stdio.h>\n\nint main() {\n printf(\"Hello, World!\\n\");\n return 0;\n}"
|
||||
@@ -162,6 +216,8 @@ fn generate_source_file(lang: &Lang) -> String {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn sanitize_folder_name(name: &str) -> String {
|
||||
let re = Regex::new(r"[^a-zA-Z0-9_-]").unwrap();
|
||||
@@ -211,14 +267,15 @@ fn interactive_mode() -> Result<(String, Lang, ProjectType, Option<CxxStandard>)
|
||||
};
|
||||
|
||||
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()?;
|
||||
Some(match standard_raw {
|
||||
"11" => CxxStandard::Cxx11,
|
||||
"14" => CxxStandard::Cxx14,
|
||||
"17" => CxxStandard::Cxx17,
|
||||
"20" => CxxStandard::Cxx20,
|
||||
_ => CxxStandard::Cxx23,
|
||||
"23" => CxxStandard::Cxx23,
|
||||
_ => CxxStandard::Cxx26,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
@@ -253,7 +310,10 @@ fn create_project(
|
||||
|
||||
// 创建目录结构
|
||||
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"))?;
|
||||
}
|
||||
|
||||
@@ -268,12 +328,15 @@ fn create_project(
|
||||
let ext = get_lang_ext(lang);
|
||||
fs::write(
|
||||
output_dir.join("src").join(format!("main.{}", ext)),
|
||||
generate_source_file(lang),
|
||||
generate_source_file(lang, project_type),
|
||||
)
|
||||
.with_context(|| "写入源文件失败")?;
|
||||
|
||||
// 为库类型创建 README.md
|
||||
if matches!(project_type, ProjectType::StaticLib | ProjectType::SharedLib) {
|
||||
if matches!(
|
||||
project_type,
|
||||
ProjectType::StaticLib | ProjectType::SharedLib
|
||||
) {
|
||||
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",
|
||||
project_name
|
||||
@@ -302,7 +365,14 @@ fn main() -> Result<()> {
|
||||
let (name, lang, project_type, cxx_standard) = interactive_mode()?;
|
||||
let folder_name = sanitize_folder_name(&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(());
|
||||
}
|
||||
|
||||
@@ -319,7 +389,14 @@ fn main() -> Result<()> {
|
||||
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(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user