refactor: adopt layered C++ project layout

This commit is contained in:
2025-09-23 14:03:16 +08:00
parent b5ccc595e0
commit b74681a0f5
6 changed files with 95 additions and 27 deletions

View File

@@ -1,22 +1,28 @@
CXX := g++ CXX := g++
CXXFLAGS := -std=c++20 -Wall -Wextra -Wpedantic -O2 CXXFLAGS := -std=c++20 -Wall -Wextra -Wpedantic -O2
CPPFLAGS :=
LDFLAGS := LDFLAGS :=
SRC_DIR := src SRC_DIR := src
INC_DIR := include
BUILD_DIR := build BUILD_DIR := build
TARGET := app TARGET := app
CLANG_FORMAT ?= clang-format CLANG_FORMAT ?= clang-format
CLANG_TIDY ?= clang-tidy CLANG_TIDY ?= clang-tidy
SRCS := $(wildcard $(SRC_DIR)/*.cpp) SRCS := $(shell find $(SRC_DIR) -name '*.cpp' 2>/dev/null)
OBJS := $(patsubst $(SRC_DIR)/%.cpp,$(BUILD_DIR)/%.o,$(SRCS)) OBJS := $(patsubst $(SRC_DIR)/%.cpp,$(BUILD_DIR)/%.o,$(SRCS))
HDRS := $(wildcard $(SRC_DIR)/*.h) $(wildcard $(SRC_DIR)/*.hpp) SRC_HDRS := $(shell find $(SRC_DIR) \( -name '*.hpp' -o -name '*.h' \) 2>/dev/null)
FORMAT_SRCS := $(SRCS) $(HDRS) INCLUDE_HDRS := $(shell [ -d $(INC_DIR) ] && find $(INC_DIR) \( -name '*.hpp' -o -name '*.h' \) 2>/dev/null)
FORMAT_SRCS := $(SRCS) $(SRC_HDRS) $(INCLUDE_HDRS)
CPPFLAGS += -I$(INC_DIR)
$(TARGET): $(OBJS) $(TARGET): $(OBJS)
$(CXX) $(OBJS) $(LDFLAGS) -o $@ $(CXX) $(OBJS) $(LDFLAGS) -o $@
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.cpp | $(BUILD_DIR) $(BUILD_DIR)/%.o: $(SRC_DIR)/%.cpp
$(CXX) $(CXXFLAGS) -c $< -o $@ @mkdir -p $(dir $@)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@
$(BUILD_DIR): $(BUILD_DIR):
mkdir -p $(BUILD_DIR) mkdir -p $(BUILD_DIR)
@@ -49,7 +55,7 @@ tidy:
@if [ -n "$(strip $(SRCS))" ]; then \ @if [ -n "$(strip $(SRCS))" ]; then \
for src in $(SRCS); do \ for src in $(SRCS); do \
echo "running clang-tidy on $$src"; \ echo "running clang-tidy on $$src"; \
$(CLANG_TIDY) $$src -- $(CXXFLAGS); \ $(CLANG_TIDY) $$src -- $(CPPFLAGS) $(CXXFLAGS); \
done; \ done; \
else \ else \
echo "warning: no source files found for clang-tidy"; \ echo "warning: no source files found for clang-tidy"; \

View File

@@ -3,12 +3,22 @@
這個專案提供一個簡單的 C++ 樣板包含基本的目錄結構、Makefile 與開發輔助工具,方便快速開始新專案。 這個專案提供一個簡單的 C++ 樣板包含基本的目錄結構、Makefile 與開發輔助工具,方便快速開始新專案。
## 目錄結構 ## 目錄結構
- `src/`: 主要的 C++ 原始碼,目前包含 `main.cpp` ```text
- `build/`: 由 Makefile 自動建立,用來存放編譯後的物件檔。 .
- `utils/`: 收錄常用腳本,例如編譯、執行、清理、格式化與 clang-tidy。 ├── include/
- `.clang-format`: 定義 clang-format 的專案格式規則。 │ └── project/
- `.clang-tidy`: 定義 clang-tidy 的檢查設定。 │ └── sample_library.hpp # 對外公開的標頭
- `Makefile`: 管理編譯、執行、清理、格式化與靜態分析等命令。 ├── src/
│ ├── app/
│ │ └── main.cpp # 可執行程式進入點
│ └── lib/
│ └── sample_library.cpp # 函式庫實作
├── utils/ # Shell 腳本工具
├── build/ # make 時產生,存放物件檔
├── .clang-format
├── .clang-tidy
└── Makefile
```
## 建置與執行 ## 建置與執行
若系統已安裝 `g++`,可使用以下命令: 若系統已安裝 `g++`,可使用以下命令:
@@ -65,11 +75,14 @@ CXX=clang++ CXXFLAGS="-std=c++20 -O3" make
- 4 空格縮排,最大列寬 100 - 4 空格縮排,最大列寬 100
- 自訂括號換行與 namespace 縮排規則 - 自訂括號換行與 namespace 縮排規則
## 範例程式碼
`include/project/sample_library.hpp``src/lib/sample_library.cpp` 呈現一個簡單的 `project::Greeter` 類別與 `generate_sequence` 函式,`.hpp` 只放宣告、`.cpp` 負責實作,示範「公開標頭放在 include/,實作放在 src/」的常見結構。`src/app/main.cpp` 會引入該標頭並呼叫它們,執行 `make run` 即可看到輸出。如果要建立自己的模組,可依此模式建立額外的標頭與來源檔,並依需求放在 `src/lib/``src/app/` 或新的子資料夾。
## 靜態分析 ## 靜態分析
`.clang-tidy` 啟用了一些常用的檢查(`bugprone-*``clang-analyzer-*``modernize-*` 等)。可使用 `make tidy``CLANG_TIDY=/path/to/clang-tidy make tidy``src/*.cpp` 逐一檢查;若要檢查特定檔案,可執行: `.clang-tidy` 啟用了一些常用的檢查(`bugprone-*``clang-analyzer-*``modernize-*` 等)。可使用 `make tidy``CLANG_TIDY=/path/to/clang-tidy make tidy``src/*.cpp` 逐一檢查;若要檢查特定檔案,可執行:
```bash ```bash
clang-tidy src/main.cpp -- clang-tidy src/app/main.cpp -- -Iinclude
``` ```
可視需求調整 `Checks``HeaderFilterRegex` 或其他設定來符合專案需求。 可視需求調整 `Checks``HeaderFilterRegex` 或其他設定來符合專案需求。

View File

@@ -0,0 +1,22 @@
#pragma once
#include <string>
#include <vector>
namespace project {
// Greeter builds a greeting message for a given name.
class Greeter {
public:
explicit Greeter(std::string base = "Hello") : base_message_(std::move(base)) {}
[[nodiscard]] std::string greet(const std::string &name) const;
private:
std::string base_message_;
};
// generate_sequence returns numbers from 0 up to limit (exclusive).
[[nodiscard]] std::vector<int> generate_sequence(int limit);
} // namespace project

20
src/app/main.cpp Normal file
View File

@@ -0,0 +1,20 @@
#include <project/sample_library.hpp>
#include <iostream>
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
const project::Greeter greeter{"Welcome"};
std::cout << greeter.greet("Coding World") << '\n';
auto sequence = project::generate_sequence(5);
std::cout << "Sample sequence:";
for (int value : sequence) {
std::cout << ' ' << value;
}
std::cout << '\n';
return 0;
}

View File

@@ -0,0 +1,21 @@
#include <project/sample_library.hpp>
#include <numeric>
namespace project {
std::string Greeter::greet(const std::string &name) const {
return base_message_ + ", " + name + "!";
}
std::vector<int> generate_sequence(int limit) {
if (limit < 0) {
limit = 0;
}
std::vector<int> result(static_cast<std::size_t>(limit));
std::iota(result.begin(), result.end(), 0);
return result;
}
} // namespace project

View File

@@ -1,14 +0,0 @@
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <numeric>
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
// TODO: Add program logic here.
return 0;
}