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,196 @@
|
|
|
1
|
+
from cppmakelib.basic.config import config
|
|
2
|
+
from cppmakelib.compiler.gcc import Gcc
|
|
3
|
+
from cppmakelib.error.config import ConfigError
|
|
4
|
+
from cppmakelib.error.subprocess import SubprocessError
|
|
5
|
+
from cppmakelib.executor.run import async_run
|
|
6
|
+
from cppmakelib.utility.decorator import member, syncable, unique
|
|
7
|
+
from cppmakelib.utility.filesystem import create_dir, exist_file, parent_dir, path
|
|
8
|
+
from cppmakelib.utility.version import Version
|
|
9
|
+
|
|
10
|
+
class Clang(Gcc):
|
|
11
|
+
def __init__ (self, file: path = 'clang++') -> None: ...
|
|
12
|
+
async def __ainit__ (self, file: path = 'clang++') -> None: ...
|
|
13
|
+
def precompile(self, module_file: path, precompiled_file: path, object_file: path, compile_flags: list[str] = [], define_macros: dict[str, str] = {}, include_dirs: list[path] = [], import_dirs: list[path] = [], diagnostic_file: path | None = None) -> None: ...
|
|
14
|
+
async def async_precompile(self, module_file: path, precompiled_file: path, object_file: path, compile_flags: list[str] = [], define_macros: dict[str, str] = {}, include_dirs: list[path] = [], import_dirs: list[path] = [], diagnostic_file: path | None = None) -> None: ...
|
|
15
|
+
def preparse (self, header_file: path, preparsed_file : path, compile_flags: list[str] = [], define_macros: dict[str, str] = {}, include_dirs: list[path] = [], diagnostic_file: path | None = None) -> None: ...
|
|
16
|
+
async def async_preparse (self, header_file: path, preparsed_file : path, compile_flags: list[str] = [], define_macros: dict[str, str] = {}, include_dirs: list[path] = [], diagnostic_file: path | None = None) -> None: ...
|
|
17
|
+
def compile (self, source_file: path, object_file : path, compile_flags: list[str] = [], define_macros: dict[str, str] = {}, include_dirs: list[path] = [], import_dirs: list[path] = [], diagnostic_file: path | None = None) -> None: ...
|
|
18
|
+
async def async_compile (self, source_file: path, object_file : path, compile_flags: list[str] = [], define_macros: dict[str, str] = {}, include_dirs: list[path] = [], import_dirs: list[path] = [], diagnostic_file: path | None = None) -> None: ...
|
|
19
|
+
preparsed_suffix : str = '.pch'
|
|
20
|
+
precompiled_suffix: str = '.pcm'
|
|
21
|
+
file : path
|
|
22
|
+
version : Version
|
|
23
|
+
stdlib_name : str
|
|
24
|
+
stdlib_module_file: path
|
|
25
|
+
stdlib_static_file: path
|
|
26
|
+
stdlib_shared_file: path
|
|
27
|
+
compile_flags : list[str]
|
|
28
|
+
link_flags : list[str]
|
|
29
|
+
define_macros : dict[str, str]
|
|
30
|
+
|
|
31
|
+
async def _async_get_version (self) -> Version: ...
|
|
32
|
+
async def _async_get_stdlib_name (self) -> str: ...
|
|
33
|
+
async def _async_get_stdlib_module_file(self) -> path : ...
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@member(Clang)
|
|
38
|
+
@syncable
|
|
39
|
+
@unique
|
|
40
|
+
async def __ainit__(
|
|
41
|
+
self: Clang,
|
|
42
|
+
file: path = 'clang++'
|
|
43
|
+
) -> None:
|
|
44
|
+
self.file = file
|
|
45
|
+
self.version = await self._async_get_version()
|
|
46
|
+
self.stdlib_name = await self._async_get_stdlib_name()
|
|
47
|
+
self.stdlib_module_file = await self._async_get_stdlib_module_file()
|
|
48
|
+
self.compile_flags = [
|
|
49
|
+
f'-std={config.std}',
|
|
50
|
+
f'-stdlib={self.stdlib_name}',
|
|
51
|
+
*(['-O0', '-g'] if config.type == 'debug' else
|
|
52
|
+
['-O3'] if config.type == 'release' else
|
|
53
|
+
['-Os'] if config.type == 'size' else
|
|
54
|
+
[])
|
|
55
|
+
]
|
|
56
|
+
self.link_flags = [
|
|
57
|
+
*(['-s'] if config.type == 'release' or config.type == 'size' else []),
|
|
58
|
+
*(['-lstdc++exp'] if self.stdlib_name == 'libstdc++' else [])
|
|
59
|
+
]
|
|
60
|
+
self.define_macros = {
|
|
61
|
+
**({'DEBUG' : 'true'} if config.type == 'debug' else
|
|
62
|
+
{'NDEBUG': 'true'} if config.type == 'release' else
|
|
63
|
+
{})
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
@member(Clang)
|
|
67
|
+
@syncable
|
|
68
|
+
async def async_precompile(
|
|
69
|
+
self : Clang,
|
|
70
|
+
module_file : path,
|
|
71
|
+
precompiled_file: path,
|
|
72
|
+
object_file : path,
|
|
73
|
+
compile_flags : list[str] = [],
|
|
74
|
+
define_macros : dict[str, str] = {},
|
|
75
|
+
include_dirs : list[path] = [],
|
|
76
|
+
import_dirs : list[path] = [],
|
|
77
|
+
diagnostic_file : path | None = None
|
|
78
|
+
) -> None:
|
|
79
|
+
create_dir(parent_dir(precompiled_file))
|
|
80
|
+
create_dir(parent_dir(object_file))
|
|
81
|
+
await async_run(
|
|
82
|
+
file=self.file,
|
|
83
|
+
args=[
|
|
84
|
+
*(self.compile_flags + compile_flags),
|
|
85
|
+
*[f'-D{key}={value}' for key, value in (self.define_macros | define_macros).items()],
|
|
86
|
+
*[f'-I{include_dir}' for include_dir in include_dirs],
|
|
87
|
+
*[f'-fprebuilt-module-path={import_dir}' for import_dir in import_dirs],
|
|
88
|
+
'--precompile', '-x', 'c++-module', module_file,
|
|
89
|
+
'-o', precompiled_file
|
|
90
|
+
]
|
|
91
|
+
)
|
|
92
|
+
await async_run(
|
|
93
|
+
file=self.file,
|
|
94
|
+
args=[
|
|
95
|
+
*[f'-fprebuilt-module-path={import_dir}' for import_dir in import_dirs],
|
|
96
|
+
'-c', module_file,
|
|
97
|
+
'-o', object_file
|
|
98
|
+
]
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
@member(Gcc)
|
|
102
|
+
@syncable
|
|
103
|
+
async def async_preparse(
|
|
104
|
+
self : Gcc,
|
|
105
|
+
header_file : path,
|
|
106
|
+
preparsed_file : path,
|
|
107
|
+
compile_flags : list[str] = [],
|
|
108
|
+
define_macros : dict[str, str] = {},
|
|
109
|
+
include_dirs : list[path] = [],
|
|
110
|
+
diagnostic_file: path | None = None
|
|
111
|
+
) -> None:
|
|
112
|
+
create_dir(parent_dir(preparsed_file))
|
|
113
|
+
await async_run(
|
|
114
|
+
file=self.file,
|
|
115
|
+
args=[
|
|
116
|
+
*(self.compile_flags + compile_flags),
|
|
117
|
+
*[f'-D{key}={value}' for key, value in (self.define_macros | define_macros).items()],
|
|
118
|
+
*[f'-I{include_dir}' for include_dir in include_dirs],
|
|
119
|
+
'-c', '-x', 'c++-header', header_file,
|
|
120
|
+
'-o', preparsed_file
|
|
121
|
+
]
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
@member(Clang)
|
|
125
|
+
@syncable
|
|
126
|
+
async def async_compile(
|
|
127
|
+
self: Clang,
|
|
128
|
+
source_file : path,
|
|
129
|
+
object_file : path,
|
|
130
|
+
compile_flags : list[str] = [],
|
|
131
|
+
define_macros : dict[str, str] = {},
|
|
132
|
+
include_dirs : list[path] = [],
|
|
133
|
+
import_dirs : list[path] = [],
|
|
134
|
+
diagnostic_file: path | None = None
|
|
135
|
+
) -> None:
|
|
136
|
+
create_dir(parent_dir(object_file))
|
|
137
|
+
await async_run(
|
|
138
|
+
file=self.file,
|
|
139
|
+
args=[
|
|
140
|
+
*(self.compile_flags + compile_flags),
|
|
141
|
+
*[f'-D{key}={value}' for key, value in (self.define_macros | define_macros).items()],
|
|
142
|
+
*[f'-I{include_dir}' for include_dir in include_dirs],
|
|
143
|
+
*[f'-fprebuilt-module-path={import_dir}' for import_dir in import_dirs],
|
|
144
|
+
'-c', '-x', 'c++', source_file,
|
|
145
|
+
'-o', object_file
|
|
146
|
+
]
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
@member(Clang)
|
|
150
|
+
async def _async_get_version(self: Clang) -> Version:
|
|
151
|
+
try:
|
|
152
|
+
stdout = await async_run(
|
|
153
|
+
file=self.file,
|
|
154
|
+
args=['--version'],
|
|
155
|
+
return_stdout=True
|
|
156
|
+
)
|
|
157
|
+
except SubprocessError as error:
|
|
158
|
+
raise ConfigError(f'clang check failed (with file = {self.file})') from error
|
|
159
|
+
if not stdout.startswith('clang') and 'clang version' not in stdout:
|
|
160
|
+
raise ConfigError(f'clang check failed (with file = {self.file}, subprocess = "{self.file} --version", stdout = "{stdout.splitlines()[0]} ...", requires = "clang++ ..." or "... clang version ...")')
|
|
161
|
+
version = Version.parse(stdout)
|
|
162
|
+
if version < 21:
|
|
163
|
+
raise ConfigError(f'clang version is too old (with file = {self.file}, version = {version}, requires = 21+)')
|
|
164
|
+
return version
|
|
165
|
+
|
|
166
|
+
async def _async_get_stdlib_name(self: Clang) -> str:
|
|
167
|
+
stderr = await async_run(
|
|
168
|
+
file=self.file,
|
|
169
|
+
args=[
|
|
170
|
+
*self.compile_flags,
|
|
171
|
+
'-v',
|
|
172
|
+
],
|
|
173
|
+
return_stderr=True
|
|
174
|
+
)
|
|
175
|
+
if 'selected gcc installation' in stderr.lower():
|
|
176
|
+
return 'libstdc++'
|
|
177
|
+
else:
|
|
178
|
+
return 'libc++'
|
|
179
|
+
|
|
180
|
+
async def _async_get_stdlib_module_file(self: Clang) -> path:
|
|
181
|
+
if self.stdlib_name == 'libc++':
|
|
182
|
+
resource_dir = await async_run(
|
|
183
|
+
file=self.file,
|
|
184
|
+
args=['--print-resource-dir'],
|
|
185
|
+
return_stdout=True,
|
|
186
|
+
)
|
|
187
|
+
resource_dir = path(resource_dir.strip())
|
|
188
|
+
search_file = f'{resource_dir}/../../../share/libc++/v1/std.cppm'
|
|
189
|
+
if exist_file(search_file):
|
|
190
|
+
return search_file
|
|
191
|
+
else:
|
|
192
|
+
raise ConfigError(f'libc++ module_file is not found (with search_file = {search_file})')
|
|
193
|
+
elif self.stdlib_name == 'libstdc++':
|
|
194
|
+
return await Gcc._async_get_stdlib_module_file(self)
|
|
195
|
+
else:
|
|
196
|
+
assert False
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
from cppmakelib.basic.config import config
|
|
2
|
+
from cppmakelib.compiler.clang import Clang
|
|
3
|
+
from cppmakelib.error.config import ConfigError
|
|
4
|
+
from cppmakelib.error.subprocess import SubprocessError
|
|
5
|
+
from cppmakelib.executor.run import async_run
|
|
6
|
+
from cppmakelib.utility.decorator import member, syncable, unique
|
|
7
|
+
from cppmakelib.utility.filesystem import path
|
|
8
|
+
from cppmakelib.utility.version import Version
|
|
9
|
+
|
|
10
|
+
class Emcc(Clang):
|
|
11
|
+
def __init__(self, file: path = 'em++') -> None: ...
|
|
12
|
+
async def __ainit__(self, file: path = 'em++') -> None: ...
|
|
13
|
+
file : path
|
|
14
|
+
version : Version
|
|
15
|
+
stdlib_name : str = 'libc++'
|
|
16
|
+
stdlib_module_file: path
|
|
17
|
+
stdlib_static_file: path
|
|
18
|
+
stdlib_shared_file: path
|
|
19
|
+
compile_flags : list[str]
|
|
20
|
+
link_flags : list[str]
|
|
21
|
+
define_macros : dict[str, str]
|
|
22
|
+
|
|
23
|
+
async def _async_get_version (self) -> Version: ...
|
|
24
|
+
async def _async_get_stdlib_name(self) -> str : ...
|
|
25
|
+
|
|
26
|
+
@member(Emcc)
|
|
27
|
+
@syncable
|
|
28
|
+
@unique
|
|
29
|
+
async def __ainit__(
|
|
30
|
+
self: Emcc,
|
|
31
|
+
file: path = 'em++'
|
|
32
|
+
) -> None:
|
|
33
|
+
self.file = file
|
|
34
|
+
self.version = await self._async_get_version()
|
|
35
|
+
self.stdlib_name = 'libc++'
|
|
36
|
+
self.stdlib_module_file = await self._async_get_stdlib_module_file()
|
|
37
|
+
self.compile_flags = [
|
|
38
|
+
f'-std={config.std}', '-fexceptions',
|
|
39
|
+
*(['-O0', '-g'] if config.type == 'debug' else
|
|
40
|
+
['-O3'] if config.type == 'release' else
|
|
41
|
+
['-Os'] if config.type == 'size' else
|
|
42
|
+
[])
|
|
43
|
+
]
|
|
44
|
+
self.link_flags = [
|
|
45
|
+
*(['-s'] if config.type == 'release' or config.type == 'size' else []),
|
|
46
|
+
]
|
|
47
|
+
self.define_macros = {
|
|
48
|
+
**({'DEBUG' : 'true'} if config.type == 'debug' else
|
|
49
|
+
{'NDEBUG': 'true'} if config.type == 'release' else
|
|
50
|
+
{})
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
@member(Emcc)
|
|
54
|
+
async def _async_get_version(self: Emcc) -> Version:
|
|
55
|
+
try:
|
|
56
|
+
stdout = await async_run(
|
|
57
|
+
file=self.file,
|
|
58
|
+
args=['--version'],
|
|
59
|
+
return_stdout=True
|
|
60
|
+
)
|
|
61
|
+
except SubprocessError as error:
|
|
62
|
+
raise ConfigError(f'emcc check failed (with file = {self.file})') from error
|
|
63
|
+
if not stdout.startswith('em++'):
|
|
64
|
+
raise ConfigError(f'emcc check failed (with file = {self.file}, subprocess = "{self.file} --version", stdout = "{stdout.splitlines()[0]} ...", requires = "em++ ...")')
|
|
65
|
+
version = Version.parse(stdout)
|
|
66
|
+
if version < 4:
|
|
67
|
+
raise ConfigError(f'emcc version is too old (with file = {self.file}, version = {version}, requires = 4+)')
|
|
68
|
+
return version
|
|
69
|
+
|
|
70
|
+
@member(Emcc)
|
|
71
|
+
async def _async_get_stdlib_module_file(self: Emcc) -> path:
|
|
72
|
+
clang_stdlib_name = await Clang._async_get_stdlib_name(self)
|
|
73
|
+
if clang_stdlib_name == 'libc++':
|
|
74
|
+
try:
|
|
75
|
+
return await Clang._async_get_stdlib_module_file(self)
|
|
76
|
+
except ConfigError as error:
|
|
77
|
+
raise ConfigError(f'libc++ module_file is not found (with file = {self.file}, subcompiler = clang++)') from error
|
|
78
|
+
else:
|
|
79
|
+
raise ConfigError(f'libc++ module_file is not found (with file = {self.file}, clang_stdlib_name = {clang_stdlib_name})')
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
from cppmakelib.basic.config import config
|
|
2
|
+
from cppmakelib.error.config import ConfigError
|
|
3
|
+
from cppmakelib.error.subprocess import SubprocessError
|
|
4
|
+
from cppmakelib.executor.run import async_run
|
|
5
|
+
from cppmakelib.logger.module_mapper import module_mapper_logger
|
|
6
|
+
from cppmakelib.utility.decorator import member, syncable, unique
|
|
7
|
+
from cppmakelib.utility.filesystem import create_dir, exist_file, parent_dir, path
|
|
8
|
+
from cppmakelib.utility.version import Version
|
|
9
|
+
import re
|
|
10
|
+
|
|
11
|
+
class Gcc:
|
|
12
|
+
def __init__ (self, file: path = 'g++') -> None: ...
|
|
13
|
+
async def __ainit__ (self, file: path = 'g++') -> None: ...
|
|
14
|
+
def preprocess(self, code_file : path, preprocessed_file: path, compile_flags: list[str] = [], define_macros: dict[str, str] = {}, include_dirs: list[path] = []) -> None: ...
|
|
15
|
+
async def async_preprocess(self, code_file : path, preprocessed_file: path, compile_flags: list[str] = [], define_macros: dict[str, str] = {}, include_dirs: list[path] = []) -> None: ...
|
|
16
|
+
def preparse (self, header_file: path, preparsed_file : path, compile_flags: list[str] = [], define_macros: dict[str, str] = {}, include_dirs: list[path] = [], diagnostic_file: path | None = None) -> None: ...
|
|
17
|
+
async def async_preparse (self, header_file: path, preparsed_file : path, compile_flags: list[str] = [], define_macros: dict[str, str] = {}, include_dirs: list[path] = [], diagnostic_file: path | None = None) -> None: ...
|
|
18
|
+
def precompile(self, module_file: path, precompiled_file : path, object_file: path, compile_flags: list[str] = [], define_macros: dict[str, str] = {}, include_dirs: list[path] = [], import_dirs: list[path] = [], diagnostic_file: path | None = None) -> None: ...
|
|
19
|
+
async def async_precompile(self, module_file: path, precompiled_file : path, object_file: path, compile_flags: list[str] = [], define_macros: dict[str, str] = {}, include_dirs: list[path] = [], import_dirs: list[path] = [], diagnostic_file: path | None = None) -> None: ...
|
|
20
|
+
def compile (self, source_file: path, object_file : path, compile_flags: list[str] = [], define_macros: dict[str, str] = {}, include_dirs: list[path] = [], import_dirs: list[path] = [], diagnostic_file: path | None = None) -> None: ...
|
|
21
|
+
async def async_compile (self, source_file: path, object_file : path, compile_flags: list[str] = [], define_macros: dict[str, str] = {}, include_dirs: list[path] = [], import_dirs: list[path] = [], diagnostic_file: path | None = None) -> None: ...
|
|
22
|
+
def share (self, object_file: path, dynamic_file : path, link_flags : list[str] = [], lib_files : list[path] = []) -> None: ...
|
|
23
|
+
async def async_share (self, object_file: path, dynamic_file : path, link_flags : list[str] = [], lib_files : list[path] = []) -> None: ...
|
|
24
|
+
def link (self, object_file: path, executable_file : path, link_flags : list[str] = [], lib_files : list[path] = []) -> None: ...
|
|
25
|
+
async def async_link (self, object_file: path, executable_file : path, link_flags : list[str] = [], lib_files : list[path] = []) -> None: ...
|
|
26
|
+
preprocessed_suffix: str = '.ipp'
|
|
27
|
+
preparsed_suffix : str = '.gch'
|
|
28
|
+
precompiled_suffix : str = '.gcm'
|
|
29
|
+
diagnostic_suffix : str = '.sarif'
|
|
30
|
+
file : path
|
|
31
|
+
version : Version
|
|
32
|
+
stdlib_name : str = 'libstdc++'
|
|
33
|
+
stdlib_module_file : path
|
|
34
|
+
stdlib_static_file : path
|
|
35
|
+
stdlib_shared_file : path
|
|
36
|
+
compile_flags : list[str]
|
|
37
|
+
link_flags : list[str]
|
|
38
|
+
define_macros : dict[str, str]
|
|
39
|
+
|
|
40
|
+
async def _async_get_version (self) -> Version: ...
|
|
41
|
+
async def _async_get_stdlib_module_file(self) -> path : ...
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@member(Gcc)
|
|
46
|
+
@syncable
|
|
47
|
+
@unique
|
|
48
|
+
async def __ainit__(
|
|
49
|
+
self: Gcc,
|
|
50
|
+
file: path = 'g++'
|
|
51
|
+
) -> None:
|
|
52
|
+
self.file = file
|
|
53
|
+
self.version = await self._async_get_version()
|
|
54
|
+
self.stdlib_module_file = await self._async_get_stdlib_module_file()
|
|
55
|
+
self.compile_flags = [
|
|
56
|
+
f'-std={config.std}', '-fmodules',
|
|
57
|
+
*(['-O0', '-g'] if config.type == 'debug' else
|
|
58
|
+
['-O3'] if config.type == 'release' else
|
|
59
|
+
['-Os'] if config.type == 'size' else
|
|
60
|
+
[])
|
|
61
|
+
]
|
|
62
|
+
self.link_flags = [
|
|
63
|
+
*(['-s'] if config.type == 'release' or config.type == 'size' else []),
|
|
64
|
+
'-lstdc++exp'
|
|
65
|
+
]
|
|
66
|
+
self.define_macros = {
|
|
67
|
+
**({'DEBUG' : 'true'} if config.type == 'debug' else
|
|
68
|
+
{'DNDEBUG': 'true'} if config.type == 'release' else
|
|
69
|
+
{})
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@member(Gcc)
|
|
73
|
+
@syncable
|
|
74
|
+
async def async_preprocess(
|
|
75
|
+
self : Gcc,
|
|
76
|
+
unit_file : path,
|
|
77
|
+
preprocessed_file: path,
|
|
78
|
+
compile_flags : list[str] = [],
|
|
79
|
+
define_macros : dict[str, str] = {},
|
|
80
|
+
include_dirs : list[path] = []
|
|
81
|
+
) -> None:
|
|
82
|
+
await async_run(
|
|
83
|
+
file=self.file,
|
|
84
|
+
args=[
|
|
85
|
+
*(self.compile_flags + compile_flags),
|
|
86
|
+
*[f'-D{key}={value}' for key, value in (self.define_macros | define_macros).items()],
|
|
87
|
+
*[f'-I{include_dir}' for include_dir in include_dirs],
|
|
88
|
+
'-E', unit_file,
|
|
89
|
+
'-o', preprocessed_file
|
|
90
|
+
],
|
|
91
|
+
print_stdout=False,
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
@member(Gcc)
|
|
95
|
+
@syncable
|
|
96
|
+
async def async_preparse(
|
|
97
|
+
self : Gcc,
|
|
98
|
+
header_file : path,
|
|
99
|
+
preparsed_file : path,
|
|
100
|
+
compile_flags : list[str] = [],
|
|
101
|
+
define_macros : dict[str, str] = {},
|
|
102
|
+
include_dirs : list[path] = [],
|
|
103
|
+
diagnostic_file: path | None = None
|
|
104
|
+
) -> None:
|
|
105
|
+
create_dir(parent_dir(preparsed_file))
|
|
106
|
+
create_dir(parent_dir(diagnostic_file)) if diagnostic_file is not None else None
|
|
107
|
+
await async_run(
|
|
108
|
+
file=self.file,
|
|
109
|
+
args=[
|
|
110
|
+
*(self.compile_flags + compile_flags),
|
|
111
|
+
*[f'-D{key}={value}' for key, value in (self.define_macros | define_macros).items()],
|
|
112
|
+
*[f'-I{include_dir}' for include_dir in include_dirs],
|
|
113
|
+
*([f'-fdiagnostics-add-output=sarif:file={diagnostic_file}'] if diagnostic_file is not None else []),
|
|
114
|
+
'-c', '-x', 'c++-header', header_file,
|
|
115
|
+
'-o', preparsed_file
|
|
116
|
+
]
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
@member(Gcc)
|
|
121
|
+
@syncable
|
|
122
|
+
async def async_precompile(
|
|
123
|
+
self : Gcc,
|
|
124
|
+
module_file : path,
|
|
125
|
+
precompiled_file: path,
|
|
126
|
+
object_file : path,
|
|
127
|
+
compile_flags : list[str] = [],
|
|
128
|
+
define_macros : dict[str, str] = {},
|
|
129
|
+
include_dirs : list[path] = [],
|
|
130
|
+
import_dirs : list[path] = [],
|
|
131
|
+
diagnostic_file : path | None = None
|
|
132
|
+
) -> None:
|
|
133
|
+
create_dir(parent_dir(precompiled_file))
|
|
134
|
+
create_dir(parent_dir(object_file))
|
|
135
|
+
create_dir(parent_dir(diagnostic_file)) if diagnostic_file is not None else None
|
|
136
|
+
await async_run(
|
|
137
|
+
file=self.file,
|
|
138
|
+
args=[
|
|
139
|
+
*(self.compile_flags + compile_flags),
|
|
140
|
+
*[f'-D{key}={value}' for key, value in (self.define_macros | define_macros).items()],
|
|
141
|
+
*[f'-I{include_dir}' for include_dir in include_dirs],
|
|
142
|
+
*[f'-fmodule-mapper={module_mapper_logger.mapper_file_of(import_dir=import_dir)}' for import_dir in import_dirs],
|
|
143
|
+
*([f'-fdiagnostics-add-output=sarif:file={diagnostic_file}'] if diagnostic_file is not None else []),
|
|
144
|
+
'-c', '-x', 'c++-module', module_file,
|
|
145
|
+
'-o', object_file
|
|
146
|
+
]
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
@member(Gcc)
|
|
150
|
+
@syncable
|
|
151
|
+
async def async_compile(
|
|
152
|
+
self : Gcc,
|
|
153
|
+
source_file : path,
|
|
154
|
+
object_file : path,
|
|
155
|
+
compile_flags : list[str] = [],
|
|
156
|
+
define_macros : dict[str, str] = {},
|
|
157
|
+
include_dirs : list[path] =[],
|
|
158
|
+
import_dirs : list[path] = [],
|
|
159
|
+
diagnostic_file: path | None = None
|
|
160
|
+
) -> None:
|
|
161
|
+
create_dir(parent_dir(object_file))
|
|
162
|
+
create_dir(parent_dir(diagnostic_file)) if diagnostic_file is not None else None
|
|
163
|
+
await async_run(
|
|
164
|
+
file=self.file,
|
|
165
|
+
args=[
|
|
166
|
+
*(self.compile_flags + compile_flags),
|
|
167
|
+
*[f'-D{key}={value}' for key, value in (self.define_macros | define_macros).items()],
|
|
168
|
+
*[f'-I{include_dir}' for include_dir in include_dirs],
|
|
169
|
+
*[f'-fmodule-mapper={module_mapper_logger.mapper_file_of(import_dir=import_dir)}' for import_dir in import_dirs],
|
|
170
|
+
*([f'-fdiagnostics-add-output=sarif:file={diagnostic_file}'] if diagnostic_file is not None else []),
|
|
171
|
+
'-c', '-x', 'c++', source_file,
|
|
172
|
+
'-o', object_file
|
|
173
|
+
]
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
@member(Gcc)
|
|
177
|
+
@syncable
|
|
178
|
+
async def async_link(
|
|
179
|
+
self : Gcc,
|
|
180
|
+
object_file : path,
|
|
181
|
+
executable_file: path,
|
|
182
|
+
link_flags : list[str] = [],
|
|
183
|
+
lib_files : list[path] = []
|
|
184
|
+
) -> None:
|
|
185
|
+
create_dir(parent_dir(executable_file))
|
|
186
|
+
await async_run(
|
|
187
|
+
file=self.file,
|
|
188
|
+
args=[
|
|
189
|
+
*(self.link_flags + link_flags),
|
|
190
|
+
*([object_file] + lib_files),
|
|
191
|
+
'-o', executable_file
|
|
192
|
+
]
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
@member(Gcc)
|
|
196
|
+
async def _async_get_version(self: Gcc) -> Version:
|
|
197
|
+
try:
|
|
198
|
+
stdout = await async_run(
|
|
199
|
+
file=self.file,
|
|
200
|
+
args=['--version'],
|
|
201
|
+
return_stdout=True
|
|
202
|
+
)
|
|
203
|
+
except SubprocessError as error:
|
|
204
|
+
raise ConfigError(f'gcc check failed (with file = {self.file})') from error
|
|
205
|
+
if not stdout.startswith('g++'):
|
|
206
|
+
raise ConfigError(f'gcc check failed (with file = {self.file}, subprocess = "{self.file} --version", stdout = "{stdout.splitlines()[0]} ...", requires = "g++ ...")')
|
|
207
|
+
version = Version.parse(stdout)
|
|
208
|
+
if version < 15:
|
|
209
|
+
raise ConfigError(f'gcc version is too old (with file = {self.file}, version = {version}, requires = 15+)')
|
|
210
|
+
return version
|
|
211
|
+
|
|
212
|
+
@member(Gcc)
|
|
213
|
+
async def _async_get_stdlib_module_file(self: Gcc) -> path:
|
|
214
|
+
stderr = await async_run(
|
|
215
|
+
file=self.file,
|
|
216
|
+
args=[
|
|
217
|
+
*self.compile_flags,
|
|
218
|
+
'-E', '-x', 'c++', '-',
|
|
219
|
+
'-v'
|
|
220
|
+
],
|
|
221
|
+
print_stderr =config.verbose,
|
|
222
|
+
return_stderr=True
|
|
223
|
+
)
|
|
224
|
+
search_dirs = re.search(
|
|
225
|
+
pattern=r'^#include <...> search starts here:$\n(.*)\n^end of search list.$',
|
|
226
|
+
string=stderr,
|
|
227
|
+
flags=re.MULTILINE | re.DOTALL | re.IGNORECASE
|
|
228
|
+
)
|
|
229
|
+
if search_dirs is None:
|
|
230
|
+
raise ConfigError(f'libstdc++ module_file is not found (with subprocess = "{self.file} -v -E -x c++ -", stdout = ..., requires = "... #include <...> starts here ... end of search list ...")')
|
|
231
|
+
search_dirs = [path(search_dir.strip()) for search_dir in search_dirs.group(1).splitlines()]
|
|
232
|
+
search_files = [f'{search_dir}/bits/std.cc' for search_dir in search_dirs]
|
|
233
|
+
for search_file in search_files:
|
|
234
|
+
if exist_file(search_file):
|
|
235
|
+
return search_file
|
|
236
|
+
else:
|
|
237
|
+
raise ConfigError(f'libstdc++ module_file is not found (with search_files = {search_files})')
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from cppmakelib.utility.decorator import syncable, unique
|
|
2
|
+
from cppmakelib.utility.version import Version
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
class Msvc:
|
|
6
|
+
name = 'msvc'
|
|
7
|
+
intermediate_suffix = '.i'
|
|
8
|
+
precompiled_suffix = '.ixx'
|
|
9
|
+
|
|
10
|
+
@syncable
|
|
11
|
+
@unique
|
|
12
|
+
async def __ainit__(self, path='cl'):
|
|
13
|
+
self.path = path
|
|
14
|
+
self.version = await self._async_get_version()
|
|
15
|
+
assert False
|
|
16
|
+
|
|
17
|
+
async def _async_get_version(self):
|
|
18
|
+
return await Version.async_parse(
|
|
19
|
+
name =self.name,
|
|
20
|
+
command=[self.path],
|
|
21
|
+
pipe =sys.stderr,
|
|
22
|
+
check =lambda stderr: stderr.startswith('Microsoft') and 'msvc' in stderr,
|
|
23
|
+
lowest =19.36
|
|
24
|
+
)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
class SubprocessError(Exception):
|
|
2
|
+
def __init__(self, stderr, is_stderr_printed, code):
|
|
3
|
+
super().__init__(stderr)
|
|
4
|
+
self.is_stderr_printed = is_stderr_printed
|
|
5
|
+
self.code = code
|
|
6
|
+
|
|
7
|
+
def __str__(self):
|
|
8
|
+
return super().__str__() if not self.is_stderr_printed else ''
|
|
9
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import typing
|
|
3
|
+
|
|
4
|
+
def sync_wait [T](task : typing.Coroutine[typing.Any, typing.Any, T] ) -> T : ...
|
|
5
|
+
def start_detached[T](task : typing.Coroutine[typing.Any, typing.Any, T] ) -> None : ...
|
|
6
|
+
def when_all [T](tasks: list[typing.Coroutine[typing.Any, typing.Any, T]]) -> list[T]: ...
|
|
7
|
+
def when_any [T](tasks: list[typing.Coroutine[typing.Any, typing.Any, T]]) -> T : ...
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def sync_wait[T](task: typing.Coroutine[typing.Any, typing.Any, T]) -> T:
|
|
12
|
+
return asyncio.run(task)
|
|
13
|
+
|
|
14
|
+
async def when_all[T](tasks: list[typing.Coroutine[typing.Any, typing.Any, T]]) -> list[T]:
|
|
15
|
+
return await asyncio.gather(*tasks)
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
from cppmakelib.basic.config import config
|
|
2
|
+
from cppmakelib.error.subprocess import SubprocessError
|
|
3
|
+
from cppmakelib.executor.operation import when_all
|
|
4
|
+
from cppmakelib.executor.scheduler import Scheduler
|
|
5
|
+
from cppmakelib.utility.filesystem import path
|
|
6
|
+
from cppmakelib.logger.compile_commands import compile_commands_logger
|
|
7
|
+
from cppmakelib.utility.decorator import syncable
|
|
8
|
+
import asyncio
|
|
9
|
+
import sys
|
|
10
|
+
import typing
|
|
11
|
+
|
|
12
|
+
def run(file: path, args: list[str] = [], cwd: path = path('.'), print_command: bool = config.verbose, print_stdout: bool = config.verbose, print_stderr: bool = True, return_stdout: bool = False, return_stderr: bool = False) -> None | str | tuple[str, str]: ...
|
|
13
|
+
async def async_run(file: path, args: list[str] = [], cwd: path = path('.'), print_command: bool = config.verbose, print_stdout: bool = config.verbose, print_stderr: bool = True, return_stdout: bool = False, return_stderr: bool = False) -> None | str | tuple[str, str]: ...
|
|
14
|
+
|
|
15
|
+
if typing.TYPE_CHECKING:
|
|
16
|
+
@typing.overload
|
|
17
|
+
def run(file: path, args: list[str] = [], cwd: path = path('.'), print_command: bool = config.verbose, print_stdout: bool = config.verbose, print_stderr: bool = True, *, return_stdout: typing.Literal[False] = False, return_stderr: typing.Literal[False] = False) -> None : ...
|
|
18
|
+
@typing.overload
|
|
19
|
+
def run(file: path, args: list[str] = [], cwd: path = path('.'), print_command: bool = config.verbose, print_stdout: bool = config.verbose, print_stderr: bool = True, *, return_stdout: typing.Literal[False] = False, return_stderr: typing.Literal[True]) -> str : ...
|
|
20
|
+
@typing.overload
|
|
21
|
+
def run(file: path, args: list[str] = [], cwd: path = path('.'), print_command: bool = config.verbose, print_stdout: bool = config.verbose, print_stderr: bool = True, *, return_stdout: typing.Literal[True], return_stderr: typing.Literal[False] = False) -> str : ...
|
|
22
|
+
@typing.overload
|
|
23
|
+
def run(file: path, args: list[str] = [], cwd: path = path('.'), print_command: bool = config.verbose, print_stdout: bool = config.verbose, print_stderr: bool = True, *, return_stdout: typing.Literal[True], return_stderr: typing.Literal[True]) -> tuple[str, str]: ...
|
|
24
|
+
@typing.overload
|
|
25
|
+
async def async_run(file: path, args: list[str] = [], cwd: path = path('.'), print_command: bool = config.verbose, print_stdout: bool = config.verbose, print_stderr: bool = True, *, return_stdout: typing.Literal[False] = False, return_stderr: typing.Literal[False] = False) -> None : ...
|
|
26
|
+
@typing.overload
|
|
27
|
+
async def async_run(file: path, args: list[str] = [], cwd: path = path('.'), print_command: bool = config.verbose, print_stdout: bool = config.verbose, print_stderr: bool = True, *, return_stdout: typing.Literal[False] = False, return_stderr: typing.Literal[True]) -> str : ...
|
|
28
|
+
@typing.overload
|
|
29
|
+
async def async_run(file: path, args: list[str] = [], cwd: path = path('.'), print_command: bool = config.verbose, print_stdout: bool = config.verbose, print_stderr: bool = True, *, return_stdout: typing.Literal[True], return_stderr: typing.Literal[False] = False) -> str : ...
|
|
30
|
+
@typing.overload
|
|
31
|
+
async def async_run(file: path, args: list[str] = [], cwd: path = path('.'), print_command: bool = config.verbose, print_stdout: bool = config.verbose, print_stderr: bool = True, *, return_stdout: typing.Literal[True], return_stderr: typing.Literal[True]) -> tuple[str, str]: ...
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
_internal_scheduler = Scheduler(config.parallel)
|
|
36
|
+
|
|
37
|
+
@syncable
|
|
38
|
+
async def async_run(
|
|
39
|
+
file : path,
|
|
40
|
+
args : list[str] = [],
|
|
41
|
+
cwd : path = path('.'),
|
|
42
|
+
print_command : bool = config.verbose,
|
|
43
|
+
print_stdout : bool = config.verbose,
|
|
44
|
+
print_stderr : bool = True,
|
|
45
|
+
return_stdout : bool = False,
|
|
46
|
+
return_stderr : bool = False,
|
|
47
|
+
) -> None | str | tuple[str, str]:
|
|
48
|
+
async with _internal_scheduler.schedule():
|
|
49
|
+
proc = await asyncio.subprocess.create_subprocess_exec(
|
|
50
|
+
file,
|
|
51
|
+
*args,
|
|
52
|
+
cwd =cwd,
|
|
53
|
+
stdout=asyncio.subprocess.PIPE,
|
|
54
|
+
stderr=asyncio.subprocess.PIPE
|
|
55
|
+
)
|
|
56
|
+
assert isinstance(proc.stdout, asyncio.StreamReader)
|
|
57
|
+
assert isinstance(proc.stderr, asyncio.StreamReader)
|
|
58
|
+
async def read(stream: asyncio.StreamReader, tee: typing.TextIO | None) -> str:
|
|
59
|
+
text = ''
|
|
60
|
+
while True:
|
|
61
|
+
line = await stream.readline()
|
|
62
|
+
if not stream.at_eof():
|
|
63
|
+
line = line.decode()
|
|
64
|
+
text += line
|
|
65
|
+
print(line, end='', file=tee) if tee is not None else None
|
|
66
|
+
else:
|
|
67
|
+
break
|
|
68
|
+
return text
|
|
69
|
+
stdout, stderr = await when_all([
|
|
70
|
+
read(stream=proc.stdout, tee=sys.stdout if print_stdout else None),
|
|
71
|
+
read(stream=proc.stderr, tee=sys.stderr if print_stderr else None)
|
|
72
|
+
])
|
|
73
|
+
code = await proc.wait()
|
|
74
|
+
if code == 0:
|
|
75
|
+
if not return_stdout and not return_stderr:
|
|
76
|
+
return None
|
|
77
|
+
elif not return_stdout and return_stderr:
|
|
78
|
+
return stderr
|
|
79
|
+
elif return_stdout and not return_stderr:
|
|
80
|
+
return stdout
|
|
81
|
+
else: # return_stdout and return_stderr
|
|
82
|
+
return stdout, stderr
|
|
83
|
+
else:
|
|
84
|
+
raise SubprocessError(stderr=stderr, is_stderr_printed=print_stderr, code=code)
|