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.
- {cppmake-0.0.1 → cppmake-0.0.2}/PKG-INFO +1 -5
- cppmake-0.0.2/cppmake/build.py +29 -0
- cppmake-0.0.2/cppmake/clean.py +6 -0
- cppmake-0.0.2/cppmake/cppmake/algorithm.py +19 -0
- cppmake-0.0.2/cppmake/cppmake/compiler.py +106 -0
- cppmake-0.0.2/cppmake/cppmake/config.py +94 -0
- cppmake-0.0.2/cppmake/cppmake/error.py +2 -0
- cppmake-0.0.2/cppmake/cppmake/executable.py +43 -0
- cppmake-0.0.2/cppmake/cppmake/make.py +70 -0
- cppmake-0.0.2/cppmake/cppmake/module.py +82 -0
- cppmake-0.0.2/cppmake/cppmake/object.py +53 -0
- cppmake-0.0.2/cppmake/cppmake/package.py +74 -0
- cppmake-0.0.2/cppmake/cppmake/run.py +23 -0
- cppmake-0.0.2/cppmake/cppmake/source.py +61 -0
- cppmake-0.0.2/cppmake/test.py +34 -0
- cppmake-0.0.2/cppmake/tree.py +50 -0
- {cppmake-0.0.1 → cppmake-0.0.2}/cppmake.egg-info/PKG-INFO +1 -5
- cppmake-0.0.2/cppmake.egg-info/SOURCES.txt +22 -0
- cppmake-0.0.2/cppmake.egg-info/top_level.txt +1 -0
- {cppmake-0.0.1 → cppmake-0.0.2}/pyproject.toml +1 -1
- cppmake-0.0.1/cppmake.egg-info/SOURCES.txt +0 -8
- cppmake-0.0.1/cppmake.egg-info/top_level.txt +0 -1
- cppmake-0.0.1/setup.py +0 -20
- {cppmake-0.0.1 → cppmake-0.0.2}/cppmake.egg-info/dependency_links.txt +0 -0
- {cppmake-0.0.1 → cppmake-0.0.2}/license.txt +0 -0
- {cppmake-0.0.1 → cppmake-0.0.2}/readme.md +0 -0
- {cppmake-0.0.1 → cppmake-0.0.2}/setup.cfg +0 -0
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cppmake
|
|
3
|
-
Version: 0.0.
|
|
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,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,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.
|
|
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
|
|
@@ -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
|
|
File without changes
|