refactor: adopt layered C++ project layout
This commit is contained in:
18
Makefile
18
Makefile
@@ -1,22 +1,28 @@
|
||||
CXX := g++
|
||||
CXXFLAGS := -std=c++20 -Wall -Wextra -Wpedantic -O2
|
||||
CPPFLAGS :=
|
||||
LDFLAGS :=
|
||||
SRC_DIR := src
|
||||
INC_DIR := include
|
||||
BUILD_DIR := build
|
||||
TARGET := app
|
||||
CLANG_FORMAT ?= clang-format
|
||||
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))
|
||||
HDRS := $(wildcard $(SRC_DIR)/*.h) $(wildcard $(SRC_DIR)/*.hpp)
|
||||
FORMAT_SRCS := $(SRCS) $(HDRS)
|
||||
SRC_HDRS := $(shell find $(SRC_DIR) \( -name '*.hpp' -o -name '*.h' \) 2>/dev/null)
|
||||
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)
|
||||
$(CXX) $(OBJS) $(LDFLAGS) -o $@
|
||||
|
||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.cpp | $(BUILD_DIR)
|
||||
$(CXX) $(CXXFLAGS) -c $< -o $@
|
||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.cpp
|
||||
@mkdir -p $(dir $@)
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@
|
||||
|
||||
$(BUILD_DIR):
|
||||
mkdir -p $(BUILD_DIR)
|
||||
@@ -49,7 +55,7 @@ tidy:
|
||||
@if [ -n "$(strip $(SRCS))" ]; then \
|
||||
for src in $(SRCS); do \
|
||||
echo "running clang-tidy on $$src"; \
|
||||
$(CLANG_TIDY) $$src -- $(CXXFLAGS); \
|
||||
$(CLANG_TIDY) $$src -- $(CPPFLAGS) $(CXXFLAGS); \
|
||||
done; \
|
||||
else \
|
||||
echo "warning: no source files found for clang-tidy"; \
|
||||
|
27
README.md
27
README.md
@@ -3,12 +3,22 @@
|
||||
這個專案提供一個簡單的 C++ 樣板,包含基本的目錄結構、Makefile 與開發輔助工具,方便快速開始新專案。
|
||||
|
||||
## 目錄結構
|
||||
- `src/`: 主要的 C++ 原始碼,目前包含 `main.cpp`。
|
||||
- `build/`: 由 Makefile 自動建立,用來存放編譯後的物件檔。
|
||||
- `utils/`: 收錄常用腳本,例如編譯、執行、清理、格式化與 clang-tidy。
|
||||
- `.clang-format`: 定義 clang-format 的專案格式規則。
|
||||
- `.clang-tidy`: 定義 clang-tidy 的檢查設定。
|
||||
- `Makefile`: 管理編譯、執行、清理、格式化與靜態分析等命令。
|
||||
```text
|
||||
.
|
||||
├── include/
|
||||
│ └── project/
|
||||
│ └── sample_library.hpp # 對外公開的標頭
|
||||
├── src/
|
||||
│ ├── app/
|
||||
│ │ └── main.cpp # 可執行程式進入點
|
||||
│ └── lib/
|
||||
│ └── sample_library.cpp # 函式庫實作
|
||||
├── utils/ # Shell 腳本工具
|
||||
├── build/ # make 時產生,存放物件檔
|
||||
├── .clang-format
|
||||
├── .clang-tidy
|
||||
└── Makefile
|
||||
```
|
||||
|
||||
## 建置與執行
|
||||
若系統已安裝 `g++`,可使用以下命令:
|
||||
@@ -65,11 +75,14 @@ CXX=clang++ CXXFLAGS="-std=c++20 -O3" make
|
||||
- 4 空格縮排,最大列寬 100
|
||||
- 自訂括號換行與 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` 逐一檢查;若要檢查特定檔案,可執行:
|
||||
|
||||
```bash
|
||||
clang-tidy src/main.cpp --
|
||||
clang-tidy src/app/main.cpp -- -Iinclude
|
||||
```
|
||||
|
||||
可視需求調整 `Checks`、`HeaderFilterRegex` 或其他設定來符合專案需求。
|
||||
|
22
include/project/sample_library.hpp
Normal file
22
include/project/sample_library.hpp
Normal 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
20
src/app/main.cpp
Normal 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;
|
||||
}
|
21
src/lib/sample_library.cpp
Normal file
21
src/lib/sample_library.cpp
Normal 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
|
14
src/main.cpp
14
src/main.cpp
@@ -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;
|
||||
}
|
Reference in New Issue
Block a user