From 3b29016c0791a370c364054fb1ce019b6f6509bf Mon Sep 17 00:00:00 2001 From: sksat Date: Thu, 29 Jan 2026 23:43:19 +0900 Subject: [PATCH 1/5] feat: support package manager for c2a-core Add support for using c2a-core as a Cargo package without requiring physical directory placement via git submodule/symlink. Changes: - Add C2A_USER_DIR auto-detection in c2a-core/CMakeLists.txt - Add include path configuration for headers - Update examples/mobc to use c2a_core::source_dir() - Support both legacy (symlink) and new (package) modes - Add use-local-c2a-core feature for local development The implementation maintains backward compatibility with existing git submodule-based projects while enabling pure Cargo-based workflows. Co-Authored-By: Claude Sonnet 4.5 --- CMakeLists.txt | 23 +++++++++++++++++++++++ examples/mobc/CMakeLists.txt | 30 ++++++++++++++++++++++++++---- examples/mobc/Cargo.toml | 11 ++++++++++- examples/mobc/build.rs | 26 +++++++++++++++++++++++--- 4 files changed, 82 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2449fcee8..710fa96af 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,6 +33,21 @@ option(C2A_USE_SIMPLE_LIBC "Use C2A-core hosted simple libc (c2a-core/l set(C2A_CORE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +# C2A user ディレクトリの検出 +# 優先順位: 1. CMake define 2. 環境変数 3. レガシーパス +if(NOT DEFINED C2A_USER_DIR) + if(DEFINED ENV{C2A_USER_DIR}) + set(C2A_USER_DIR $ENV{C2A_USER_DIR}) + message(STATUS "C2A user directory from environment: ${C2A_USER_DIR}") + elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../src_user") + # レガシー git submodule 方式のフォールバック + set(C2A_USER_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../src_user") + message(STATUS "C2A user directory (legacy fallback): ${C2A_USER_DIR}") + else() + message(WARNING "C2A_USER_DIR not set. Build may fail if src_user includes are used.") + endif() +endif() + set(C2A_SRCS c2a_core_main.c component_driver/cdrv_common_tlm_cmd_packet.c @@ -94,6 +109,14 @@ endif() add_library(${PROJECT_NAME} OBJECT ${C2A_SRCS}) +# C2A user の親ディレクトリをインクルードパスに追加 +# これにより が解決可能になる +if(DEFINED C2A_USER_DIR AND EXISTS "${C2A_USER_DIR}") + get_filename_component(C2A_USER_PARENT_DIR "${C2A_USER_DIR}" DIRECTORY) + target_include_directories(${PROJECT_NAME} PUBLIC "${C2A_USER_PARENT_DIR}") + message(STATUS "C2A user include path: ${C2A_USER_PARENT_DIR}") +endif() + if(C2A_USE_ALL_CORE_APPS) add_subdirectory(applications) target_sources(${PROJECT_NAME} PUBLIC $) diff --git a/examples/mobc/CMakeLists.txt b/examples/mobc/CMakeLists.txt index bd6d88cba..7c35b2a34 100644 --- a/examples/mobc/CMakeLists.txt +++ b/examples/mobc/CMakeLists.txt @@ -35,10 +35,31 @@ if(C2A_BUILD_AS_CXX) message("Build C2A as C++!") endif() -set(C2A_CORE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src/src_core) -set(C2A_USER_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src/src_user) +# C2A_CORE_DIR と C2A_USER_DIR の設定 +# 優先順位: 1. CMake define (-D で指定) 2. レガシーパス(シンボリックリンク) +if(NOT DEFINED C2A_CORE_DIR) + set(C2A_CORE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src/src_core) + message(STATUS "C2A_CORE_DIR (legacy): ${C2A_CORE_DIR}") +else() + message(STATUS "C2A_CORE_DIR (defined): ${C2A_CORE_DIR}") +endif() -include_directories(src) +if(NOT DEFINED C2A_USER_DIR) + set(C2A_USER_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src/src_user) + message(STATUS "C2A_USER_DIR (legacy): ${C2A_USER_DIR}") +else() + message(STATUS "C2A_USER_DIR (defined): ${C2A_USER_DIR}") +endif() + +# C2A user の親ディレクトリをインクルードパスに追加 +get_filename_component(C2A_USER_PARENT_DIR "${C2A_USER_DIR}" DIRECTORY) +include_directories("${C2A_USER_PARENT_DIR}") + +# C2A core の親ディレクトリもインクルードパスに追加( 用) +get_filename_component(C2A_CORE_PARENT_DIR "${C2A_CORE_DIR}" DIRECTORY) +if(NOT "${C2A_CORE_PARENT_DIR}" STREQUAL "${C2A_USER_PARENT_DIR}") + include_directories("${C2A_CORE_PARENT_DIR}") +endif() # Output debug print to SILS console window option(C2A_SHOW_DEBUG_PRINT_ON_SILS "Show debug print" ON) @@ -62,7 +83,8 @@ execute_process( add_definitions("-DGIT_REVISION_C2A_USER=\"${GIT_REVISION_C2A_USER}\"") add_definitions("-DGIT_REVISION_C2A_USER_SHORT=0x${GIT_REVISION_C2A_USER_SHORT}") -add_subdirectory(${C2A_CORE_DIR}) +# out-of-tree source の場合、binary directory を明示的に指定 +add_subdirectory(${C2A_CORE_DIR} ${CMAKE_BINARY_DIR}/c2a_core) add_subdirectory(${C2A_USER_DIR}/applications) add_subdirectory(${C2A_USER_DIR}/component_driver) diff --git a/examples/mobc/Cargo.toml b/examples/mobc/Cargo.toml index f5a08a85f..1252baa30 100644 --- a/examples/mobc/Cargo.toml +++ b/examples/mobc/Cargo.toml @@ -4,7 +4,8 @@ version.workspace = true edition = "2021" [dependencies] -c2a-core.workspace = true +# export-src は build.rs で source_dir() を使うため常に必要 +c2a-core = { workspace = true, features = ["export-src"] } # runtime c2a-dev-runtime.workspace = true @@ -16,3 +17,11 @@ c2a-wdt-noop.workspace = true [build-dependencies] cmake = "0.1" +# build.rs では source_dir() を呼ぶだけなので、no-c2a-link で C ライブラリをリンクしない +c2a-core = { workspace = true, features = ["export-src", "no-c2a-link"] } + +[features] +default = [] +# ローカル開発用: シンボリックリンク方式を使う +# cargo build --features use-local-c2a-core +use-local-c2a-core = [] diff --git a/examples/mobc/build.rs b/examples/mobc/build.rs index 865f73701..ff79bd985 100644 --- a/examples/mobc/build.rs +++ b/examples/mobc/build.rs @@ -1,4 +1,24 @@ fn main() { + // C2A core のソースディレクトリを取得 + let c2a_core_dir = if cfg!(feature = "use-local-c2a-core") { + // ローカル開発用: 従来のシンボリックリンク方式 + std::path::PathBuf::from("./src/src_core") + .canonicalize() + .expect("Failed to canonicalize C2A core directory (symlink)") + } else { + // Cargo 経由: c2a-core crate のソースディレクトリを取得 + c2a_core::source_dir() + }; + + // C2A user のソースディレクトリ + let c2a_user_dir = std::path::PathBuf::from("./src/src_user"); + let c2a_user_dir = c2a_user_dir + .canonicalize() + .expect("Failed to canonicalize C2A user directory"); + + println!("cargo:rerun-if-changed=./src/src_core"); + println!("cargo:rerun-if-changed=./src/src_user"); + // Build C2A & link let mut c2a_cmake = cmake::Config::new("."); let libc2a = c2a_cmake @@ -7,11 +27,11 @@ fn main() { .define("C2A_BUILD_AS_C99", "ON") .define("C2A_BUILD_FOR_SILS", "ON") .define("C2A_USE_SCI_COM_WINGS", "OFF") + // C2A core と user のディレクトリを明示的に指定 + .define("C2A_CORE_DIR", c2a_core_dir.to_str().unwrap()) + .define("C2A_USER_DIR", c2a_user_dir.to_str().unwrap()) .build_target("C2A"); - println!("cargo:rerun-if-changed=./src/src_core"); - println!("cargo:rerun-if-changed=./src/src_user"); - let libc2a = libc2a.build(); println!( "cargo:rustc-link-search=native={}/build", // no install step in libC2A From 97fb092d2e8b5f21bb138d9a4970ef8c4ad681ce Mon Sep 17 00:00:00 2001 From: sksat Date: Fri, 30 Jan 2026 01:42:50 +0900 Subject: [PATCH 2/5] feat(core): add src_user symlink support and crate version export - Create src_user symlink in OUT_DIR for flexible directory naming - Add C2A_BUILD_OUT_DIR to CMake include paths - Export crate version for git revision fallback - Handle CMake project() variable reset issue This allows user code directories to have any name (not limited to src_user) and enables c2a-core to work from crates.io without git repository. Co-Authored-By: Claude Sonnet 4.5 --- CMakeLists.txt | 59 ++++++++++++++++++++++++++++++++++++++++++++- Cargo.lock | 19 +++++++++++++++ Cargo.toml | 8 ++++-- build.rs | 3 +++ rust-toolchain.toml | 2 +- 5 files changed, 87 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 710fa96af..db43fb73c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,18 @@ cmake_minimum_required(VERSION 3.13) +# Save C2A_CORE_VERSION before project() command (project() can reset cache variables) +if(DEFINED C2A_CORE_VERSION) + set(_C2A_CORE_VERSION_SAVED "${C2A_CORE_VERSION}") +endif() + project(C2A_CORE) +# Restore C2A_CORE_VERSION after project() +if(DEFINED _C2A_CORE_VERSION_SAVED) + set(C2A_CORE_VERSION "${_C2A_CORE_VERSION_SAVED}" CACHE STRING "C2A Core version" FORCE) + unset(_C2A_CORE_VERSION_SAVED) +endif() + # Build option ## C2A compile config option(C2A_BUILD_AS_UTF8 "Build C2A as UTF-8" ON) @@ -93,13 +104,51 @@ execute_process( WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} OUTPUT_VARIABLE GIT_REVISION_C2A_CORE OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET ) execute_process( COMMAND git log -1 --format=%h WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} OUTPUT_VARIABLE GIT_REVISION_C2A_CORE_SHORT OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET ) + +# Git revision が取得できない場合のフォールバック(crates.io からのダウンロード時など) +if(NOT GIT_REVISION_C2A_CORE) + # C2A_CORE_VERSION が指定されている場合は crate version を使用 + if(DEFINED C2A_CORE_VERSION) + set(GIT_REVISION_C2A_CORE "v${C2A_CORE_VERSION}") + message(STATUS "Using crate version as revision: v${C2A_CORE_VERSION}") + else() + set(GIT_REVISION_C2A_CORE "unknown") + message(WARNING "Git revision not available (not a git repository)") + endif() +endif() +if(NOT GIT_REVISION_C2A_CORE_SHORT) + # C2A_CORE_VERSION が指定されている場合は version から数値を生成 + if(DEFINED C2A_CORE_VERSION) + # バージョンを 0xMMmmpp 形式に変換 (例: 4.5.1 -> 0x00040501) + string(REPLACE "." ";" VERSION_LIST ${C2A_CORE_VERSION}) + list(GET VERSION_LIST 0 VERSION_MAJOR) + list(GET VERSION_LIST 1 VERSION_MINOR) + list(LENGTH VERSION_LIST VERSION_LIST_LEN) + if(VERSION_LIST_LEN GREATER 2) + list(GET VERSION_LIST 2 VERSION_PATCH) + else() + set(VERSION_PATCH 0) + endif() + math(EXPR VERSION_HEX "(${VERSION_MAJOR} << 16) + (${VERSION_MINOR} << 8) + ${VERSION_PATCH}" OUTPUT_FORMAT HEXADECIMAL) + # Remove 0x prefix since add_definitions will add it + string(SUBSTRING "${VERSION_HEX}" 2 -1 VERSION_HEX_NO_PREFIX) + set(GIT_REVISION_C2A_CORE_SHORT "${VERSION_HEX_NO_PREFIX}") + message(STATUS "Using crate version as short revision: 0x${VERSION_HEX_NO_PREFIX}") + else() + set(GIT_REVISION_C2A_CORE_SHORT "00000000") + message(WARNING "Git short revision not available (not a git repository)") + endif() +endif() + add_definitions("-DGIT_REVISION_C2A_CORE=\"${GIT_REVISION_C2A_CORE}\"") add_definitions("-DGIT_REVISION_C2A_CORE_SHORT=0x${GIT_REVISION_C2A_CORE_SHORT}") @@ -110,13 +159,21 @@ endif() add_library(${PROJECT_NAME} OBJECT ${C2A_SRCS}) # C2A user の親ディレクトリをインクルードパスに追加 -# これにより が解決可能になる +# これにより が解決可能になる(レガシー方式用) if(DEFINED C2A_USER_DIR AND EXISTS "${C2A_USER_DIR}") get_filename_component(C2A_USER_PARENT_DIR "${C2A_USER_DIR}" DIRECTORY) target_include_directories(${PROJECT_NAME} PUBLIC "${C2A_USER_PARENT_DIR}") message(STATUS "C2A user include path: ${C2A_USER_PARENT_DIR}") endif() +# ビルドディレクトリ内の src_user シンボリックリンクを解決するため、 +# C2A_BUILD_OUT_DIR が指定されている場合は include path に追加 +# これにより実際のディレクトリ名を src_user に限定する必要がなくなる +if(DEFINED C2A_BUILD_OUT_DIR) + target_include_directories(${PROJECT_NAME} PUBLIC "${C2A_BUILD_OUT_DIR}") + message(STATUS "C2A build output directory: ${C2A_BUILD_OUT_DIR}") +endif() + if(C2A_USE_ALL_CORE_APPS) add_subdirectory(applications) target_sources(${PROJECT_NAME} PUBLIC $) diff --git a/Cargo.lock b/Cargo.lock index 601eafeb6..dba91b6a4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -261,6 +261,7 @@ dependencies = [ "c2a-uart-kble", "c2a-wdt-noop", "cmake", + "serde_json", ] [[package]] @@ -1166,6 +1167,12 @@ version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" +[[package]] +name = "ryu" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984" + [[package]] name = "semver" version = "1.0.26" @@ -1192,6 +1199,18 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.143" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + [[package]] name = "sha1" version = "0.10.6" diff --git a/Cargo.toml b/Cargo.toml index b159c487f..a48cdff13 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,8 +20,12 @@ members = [ "./examples/subobc", ] +exclude = [ + "./examples/tmp", # テスト用 +] + [workspace.dependencies] -c2a-core = { path = "." } +c2a-core = { path = ".", version = "4.5.1" } c2a-bind-utils = { path = "./library/bind-utils" } c2a-dev-runtime = { path = "./dev-runtime" } @@ -58,4 +62,4 @@ c2a-bind-utils = "4.0.0-beta.0" [dev-dependencies] # unit test 時に libC2A.a を要求しないようにする -c2a-core = { path = ".", features = ["no-c2a-link"] } +c2a-core = { path = ".", version = "4.5.1", features = ["no-c2a-link"] } diff --git a/build.rs b/build.rs index 35d79def5..d2665af58 100644 --- a/build.rs +++ b/build.rs @@ -24,6 +24,9 @@ fn main() { println!("cargo:return-if-changed=tlm_cmd/"); let ver = env!("CARGO_PKG_VERSION"); + // crate version を依存 crate に export(git revision の代替として使用) + println!("cargo:VERSION={}", ver); + let ver = Version::parse(ver).unwrap(); dbg!(&ver); diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 11d7d1e57..5ea286c83 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "1.81.0" +channel = "1.88.0" targets = ["i686-unknown-linux-gnu"] From c49aeae415edd76fc1e49be1b65574744db65b58 Mon Sep 17 00:00:00 2001 From: sksat Date: Fri, 30 Jan 2026 01:43:11 +0900 Subject: [PATCH 3/5] feat(mobc): add VSCode IntelliSense and build system improvements - Create src_core and src_user symlinks in OUT_DIR - Generate compile_commands.json for VSCode C/C++ extension - Dynamically update .vscode/c_cpp_properties.json - Add .gitignore for auto-generated files - Add serde_json dependency for JSON manipulation This enables VSCode code navigation for both c2a-core and user C code, and allows flexible directory naming (not limited to src_user). Co-Authored-By: Claude Sonnet 4.5 --- examples/mobc/.gitignore | 2 + examples/mobc/CMakeLists.txt | 8 ++ examples/mobc/Cargo.toml | 1 + examples/mobc/build.rs | 152 ++++++++++++++++++++++++++++++++++- 4 files changed, 162 insertions(+), 1 deletion(-) create mode 100644 examples/mobc/.gitignore diff --git a/examples/mobc/.gitignore b/examples/mobc/.gitignore new file mode 100644 index 000000000..032b53a32 --- /dev/null +++ b/examples/mobc/.gitignore @@ -0,0 +1,2 @@ +/compile_commands.json +/.vscode/c_cpp_properties.json diff --git a/examples/mobc/CMakeLists.txt b/examples/mobc/CMakeLists.txt index 7c35b2a34..8b37d4461 100644 --- a/examples/mobc/CMakeLists.txt +++ b/examples/mobc/CMakeLists.txt @@ -61,6 +61,14 @@ if(NOT "${C2A_CORE_PARENT_DIR}" STREQUAL "${C2A_USER_PARENT_DIR}") include_directories("${C2A_CORE_PARENT_DIR}") endif() +# ビルドディレクトリ内の src_core と src_user シンボリックリンクを解決するため、 +# C2A_BUILD_OUT_DIR が指定されている場合は include path に追加 +# これにより実際のディレクトリ名を src_core/src_user に限定する必要がなくなる +if(DEFINED C2A_BUILD_OUT_DIR) + include_directories("${C2A_BUILD_OUT_DIR}") + message(STATUS "C2A build output directory: ${C2A_BUILD_OUT_DIR}") +endif() + # Output debug print to SILS console window option(C2A_SHOW_DEBUG_PRINT_ON_SILS "Show debug print" ON) if(C2A_SHOW_DEBUG_PRINT_ON_SILS) diff --git a/examples/mobc/Cargo.toml b/examples/mobc/Cargo.toml index 1252baa30..b931b0851 100644 --- a/examples/mobc/Cargo.toml +++ b/examples/mobc/Cargo.toml @@ -17,6 +17,7 @@ c2a-wdt-noop.workspace = true [build-dependencies] cmake = "0.1" +serde_json = "1.0" # build.rs では source_dir() を呼ぶだけなので、no-c2a-link で C ライブラリをリンクしない c2a-core = { workspace = true, features = ["export-src", "no-c2a-link"] } diff --git a/examples/mobc/build.rs b/examples/mobc/build.rs index ff79bd985..fe069044d 100644 --- a/examples/mobc/build.rs +++ b/examples/mobc/build.rs @@ -1,4 +1,8 @@ fn main() { + // Cargo のビルド出力ディレクトリを取得 + let out_dir = std::env::var("OUT_DIR").unwrap(); + let out_dir_path = std::path::PathBuf::from(&out_dir); + // C2A core のソースディレクトリを取得 let c2a_core_dir = if cfg!(feature = "use-local-c2a-core") { // ローカル開発用: 従来のシンボリックリンク方式 @@ -7,7 +11,27 @@ fn main() { .expect("Failed to canonicalize C2A core directory (symlink)") } else { // Cargo 経由: c2a-core crate のソースディレクトリを取得 - c2a_core::source_dir() + let core_dir = c2a_core::source_dir(); + + // ビルドディレクトリ内に src_core シンボリックリンクを作成 + // これにより CMake が を解決できるようになる + let src_core_link = out_dir_path.join("src_core"); + + // 既存のシンボリックリンクを削除(古いパスを指している可能性があるため) + if src_core_link.exists() || src_core_link.read_link().is_ok() { + let _ = std::fs::remove_file(&src_core_link); + } + + // 新しいシンボリックリンクを作成 + #[cfg(unix)] + std::os::unix::fs::symlink(&core_dir, &src_core_link) + .expect("Failed to create src_core symlink in build directory"); + + #[cfg(windows)] + std::os::windows::fs::symlink_dir(&core_dir, &src_core_link) + .expect("Failed to create src_core symlink in build directory"); + + core_dir }; // C2A user のソースディレクトリ @@ -16,9 +40,33 @@ fn main() { .canonicalize() .expect("Failed to canonicalize C2A user directory"); + // ビルドディレクトリ内に src_user シンボリックリンクを作成 + // これにより CMake が を解決できるようになる + // これで実際のディレクトリ名を src_user に限定する必要がなくなる + let src_user_link = out_dir_path.join("src_user"); + + // 既存のシンボリックリンクを削除(古いパスを指している可能性があるため) + if src_user_link.exists() || src_user_link.read_link().is_ok() { + let _ = std::fs::remove_file(&src_user_link); + } + + // 新しいシンボリックリンクを作成 + #[cfg(unix)] + std::os::unix::fs::symlink(&c2a_user_dir, &src_user_link) + .expect("Failed to create src_user symlink in build directory"); + + #[cfg(windows)] + std::os::windows::fs::symlink_dir(&c2a_user_dir, &src_user_link) + .expect("Failed to create src_user symlink in build directory"); + println!("cargo:rerun-if-changed=./src/src_core"); println!("cargo:rerun-if-changed=./src/src_user"); + // C2A core の crate version を取得(crates.io からの場合に git revision の代わりに使用) + let c2a_core_version = std::env::var("DEP_C2A_CORE_VERSION") + .or_else(|_| std::env::var("CARGO_PKG_VERSION")) + .unwrap_or_else(|_| "0.0.0".to_string()); + // Build C2A & link let mut c2a_cmake = cmake::Config::new("."); let libc2a = c2a_cmake @@ -30,6 +78,12 @@ fn main() { // C2A core と user のディレクトリを明示的に指定 .define("C2A_CORE_DIR", c2a_core_dir.to_str().unwrap()) .define("C2A_USER_DIR", c2a_user_dir.to_str().unwrap()) + // ビルドディレクトリを include path に追加するため CMake に渡す + .define("C2A_BUILD_OUT_DIR", &out_dir) + // C2A core の version を渡す(git revision が取得できない場合の代替) + .define("C2A_CORE_VERSION", &c2a_core_version) + // VSCode の IntelliSense 用に compile_commands.json を生成 + .define("CMAKE_EXPORT_COMPILE_COMMANDS", "ON") .build_target("C2A"); let libc2a = libc2a.build(); @@ -38,4 +92,100 @@ fn main() { libc2a.display() ); println!("cargo:rustc-link-lib=static=C2A"); + + // VSCode の IntelliSense 用に compile_commands.json へのシンボリックリンクを作成 + let compile_commands_src = libc2a.join("build/compile_commands.json"); + let compile_commands_dst = std::path::PathBuf::from("./compile_commands.json"); + + if compile_commands_src.exists() { + // 既存のシンボリックリンクを削除 + if compile_commands_dst.exists() || compile_commands_dst.read_link().is_ok() { + let _ = std::fs::remove_file(&compile_commands_dst); + } + + // 新しいシンボリックリンクを作成 + #[cfg(unix)] + { + let _ = std::os::unix::fs::symlink(&compile_commands_src, &compile_commands_dst); + } + + #[cfg(windows)] + { + let _ = std::os::windows::fs::symlink_file(&compile_commands_src, &compile_commands_dst); + } + } + + // VSCode の IntelliSense 用に .vscode/c_cpp_properties.json を動的に生成/更新 + let vscode_dir = std::path::PathBuf::from("./.vscode"); + std::fs::create_dir_all(&vscode_dir).ok(); + + let c_cpp_properties_path = vscode_dir.join("c_cpp_properties.json"); + let c2a_core_path = format!("{}/**", c2a_core_dir.display()); + let out_dir_path = format!("{}/**", out_dir); + + // 既存の c_cpp_properties.json を読み込むか、デフォルトを作成 + let mut config: serde_json::Value = if c_cpp_properties_path.exists() { + let content = std::fs::read_to_string(&c_cpp_properties_path).ok(); + content + .and_then(|s| serde_json::from_str(&s).ok()) + .unwrap_or_else(|| create_default_c_cpp_properties()) + } else { + create_default_c_cpp_properties() + }; + + // configurations[0].includePath に c2a_core と out_dir を追加(存在しない場合のみ) + if let Some(configurations) = config.get_mut("configurations").and_then(|c| c.as_array_mut()) { + if let Some(first_config) = configurations.get_mut(0) { + if let Some(include_path) = first_config.get_mut("includePath").and_then(|p| p.as_array_mut()) { + // 古い out_dir パス(target/.../out/** パターン)を削除 + include_path.retain(|p| { + if let Some(path_str) = p.as_str() { + !path_str.contains("/target/") || !path_str.contains("/out/**") + } else { + true + } + }); + + // c2a_core_path が存在しない場合は追加 + if !include_path.iter().any(|p| p.as_str() == Some(&c2a_core_path)) { + include_path.push(serde_json::Value::String(c2a_core_path.clone())); + } + // 新しい out_dir_path を追加 + include_path.push(serde_json::Value::String(out_dir_path.clone())); + } + + // compileCommands が設定されていない場合は追加 + if first_config.get("compileCommands").is_none() { + first_config["compileCommands"] = serde_json::Value::String("${workspaceFolder}/compile_commands.json".to_string()); + } + } + } + + // 整形して書き込み + if let Ok(pretty_json) = serde_json::to_string_pretty(&config) { + std::fs::write(&c_cpp_properties_path, pretty_json).ok(); + } +} + +fn create_default_c_cpp_properties() -> serde_json::Value { + serde_json::json!({ + "configurations": [ + { + "name": "Linux", + "includePath": [ + "${workspaceFolder}/**", + "${workspaceFolder}/src/src_user/**" + ], + "defines": [ + "SHOW_DEBUG_PRINT_ON_SILS" + ], + "compilerPath": "/usr/bin/gcc", + "cStandard": "c99", + "cppStandard": "c++17", + "intelliSenseMode": "linux-gcc-x64", + "compileCommands": "${workspaceFolder}/compile_commands.json" + } + ], + "version": 4 + }) } From 9e107f31334c6c01640591bd6e4a12080f31d175 Mon Sep 17 00:00:00 2001 From: sksat Date: Fri, 30 Jan 2026 01:54:23 +0900 Subject: [PATCH 4/5] fix: apply cargo fmt and fix clippy warnings --- build.rs | 85 ++++++++++++++++++++---------------------- examples/mobc/build.rs | 22 ++++++++--- 2 files changed, 58 insertions(+), 49 deletions(-) diff --git a/build.rs b/build.rs index d2665af58..14ef4834e 100644 --- a/build.rs +++ b/build.rs @@ -25,7 +25,7 @@ fn main() { let ver = env!("CARGO_PKG_VERSION"); // crate version を依存 crate に export(git revision の代替として使用) - println!("cargo:VERSION={}", ver); + println!("cargo:VERSION={ver}"); let ver = Version::parse(ver).unwrap(); dbg!(&ver); @@ -115,51 +115,48 @@ fn get_definitions(src_file: &str) -> HashMap> { let childlen = entity.get_children().into_iter(); for cursor in childlen { - match cursor.get_kind() { - clang::EntityKind::MacroDefinition => { - let location = cursor.get_location().unwrap().get_file_location(); - if let Some(file) = location.file { - let file = file.get_path(); - let _f = file.to_str().unwrap(); - } else { - continue; - } - - let name = cursor.get_display_name().unwrap(); - let mut token = cursor.get_range().unwrap().tokenize(); - token.remove(0); // remove macro Identifier token - if token.is_empty() { - macros.insert(name, None); - continue; // remove define only - } - - let first = token.first().unwrap(); - let last = token.last().unwrap(); - if first.get_kind() == Punctuation - && last.get_kind() == Punctuation - && first.get_spelling() == "(" - && last.get_spelling() == ")" - { - token.remove(0); - token.remove(token.len() - 1); - } - - if token.len() == 1 { - let value = token[0].get_spelling(); - - let value = if value.starts_with('\"') && value.ends_with('\"') { - let value = value.strip_prefix('\"').unwrap(); - value.strip_suffix('\"').unwrap().to_string() - } else { - value - }; - macros.insert(name, Some(value)); + if cursor.get_kind() == clang::EntityKind::MacroDefinition { + let location = cursor.get_location().unwrap().get_file_location(); + if let Some(file) = location.file { + let file = file.get_path(); + let _f = file.to_str().unwrap(); + } else { + continue; + } + + let name = cursor.get_display_name().unwrap(); + let mut token = cursor.get_range().unwrap().tokenize(); + token.remove(0); // remove macro Identifier token + if token.is_empty() { + macros.insert(name, None); + continue; // remove define only + } + + let first = token.first().unwrap(); + let last = token.last().unwrap(); + if first.get_kind() == Punctuation + && last.get_kind() == Punctuation + && first.get_spelling() == "(" + && last.get_spelling() == ")" + { + token.remove(0); + token.remove(token.len() - 1); + } + + if token.len() == 1 { + let value = token[0].get_spelling(); + + let value = if value.starts_with('\"') && value.ends_with('\"') { + let value = value.strip_prefix('\"').unwrap(); + value.strip_suffix('\"').unwrap().to_string() } else { - // 単純な値ではなかった(ex: 関数マクロ) - dbg!(token); - } + value + }; + macros.insert(name, Some(value)); + } else { + // 単純な値ではなかった(ex: 関数マクロ) + dbg!(token); } - _ => {} } } diff --git a/examples/mobc/build.rs b/examples/mobc/build.rs index fe069044d..0bbb762fa 100644 --- a/examples/mobc/build.rs +++ b/examples/mobc/build.rs @@ -111,7 +111,8 @@ fn main() { #[cfg(windows)] { - let _ = std::os::windows::fs::symlink_file(&compile_commands_src, &compile_commands_dst); + let _ = + std::os::windows::fs::symlink_file(&compile_commands_src, &compile_commands_dst); } } @@ -134,9 +135,15 @@ fn main() { }; // configurations[0].includePath に c2a_core と out_dir を追加(存在しない場合のみ) - if let Some(configurations) = config.get_mut("configurations").and_then(|c| c.as_array_mut()) { + if let Some(configurations) = config + .get_mut("configurations") + .and_then(|c| c.as_array_mut()) + { if let Some(first_config) = configurations.get_mut(0) { - if let Some(include_path) = first_config.get_mut("includePath").and_then(|p| p.as_array_mut()) { + if let Some(include_path) = first_config + .get_mut("includePath") + .and_then(|p| p.as_array_mut()) + { // 古い out_dir パス(target/.../out/** パターン)を削除 include_path.retain(|p| { if let Some(path_str) = p.as_str() { @@ -147,7 +154,10 @@ fn main() { }); // c2a_core_path が存在しない場合は追加 - if !include_path.iter().any(|p| p.as_str() == Some(&c2a_core_path)) { + if !include_path + .iter() + .any(|p| p.as_str() == Some(&c2a_core_path)) + { include_path.push(serde_json::Value::String(c2a_core_path.clone())); } // 新しい out_dir_path を追加 @@ -156,7 +166,9 @@ fn main() { // compileCommands が設定されていない場合は追加 if first_config.get("compileCommands").is_none() { - first_config["compileCommands"] = serde_json::Value::String("${workspaceFolder}/compile_commands.json".to_string()); + first_config["compileCommands"] = serde_json::Value::String( + "${workspaceFolder}/compile_commands.json".to_string(), + ); } } } From 1952cbdc634f4cb00273d0dc6fc850d1db42114d Mon Sep 17 00:00:00 2001 From: sksat Date: Fri, 30 Jan 2026 02:01:35 +0900 Subject: [PATCH 5/5] fix: address Copilot review comments - Rename out_dir_path to out_dir_glob to avoid variable shadowing - Check for existing out_dir_glob before adding to prevent duplicates - Remove redundant closure in unwrap_or_else --- examples/mobc/build.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/examples/mobc/build.rs b/examples/mobc/build.rs index 0bbb762fa..a680ef978 100644 --- a/examples/mobc/build.rs +++ b/examples/mobc/build.rs @@ -122,14 +122,14 @@ fn main() { let c_cpp_properties_path = vscode_dir.join("c_cpp_properties.json"); let c2a_core_path = format!("{}/**", c2a_core_dir.display()); - let out_dir_path = format!("{}/**", out_dir); + let out_dir_glob = format!("{}/**", out_dir); // 既存の c_cpp_properties.json を読み込むか、デフォルトを作成 let mut config: serde_json::Value = if c_cpp_properties_path.exists() { let content = std::fs::read_to_string(&c_cpp_properties_path).ok(); content .and_then(|s| serde_json::from_str(&s).ok()) - .unwrap_or_else(|| create_default_c_cpp_properties()) + .unwrap_or_else(create_default_c_cpp_properties) } else { create_default_c_cpp_properties() }; @@ -160,8 +160,13 @@ fn main() { { include_path.push(serde_json::Value::String(c2a_core_path.clone())); } - // 新しい out_dir_path を追加 - include_path.push(serde_json::Value::String(out_dir_path.clone())); + // out_dir_glob が存在しない場合は追加 + if !include_path + .iter() + .any(|p| p.as_str() == Some(&out_dir_glob)) + { + include_path.push(serde_json::Value::String(out_dir_glob.clone())); + } } // compileCommands が設定されていない場合は追加