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 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
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
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,9 @@
1
+ README.md
2
+ pyproject.toml
3
+ src/pcmake/__init__.py
4
+ src/pcmake/main.py
5
+ src/pcmake.egg-info/PKG-INFO
6
+ src/pcmake.egg-info/SOURCES.txt
7
+ src/pcmake.egg-info/dependency_links.txt
8
+ src/pcmake.egg-info/entry_points.txt
9
+ src/pcmake.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ pcmake = pcmake.main:main
@@ -0,0 +1 @@
1
+ pcmake