cppmake 0.0.1__tar.gz → 0.0.2__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.
@@ -1,9 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cppmake
3
- Version: 0.0.1
3
+ Version: 0.0.2
4
4
  Summary: none
5
- Home-page: https://github.com/anonymouspc/cppmake
6
- Author: {'name': 'anonymouspc', 'email': 'shyeyian@petalmail.com'}
7
5
  Author-email: anonymouspc <shyeyian@petalmail.com>
8
6
  License-Expression: MIT
9
7
  Project-URL: Homepage, https://github.com/anonymouspc/cppmake
@@ -11,6 +9,4 @@ Classifier: Programming Language :: Python :: 3
11
9
  Requires-Python: >=3.13
12
10
  Description-Content-Type: text/markdown
13
11
  License-File: license.txt
14
- Dynamic: author
15
- Dynamic: home-page
16
12
  Dynamic: license-file
@@ -0,0 +1,29 @@
1
+ from cppmake.error import BuildError
2
+ from cppmake.module import Module
3
+ from cppmake.object import Object
4
+ from cppmake.package import Package
5
+ from cppmake.source import Source
6
+ import sys
7
+
8
+ if __name__ == "__main__":
9
+ open(".log", 'w')
10
+
11
+ try:
12
+ Object("main")
13
+ for package in Package.pool.values():
14
+ package.build()
15
+ for module in Module.pool.values():
16
+ module.compile()
17
+ for source in Source.pool.values():
18
+ source.compile()
19
+ for object in Object.pool.values():
20
+ object.link()
21
+
22
+ except BuildError as e:
23
+ print(e, end="", file=sys.stderr)
24
+ print(e, end="", file=open(".log", 'a'))
25
+ exit(-1)
26
+
27
+ except KeyboardInterrupt as e:
28
+ exit(-1)
29
+
@@ -0,0 +1,6 @@
1
+ from cppmake.config import type
2
+ import shutil
3
+
4
+ if __name__ == "__main__":
5
+ try: shutil.rmtree(f"./bin/{type}/module")
6
+ except: pass
@@ -0,0 +1,19 @@
1
+ def recursive_find(node, func, root=True, flatten=False):
2
+ return _recursive_find_with_cache(node=node, func=func, root=root, flatten=flatten, cache=[])
3
+
4
+ def _recursive_find_with_cache(node, func, root, flatten, cache):
5
+ if root:
6
+ result = func(node)
7
+ if result is not None:
8
+ if not flatten:
9
+ if result not in cache:
10
+ cache += [result]
11
+ else:
12
+ for element in result:
13
+ if element not in cache:
14
+ cache += [element]
15
+
16
+ for import_module in node.import_modules:
17
+ _recursive_find_with_cache(node=import_module, func=func, root=True, flatten=flatten, cache=cache)
18
+
19
+ return cache
@@ -0,0 +1,106 @@
1
+ from cppmake.config import type, compiler, compile_flags, link_flags, define_flags
2
+ from cppmake.error import BuildError
3
+ from cppmake.run import run
4
+ import os
5
+ import re
6
+ import subprocess
7
+
8
+ def preprocess_file(code_file, name=None, module_file=None):
9
+ command = ""
10
+ if compiler == "g++" or compiler == "clang++":
11
+ command = f"{compiler} " \
12
+ f"{' '.join(compile_flags)} " \
13
+ f"-E -x c++ - " \
14
+ f"-o -"
15
+ if compiler == "g++":
16
+ if not hasattr(preprocess_file, "initialized"):
17
+ open(f"./bin/{type}/module/mapper.txt", 'w')
18
+ preprocess_file.initialized = True
19
+ if name is not None and module_file is not None:
20
+ with open(f"./bin/{type}/module/mapper.txt", 'a') as writer:
21
+ writer.write(f"{name} {module_file}\n")
22
+ elif compiler == "cl":
23
+ command = f"{compiler} " \
24
+ f"/E {code_file}"
25
+
26
+ try:
27
+ reader = open(code_file, 'r').read()
28
+ reader = re.sub(r'^\s*#\s*include\s+(?!<version>).*$', "", reader, flags=re.MULTILINE)
29
+ return subprocess.run(command, shell=True, check=True, capture_output=True, text=True, input=reader).stdout
30
+ except FileNotFoundError as e:
31
+ raise BuildError(f"fatal error: {e.filename} not found")
32
+ except subprocess.CalledProcessError as e:
33
+ raise BuildError(e.stderr)
34
+
35
+ def compile_module(code_file, include_dirs, module_file, object_file):
36
+ os.makedirs(os.path.dirname(module_file), exist_ok=True)
37
+ os.makedirs(os.path.dirname(object_file), exist_ok=True)
38
+ commands = []
39
+ if compiler == "g++":
40
+ commands = [f"g++ "
41
+ f"{' '.join(compile_flags)} "
42
+ f"{' '.join(f'-I {include_path}' for include_path in include_dirs)} "
43
+ f"{' '.join(f'-D {key}="{value}"' for key, value in define_flags.items())} "
44
+ f"-c {code_file} "
45
+ f"-o {object_file}"]
46
+ elif compiler == "clang++":
47
+ commands = [f"clang++ "
48
+ f"{' '.join(compile_flags)} "
49
+ f"{' '.join(f'-I {include_path}' for include_path in include_dirs)} "
50
+ f"{' '.join(f'-D {key}="{value}"' for key, value in define_flags.items())} "
51
+ f"--precompile -x c++-module {code_file} "
52
+ f"-o {module_file}",
53
+
54
+ f"clang++ "
55
+ f"{' '.join(compile_flags)} "
56
+ f"-c {module_file} "
57
+ f"-o {object_file}"]
58
+ elif compiler == "cl":
59
+ commands = [f"cl "
60
+ f"{' '.join(compile_flags)} "
61
+ f"{' '.join(f'/I {include_path}' for include_path in include_dirs)} "
62
+ f"{' '.join(f'/D {key}="{value}"' for key, value in define_flags.items())} "
63
+ f"/c /interface /TP {code_file} "
64
+ f"/ifcOutput {module_file} "
65
+ f"/Fo {object_file}"]
66
+ for command in commands:
67
+ run(command)
68
+
69
+ def compile_source(code_file, include_dirs, object_file):
70
+ os.makedirs(os.path.dirname(object_file), exist_ok=True)
71
+ command = ""
72
+ if compiler == "g++" or compiler == "clang++":
73
+ command = f"{compiler} " \
74
+ f"{' '.join(compile_flags)} " \
75
+ f"{' '.join(f'-I {include_path}' for include_path in include_dirs)} " \
76
+ f"{' '.join(f'-D {key}="{value}"' for key, value in define_flags.items())} " \
77
+ f"-c {code_file} " \
78
+ f"-o {object_file}"
79
+ elif compiler == "cl":
80
+ command = f"cl " \
81
+ f"{' '.join(compile_flags)} " \
82
+ f"{' '.join(f'/I {include_path}' for include_path in include_dirs)} " \
83
+ f"{' '.join(f'/D {key}="{value}"' for key, value in define_flags.items())} " \
84
+ f"/c {code_file} " \
85
+ f"/Fo {object_file}"
86
+ run(command)
87
+
88
+ def link_object(object_files, library_files, executable_file):
89
+ os.makedirs(os.path.dirname(executable_file), exist_ok=True)
90
+ command = ""
91
+ if compiler == "g++" or compiler == "clang++":
92
+ command = f"{compiler} " \
93
+ f"{' '.join(link_flags)} " \
94
+ f"{' '.join(object_files)} " \
95
+ f"{' '.join(library_files)} " \
96
+ f"-o {executable_file}"
97
+ elif compiler == "cl":
98
+ command = f"cl " \
99
+ f"{' '.join(link_flags)} " \
100
+ f"{' '.join(object_files)} " \
101
+ f"{' '.join(library_files)} " \
102
+ f"/Fe {executable_file}"
103
+ run(command)
104
+
105
+ def run_executable(executable_file):
106
+ run(f"./{executable_file}")
@@ -0,0 +1,94 @@
1
+ import argparse
2
+ import os
3
+ import sys
4
+ os.environ["LANG"] = "en_US.UTF-8"
5
+
6
+
7
+
8
+ # Arguments
9
+
10
+ parser = argparse.ArgumentParser(description="build.py")
11
+ parser.add_argument("--type", choices=["debug", "release"], default="debug")
12
+ parser.add_argument("--verbose", action="store_true", )
13
+ argv = parser.parse_args()
14
+ type = argv.type
15
+ verbose = argv.verbose
16
+
17
+
18
+
19
+ # System
20
+
21
+ if sys.platform == "win32":
22
+ system = "windows"
23
+ compiler = "cl"
24
+ executable_suffix = "exe"
25
+ shared_suffix = "dll"
26
+ elif sys.platform == "linux":
27
+ system = "linux"
28
+ compiler = "g++"
29
+ executable_suffix = ""
30
+ shared_suffix = "so"
31
+ elif sys.platform == "darwin":
32
+ system = "macos"
33
+ compiler = "clang++"
34
+ executable_suffix = ""
35
+ shared_suffix = "dylib"
36
+
37
+
38
+
39
+ # Flags
40
+
41
+ if compiler == "g++":
42
+ compile_flags = [
43
+ "-std=c++26",
44
+ "-Wall",
45
+ "-fdiagnostics-color=always",
46
+ "-fmodules",
47
+ f"-fmodule-mapper=./bin/{type}/module/mapper.txt",
48
+ ]
49
+ link_flags = ["-static"]
50
+ if type == "debug":
51
+ compile_flags += ["-g", "-O0", "-DDEBUG" ]
52
+ elif type == "release":
53
+ compile_flags += [ "-O3", "-DNDEBUG"]
54
+ compile_flags += ["-s"]
55
+ module_suffix = "gcm"
56
+ object_suffix = "o"
57
+ library_suffix = "a"
58
+ elif compiler == "clang++":
59
+ compile_flags = [
60
+ "-std=c++26",
61
+ "-Wall",
62
+ "-fdiagnostics-color=always",
63
+ f"-fprebuilt-module-path=./bin/{type}/module",
64
+ ]
65
+ link_flags = []
66
+ if type == "debug":
67
+ compile_flags += ["-g", "-O0", "-DDEBUG" ]
68
+ elif type == "release":
69
+ compile_flags += [ "-O3", "-DNDEBUG"]
70
+ link_flags += ["-s"]
71
+ module_suffix = "pcm"
72
+ object_suffix = "o"
73
+ library_suffix = "a"
74
+ elif compiler == "cl":
75
+ compile_flags = [
76
+ "/std:c++latest",
77
+ "/EHsc",
78
+ "/W4"
79
+ ]
80
+ link_flags = ["/MT"]
81
+ if type == "debug":
82
+ compile_flags += ["/Z7", "/Od", "/DDEBUG" ]
83
+ elif type == "release":
84
+ compile_flags += [ "/O2", "/DNDEBUG"]
85
+ module_suffix = "ifc"
86
+ object_suffix = "obj"
87
+ library_suffix = "lib"
88
+
89
+ define_flags = {
90
+ "abstract": '0',
91
+ "extends" : ':',
92
+ "in" : ':',
93
+ "self" : "(*this)"
94
+ }
@@ -0,0 +1,2 @@
1
+ class BuildError(Exception):
2
+ pass
@@ -0,0 +1,43 @@
1
+ from cppmake.compiler import run_executable
2
+ from cppmake.config import executable_suffix, type
3
+ from cppmake.object import Object
4
+
5
+ class Executable:
6
+ pool = {}
7
+ current = 0
8
+ total = 0
9
+
10
+ def __new__(self, name):
11
+ if name in Executable.pool.keys():
12
+ return Executable.pool[name]
13
+ else:
14
+ self = super().__new__(self)
15
+ Executable.pool[name] = self
16
+
17
+ # Info
18
+ self.name = name
19
+ self.executable_file = f"./bin/{type}/src/{self.name.replace('.', '.').replace(':', '/')}.{executable_suffix}" if executable_suffix != "" else \
20
+ f"./bin/{type}/src/{self.name.replace('.' ,'.').replace(':', '/')}"
21
+
22
+ # Subtask
23
+ Object(self.name)
24
+
25
+ # Status
26
+ self.runned = False
27
+ Executable.total += 1
28
+
29
+ # Return
30
+ return self
31
+
32
+ def run(self):
33
+ if not self.runned:
34
+ # Subtask
35
+ Object(self.name).link()
36
+
37
+ # Self
38
+ Executable.current += 1
39
+ print(f"run executable [{Executable.current}/{Executable.total}]: {self.name}")
40
+ run_executable(executable_file=f"./{self.executable_file}")
41
+
42
+ # Status
43
+ self.runned = True
@@ -0,0 +1,70 @@
1
+ from cppmake.algorithm import recursive_find
2
+ from cppmake.config import system, type
3
+ from cppmake.error import BuildError
4
+ from cppmake.module import Module
5
+ from cppmake.package import Package
6
+ from cppmake.run import run
7
+ import os
8
+ import shutil
9
+
10
+ def include(name, dir=None, file=None):
11
+ if dir is not None:
12
+ shutil.copytree(dir, f"./bin/{type}/package/{name}/install/include", dirs_exist_ok=True)
13
+ if file is not None:
14
+ os.makedirs (f"./bin/{type}/package/{name}/install/include", exist_ok=True)
15
+ shutil.copyfile(file, f"./bin/{type}/package/{name}/install/include/{os.path.basename(file)}")
16
+ if dir is None and file is None:
17
+ raise BuildError("include() accepts at least 2 arguments")
18
+
19
+ def src(name, dir, src_to_include=None):
20
+ if src_to_include is None:
21
+ src_to_include = f"{name}/src"
22
+ shutil.copytree(dir, f"./bin/{type}/package/{name}/install/include/{src_to_include}", dirs_exist_ok=True)
23
+
24
+ def module(name, file, replace={}):
25
+ with open(file, 'r') as reader, open(f"./module/{name}.cpp", 'w') as writer:
26
+ content = reader.read()
27
+ content = content.replace("module;", "module;\n#undef in\n#undef self")
28
+ for old, new in replace.items():
29
+ content = content.replace(old, new)
30
+ writer.write(content)
31
+
32
+ def cmake(name, dir, args=[]):
33
+ run(f"cmake -S ./{dir} "
34
+ f" -B ./bin/{type}/package/{name}/build "
35
+ f' -DCMAKE_PREFIX_PATH="{';'.join(recursive_find(node=Module(name), func=lambda module: Package(module.name).install_dir if Package.exist(module.name) else None, root=True))}" '
36
+ f" -DCMAKE_INSTALL_PREFIX=./bin/{type}/package/{name}/install "
37
+ f" -DCMAKE_BUILD_TYPE={type} "
38
+ f"{' '.join(args)}")
39
+ run(f"cmake --build ./bin/{type}/package/{name}/build -j {os.cpu_count()}", quiet=True)
40
+ run(f"cmake --install ./bin/{type}/package/{name}/build -j {os.cpu_count()}")
41
+
42
+ def autogen(name, file, args=[]):
43
+ if not Package(name).is_configured:
44
+ run(f"./{file} {' '.join(args)}")
45
+
46
+ def configure(name, file, args=[]):
47
+ if not Package(name).is_configured:
48
+ cwd = f"./bin/{type}/package/{name}/build"
49
+ try:
50
+ os.makedirs(cwd, exist_ok=True)
51
+ run(f"./{os.path.relpath(file, cwd)} --prefix={os.path.abspath(f"./bin/{type}/package/{name}/install")} {' '.join(args)}", cwd=cwd)
52
+ except:
53
+ shutil.rmtree(cwd)
54
+ raise
55
+
56
+ def make(name, dir, args=[]):
57
+ if system == "linux" or system == "macos":
58
+ cwd = f"./bin/{type}/package/{name}/build"
59
+ run(f"make -j{os.cpu_count()} {' '.join(args)}", cwd=cwd, quiet=True)
60
+ run(f"make install -j{os.cpu_count()}", cwd=cwd, quiet=True)
61
+ else:
62
+ raise BuildError("make is only supported on linux and macos")
63
+
64
+ def nmake(name, dir, args=[]):
65
+ if system == "windows":
66
+ cwd = f"./bin/{type}/package/{name}/build"
67
+ run(f"nmake -j{os.cpu_count()} {' '.join(args)}", cwd=cwd, quiet=True)
68
+ run(f"nmake install -j{os.cpu_count()}", cwd=cwd, quiet=True)
69
+ else:
70
+ raise BuildError("nmake is only supported on windows")
@@ -0,0 +1,82 @@
1
+ from cppmake.algorithm import recursive_find
2
+ from cppmake.config import type, module_suffix, object_suffix
3
+ from cppmake.compiler import preprocess_file, compile_module
4
+ from cppmake.error import BuildError
5
+ from cppmake.package import Package
6
+ import os
7
+ import re
8
+
9
+ class Module:
10
+ pool = {}
11
+ current = 0
12
+ total = 0
13
+
14
+ def __new__(self, name, from_modules=[]):
15
+ if name in Module.pool.keys():
16
+ return Module.pool[name]
17
+ else:
18
+ self = super().__new__(self)
19
+ Module.pool[name] = self
20
+
21
+ # Info
22
+ self.name = name
23
+ self.code_file = f"./module/{self.name.replace('.', '/').replace(':', '/')}.cpp"
24
+ self.module_file = f"./bin/{type}/module/{self.name.replace('.', '.').replace(':', '-')}.{module_suffix}"
25
+ self.object_file = f"./bin/{type}/module/{self.name.replace('.', '.').replace(':', '-')}.{object_suffix}"
26
+ self.content = preprocess_file(code_file=self.code_file, name=self.name, module_file=self.module_file)
27
+
28
+ # Import
29
+ self.from_modules = from_modules
30
+ self.import_modules = []
31
+ import_names = re.findall(r'^\s*(?:export\s+)?import\s+([\w\.:]+)\s*;\s*$', self.content, flags=re.MULTILINE)
32
+ for import_name in import_names:
33
+ if import_name.startswith(':'):
34
+ import_name = f"{self.name.partition(':')[0]}{import_name}"
35
+ if import_name in self.from_modules:
36
+ raise BuildError(f"fatal error: module dependency circle {' -> '.join(module.name for module in self.from_modules + [self] + [Module(import_name)])}")
37
+ self.import_modules += [Module(name=import_name, from_modules=self.from_modules + [self])]
38
+
39
+ # Subtask
40
+ if Package.exist(self.name):
41
+ Package(self.name, by_module=self)
42
+
43
+ # Status
44
+ self.is_compiled = all(module.is_compiled for module in self.import_modules) and \
45
+ (not Package.exist(self.name) or Package(self.name).is_built) and \
46
+ os.path.isfile(self.module_file) and \
47
+ os.path.getmtime(self.code_file) <= os.path.getmtime(self.module_file)
48
+ if not self.is_compiled:
49
+ Module.total += 1
50
+
51
+ # Check
52
+ if self.module_file is not None:
53
+ export_names = re.findall(r'^\s*export\s+module\s+([\w\.:]+)\s*;\s*$', self.content, flags=re.MULTILINE)
54
+ if (len(export_names) != 1 or export_names[0] != self.name):
55
+ raise BuildError(f"fatal error: file {self.code_file} should export module {self.name}")
56
+
57
+ # Return
58
+ return self
59
+
60
+ def compile(self):
61
+ if not self.is_compiled:
62
+ # Import
63
+ for import_module in self.import_modules:
64
+ import_module.compile()
65
+
66
+ # Subtask
67
+ if Package.exist(self.name):
68
+ Package(self.name).build()
69
+
70
+ # Self
71
+ Module.current += 1
72
+ print(f"compile module [{Module.current}/{Module.total}]: {self.name}")
73
+ compile_module(code_file =self.code_file,
74
+ include_dirs=recursive_find(node=self, func=lambda module: Package(module.name).include_dir if Package.exist(module.name) else None, root=True),
75
+ module_file =self.module_file,
76
+ object_file =self.object_file)
77
+
78
+ # Status
79
+ self.is_compiled = True
80
+
81
+ def __eq__(self, str):
82
+ return self.name == str
@@ -0,0 +1,53 @@
1
+ from cppmake.algorithm import recursive_find
2
+ from cppmake.compiler import link_object
3
+ from cppmake.config import type, object_suffix, executable_suffix
4
+ from cppmake.package import Package
5
+ from cppmake.source import Source
6
+ import os
7
+
8
+ class Object:
9
+ pool = {}
10
+ current = 0
11
+ total = 0
12
+
13
+ def __new__(self, name):
14
+ if name in Object.pool.keys():
15
+ return Object.pool[name]
16
+ else:
17
+ self = super().__new__(self)
18
+ Object.pool[name] = self
19
+
20
+ # Info
21
+ self.name = name
22
+ self.object_file = f"./bin/{type}/src/{self.name.replace('.', '.').replace(':', '-')}.{object_suffix}"
23
+ self.executable_file = f"./bin/{type}/src/{self.name.replace('.', '.').replace(':', '-')}.{executable_suffix}" if executable_suffix != "" else \
24
+ f"./bin/{type}/src/{self.name.replace('.', '.').replace(':', '-')}"
25
+
26
+ # Subtask
27
+ Source(self.name)
28
+
29
+ # Status
30
+ self.is_linked = Source(self.name).is_compiled and \
31
+ os.path.isfile(self.object_file) and \
32
+ os.path.isfile(self.executable_file) and \
33
+ os.path.getmtime(self.object_file) <= os.path.getmtime(self.executable_file)
34
+ if not self.is_linked:
35
+ Object.total += 1
36
+
37
+ # Return
38
+ return self
39
+
40
+ def link(self):
41
+ if not self.is_linked:
42
+ # Subtask
43
+ Source(self.name).compile()
44
+
45
+ # Self
46
+ Object.current += 1
47
+ print(f"link object [{Object.current}/{Object.total}]: {self.name}")
48
+ link_object(object_files =recursive_find(node=Source(self.name), func=lambda source_or_module: source_or_module.object_file, root=True ),
49
+ library_files =recursive_find(node=Source(self.name), func=lambda module: Package(module.name).library_files if Package.exist(module.name) else None, root=False, flatten=True),
50
+ executable_file=self.executable_file)
51
+
52
+ # Status
53
+ self.is_linked = True
@@ -0,0 +1,74 @@
1
+ from cppmake.algorithm import recursive_find
2
+ from cppmake.config import type, library_suffix, shared_suffix
3
+ import os
4
+
5
+ class Package:
6
+ pool = {}
7
+ current = 0
8
+ total = 0
9
+
10
+ def __new__(self, name, by_module=None):
11
+ name = name.partition('.')[0]
12
+
13
+ if name in Package.pool.keys():
14
+ Package.pool[name].by_modules += [by_module] if by_module is not None else []
15
+ return Package.pool[name]
16
+ else:
17
+ self = super().__new__(self)
18
+ self.by_modules = [by_module] if by_module is not None else []
19
+ Package.pool[name] = self
20
+
21
+ # Info
22
+ self.name = name
23
+ self.package_file = f"./tool/package/{self.name.replace('.', '/').replace(':', '/')}.py"
24
+ self.install_dir = None
25
+ self.include_dir = None
26
+ self.library_files = None
27
+ self.update()
28
+
29
+ # Status
30
+ self.is_configured = os.path.isdir(f"./bin/{type}/package/{self.name}/build")
31
+ self.is_built = os.path.isdir(f"./bin/{type}/package/{self.name}/install")
32
+ self.is_installed = (not os.path.isdir(f"./bin/{type}/package/{self.name}/install/include") or os.path.getmtime(f"./bin/{type}/package/{self.name}/install/include") < os.path.getmtime("./include")) and \
33
+ (not os.path.isdir(f"./bin/{type}/package/{self.name}/install/lib" ) or os.path.getmtime(f"./bin/{type}/package/{self.name}/install/lib" ) < os.path.getmtime("./lib" ))
34
+ if not self.is_built:
35
+ Package.total += 1
36
+
37
+ # Check
38
+ assert Package.exist(self.name)
39
+
40
+ # Return
41
+ return self
42
+
43
+ def build(self, from_packages=[]):
44
+ if not self.is_built:
45
+ # Import
46
+ for by_module in self.by_modules:
47
+ for import_package in recursive_find(node=by_module, func=lambda module: Package(module.name) if Package.exist(module.name) else None):
48
+ if import_package not in from_packages and import_package is not self:
49
+ import_package.build(from_packages=from_packages + [self])
50
+
51
+ # Self
52
+ Package.current += 1
53
+ print(f"build package [{Package.current}/{Package.total}]: {self.name}")
54
+ exec(f"from package.{self.name} import *")
55
+ self.update()
56
+
57
+ # Status
58
+ self.is_built = True
59
+
60
+ def exist(name):
61
+ name = name.partition('.')[0]
62
+ return os.path.isfile(f"./tool/package/{name}.py")
63
+
64
+ def update(self):
65
+ self.install_dir = f"./bin/{type}/package/{self.name}/install" if os.path.isdir (f"./bin/{type}/package/{self.name}/install") else None
66
+ self.include_dir = f"./bin/{type}/package/{self.name}/install/include" if os.path.isdir (f"./bin/{type}/package/{self.name}/install/include") else None
67
+ self.library_files = [f"./bin/{type}/package/{self.name}/install/lib/{file}" \
68
+ for file in os.listdir (f"./bin/{type}/package/{self.name}/install/lib") \
69
+ if os.path.isfile(f"./bin/{type}/package/{self.name}/install/lib/{file}") and (file.endswith(f".{library_suffix}") or file.endswith(f".{shared_suffix}"))] \
70
+ if os.path.isdir (f"./bin/{type}/package/{self.name}/install/lib") else None
71
+
72
+ def __eq__(self, str):
73
+ return self.name == str
74
+
@@ -0,0 +1,23 @@
1
+ from cppmake.error import BuildError
2
+ from cppmake.config import verbose
3
+ import subprocess
4
+ import sys
5
+
6
+ def run(command, quiet=False, **kwargs):
7
+ if verbose:
8
+ print(command)
9
+ p = subprocess.Popen(command, shell=True, stdout=None if verbose >= 2 else subprocess.DEVNULL, stderr=subprocess.PIPE, text=True, **kwargs)
10
+ e = ""
11
+ while p.poll() is None:
12
+ e += p.stderr.readline()
13
+ if p.poll() == 0:
14
+ print(e, end="", file=sys.stderr)
15
+ else:
16
+ raise BuildError(e)
17
+ else:
18
+ try:
19
+ p = subprocess.run(command, shell=True, check=True, capture_output=True, text=True, **kwargs)
20
+ if not quiet:
21
+ print(p.stderr, end="", file=sys.stderr)
22
+ except subprocess.CalledProcessError as e:
23
+ raise BuildError(e.stderr)
@@ -0,0 +1,61 @@
1
+ from cppmake.algorithm import recursive_find
2
+ from cppmake.compiler import preprocess_file, compile_source
3
+ from cppmake.config import type, object_suffix
4
+ from cppmake.module import Module
5
+ from cppmake.package import Package
6
+ import os
7
+ import re
8
+
9
+ class Source:
10
+ pool = {}
11
+ current = 0
12
+ total = 0
13
+
14
+ def __new__(self, name):
15
+ if name in Source.pool.keys():
16
+ return Source.pool[name]
17
+ else:
18
+ self = super().__new__(self)
19
+ Source.pool[name] = self
20
+
21
+ # Info
22
+ self.name = name
23
+ self.code_file = f"./src/{self.name.replace('.', '/').replace(':', '/')}.cpp"
24
+ self.object_file = f"./bin/{type}/src/{self.name.replace('.', '.').replace(':', '-')}.{object_suffix}"
25
+ self.content = preprocess_file(code_file=self.code_file)
26
+
27
+ # Import
28
+ self.import_modules = []
29
+ import_names = re.findall(r'^\s*import\s+([\w\.:]+)\s*;\s*$', self.content, flags=re.MULTILINE)
30
+ for import_name in import_names:
31
+ self.import_modules += [Module(name=import_name)]
32
+
33
+ # Status
34
+ self.is_compiled = all(module.is_compiled for module in self.import_modules) and \
35
+ os.path.isfile(self.object_file) and \
36
+ os.path.getmtime(self.code_file) <= os.path.getmtime(self.object_file)
37
+ if not self.is_compiled:
38
+ Source.total += 1
39
+
40
+ # Return
41
+ return self
42
+
43
+ def compile(self):
44
+ if not self.is_compiled:
45
+ # Import
46
+ for import_module in self.import_modules:
47
+ import_module.compile()
48
+
49
+ # Self
50
+ Source.current += 1
51
+ print(f"compile source [{Source.current}/{Source.total}]: {self.name}")
52
+ compile_source(code_file =self.code_file,
53
+ include_dirs=recursive_find(node=self, func=lambda module: Package(module.name).include_dir if Package.exist(module.name) else None, root=False),
54
+ object_file =self.object_file)
55
+
56
+ # Status
57
+ self.is_compiled = True
58
+
59
+ def __eq__(self, str):
60
+ return self.name == str
61
+
@@ -0,0 +1,34 @@
1
+ from cppmake.error import BuildError
2
+ from cppmake.executable import Executable
3
+ from cppmake.module import Module
4
+ from cppmake.object import Object
5
+ from cppmake.package import Package
6
+ from cppmake.source import Source
7
+ import os
8
+ import sys
9
+
10
+ if __name__ == "__main__":
11
+ open(".log", 'w')
12
+
13
+ try:
14
+ for root, _, files in os.walk("./src/test"):
15
+ for file in files:
16
+ Executable(f"{root.replace('/', '.').lstrip('.')}.{file.removesuffix(".cpp")}")
17
+ for package in Package.pool.values():
18
+ package.build()
19
+ for module in Module.pool.values():
20
+ module.compile()
21
+ for source in Source.pool.values():
22
+ source.compile()
23
+ for object in Object.pool.values():
24
+ object.link()
25
+ for executable in Executable.pool.values():
26
+ executable.run()
27
+
28
+ except BuildError as e:
29
+ print(e, end="", file=sys.stderr)
30
+ print(e, end="", file=open(".log", 'a'))
31
+ exit(-1)
32
+
33
+ except KeyboardInterrupt as e:
34
+ exit(-1)
@@ -0,0 +1,50 @@
1
+ import matplotlib.pyplot as plt
2
+ import networkx as nx
3
+ from cppmake.source import *
4
+
5
+ if __name__ == "__main__":
6
+ G = nx.DiGraph()
7
+
8
+ def _get_name(module):
9
+ if hasattr(module, "name"):
10
+ return module.name
11
+ elif hasattr(module, "name"):
12
+ return module.name
13
+
14
+ def _summon_graph(module):
15
+ G.add_node(_get_name(module))
16
+ for import_module in module.import_modules:
17
+ G.add_node(_get_name(import_module))
18
+ G.add_edge(_get_name(module), _get_name(import_module))
19
+ _summon_graph(import_module)
20
+
21
+ def _get_rgb(rank, total):
22
+ k = rank / (total - 1)
23
+ if 0.00 <= k <= 0.25:
24
+ r = 1
25
+ g = 4 * (k - 0.0)
26
+ b = 0
27
+ elif 0.25 <= k <= 0.50:
28
+ r = 1 - 4 * (k - 0.25)
29
+ g = 1
30
+ b = 0
31
+ elif 0.50 <= k <= 0.75:
32
+ r = 0
33
+ g = 1
34
+ b = 4 * (k - 0.50)
35
+ elif 0.75 <= k <= 1.00:
36
+ r = 0
37
+ g = 1 - 4 * (k - 0.75)
38
+ b = 1
39
+ return r, g, b
40
+
41
+ _summon_graph(Source("main"))
42
+ node_pos = nx.spring_layout(G, k=12.5/(len(G.nodes)**0.5), iterations=100, scale=1.0)
43
+ label_pos = {k: (v[0], v[1] + 0.05) for k, v in node_pos.items()}
44
+ ancest_dict = {node: len(nx.ancestors(G, node)) for node in G.nodes}
45
+ ancest_seq = list(reversed(sorted(list(set(ancest_dict.values())))))
46
+ rank_dict = {node: ancest_seq.index(ancest_dict[node]) for node in G.nodes}
47
+ node_color = [_get_rgb(rank=rank_dict[node], total=len(ancest_seq)) for node in G.nodes]
48
+ nx.draw (G, pos=node_pos, node_size=1000/(len(G.nodes)**0.5), node_shape='.', edge_color="#B0B0B0", width=0.5, with_labels=False, node_color=node_color)
49
+ nx.draw_networkx_labels(G, pos=label_pos, font_size= 60/(len(G.nodes)**0.5), font_weight="bold")
50
+ plt.show()
@@ -1,9 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cppmake
3
- Version: 0.0.1
3
+ Version: 0.0.2
4
4
  Summary: none
5
- Home-page: https://github.com/anonymouspc/cppmake
6
- Author: {'name': 'anonymouspc', 'email': 'shyeyian@petalmail.com'}
7
5
  Author-email: anonymouspc <shyeyian@petalmail.com>
8
6
  License-Expression: MIT
9
7
  Project-URL: Homepage, https://github.com/anonymouspc/cppmake
@@ -11,6 +9,4 @@ Classifier: Programming Language :: Python :: 3
11
9
  Requires-Python: >=3.13
12
10
  Description-Content-Type: text/markdown
13
11
  License-File: license.txt
14
- Dynamic: author
15
- Dynamic: home-page
16
12
  Dynamic: license-file
@@ -0,0 +1,22 @@
1
+ license.txt
2
+ pyproject.toml
3
+ readme.md
4
+ cppmake/build.py
5
+ cppmake/clean.py
6
+ cppmake/test.py
7
+ cppmake/tree.py
8
+ cppmake.egg-info/PKG-INFO
9
+ cppmake.egg-info/SOURCES.txt
10
+ cppmake.egg-info/dependency_links.txt
11
+ cppmake.egg-info/top_level.txt
12
+ cppmake/cppmake/algorithm.py
13
+ cppmake/cppmake/compiler.py
14
+ cppmake/cppmake/config.py
15
+ cppmake/cppmake/error.py
16
+ cppmake/cppmake/executable.py
17
+ cppmake/cppmake/make.py
18
+ cppmake/cppmake/module.py
19
+ cppmake/cppmake/object.py
20
+ cppmake/cppmake/package.py
21
+ cppmake/cppmake/run.py
22
+ cppmake/cppmake/source.py
@@ -0,0 +1 @@
1
+ cppmake
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "cppmake"
7
- version = "0.0.1"
7
+ version = "0.0.2"
8
8
  authors = [{name = "anonymouspc", email = "shyeyian@petalmail.com"}]
9
9
  description = "none"
10
10
  readme = "readme.md"
@@ -1,8 +0,0 @@
1
- license.txt
2
- pyproject.toml
3
- readme.md
4
- setup.py
5
- cppmake.egg-info/PKG-INFO
6
- cppmake.egg-info/SOURCES.txt
7
- cppmake.egg-info/dependency_links.txt
8
- cppmake.egg-info/top_level.txt
@@ -1 +0,0 @@
1
-
cppmake-0.0.1/setup.py DELETED
@@ -1,20 +0,0 @@
1
- from setuptools import setup, find_packages
2
- from time import time
3
-
4
- setup(
5
- name="cppmake",
6
- version=f"{time()}",
7
- packages=find_packages(include=["cppmake", "cppmake.*"]),
8
- install_requires=[],
9
- entry_points={
10
- "console_scripts": [
11
- "cppmake=cppmake.build:main",
12
- ],
13
- },
14
- author={
15
- "name": "anonymouspc",
16
- "email": "shyeyian@petalmail.com"
17
- },
18
- url="https://github.com/anonymouspc/cppmake",
19
- license=""
20
- )
File without changes
File without changes
File without changes