cppmake 127.0.14__py3-none-any.whl → 127.0.17__py3-none-any.whl
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-127.0.17.dist-info/METADATA +191 -0
- cppmake-127.0.17.dist-info/RECORD +55 -0
- {cppmake-127.0.14.dist-info → cppmake-127.0.17.dist-info}/WHEEL +1 -1
- cppmake-127.0.17.dist-info/entry_points.txt +3 -0
- cppmake-127.0.17.dist-info/top_level.txt +3 -0
- cppmaked.py +2 -0
- cppmakelib/__init__.py +32 -0
- cppmakelib/basic/config.py +50 -0
- cppmakelib/basic/context.py +39 -0
- cppmakelib/builder/cmake.py +71 -0
- cppmakelib/builder/include.py +15 -0
- cppmakelib/builder/makefile.py +68 -0
- cppmakelib/compiler/all.py +26 -0
- cppmakelib/compiler/clang.py +196 -0
- cppmakelib/compiler/emcc.py +79 -0
- cppmakelib/compiler/gcc.py +237 -0
- cppmakelib/compiler/msvc.py +24 -0
- cppmakelib/error/config.py +5 -0
- cppmakelib/error/logic.py +6 -0
- cppmakelib/error/subprocess.py +9 -0
- cppmakelib/executor/operation.py +15 -0
- cppmakelib/executor/run.py +84 -0
- cppmakelib/executor/scheduler.py +91 -0
- cppmakelib/logger/compile_commands.py +30 -0
- cppmakelib/logger/make_progress.py +0 -0
- cppmakelib/logger/module_mapper.py +6 -0
- cppmakelib/logger/unit_status.py +224 -0
- cppmakelib/system/all.py +25 -0
- cppmakelib/system/linux.py +26 -0
- cppmakelib/system/macos.py +26 -0
- cppmakelib/system/windows.py +26 -0
- cppmakelib/unit/binary.py +26 -0
- cppmakelib/unit/code.py +62 -0
- cppmakelib/unit/dynamic.py +12 -0
- cppmakelib/unit/executable.py +35 -0
- cppmakelib/unit/header.py +63 -0
- cppmakelib/unit/module.py +69 -0
- cppmakelib/unit/object.py +71 -0
- cppmakelib/unit/package.py +87 -0
- cppmakelib/unit/precompiled.py +6 -0
- cppmakelib/unit/preparsed.py +6 -0
- cppmakelib/unit/preprocessed.py +3 -0
- cppmakelib/unit/source.py +64 -0
- cppmakelib/utility/algorithm.py +44 -0
- cppmakelib/utility/color.py +14 -0
- cppmakelib/utility/decorator.py +120 -0
- cppmakelib/utility/filesystem.py +71 -0
- cppmakelib/utility/import_.py +21 -0
- cppmakelib/utility/remote/client.py +2 -0
- cppmakelib/utility/remote/protocol.py +32 -0
- cppmakelib/utility/remote/remote.py +43 -0
- cppmakelib/utility/remote/server.py +0 -0
- cppmakelib/utility/time.py +1 -0
- cppmakelib/utility/version.py +65 -0
- cppmake-127.0.14.dist-info/METADATA +0 -9
- cppmake-127.0.14.dist-info/RECORD +0 -6
- cppmake-127.0.14.dist-info/entry_points.txt +0 -2
- cppmake-127.0.14.dist-info/top_level.txt +0 -1
- /cppmake/__main__.py → /cppmake.py +0 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
from cppmakelib.basic.config import config
|
|
2
|
+
from cppmakelib.utility.decorator import member
|
|
3
|
+
import asyncio
|
|
4
|
+
import typing
|
|
5
|
+
|
|
6
|
+
class Scheduler:
|
|
7
|
+
def __init__(self, value: int = config.parallel) -> None : ...
|
|
8
|
+
def schedule(self, value: int = 1) -> typing.AsyncContextManager[None]: ...
|
|
9
|
+
max: int
|
|
10
|
+
|
|
11
|
+
class _ContextManager:
|
|
12
|
+
def __init__ (self, scheduler: Scheduler, value: int) -> None: ...
|
|
13
|
+
async def __aenter__(self) -> None: ...
|
|
14
|
+
async def __aexit__ (self, *args: typing.Any, **kwargs: typing.Any) -> None: ...
|
|
15
|
+
_scheduler: Scheduler
|
|
16
|
+
_value : int
|
|
17
|
+
class _NotifyFailedError(RuntimeError):
|
|
18
|
+
pass
|
|
19
|
+
async def _acquire (self, value: int = 1) -> None: ...
|
|
20
|
+
def _release (self, value: int = 1) -> None: ...
|
|
21
|
+
def _notify_one(self) -> None: ...
|
|
22
|
+
_value : int
|
|
23
|
+
_waiters: dict[asyncio.Future[None], int]
|
|
24
|
+
|
|
25
|
+
scheduler: Scheduler
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@member(Scheduler)
|
|
30
|
+
def __init__(self: Scheduler, value: int = config.parallel) -> None:
|
|
31
|
+
assert value >= 0
|
|
32
|
+
self.max = value
|
|
33
|
+
self._value = value
|
|
34
|
+
self._waiters = {}
|
|
35
|
+
|
|
36
|
+
@member(Scheduler)
|
|
37
|
+
def schedule(self: Scheduler, value: int = 1) -> typing.AsyncContextManager[None]:
|
|
38
|
+
return Scheduler._ContextManager(self, value)
|
|
39
|
+
|
|
40
|
+
@member(Scheduler._ContextManager)
|
|
41
|
+
def __init__(self: Scheduler._ContextManager, scheduler: Scheduler, value: int):
|
|
42
|
+
self._scheduler = scheduler
|
|
43
|
+
self._value = value
|
|
44
|
+
|
|
45
|
+
@member(Scheduler._ContextManager)
|
|
46
|
+
async def __aenter__(self: Scheduler._ContextManager) -> None:
|
|
47
|
+
return await self._scheduler._acquire(self._value)
|
|
48
|
+
|
|
49
|
+
@member(Scheduler._ContextManager)
|
|
50
|
+
async def __aexit__(self: Scheduler._ContextManager, *args: typing.Any, **kwargs: typing.Any) -> None:
|
|
51
|
+
self._scheduler._release(self._value)
|
|
52
|
+
|
|
53
|
+
@member(Scheduler)
|
|
54
|
+
async def _acquire(self: Scheduler, value: int = 1) -> None:
|
|
55
|
+
if self._value >= value and all(not waiter.cancelled() for waiter in self._waiters.keys()):
|
|
56
|
+
self._value -= value
|
|
57
|
+
return
|
|
58
|
+
future = asyncio.get_event_loop().create_future()
|
|
59
|
+
self._waiters[future] = value
|
|
60
|
+
try:
|
|
61
|
+
try:
|
|
62
|
+
await future
|
|
63
|
+
finally:
|
|
64
|
+
self._waiters.pop(future)
|
|
65
|
+
except asyncio.CancelledError:
|
|
66
|
+
if future.done() and not future.cancelled():
|
|
67
|
+
self._value += value
|
|
68
|
+
raise
|
|
69
|
+
finally:
|
|
70
|
+
while self._value > 0:
|
|
71
|
+
try:
|
|
72
|
+
self._notify_one()
|
|
73
|
+
except Scheduler._NotifyFailedError:
|
|
74
|
+
break
|
|
75
|
+
return
|
|
76
|
+
|
|
77
|
+
@member(Scheduler)
|
|
78
|
+
def _release(self: Scheduler, value: int = 1) -> None:
|
|
79
|
+
self._value += value
|
|
80
|
+
self._notify_one()
|
|
81
|
+
|
|
82
|
+
@member(Scheduler)
|
|
83
|
+
def _notify_one(self: Scheduler) -> None:
|
|
84
|
+
for future in self._waiters.keys():
|
|
85
|
+
if not future.done() and self._value >= self._waiters[future]:
|
|
86
|
+
self._value -= self._waiters[future]
|
|
87
|
+
future.set_result(None)
|
|
88
|
+
return
|
|
89
|
+
raise Scheduler._NotifyFailedError('no waiters notified')
|
|
90
|
+
|
|
91
|
+
scheduler = Scheduler()
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from cppmakelib.utility.filesystemimport absolute_path, parent_path, create_dir
|
|
2
|
+
from cppmakelib.utility.decorator import member
|
|
3
|
+
import json
|
|
4
|
+
|
|
5
|
+
class CompileCommandsLogger:
|
|
6
|
+
def __init__(self):
|
|
7
|
+
self.file = 'binary/.cache/compile_commands.json'
|
|
8
|
+
try:
|
|
9
|
+
self._content = json.load(open(self.file, 'r'))
|
|
10
|
+
except:
|
|
11
|
+
self._content = []
|
|
12
|
+
|
|
13
|
+
def __del__(self):
|
|
14
|
+
if len(self._content) > 0:
|
|
15
|
+
create_dir(parent_path(self.file))
|
|
16
|
+
json.dump(self._content, open(self.file, 'w'), indent=4)
|
|
17
|
+
|
|
18
|
+
def log_command(self, command, file):
|
|
19
|
+
for entry in self._content:
|
|
20
|
+
if entry['file'] == file:
|
|
21
|
+
self._content.remove(entry)
|
|
22
|
+
self._content.append({
|
|
23
|
+
'directory': absolute_path('.'),
|
|
24
|
+
'file' : file,
|
|
25
|
+
'command' : ' '.join(command)
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
compile_commands_logger = CompileCommandsLogger()
|
|
File without changes
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
from cppmakelib.compiler.all import compiler
|
|
2
|
+
from cppmakelib.error.logic import LogicError
|
|
3
|
+
from cppmakelib.executor.operation import when_all
|
|
4
|
+
from cppmakelib.unit.code import Code
|
|
5
|
+
from cppmakelib.unit.module import Module
|
|
6
|
+
from cppmakelib.unit.object import Object
|
|
7
|
+
from cppmakelib.unit.source import Source
|
|
8
|
+
from cppmakelib.utility.filesystem import path
|
|
9
|
+
from cppmakelib.utility.decorator import member
|
|
10
|
+
import json
|
|
11
|
+
import re
|
|
12
|
+
import typing
|
|
13
|
+
|
|
14
|
+
class UnitStatusLogger:
|
|
15
|
+
# ========
|
|
16
|
+
def __init__ (self, build_cache_dir: path) -> None : ...
|
|
17
|
+
def __del__ (self) -> None : ...
|
|
18
|
+
# ========
|
|
19
|
+
def get_code_preprocessed (self, code : Code) -> bool : ...
|
|
20
|
+
def set_code_preprocessed (self, code : Code, preprocessed: bool) -> None : ...
|
|
21
|
+
# ========
|
|
22
|
+
async def async_get_module_name (self, module: Module) -> str : ...
|
|
23
|
+
def set_module_name (self, module: Module, name : str) -> None : ...
|
|
24
|
+
async def async_get_module_imports (self, module: Module) -> list[path]: ...
|
|
25
|
+
async def async_set_module_imports (self, module: Module, imports : list[path]) -> None : ...
|
|
26
|
+
def get_module_precompiled(self, module: Module) -> bool : ...
|
|
27
|
+
def set_module_precompiled(self, module: Module, precompiled : bool) -> None : ...
|
|
28
|
+
# ========
|
|
29
|
+
async def async_get_source_imports (self, source: Source) -> list[path]: ...
|
|
30
|
+
async def async_set_source_imports (self, source: Source, imports : list[path]) -> None : ...
|
|
31
|
+
def get_source_compiled (self, source: Source) -> bool : ...
|
|
32
|
+
def set_source_compiled (self, source: Source, compiled : bool) -> None : ...
|
|
33
|
+
# ========
|
|
34
|
+
def get_object_libs (self, object: Object) -> list[path]: ...
|
|
35
|
+
def set_object_libs (self, object: Object, libs : list[path]) -> None : ...
|
|
36
|
+
def get_object_shared (self, object: Object) -> bool : ...
|
|
37
|
+
def set_object_shared (self, object: Object, shared : bool) -> None : ...
|
|
38
|
+
def get_object_linked (self, object: Object) -> bool : ...
|
|
39
|
+
def set_object_linked (self, object: Object, linked : bool) -> None : ...
|
|
40
|
+
# ========
|
|
41
|
+
|
|
42
|
+
class _StatusNotFoundError(KeyError):
|
|
43
|
+
pass
|
|
44
|
+
def _get (self, entry: list[str], check: dict[str, typing.Any], result: str) -> typing.Any : ...
|
|
45
|
+
def _set (self, entry: list[str], check: dict[str, typing.Any], result: dict[str, typing.Any]) -> None : ...
|
|
46
|
+
def _reflect(self, object: object) -> dict[str, typing.Any]: ...
|
|
47
|
+
_content : typing.Any
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@member(UnitStatusLogger)
|
|
52
|
+
def __init__(self: UnitStatusLogger, build_cache_dir: path) -> None:
|
|
53
|
+
try:
|
|
54
|
+
self._content = json.load(open(f'{build_cache_dir}/unit_status.json', 'r'))
|
|
55
|
+
except:
|
|
56
|
+
self._content = {}
|
|
57
|
+
|
|
58
|
+
@member(UnitStatusLogger)
|
|
59
|
+
def get_code_preprocessed(self: UnitStatusLogger, code: Code) -> bool:
|
|
60
|
+
try:
|
|
61
|
+
return self._get(entry=['code', 'preprocessed', code.file], check={'code': code, 'compiler': compiler}, result='preprocessed')
|
|
62
|
+
except UnitStatusLogger._StatusNotFoundError:
|
|
63
|
+
return False
|
|
64
|
+
|
|
65
|
+
@member(UnitStatusLogger)
|
|
66
|
+
def set_code_preprocessed(self: UnitStatusLogger, code: Code, preprocessed: bool) -> None:
|
|
67
|
+
self._set(entry=['code', 'preprocessed', code.file], check={'code': code, 'compiler': compiler}, result={'preprocessed': preprocessed})
|
|
68
|
+
|
|
69
|
+
@member(UnitStatusLogger)
|
|
70
|
+
async def async_get_module_name(self: UnitStatusLogger, module: Module) -> str:
|
|
71
|
+
try:
|
|
72
|
+
name = self._get(entry=['module', 'name', module.file], check={'module': module, 'compiler': compiler}, result='name')
|
|
73
|
+
except UnitStatusLogger._StatusNotFoundError:
|
|
74
|
+
await module.async_preprocess()
|
|
75
|
+
statements = re.findall(
|
|
76
|
+
pattern=r'^\s*(export\s+)?module\s+(\w+([\.:]\w+)*)\s*;\s*$',
|
|
77
|
+
string =open(module.preprocessed_file).read(),
|
|
78
|
+
flags =re.MULTILINE
|
|
79
|
+
)
|
|
80
|
+
if len(statements) == 0:
|
|
81
|
+
raise LogicError(f'module {module.file} does not have a export statement')
|
|
82
|
+
elif len(statements) == 1:
|
|
83
|
+
name = statements[0].group(2)
|
|
84
|
+
self.set_module_name(module=module, name=name)
|
|
85
|
+
else: # len(exports) >= 2:
|
|
86
|
+
raise LogicError(f'module {module.file} has multiple export statements (with statements = {statements})')
|
|
87
|
+
return name
|
|
88
|
+
|
|
89
|
+
@member(UnitStatusLogger)
|
|
90
|
+
def set_module_name(self: UnitStatusLogger, module: Module, name: str) -> None:
|
|
91
|
+
self._set(entry=['module', 'name', module.file], check={'module': module, 'compiler': compiler}, result={'name': name})
|
|
92
|
+
|
|
93
|
+
@member(UnitStatusLogger)
|
|
94
|
+
async def async_get_module_imports(self: UnitStatusLogger, module: Module) -> list[path]:
|
|
95
|
+
try:
|
|
96
|
+
imports = self._get(entry=['module', 'imports', module.file], check={'module': module, 'compiler': compiler}, result='imports')
|
|
97
|
+
except UnitStatusLogger._StatusNotFoundError:
|
|
98
|
+
await module.async_preprocess()
|
|
99
|
+
statements = re.findall(
|
|
100
|
+
pattern=r'^\s*import\s+module\s+(\w+([\.:]\w+)*)\s*;\s$',
|
|
101
|
+
string =open(module.preprocessed_file, 'r').read(),
|
|
102
|
+
flags =re.MULTILINE
|
|
103
|
+
)
|
|
104
|
+
imports = [f'{module.context_package.search_module_dir}/{statement.group(1).replace('.', '/').replace(':', '/')}' for statement in statements]
|
|
105
|
+
await self.async_set_module_imports(module=module, imports=imports)
|
|
106
|
+
return imports
|
|
107
|
+
|
|
108
|
+
@member(UnitStatusLogger)
|
|
109
|
+
async def async_set_module_imports(self: UnitStatusLogger, module: Module, imports: list[path]) -> None:
|
|
110
|
+
self._set(entry=['module', 'imports', module.file], check={'module': module, 'compiler': compiler}, result={'imports': imports})
|
|
111
|
+
self._set(entry=['object', 'libs', module.object_file], check={'object': Object(module.object_file), 'compiler': compiler}, result={'libs' : [module.object_file for module in await when_all([Module.__anew__(Module, import_) for import_ in imports])]})
|
|
112
|
+
|
|
113
|
+
@member(UnitStatusLogger)
|
|
114
|
+
def get_module_precompiled(self: UnitStatusLogger, module: Module) -> bool:
|
|
115
|
+
try:
|
|
116
|
+
return self._get(entry=['module', 'precompiled', module.file], check={'module': module, 'compiler': compiler}, result='precompiled')
|
|
117
|
+
except UnitStatusLogger._StatusNotFoundError:
|
|
118
|
+
return False
|
|
119
|
+
|
|
120
|
+
@member(UnitStatusLogger)
|
|
121
|
+
def set_module_precompiled(self: UnitStatusLogger, module: Module, precompiled: bool) -> None:
|
|
122
|
+
self._set(entry=['module', 'precompiled', module.file], check={'module': module, 'compiler': compiler}, result={'precompiled': precompiled})
|
|
123
|
+
|
|
124
|
+
@member(UnitStatusLogger)
|
|
125
|
+
async def async_get_source_imports(self: UnitStatusLogger, source: Source) -> list[path]:
|
|
126
|
+
try:
|
|
127
|
+
imports = self._get(entry=['source', 'imports', source.file], check={'source': source, 'compiler': compiler}, result='imports')
|
|
128
|
+
except UnitStatusLogger._StatusNotFoundError:
|
|
129
|
+
await source.async_preprocess()
|
|
130
|
+
statements = re.findall(
|
|
131
|
+
pattern=r'^\s*import\s+module\s+(\w+([\.:]\w+)*)\s*;\s$',
|
|
132
|
+
string =open(source.preprocessed_file, 'r').read(),
|
|
133
|
+
flags =re.MULTILINE
|
|
134
|
+
)
|
|
135
|
+
imports = [f'{source.context_package.search_module_dir}/{statement.group(1).replace('.', '/').replace(':', '/')}' for statement in statements]
|
|
136
|
+
await self.async_set_source_imports(source=source, imports=imports)
|
|
137
|
+
return imports
|
|
138
|
+
|
|
139
|
+
@member(UnitStatusLogger)
|
|
140
|
+
async def async_set_source_imports(self: UnitStatusLogger, source: Source, imports: list[path]) -> None:
|
|
141
|
+
self._set(entry=['source', 'imports', source.file], check={'source': source, 'compiler': compiler}, result={'imports': imports})
|
|
142
|
+
self._set(entry=['object', 'libs', source.object_file], check={'object': Object(source.object_file), 'compiler': compiler}, result={'libs' : [module.object_file for module in await when_all([Module.__anew__(Module, import_) for import_ in imports])]})
|
|
143
|
+
|
|
144
|
+
@member(UnitStatusLogger)
|
|
145
|
+
def get_source_compiled(self: UnitStatusLogger, source: Source) -> bool:
|
|
146
|
+
try:
|
|
147
|
+
return self._get(entry=['source', 'compiled', source.file], check={'source': source, 'compiler': compiler}, result='compiled')
|
|
148
|
+
except UnitStatusLogger._StatusNotFoundError:
|
|
149
|
+
return False
|
|
150
|
+
|
|
151
|
+
@member(UnitStatusLogger)
|
|
152
|
+
def set_source_compiled(self: UnitStatusLogger, source: Source, compiled: bool) -> None:
|
|
153
|
+
self._set(entry=['source', 'compiled', source.file], check={'source': source, 'compiler': compiler}, result={'compiled': compiled})
|
|
154
|
+
|
|
155
|
+
@member(UnitStatusLogger)
|
|
156
|
+
def get_object_libs(self: UnitStatusLogger, object: Object) -> list[path]:
|
|
157
|
+
try:
|
|
158
|
+
return self._get(entry=['object', 'libs', object.file], check={'object': object, 'compiler': compiler}, result='libs')
|
|
159
|
+
except UnitStatusLogger._StatusNotFoundError:
|
|
160
|
+
raise LogicError(f'object does not have a libs cache (from a module or source)')
|
|
161
|
+
|
|
162
|
+
@member(UnitStatusLogger)
|
|
163
|
+
def set_object_libs(self: UnitStatusLogger, object: Object, libs: list[path]) -> None:
|
|
164
|
+
self._set(entry=['object', 'libs', object.file], check={'object': object, 'compiler': compiler}, result={'libs': libs})
|
|
165
|
+
|
|
166
|
+
@member(UnitStatusLogger)
|
|
167
|
+
def get_object_shared(self: UnitStatusLogger, object: Object) -> bool:
|
|
168
|
+
try:
|
|
169
|
+
return self._get(entry=['object', 'shared', object.file], check={'object': object, 'compiler': compiler}, result='shared')
|
|
170
|
+
except UnitStatusLogger._StatusNotFoundError:
|
|
171
|
+
return False
|
|
172
|
+
|
|
173
|
+
@member(UnitStatusLogger)
|
|
174
|
+
def set_object_shared(self: UnitStatusLogger, object: Object, shared: bool) -> None:
|
|
175
|
+
self._set(entry=['object', 'shared', object.file], check={'object': object, 'compiler': compiler}, result={'shared': shared})
|
|
176
|
+
|
|
177
|
+
@member(UnitStatusLogger)
|
|
178
|
+
def get_object_linked(self: UnitStatusLogger, object: Object) -> bool:
|
|
179
|
+
try:
|
|
180
|
+
return self._get(entry=['object', 'linked', object.file], check={'object': object, 'compiler': compiler}, result='linked')
|
|
181
|
+
except UnitStatusLogger._StatusNotFoundError:
|
|
182
|
+
return False
|
|
183
|
+
|
|
184
|
+
@member(UnitStatusLogger)
|
|
185
|
+
def set_object_linked(self: UnitStatusLogger, object: Object, linked: bool) -> None:
|
|
186
|
+
self._set(entry=['object', 'linked', object.file], check={'object': object, 'compiler': compiler}, result={'linked': linked})
|
|
187
|
+
|
|
188
|
+
@member(UnitStatusLogger)
|
|
189
|
+
def _get(self: UnitStatusLogger, entry: list[str], check: dict[str, typing.Any], result: str) -> typing.Any | typing.Literal[False]:
|
|
190
|
+
ptr = self._content
|
|
191
|
+
for subentry in entry:
|
|
192
|
+
if subentry not in ptr.keys():
|
|
193
|
+
raise UnitStatusLogger._StatusNotFoundError()
|
|
194
|
+
ptr = ptr[subentry]
|
|
195
|
+
for subcheck in check.keys():
|
|
196
|
+
if ptr[subcheck] != self._reflect(ptr[subcheck]):
|
|
197
|
+
raise UnitStatusLogger._StatusNotFoundError()
|
|
198
|
+
return ptr[result]
|
|
199
|
+
|
|
200
|
+
@member(UnitStatusLogger)
|
|
201
|
+
def _set(self: UnitStatusLogger, entry: list[str], check: dict[str, typing.Any], result: dict[str, typing.Any]) -> None:
|
|
202
|
+
ptr = self._content
|
|
203
|
+
for subentry in entry:
|
|
204
|
+
if subentry not in ptr.keys():
|
|
205
|
+
ptr[subentry] = {}
|
|
206
|
+
ptr = ptr[subentry]
|
|
207
|
+
for subcheck in check.keys():
|
|
208
|
+
ptr[subcheck] = self._reflect(check[subcheck])
|
|
209
|
+
for subresult in result.keys():
|
|
210
|
+
ptr[subresult] = self._reflect(result[subresult])
|
|
211
|
+
|
|
212
|
+
@member(UnitStatusLogger)
|
|
213
|
+
def _reflect(self: UnitStatusLogger, object: object) -> dict[str, typing.Any]:
|
|
214
|
+
reflected = vars(object)
|
|
215
|
+
for key, value in reflected.items():
|
|
216
|
+
if hasattr(value, '__dict__'):
|
|
217
|
+
reflected[key] = '...'
|
|
218
|
+
elif isinstance(value, list):
|
|
219
|
+
for index, subvalue in enumerate(typing.cast(list[object], value)):
|
|
220
|
+
value[index] = self._reflect(subvalue)
|
|
221
|
+
else:
|
|
222
|
+
reflected.pop(key)
|
|
223
|
+
return reflected
|
|
224
|
+
|
cppmakelib/system/all.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from cppmakelib.error.config import ConfigError
|
|
2
|
+
from cppmakelib.system.linux import Linux
|
|
3
|
+
from cppmakelib.system.macos import Macos
|
|
4
|
+
from cppmakelib.system.windows import Windows
|
|
5
|
+
|
|
6
|
+
system: Linux | Macos | Windows
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _choose_system() -> Linux | Macos | Windows:
|
|
11
|
+
matches: list[Linux | Macos | Windows] = []
|
|
12
|
+
errors : list[Exception] = []
|
|
13
|
+
for System in (Linux, Macos, Windows):
|
|
14
|
+
try:
|
|
15
|
+
matches += [System()]
|
|
16
|
+
except ConfigError as error:
|
|
17
|
+
errors += [error]
|
|
18
|
+
if len(matches) == 0:
|
|
19
|
+
raise ConfigError(f'system is not supported (with matches = {matches})') from ExceptionGroup('no compiler is matched', errors)
|
|
20
|
+
elif len(matches) == 1:
|
|
21
|
+
return matches[0]
|
|
22
|
+
else:
|
|
23
|
+
raise ConfigError(f'system is ambiguous (with matches = {matches})')
|
|
24
|
+
|
|
25
|
+
system = _choose_system()
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from cppmakelib.error.config import ConfigError
|
|
2
|
+
from cppmakelib.utility.decorator import member
|
|
3
|
+
from cppmakelib.utility.filesystem import path
|
|
4
|
+
|
|
5
|
+
import sys
|
|
6
|
+
|
|
7
|
+
class Linux:
|
|
8
|
+
def __init__(self) -> None: ...
|
|
9
|
+
executable_suffix: str = ''
|
|
10
|
+
object_suffix : str = '.o'
|
|
11
|
+
static_suffix : str = '.a'
|
|
12
|
+
dynamic_suffix : str = '.so'
|
|
13
|
+
compiler : path = 'g++'
|
|
14
|
+
|
|
15
|
+
def _check(self) -> None: ...
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@member(Linux)
|
|
20
|
+
def __init__(self: Linux) -> None:
|
|
21
|
+
self._check()
|
|
22
|
+
|
|
23
|
+
@member(Linux)
|
|
24
|
+
def _check(self: Linux) -> None:
|
|
25
|
+
if sys.platform != 'linux':
|
|
26
|
+
raise ConfigError(f'linux check failed (with sys.platform = {sys.platform})')
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from cppmakelib.error.config import ConfigError
|
|
2
|
+
from cppmakelib.utility.decorator import member
|
|
3
|
+
from cppmakelib.utility.filesystem import path
|
|
4
|
+
|
|
5
|
+
import sys
|
|
6
|
+
|
|
7
|
+
class Macos:
|
|
8
|
+
def __init__(self) -> None: ...
|
|
9
|
+
executable_suffix: str = ''
|
|
10
|
+
object_suffix : str = '.o'
|
|
11
|
+
static_suffix : str = '.a'
|
|
12
|
+
dynamic_suffix : str = '.dylib'
|
|
13
|
+
compiler : path = 'clang++'
|
|
14
|
+
|
|
15
|
+
def _check(self) -> None: ...
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@member(Macos)
|
|
20
|
+
def __init__(self: Macos) -> None:
|
|
21
|
+
self._check()
|
|
22
|
+
|
|
23
|
+
@member(Macos)
|
|
24
|
+
def _check(self: Macos) -> None:
|
|
25
|
+
if sys.platform != 'darwin':
|
|
26
|
+
raise ConfigError(f'macos check failed (with sys.platform = {sys.platform})')
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from cppmakelib.error.config import ConfigError
|
|
2
|
+
from cppmakelib.utility.decorator import member
|
|
3
|
+
from cppmakelib.utility.filesystem import path
|
|
4
|
+
|
|
5
|
+
import sys
|
|
6
|
+
|
|
7
|
+
class Windows:
|
|
8
|
+
def __init__(self) -> None: ...
|
|
9
|
+
executable_suffix: str = '.exe'
|
|
10
|
+
object_suffix : str = '.obj'
|
|
11
|
+
static_suffix : str = '.lib'
|
|
12
|
+
dynamic_suffix : str = '.dll'
|
|
13
|
+
compiler : path = 'cl.exe'
|
|
14
|
+
|
|
15
|
+
def _check(self) -> None: ...
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@member(Windows)
|
|
20
|
+
def __init__(self: Windows) -> None:
|
|
21
|
+
self._check()
|
|
22
|
+
|
|
23
|
+
@member(Windows)
|
|
24
|
+
def _check(self: Windows) -> None:
|
|
25
|
+
if sys.platform != 'win32' and sys.platform != 'win64':
|
|
26
|
+
raise ConfigError(f'windows check failed (with sys.platform = {sys.platform})')
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from cppmakelib.basic.context import context
|
|
2
|
+
from cppmakelib.unit.package import Package
|
|
3
|
+
from cppmakelib.utility.decorator import member, unique
|
|
4
|
+
from cppmakelib.utility.filesystem import path
|
|
5
|
+
|
|
6
|
+
class Binary:
|
|
7
|
+
def __new__ (cls, file : path) -> Binary: ...
|
|
8
|
+
def __init__ (self, file : path) -> None : ...
|
|
9
|
+
def install(self, install_dir: path) -> Binary: ...
|
|
10
|
+
async def async_install(self, install_dir: path) -> Binary: ...
|
|
11
|
+
def sign (self) -> Binary: ...
|
|
12
|
+
async def async_sign (self) -> Binary: ...
|
|
13
|
+
def strip (self) -> Binary: ...
|
|
14
|
+
async def async_strip (self) -> Binary: ...
|
|
15
|
+
file : path
|
|
16
|
+
context_package: Package
|
|
17
|
+
link_flags : list[str]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@member(Binary)
|
|
22
|
+
@unique
|
|
23
|
+
def __init__(self: Binary, file: path) -> None:
|
|
24
|
+
self.file = file
|
|
25
|
+
self.context_package = context.package
|
|
26
|
+
self.link_flags = self.context_package.link_flags
|
cppmakelib/unit/code.py
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
from cppmakelib.basic.context import context
|
|
2
|
+
from cppmakelib.compiler.all import compiler
|
|
3
|
+
from cppmakelib.executor.scheduler import scheduler
|
|
4
|
+
from cppmakelib.unit.package import Package
|
|
5
|
+
from cppmakelib.unit.preprocessed import Preprocessed
|
|
6
|
+
from cppmakelib.utility.algorithm import recursive_collect
|
|
7
|
+
from cppmakelib.utility.decorator import member, once, relocatable, syncable, unique
|
|
8
|
+
from cppmakelib.utility.filesystem import modified_time_file, path, relative_path
|
|
9
|
+
from cppmakelib.utility.time import time
|
|
10
|
+
|
|
11
|
+
class Code:
|
|
12
|
+
def __new__ (cls: ..., file: path) -> Code : ...
|
|
13
|
+
async def __anew__ (cls: ..., file: path) -> Code : ...
|
|
14
|
+
def __init__ (self, file: path) -> None : ...
|
|
15
|
+
async def __ainit__ (self, file: path) -> None : ...
|
|
16
|
+
def preprocess (self) -> Preprocessed: ...
|
|
17
|
+
async def async_preprocess (self) -> Preprocessed: ...
|
|
18
|
+
def is_preprocessed(self) -> bool : ...
|
|
19
|
+
async def async_is_preprocessed(self) -> bool : ...
|
|
20
|
+
file : path
|
|
21
|
+
modified_time : time
|
|
22
|
+
preprocessed_file: path
|
|
23
|
+
compile_flags : list[str]
|
|
24
|
+
define_macros : dict[str, str]
|
|
25
|
+
context_package : Package
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@member(Code)
|
|
30
|
+
@relocatable
|
|
31
|
+
@syncable
|
|
32
|
+
@unique
|
|
33
|
+
async def __ainit__(self: Code, file: path) -> None:
|
|
34
|
+
self.file = file
|
|
35
|
+
self.modified_time = modified_time_file(self.file)
|
|
36
|
+
self.context_package = context.package
|
|
37
|
+
self.preprocessed_file = f'{self.context_package.build_code_dir}/{relative_path(from_path=self.context_package.dir, to_path=self.file)}'
|
|
38
|
+
self.compile_flags = self.context_package.compile_flags
|
|
39
|
+
self.define_macros = self.context_package.define_macros
|
|
40
|
+
|
|
41
|
+
@member(Code)
|
|
42
|
+
@syncable
|
|
43
|
+
@once
|
|
44
|
+
async def async_preprocess(self: Code) -> Preprocessed:
|
|
45
|
+
if not await self.async_is_preprocessed():
|
|
46
|
+
async with scheduler.schedule():
|
|
47
|
+
await compiler.async_preprocess(
|
|
48
|
+
code_file =self.file,
|
|
49
|
+
preprocessed_file=self.preprocessed_file,
|
|
50
|
+
compile_flags =self.compile_flags,
|
|
51
|
+
define_macros =self.define_macros,
|
|
52
|
+
include_dirs =[self.context_package.search_header_dir] + recursive_collect(self.context_package, next=lambda package: package.require_packages, collect=lambda package: package.install_include_dir)
|
|
53
|
+
)
|
|
54
|
+
self.context_package.unit_status_logger.set_code_preprocessed(code=self, preprocessed=True)
|
|
55
|
+
return Preprocessed(self.preprocessed_file)
|
|
56
|
+
|
|
57
|
+
@member(Code)
|
|
58
|
+
@syncable
|
|
59
|
+
@once
|
|
60
|
+
async def async_is_preprocessed(self: Code) -> bool:
|
|
61
|
+
return self.context_package.unit_status_logger.get_code_preprocessed(code=self)
|
|
62
|
+
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from cppmakelib.unit.binary import Binary
|
|
2
|
+
from cppmakelib.utility.decorator import member, unique
|
|
3
|
+
from cppmakelib.utility.filesystem import path
|
|
4
|
+
|
|
5
|
+
class Dynamic(Binary):
|
|
6
|
+
def __new__ (cls, file: path) -> Dynamic: ...
|
|
7
|
+
def __init__ (self, file: path) -> None : ...
|
|
8
|
+
|
|
9
|
+
@member(Dynamic)
|
|
10
|
+
@unique
|
|
11
|
+
def __init__(self: Dynamic, file: path) -> None:
|
|
12
|
+
super(Dynamic, self).__init__(file)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from cppmakelib.error.subprocess import SubprocessError
|
|
2
|
+
from cppmakelib.executor.run import async_run
|
|
3
|
+
from cppmakelib.unit.binary import Binary
|
|
4
|
+
from cppmakelib.utility.decorator import member, once, syncable, unique
|
|
5
|
+
from cppmakelib.utility.filesystem import path
|
|
6
|
+
|
|
7
|
+
class Executable(Binary):
|
|
8
|
+
def __new__ (cls, file: path) -> Executable: ...
|
|
9
|
+
def __init__ (self, file: path) -> None : ...
|
|
10
|
+
def execute(self) -> None : ...
|
|
11
|
+
async def async_execute(self) -> None : ...
|
|
12
|
+
def test (self) -> None : ...
|
|
13
|
+
async def async_test (self) -> None : ...
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@member(Executable)
|
|
18
|
+
@unique
|
|
19
|
+
def __init__(self: Executable, file: path) -> None:
|
|
20
|
+
super(Executable, self).__init__(file)
|
|
21
|
+
|
|
22
|
+
@member(Executable)
|
|
23
|
+
@syncable
|
|
24
|
+
@once
|
|
25
|
+
async def async_execute(self: Executable) -> None:
|
|
26
|
+
try:
|
|
27
|
+
await async_run(file=self.file)
|
|
28
|
+
except SubprocessError:
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
@member(Executable)
|
|
32
|
+
@syncable
|
|
33
|
+
@once
|
|
34
|
+
async def async_test(self: Executable) -> None:
|
|
35
|
+
await async_run(file=self.file)
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
from cppmakelib.compiler.all import compiler
|
|
2
|
+
from cppmakelib.executor.operation import when_all
|
|
3
|
+
from cppmakelib.executor.scheduler import scheduler
|
|
4
|
+
from cppmakelib.unit.code import Code
|
|
5
|
+
from cppmakelib.unit.preparsed import Preparsed
|
|
6
|
+
from cppmakelib.utility.algorithm import recursive_collect
|
|
7
|
+
from cppmakelib.utility.decorator import member, once, relocatable, syncable, unique
|
|
8
|
+
from cppmakelib.utility.filesystem import path, relative_path
|
|
9
|
+
|
|
10
|
+
class Header(Code):
|
|
11
|
+
def __new__ (cls: ..., file: path) -> Header : ...
|
|
12
|
+
async def __anew__ (cls: ..., file: path) -> Header : ...
|
|
13
|
+
def __init__ (self, file: path) -> None : ...
|
|
14
|
+
async def __ainit__ (self, file: path) -> None : ...
|
|
15
|
+
def preparse (self) -> Preparsed: ...
|
|
16
|
+
async def async_preparse (self) -> Preparsed: ...
|
|
17
|
+
def is_preparsed(self) -> bool : ...
|
|
18
|
+
async def async_is_preparsed(self) -> bool : ...
|
|
19
|
+
name : str
|
|
20
|
+
preparsed_file : path
|
|
21
|
+
object_file : path
|
|
22
|
+
diagnostic_file : path
|
|
23
|
+
include_headers : list[Header]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@member(Header)
|
|
28
|
+
@relocatable
|
|
29
|
+
@syncable
|
|
30
|
+
@unique
|
|
31
|
+
async def __ainit__(self: Header, file: path) -> None:
|
|
32
|
+
await super(Header, self).__ainit__(file)
|
|
33
|
+
self.name = relative_path(from_path=self.context_package.search_header_dir, to_path=self.file)
|
|
34
|
+
self.preparsed_file = f'{self.context_package.build_header_dir}/{self.name}{compiler.preparsed_suffix}'
|
|
35
|
+
self.diagnostic_file = f'{self.context_package.build_header_dir}/{self.name}{compiler.diagnostic_suffix}'
|
|
36
|
+
self.include_headers = await when_all([Header.__anew__(Header, file) for file in self.context_package.unit_status_logger.get_header_includes(header=self)])
|
|
37
|
+
|
|
38
|
+
@member(Header)
|
|
39
|
+
@syncable
|
|
40
|
+
@once
|
|
41
|
+
async def async_preparse(self: Header) -> Preparsed:
|
|
42
|
+
if not await self.async_is_preparsed():
|
|
43
|
+
await when_all([header.async_preparse() for header in self.include_headers])
|
|
44
|
+
await self.async_preprocess()
|
|
45
|
+
async with scheduler.schedule():
|
|
46
|
+
await compiler.async_preparse(
|
|
47
|
+
header_file =self.file,
|
|
48
|
+
preparsed_file =self.preparsed_file,
|
|
49
|
+
compile_flags =self.compile_flags,
|
|
50
|
+
define_macros =self.define_macros,
|
|
51
|
+
include_dirs =[self.context_package.build_header_dir] + recursive_collect(self.context_package, next=lambda package: package.require_packages, collect=lambda package: package.install_include_dir),
|
|
52
|
+
diagnostic_file=self.diagnostic_file
|
|
53
|
+
)
|
|
54
|
+
self.context_package.unit_status_logger.set_header_preparsed(header=self, result=True)
|
|
55
|
+
return Preparsed(self.preparsed_file)
|
|
56
|
+
|
|
57
|
+
@member(Header)
|
|
58
|
+
@syncable
|
|
59
|
+
@once
|
|
60
|
+
async def async_is_preparsed(self: Header) -> bool:
|
|
61
|
+
return all(await when_all([header.async_is_preparsed() for header in self.include_headers])) and \
|
|
62
|
+
await self.async_is_preparsed() and \
|
|
63
|
+
self.context_package.unit_status_logger.get_header_preparsed(header=self)
|