pcmake 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pcmake-0.1.0/PKG-INFO +37 -0
- pcmake-0.1.0/README.md +26 -0
- pcmake-0.1.0/pyproject.toml +23 -0
- pcmake-0.1.0/setup.cfg +4 -0
- pcmake-0.1.0/src/pcmake/__init__.py +0 -0
- pcmake-0.1.0/src/pcmake/main.py +208 -0
- pcmake-0.1.0/src/pcmake.egg-info/PKG-INFO +37 -0
- pcmake-0.1.0/src/pcmake.egg-info/SOURCES.txt +9 -0
- pcmake-0.1.0/src/pcmake.egg-info/dependency_links.txt +1 -0
- pcmake-0.1.0/src/pcmake.egg-info/entry_points.txt +2 -0
- pcmake-0.1.0/src/pcmake.egg-info/top_level.txt +1 -0
pcmake-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pcmake
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A lightweight cross-platform C/C++ build system written in Python.
|
|
5
|
+
Author-email: Your Name <your.email@example.com>
|
|
6
|
+
Classifier: Programming Language :: Python :: 3
|
|
7
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
8
|
+
Classifier: Operating System :: OS Independent
|
|
9
|
+
Requires-Python: >=3.7
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
|
|
12
|
+
# pcmake
|
|
13
|
+
|
|
14
|
+
`pcmake` 是一個輕量級、跨平台的 C/C++ 專案建置工具。
|
|
15
|
+
|
|
16
|
+
## 安裝
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pip install pcmake
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## 使用方法
|
|
23
|
+
|
|
24
|
+
在專案目錄下建立 `Pcmakefile`:
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
app = target("ssl_app")
|
|
28
|
+
app.set_kind("binary")
|
|
29
|
+
app.add_files("main.c", "math_utils.c")
|
|
30
|
+
app.add_packages("openssl")
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
然後執行建置:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
pcmake build
|
|
37
|
+
```
|
pcmake-0.1.0/README.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# pcmake
|
|
2
|
+
|
|
3
|
+
`pcmake` 是一個輕量級、跨平台的 C/C++ 專案建置工具。
|
|
4
|
+
|
|
5
|
+
## 安裝
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install pcmake
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 使用方法
|
|
12
|
+
|
|
13
|
+
在專案目錄下建立 `Pcmakefile`:
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
app = target("ssl_app")
|
|
17
|
+
app.set_kind("binary")
|
|
18
|
+
app.add_files("main.c", "math_utils.c")
|
|
19
|
+
app.add_packages("openssl")
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
然後執行建置:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pcmake build
|
|
26
|
+
```
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
# 套件名稱 (使用者用 pip install pcmake 安裝)
|
|
7
|
+
name = "pcmake"
|
|
8
|
+
version = "0.1.0"
|
|
9
|
+
authors =[
|
|
10
|
+
{ name="Your Name", email="your.email@example.com" },
|
|
11
|
+
]
|
|
12
|
+
description = "A lightweight cross-platform C/C++ build system written in Python."
|
|
13
|
+
readme = "README.md"
|
|
14
|
+
requires-python = ">=3.7"
|
|
15
|
+
classifiers =[
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"License :: OSI Approved :: MIT License",
|
|
18
|
+
"Operating System :: OS Independent",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
[project.scripts]
|
|
22
|
+
# 左邊是終端機執行的指令,右邊是對應到 src/pcmake/main.py 裡的 main() 函式
|
|
23
|
+
pcmake = "pcmake.main:main"
|
pcmake-0.1.0/setup.cfg
ADDED
|
File without changes
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import glob
|
|
4
|
+
import platform
|
|
5
|
+
import subprocess
|
|
6
|
+
import argparse
|
|
7
|
+
import re
|
|
8
|
+
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
9
|
+
|
|
10
|
+
# --- 專案配置類別 ---
|
|
11
|
+
_targets = []
|
|
12
|
+
|
|
13
|
+
class Target:
|
|
14
|
+
def __init__(self, name):
|
|
15
|
+
self.name = name
|
|
16
|
+
self.kind = "binary"
|
|
17
|
+
self.srcs = []
|
|
18
|
+
self.includes = []
|
|
19
|
+
self.cflags = []
|
|
20
|
+
self.ldflags = []
|
|
21
|
+
self.packages = []
|
|
22
|
+
|
|
23
|
+
def set_kind(self, kind): self.kind = kind
|
|
24
|
+
def add_files(self, *patterns):
|
|
25
|
+
for p in patterns:
|
|
26
|
+
self.srcs.extend(glob.glob(p))
|
|
27
|
+
def add_includedirs(self, *dirs): self.includes.extend(dirs)
|
|
28
|
+
def add_packages(self, *pkgs): self.packages.extend(pkgs)
|
|
29
|
+
def add_cflags(self, *flags): self.cflags.append(flags)
|
|
30
|
+
def add_ldflags(self, *flags): self.ldflags.append(flags)
|
|
31
|
+
|
|
32
|
+
def target(name):
|
|
33
|
+
t = Target(name)
|
|
34
|
+
_targets.append(t)
|
|
35
|
+
return t
|
|
36
|
+
|
|
37
|
+
# --- 核心引擎 ---
|
|
38
|
+
class Toolchain:
|
|
39
|
+
def __init__(self):
|
|
40
|
+
self.os = platform.system()
|
|
41
|
+
self.is_win = (self.os == "Windows")
|
|
42
|
+
self.cc = "cl" if self.is_win else "clang"
|
|
43
|
+
self.obj_ext = ".obj" if self.is_win else ".o"
|
|
44
|
+
self.exe_ext = ".exe" if self.is_win else ""
|
|
45
|
+
|
|
46
|
+
def get_compile_cmd(self, src, obj, includes):
|
|
47
|
+
# 轉換 include 路徑為編譯器參數
|
|
48
|
+
inc_args = [(f"/I{d}" if self.is_win else f"-I{d}") for d in includes]
|
|
49
|
+
if self.is_win:
|
|
50
|
+
return [self.cc, "/nologo", "/c", src, f"/Fo{obj}", "/EHsc"] + inc_args
|
|
51
|
+
else:
|
|
52
|
+
return [self.cc, "-c", src, "-o", obj, "-O2", "-Wall"] + inc_args
|
|
53
|
+
|
|
54
|
+
def get_link_cmd(self, objs, output, ldflags):
|
|
55
|
+
if self.is_win:
|
|
56
|
+
# Windows 連結通常需要處理 .lib 路徑
|
|
57
|
+
return [self.cc, "/nologo"] + objs + [f"/Fe{output}", "/link"] + ldflags
|
|
58
|
+
else:
|
|
59
|
+
return [self.cc] + objs + ["-o", output] + ldflags
|
|
60
|
+
|
|
61
|
+
class Builder:
|
|
62
|
+
def __init__(self):
|
|
63
|
+
self.tc = Toolchain()
|
|
64
|
+
self.build_dir = ".pmake_cache"
|
|
65
|
+
os.makedirs(self.build_dir, exist_ok=True)
|
|
66
|
+
self.inc_regex = re.compile(r'^\s*#\s*include\s*"([^"]+)"')
|
|
67
|
+
|
|
68
|
+
def _find_package(self, name):
|
|
69
|
+
"""自動偵測套件路徑:封裝平台差異"""
|
|
70
|
+
res = {"inc": [], "link": []}
|
|
71
|
+
if name.lower() == "openssl":
|
|
72
|
+
if self.tc.os == "Darwin": # macOS (Homebrew)
|
|
73
|
+
paths = ["/opt/homebrew/opt/openssl", "/usr/local/opt/openssl"]
|
|
74
|
+
for p in paths:
|
|
75
|
+
if os.path.exists(p):
|
|
76
|
+
res["inc"].append(f"{p}/include")
|
|
77
|
+
res["link"].extend([f"-L{p}/lib", "-lssl", "-lcrypto"])
|
|
78
|
+
break
|
|
79
|
+
elif self.tc.os == "Linux":
|
|
80
|
+
res["link"].extend(["-lssl", "-lcrypto"])
|
|
81
|
+
elif self.tc.os == "Windows":
|
|
82
|
+
# 搜尋常見安裝路徑
|
|
83
|
+
roots = [os.environ.get("OPENSSL_ROOT"), "C:/Program Files/OpenSSL-Win64"]
|
|
84
|
+
for r in roots:
|
|
85
|
+
if r and os.path.exists(r):
|
|
86
|
+
res["inc"].append(f"{r}/include")
|
|
87
|
+
res["link"].extend([f"{r}/lib/libssl.lib", f"{r}/lib/libcrypto.lib"])
|
|
88
|
+
break
|
|
89
|
+
return res
|
|
90
|
+
|
|
91
|
+
def _get_deps(self, src, include_dirs):
|
|
92
|
+
"""遞迴追蹤標頭檔依賴"""
|
|
93
|
+
deps, stack = set(), [src]
|
|
94
|
+
while stack:
|
|
95
|
+
curr = stack.pop()
|
|
96
|
+
if curr in deps: continue
|
|
97
|
+
if curr != src: deps.add(curr)
|
|
98
|
+
if not os.path.exists(curr): continue
|
|
99
|
+
|
|
100
|
+
with open(curr, 'r', encoding='utf-8', errors='ignore') as f:
|
|
101
|
+
for line in f:
|
|
102
|
+
m = self.inc_regex.match(line)
|
|
103
|
+
if m:
|
|
104
|
+
h_name = m.group(1)
|
|
105
|
+
# 搜尋路徑:目前檔案目錄 -> 使用者指定目錄
|
|
106
|
+
search_dirs = [os.path.dirname(curr)] + include_dirs
|
|
107
|
+
for d in search_dirs:
|
|
108
|
+
h_path = os.path.normpath(os.path.join(d, h_name))
|
|
109
|
+
if os.path.exists(h_path):
|
|
110
|
+
stack.append(h_path)
|
|
111
|
+
break
|
|
112
|
+
return deps
|
|
113
|
+
|
|
114
|
+
def _needs_build(self, src, obj, includes):
|
|
115
|
+
if not os.path.exists(obj): return True
|
|
116
|
+
mtime = os.path.getmtime(obj)
|
|
117
|
+
if os.path.getmtime(src) > mtime: return True
|
|
118
|
+
return any(os.path.getmtime(h) > mtime for h in self._get_deps(src, includes))
|
|
119
|
+
|
|
120
|
+
def _print_install_suggestion(self, pkg_name):
|
|
121
|
+
"""當出錯時,給予針對性的安裝建議"""
|
|
122
|
+
sys_platform = platform.system()
|
|
123
|
+
suggestions = {
|
|
124
|
+
"openssl": {
|
|
125
|
+
"Darwin": "brew install openssl",
|
|
126
|
+
"Linux": "sudo apt-get install libssl-dev (Ubuntu/Debian) 或 sudo dnf install openssl-devel (Fedora)",
|
|
127
|
+
"Windows": "請至 https://slproweb.com/products/Win32OpenSSL.html 下載安裝,或使用 vcpkg install openssl"
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
msg = suggestions.get(pkg_name.lower(), {}).get(sys_platform, "請檢查該套件是否已安裝並配置於系統路徑中。")
|
|
132
|
+
print(f"\n💡 [pmake 建議] 偵測到 {pkg_name} 可能未正確安裝或連結失敗。")
|
|
133
|
+
print(f"👉 嘗試執行: {msg}\n")
|
|
134
|
+
|
|
135
|
+
def build_target(self, t):
|
|
136
|
+
print(f"🛠️ 正在建置目標: {t.name}")
|
|
137
|
+
|
|
138
|
+
# 1. 偵測套件 (如果找不到路徑就發出警告)
|
|
139
|
+
for pkg in t.packages:
|
|
140
|
+
info = self._find_package(pkg)
|
|
141
|
+
if not info["inc"] and not info["link"]:
|
|
142
|
+
print(f"⚠️ 警告: 無法在系統中自動找到套件 '{pkg}'")
|
|
143
|
+
self._print_install_suggestion(pkg)
|
|
144
|
+
t.includes.extend(info["inc"])
|
|
145
|
+
t.ldflags.extend(info["link"])
|
|
146
|
+
|
|
147
|
+
# 2. 編譯階段 (將 .c 檔編譯為 .o 檔)
|
|
148
|
+
objs =[]
|
|
149
|
+
for src in t.srcs:
|
|
150
|
+
# 決定對應的目的檔 (.o 或 .obj) 路徑
|
|
151
|
+
obj = os.path.join(self.build_dir, os.path.basename(src) + self.tc.obj_ext)
|
|
152
|
+
objs.append(obj)
|
|
153
|
+
|
|
154
|
+
# 透過 _needs_build 判斷是否需要重新編譯
|
|
155
|
+
if self._needs_build(src, obj, t.includes):
|
|
156
|
+
print(f" [CC] {src}")
|
|
157
|
+
compile_cmd = self.tc.get_compile_cmd(src, obj, t.includes)
|
|
158
|
+
try:
|
|
159
|
+
subprocess.run(compile_cmd, check=True)
|
|
160
|
+
except subprocess.CalledProcessError as e:
|
|
161
|
+
print(f"\n❌ 編譯失敗!")
|
|
162
|
+
print(f"指令: {' '.join(compile_cmd)}")
|
|
163
|
+
sys.exit(1)
|
|
164
|
+
|
|
165
|
+
# 3. 連結階段 (將所有 .o 檔連結成執行檔)
|
|
166
|
+
out_exe = t.name + self.tc.exe_ext
|
|
167
|
+
link_cmd = self.tc.get_link_cmd(objs, out_exe, t.ldflags)
|
|
168
|
+
|
|
169
|
+
try:
|
|
170
|
+
print(f" [LINK] {out_exe}")
|
|
171
|
+
subprocess.run(link_cmd, check=True, capture_output=True, text=True)
|
|
172
|
+
print(f"✅ 建置成功: {out_exe}\n")
|
|
173
|
+
except subprocess.CalledProcessError as e:
|
|
174
|
+
print(f"\n❌ 連結失敗!")
|
|
175
|
+
print(f"指令: {' '.join(link_cmd)}")
|
|
176
|
+
print(f"錯誤訊息:\n{e.stderr}")
|
|
177
|
+
|
|
178
|
+
# 檢查錯誤訊息中是否包含 ssl 關鍵字,以給出建議
|
|
179
|
+
if "ssl" in e.stderr.lower() or "crypto" in e.stderr.lower():
|
|
180
|
+
self._print_install_suggestion("openssl")
|
|
181
|
+
|
|
182
|
+
sys.exit(1)
|
|
183
|
+
|
|
184
|
+
# --- 執行入口 ---
|
|
185
|
+
def main():
|
|
186
|
+
parser = argparse.ArgumentParser()
|
|
187
|
+
parser.add_argument("action", choices=["build", "clean"], default="build", nargs="?")
|
|
188
|
+
args = parser.parse_args()
|
|
189
|
+
|
|
190
|
+
if not os.path.exists("Pcmakefile"):
|
|
191
|
+
print("❌ 錯誤: 找不到 Pcmakefile")
|
|
192
|
+
return
|
|
193
|
+
|
|
194
|
+
# 執行 Pcmakefile 配置
|
|
195
|
+
with open("Pcmakefile", "r") as f:
|
|
196
|
+
exec(f.read(), globals())
|
|
197
|
+
|
|
198
|
+
builder = Builder()
|
|
199
|
+
if args.action == "clean":
|
|
200
|
+
import shutil
|
|
201
|
+
if os.path.exists(builder.build_dir): shutil.rmtree(builder.build_dir)
|
|
202
|
+
print("🧹 已清理快取")
|
|
203
|
+
else:
|
|
204
|
+
for t in _targets:
|
|
205
|
+
builder.build_target(t)
|
|
206
|
+
|
|
207
|
+
if __name__ == "__main__":
|
|
208
|
+
main()
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pcmake
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A lightweight cross-platform C/C++ build system written in Python.
|
|
5
|
+
Author-email: Your Name <your.email@example.com>
|
|
6
|
+
Classifier: Programming Language :: Python :: 3
|
|
7
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
8
|
+
Classifier: Operating System :: OS Independent
|
|
9
|
+
Requires-Python: >=3.7
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
|
|
12
|
+
# pcmake
|
|
13
|
+
|
|
14
|
+
`pcmake` 是一個輕量級、跨平台的 C/C++ 專案建置工具。
|
|
15
|
+
|
|
16
|
+
## 安裝
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pip install pcmake
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## 使用方法
|
|
23
|
+
|
|
24
|
+
在專案目錄下建立 `Pcmakefile`:
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
app = target("ssl_app")
|
|
28
|
+
app.set_kind("binary")
|
|
29
|
+
app.add_files("main.c", "math_utils.c")
|
|
30
|
+
app.add_packages("openssl")
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
然後執行建置:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
pcmake build
|
|
37
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pcmake
|