SCons: Make builders prettier, utilize constexpr
This commit is contained in:
parent
7893202fba
commit
be429eb404
@ -968,8 +968,6 @@ if env.editor_build:
|
|||||||
print_error("Not all modules required by editor builds are enabled.")
|
print_error("Not all modules required by editor builds are enabled.")
|
||||||
Exit(255)
|
Exit(255)
|
||||||
|
|
||||||
env.version_info = methods.get_version_info(env.module_version_string)
|
|
||||||
|
|
||||||
env["PROGSUFFIX_WRAP"] = suffix + env.module_version_string + ".console" + env["PROGSUFFIX"]
|
env["PROGSUFFIX_WRAP"] = suffix + env.module_version_string + ".console" + env["PROGSUFFIX"]
|
||||||
env["PROGSUFFIX"] = suffix + env.module_version_string + env["PROGSUFFIX"]
|
env["PROGSUFFIX"] = suffix + env.module_version_string + env["PROGSUFFIX"]
|
||||||
env["OBJSUFFIX"] = suffix + env["OBJSUFFIX"]
|
env["OBJSUFFIX"] = suffix + env["OBJSUFFIX"]
|
||||||
|
42
core/SCsub
42
core/SCsub
@ -167,10 +167,9 @@ env.add_source_files(env.core_sources, "*.cpp")
|
|||||||
|
|
||||||
# Generate disabled classes
|
# Generate disabled classes
|
||||||
def disabled_class_builder(target, source, env):
|
def disabled_class_builder(target, source, env):
|
||||||
with methods.generated_wrapper(target) as file:
|
with methods.generated_wrapper(str(target[0])) as file:
|
||||||
for c in source[0].read():
|
for c in source[0].read():
|
||||||
cs = c.strip()
|
if cs := c.strip():
|
||||||
if cs != "":
|
|
||||||
file.write(f"#define ClassDB_Disable_{cs} 1\n")
|
file.write(f"#define ClassDB_Disable_{cs} 1\n")
|
||||||
|
|
||||||
|
|
||||||
@ -179,7 +178,7 @@ env.CommandNoCache("disabled_classes.gen.h", env.Value(env.disabled_classes), en
|
|||||||
|
|
||||||
# Generate version info
|
# Generate version info
|
||||||
def version_info_builder(target, source, env):
|
def version_info_builder(target, source, env):
|
||||||
with methods.generated_wrapper(target) as file:
|
with methods.generated_wrapper(str(target[0])) as file:
|
||||||
file.write(
|
file.write(
|
||||||
"""\
|
"""\
|
||||||
#define VERSION_SHORT_NAME "{short_name}"
|
#define VERSION_SHORT_NAME "{short_name}"
|
||||||
@ -193,35 +192,37 @@ def version_info_builder(target, source, env):
|
|||||||
#define VERSION_WEBSITE "{website}"
|
#define VERSION_WEBSITE "{website}"
|
||||||
#define VERSION_DOCS_BRANCH "{docs_branch}"
|
#define VERSION_DOCS_BRANCH "{docs_branch}"
|
||||||
#define VERSION_DOCS_URL "https://docs.godotengine.org/en/" VERSION_DOCS_BRANCH
|
#define VERSION_DOCS_URL "https://docs.godotengine.org/en/" VERSION_DOCS_BRANCH
|
||||||
""".format(**env.version_info)
|
""".format(**source[0].read())
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
env.CommandNoCache("version_generated.gen.h", env.Value(env.version_info), env.Run(version_info_builder))
|
env.CommandNoCache(
|
||||||
|
"version_generated.gen.h",
|
||||||
|
env.Value(methods.get_version_info(env.module_version_string)),
|
||||||
|
env.Run(version_info_builder),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# Generate version hash
|
# Generate version hash
|
||||||
def version_hash_builder(target, source, env):
|
def version_hash_builder(target, source, env):
|
||||||
with methods.generated_wrapper(target) as file:
|
with methods.generated_wrapper(str(target[0])) as file:
|
||||||
file.write(
|
file.write(
|
||||||
"""\
|
"""\
|
||||||
#include "core/version.h"
|
#include "core/version.h"
|
||||||
|
|
||||||
const char *const VERSION_HASH = "{git_hash}";
|
const char *const VERSION_HASH = "{git_hash}";
|
||||||
const uint64_t VERSION_TIMESTAMP = {git_timestamp};
|
const uint64_t VERSION_TIMESTAMP = {git_timestamp};
|
||||||
""".format(**env.version_info)
|
""".format(**source[0].read())
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
gen_hash = env.CommandNoCache(
|
gen_hash = env.CommandNoCache("version_hash.gen.cpp", env.Value(methods.get_git_info()), env.Run(version_hash_builder))
|
||||||
"version_hash.gen.cpp", env.Value(env.version_info["git_hash"]), env.Run(version_hash_builder)
|
|
||||||
)
|
|
||||||
env.add_source_files(env.core_sources, gen_hash)
|
env.add_source_files(env.core_sources, gen_hash)
|
||||||
|
|
||||||
|
|
||||||
# Generate AES256 script encryption key
|
# Generate AES256 script encryption key
|
||||||
def encryption_key_builder(target, source, env):
|
def encryption_key_builder(target, source, env):
|
||||||
with methods.generated_wrapper(target) as file:
|
with methods.generated_wrapper(str(target[0])) as file:
|
||||||
file.write(
|
file.write(
|
||||||
f"""\
|
f"""\
|
||||||
#include "core/config/project_settings.h"
|
#include "core/config/project_settings.h"
|
||||||
@ -251,30 +252,21 @@ env.add_source_files(env.core_sources, gen_encrypt)
|
|||||||
|
|
||||||
|
|
||||||
# Certificates
|
# Certificates
|
||||||
env.Depends(
|
|
||||||
"#core/io/certs_compressed.gen.h",
|
|
||||||
["#thirdparty/certs/ca-certificates.crt", env.Value(env["builtin_certs"]), env.Value(env["system_certs_path"])],
|
|
||||||
)
|
|
||||||
env.CommandNoCache(
|
env.CommandNoCache(
|
||||||
"#core/io/certs_compressed.gen.h",
|
"#core/io/certs_compressed.gen.h",
|
||||||
"#thirdparty/certs/ca-certificates.crt",
|
["#thirdparty/certs/ca-certificates.crt", env.Value(env["builtin_certs"]), env.Value(env["system_certs_path"])],
|
||||||
env.Run(core_builders.make_certs_header),
|
env.Run(core_builders.make_certs_header),
|
||||||
)
|
)
|
||||||
|
|
||||||
# Authors
|
# Authors
|
||||||
env.Depends("#core/authors.gen.h", "../AUTHORS.md")
|
env.CommandNoCache("#core/authors.gen.h", "#AUTHORS.md", env.Run(core_builders.make_authors_header))
|
||||||
env.CommandNoCache("#core/authors.gen.h", "../AUTHORS.md", env.Run(core_builders.make_authors_header))
|
|
||||||
|
|
||||||
# Donors
|
# Donors
|
||||||
env.Depends("#core/donors.gen.h", "../DONORS.md")
|
env.CommandNoCache("#core/donors.gen.h", "#DONORS.md", env.Run(core_builders.make_donors_header))
|
||||||
env.CommandNoCache("#core/donors.gen.h", "../DONORS.md", env.Run(core_builders.make_donors_header))
|
|
||||||
|
|
||||||
# License
|
# License
|
||||||
env.Depends("#core/license.gen.h", ["../COPYRIGHT.txt", "../LICENSE.txt"])
|
|
||||||
env.CommandNoCache(
|
env.CommandNoCache(
|
||||||
"#core/license.gen.h",
|
"#core/license.gen.h", ["#COPYRIGHT.txt", "#LICENSE.txt"], env.Run(core_builders.make_license_header)
|
||||||
["../COPYRIGHT.txt", "../LICENSE.txt"],
|
|
||||||
env.Run(core_builders.make_license_header),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Chain load SCsubs
|
# Chain load SCsubs
|
||||||
|
@ -1,171 +1,104 @@
|
|||||||
"""Functions used to generate source files during build time"""
|
"""Functions used to generate source files during build time"""
|
||||||
|
|
||||||
import zlib
|
from collections import OrderedDict
|
||||||
|
from io import TextIOWrapper
|
||||||
|
|
||||||
|
import methods
|
||||||
def escape_string(s):
|
|
||||||
def charcode_to_c_escapes(c):
|
|
||||||
rev_result = []
|
|
||||||
while c >= 256:
|
|
||||||
c, low = (c // 256, c % 256)
|
|
||||||
rev_result.append("\\%03o" % low)
|
|
||||||
rev_result.append("\\%03o" % c)
|
|
||||||
return "".join(reversed(rev_result))
|
|
||||||
|
|
||||||
result = ""
|
|
||||||
if isinstance(s, str):
|
|
||||||
s = s.encode("utf-8")
|
|
||||||
for c in s:
|
|
||||||
if not (32 <= c < 127) or c in (ord("\\"), ord('"')):
|
|
||||||
result += charcode_to_c_escapes(c)
|
|
||||||
else:
|
|
||||||
result += chr(c)
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def make_certs_header(target, source, env):
|
def make_certs_header(target, source, env):
|
||||||
src = str(source[0])
|
buffer = methods.get_buffer(str(source[0]))
|
||||||
dst = str(target[0])
|
decomp_size = len(buffer)
|
||||||
with open(src, "rb") as f, open(dst, "w", encoding="utf-8", newline="\n") as g:
|
buffer = methods.compress_buffer(buffer)
|
||||||
buf = f.read()
|
|
||||||
decomp_size = len(buf)
|
|
||||||
|
|
||||||
# Use maximum zlib compression level to further reduce file size
|
|
||||||
# (at the cost of initial build times).
|
|
||||||
buf = zlib.compress(buf, zlib.Z_BEST_COMPRESSION)
|
|
||||||
|
|
||||||
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
|
|
||||||
g.write("#ifndef CERTS_COMPRESSED_GEN_H\n")
|
|
||||||
g.write("#define CERTS_COMPRESSED_GEN_H\n")
|
|
||||||
|
|
||||||
|
with methods.generated_wrapper(str(target[0])) as file:
|
||||||
# System certs path. Editor will use them if defined. (for package maintainers)
|
# System certs path. Editor will use them if defined. (for package maintainers)
|
||||||
path = env["system_certs_path"]
|
file.write('#define _SYSTEM_CERTS_PATH "{}"\n'.format(env["system_certs_path"]))
|
||||||
g.write('#define _SYSTEM_CERTS_PATH "%s"\n' % str(path))
|
|
||||||
if env["builtin_certs"]:
|
if env["builtin_certs"]:
|
||||||
# Defined here and not in env so changing it does not trigger a full rebuild.
|
# Defined here and not in env so changing it does not trigger a full rebuild.
|
||||||
g.write("#define BUILTIN_CERTS_ENABLED\n")
|
file.write(f"""\
|
||||||
g.write("static const int _certs_compressed_size = " + str(len(buf)) + ";\n")
|
#define BUILTIN_CERTS_ENABLED
|
||||||
g.write("static const int _certs_uncompressed_size = " + str(decomp_size) + ";\n")
|
|
||||||
g.write("static const unsigned char _certs_compressed[] = {\n")
|
inline constexpr int _certs_compressed_size = {len(buffer)};
|
||||||
for i in range(len(buf)):
|
inline constexpr int _certs_uncompressed_size = {decomp_size};
|
||||||
g.write("\t" + str(buf[i]) + ",\n")
|
inline constexpr unsigned char _certs_compressed[] = {{
|
||||||
g.write("};\n")
|
{methods.format_buffer(buffer, 1)}
|
||||||
g.write("#endif // CERTS_COMPRESSED_GEN_H")
|
}};
|
||||||
|
""")
|
||||||
|
|
||||||
|
|
||||||
def make_authors_header(target, source, env):
|
def make_authors_header(target, source, env):
|
||||||
sections = [
|
SECTIONS = {
|
||||||
"Project Founders",
|
"Project Founders": "AUTHORS_FOUNDERS",
|
||||||
"Lead Developer",
|
"Lead Developer": "AUTHORS_LEAD_DEVELOPERS",
|
||||||
"Project Manager",
|
"Project Manager": "AUTHORS_PROJECT_MANAGERS",
|
||||||
"Developers",
|
"Developers": "AUTHORS_DEVELOPERS",
|
||||||
]
|
}
|
||||||
sections_id = [
|
buffer = methods.get_buffer(str(source[0]))
|
||||||
"AUTHORS_FOUNDERS",
|
reading = False
|
||||||
"AUTHORS_LEAD_DEVELOPERS",
|
|
||||||
"AUTHORS_PROJECT_MANAGERS",
|
|
||||||
"AUTHORS_DEVELOPERS",
|
|
||||||
]
|
|
||||||
|
|
||||||
src = str(source[0])
|
with methods.generated_wrapper(str(target[0])) as file:
|
||||||
dst = str(target[0])
|
|
||||||
with open(src, "r", encoding="utf-8") as f, open(dst, "w", encoding="utf-8", newline="\n") as g:
|
|
||||||
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
|
|
||||||
g.write("#ifndef AUTHORS_GEN_H\n")
|
|
||||||
g.write("#define AUTHORS_GEN_H\n")
|
|
||||||
|
|
||||||
reading = False
|
|
||||||
|
|
||||||
def close_section():
|
def close_section():
|
||||||
g.write("\t0\n")
|
file.write("\tnullptr,\n};\n\n")
|
||||||
g.write("};\n")
|
|
||||||
|
|
||||||
for line in f:
|
for line in buffer.decode().splitlines():
|
||||||
if reading:
|
if line.startswith(" ") and reading:
|
||||||
if line.startswith(" "):
|
file.write(f'\t"{methods.to_escaped_cstring(line).strip()}",\n')
|
||||||
g.write('\t"' + escape_string(line.strip()) + '",\n')
|
elif line.startswith("## "):
|
||||||
continue
|
|
||||||
if line.startswith("## "):
|
|
||||||
if reading:
|
if reading:
|
||||||
close_section()
|
close_section()
|
||||||
reading = False
|
reading = False
|
||||||
for section, section_id in zip(sections, sections_id):
|
section = SECTIONS[line[3:].strip()]
|
||||||
if line.strip().endswith(section):
|
if section:
|
||||||
current_section = escape_string(section_id)
|
file.write(f"inline constexpr const char *{section}[] = {{\n")
|
||||||
reading = True
|
reading = True
|
||||||
g.write("const char *const " + current_section + "[] = {\n")
|
|
||||||
break
|
|
||||||
|
|
||||||
if reading:
|
if reading:
|
||||||
close_section()
|
close_section()
|
||||||
|
|
||||||
g.write("#endif // AUTHORS_GEN_H\n")
|
|
||||||
|
|
||||||
|
|
||||||
def make_donors_header(target, source, env):
|
def make_donors_header(target, source, env):
|
||||||
sections = [
|
SECTIONS = {
|
||||||
"Patrons",
|
"Patrons": "DONORS_PATRONS",
|
||||||
"Platinum sponsors",
|
"Platinum sponsors": "DONORS_SPONSORS_PLATINUM",
|
||||||
"Gold sponsors",
|
"Gold sponsors": "DONORS_SPONSORS_GOLD",
|
||||||
"Silver sponsors",
|
"Silver sponsors": "DONORS_SPONSORS_SILVER",
|
||||||
"Diamond members",
|
"Diamond members": "DONORS_MEMBERS_DIAMOND",
|
||||||
"Titanium members",
|
"Titanium members": "DONORS_MEMBERS_TITANIUM",
|
||||||
"Platinum members",
|
"Platinum members": "DONORS_MEMBERS_PLATINUM",
|
||||||
"Gold members",
|
"Gold members": "DONORS_MEMBERS_GOLD",
|
||||||
]
|
}
|
||||||
sections_id = [
|
buffer = methods.get_buffer(str(source[0]))
|
||||||
"DONORS_PATRONS",
|
reading = False
|
||||||
"DONORS_SPONSORS_PLATINUM",
|
|
||||||
"DONORS_SPONSORS_GOLD",
|
|
||||||
"DONORS_SPONSORS_SILVER",
|
|
||||||
"DONORS_MEMBERS_DIAMOND",
|
|
||||||
"DONORS_MEMBERS_TITANIUM",
|
|
||||||
"DONORS_MEMBERS_PLATINUM",
|
|
||||||
"DONORS_MEMBERS_GOLD",
|
|
||||||
]
|
|
||||||
|
|
||||||
src = str(source[0])
|
with methods.generated_wrapper(str(target[0])) as file:
|
||||||
dst = str(target[0])
|
|
||||||
with open(src, "r", encoding="utf-8") as f, open(dst, "w", encoding="utf-8", newline="\n") as g:
|
|
||||||
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
|
|
||||||
g.write("#ifndef DONORS_GEN_H\n")
|
|
||||||
g.write("#define DONORS_GEN_H\n")
|
|
||||||
|
|
||||||
reading = False
|
|
||||||
|
|
||||||
def close_section():
|
def close_section():
|
||||||
g.write("\t0\n")
|
file.write("\tnullptr,\n};\n\n")
|
||||||
g.write("};\n")
|
|
||||||
|
|
||||||
for line in f:
|
for line in buffer.decode().splitlines():
|
||||||
if reading >= 0:
|
if line.startswith(" ") and reading:
|
||||||
if line.startswith(" "):
|
file.write(f'\t"{methods.to_escaped_cstring(line).strip()}",\n')
|
||||||
g.write('\t"' + escape_string(line.strip()) + '",\n')
|
elif line.startswith("## "):
|
||||||
continue
|
|
||||||
if line.startswith("## "):
|
|
||||||
if reading:
|
if reading:
|
||||||
close_section()
|
close_section()
|
||||||
reading = False
|
reading = False
|
||||||
for section, section_id in zip(sections, sections_id):
|
section = SECTIONS.get(line[3:].strip())
|
||||||
if line.strip().endswith(section):
|
if section:
|
||||||
current_section = escape_string(section_id)
|
file.write(f"inline constexpr const char *{section}[] = {{\n")
|
||||||
reading = True
|
reading = True
|
||||||
g.write("const char *const " + current_section + "[] = {\n")
|
|
||||||
break
|
|
||||||
|
|
||||||
if reading:
|
if reading:
|
||||||
close_section()
|
close_section()
|
||||||
|
|
||||||
g.write("#endif // DONORS_GEN_H\n")
|
|
||||||
|
|
||||||
|
|
||||||
def make_license_header(target, source, env):
|
def make_license_header(target, source, env):
|
||||||
src_copyright = str(source[0])
|
src_copyright = str(source[0])
|
||||||
src_license = str(source[1])
|
src_license = str(source[1])
|
||||||
dst = str(target[0])
|
|
||||||
|
|
||||||
class LicenseReader:
|
class LicenseReader:
|
||||||
def __init__(self, license_file):
|
def __init__(self, license_file: TextIOWrapper):
|
||||||
self._license_file = license_file
|
self._license_file = license_file
|
||||||
self.line_num = 0
|
self.line_num = 0
|
||||||
self.current = self.next_line()
|
self.current = self.next_line()
|
||||||
@ -188,9 +121,7 @@ def make_license_header(target, source, env):
|
|||||||
lines.append(self.current.strip())
|
lines.append(self.current.strip())
|
||||||
return (tag, lines)
|
return (tag, lines)
|
||||||
|
|
||||||
from collections import OrderedDict
|
projects = OrderedDict()
|
||||||
|
|
||||||
projects: dict = OrderedDict()
|
|
||||||
license_list = []
|
license_list = []
|
||||||
|
|
||||||
with open(src_copyright, "r", encoding="utf-8") as copyright_file:
|
with open(src_copyright, "r", encoding="utf-8") as copyright_file:
|
||||||
@ -212,7 +143,7 @@ def make_license_header(target, source, env):
|
|||||||
part = {}
|
part = {}
|
||||||
reader.next_line()
|
reader.next_line()
|
||||||
|
|
||||||
data_list: list = []
|
data_list = []
|
||||||
for project in iter(projects.values()):
|
for project in iter(projects.values()):
|
||||||
for part in project:
|
for part in project:
|
||||||
part["file_index"] = len(data_list)
|
part["file_index"] = len(data_list)
|
||||||
@ -220,96 +151,76 @@ def make_license_header(target, source, env):
|
|||||||
part["copyright_index"] = len(data_list)
|
part["copyright_index"] = len(data_list)
|
||||||
data_list += part["Copyright"]
|
data_list += part["Copyright"]
|
||||||
|
|
||||||
with open(dst, "w", encoding="utf-8", newline="\n") as f:
|
with open(src_license, "r", encoding="utf-8") as file:
|
||||||
f.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
|
license_text = file.read()
|
||||||
f.write("#ifndef LICENSE_GEN_H\n")
|
|
||||||
f.write("#define LICENSE_GEN_H\n")
|
|
||||||
f.write("const char *const GODOT_LICENSE_TEXT =")
|
|
||||||
|
|
||||||
with open(src_license, "r", encoding="utf-8") as license_file:
|
with methods.generated_wrapper(str(target[0])) as file:
|
||||||
for line in license_file:
|
file.write(f"""\
|
||||||
escaped_string = escape_string(line.strip())
|
inline constexpr const char *GODOT_LICENSE_TEXT = {{
|
||||||
f.write('\n\t\t"' + escaped_string + '\\n"')
|
{methods.to_raw_cstring(license_text)}
|
||||||
f.write(";\n\n")
|
}};
|
||||||
|
|
||||||
f.write(
|
struct ComponentCopyrightPart {{
|
||||||
"struct ComponentCopyrightPart {\n"
|
const char *license;
|
||||||
"\tconst char *license;\n"
|
const char *const *files;
|
||||||
"\tconst char *const *files;\n"
|
const char *const *copyright_statements;
|
||||||
"\tconst char *const *copyright_statements;\n"
|
int file_count;
|
||||||
"\tint file_count;\n"
|
int copyright_count;
|
||||||
"\tint copyright_count;\n"
|
}};
|
||||||
"};\n\n"
|
|
||||||
)
|
|
||||||
|
|
||||||
f.write(
|
struct ComponentCopyright {{
|
||||||
"struct ComponentCopyright {\n"
|
const char *name;
|
||||||
"\tconst char *name;\n"
|
const ComponentCopyrightPart *parts;
|
||||||
"\tconst ComponentCopyrightPart *parts;\n"
|
int part_count;
|
||||||
"\tint part_count;\n"
|
}};
|
||||||
"};\n\n"
|
|
||||||
)
|
|
||||||
|
|
||||||
f.write("const char *const COPYRIGHT_INFO_DATA[] = {\n")
|
""")
|
||||||
|
|
||||||
|
file.write("inline constexpr const char *COPYRIGHT_INFO_DATA[] = {\n")
|
||||||
for line in data_list:
|
for line in data_list:
|
||||||
f.write('\t"' + escape_string(line) + '",\n')
|
file.write(f'\t"{methods.to_escaped_cstring(line)}",\n')
|
||||||
f.write("};\n\n")
|
file.write("};\n\n")
|
||||||
|
|
||||||
f.write("const ComponentCopyrightPart COPYRIGHT_PROJECT_PARTS[] = {\n")
|
file.write("inline constexpr ComponentCopyrightPart COPYRIGHT_PROJECT_PARTS[] = {\n")
|
||||||
part_index = 0
|
part_index = 0
|
||||||
part_indexes = {}
|
part_indexes = {}
|
||||||
for project_name, project in iter(projects.items()):
|
for project_name, project in iter(projects.items()):
|
||||||
part_indexes[project_name] = part_index
|
part_indexes[project_name] = part_index
|
||||||
for part in project:
|
for part in project:
|
||||||
f.write(
|
file.write(
|
||||||
'\t{ "'
|
f'\t{{ "{methods.to_escaped_cstring(part["License"][0])}", '
|
||||||
+ escape_string(part["License"][0])
|
+ f"©RIGHT_INFO_DATA[{part['file_index']}], "
|
||||||
+ '", '
|
+ f"©RIGHT_INFO_DATA[{part['copyright_index']}], "
|
||||||
+ "©RIGHT_INFO_DATA["
|
+ f"{len(part['Files'])}, {len(part['Copyright'])} }},\n"
|
||||||
+ str(part["file_index"])
|
|
||||||
+ "], "
|
|
||||||
+ "©RIGHT_INFO_DATA["
|
|
||||||
+ str(part["copyright_index"])
|
|
||||||
+ "], "
|
|
||||||
+ str(len(part["Files"]))
|
|
||||||
+ ", "
|
|
||||||
+ str(len(part["Copyright"]))
|
|
||||||
+ " },\n"
|
|
||||||
)
|
)
|
||||||
part_index += 1
|
part_index += 1
|
||||||
f.write("};\n\n")
|
file.write("};\n\n")
|
||||||
|
|
||||||
f.write("const int COPYRIGHT_INFO_COUNT = " + str(len(projects)) + ";\n")
|
file.write(f"inline constexpr int COPYRIGHT_INFO_COUNT = {len(projects)};\n")
|
||||||
|
|
||||||
f.write("const ComponentCopyright COPYRIGHT_INFO[] = {\n")
|
file.write("inline constexpr ComponentCopyright COPYRIGHT_INFO[] = {\n")
|
||||||
for project_name, project in iter(projects.items()):
|
for project_name, project in iter(projects.items()):
|
||||||
f.write(
|
file.write(
|
||||||
'\t{ "'
|
f'\t{{ "{methods.to_escaped_cstring(project_name)}", '
|
||||||
+ escape_string(project_name)
|
+ f"©RIGHT_PROJECT_PARTS[{part_indexes[project_name]}], "
|
||||||
+ '", '
|
+ f"{len(project)} }},\n"
|
||||||
+ "©RIGHT_PROJECT_PARTS["
|
|
||||||
+ str(part_indexes[project_name])
|
|
||||||
+ "], "
|
|
||||||
+ str(len(project))
|
|
||||||
+ " },\n"
|
|
||||||
)
|
)
|
||||||
f.write("};\n\n")
|
file.write("};\n\n")
|
||||||
|
|
||||||
f.write("const int LICENSE_COUNT = " + str(len(license_list)) + ";\n")
|
file.write(f"inline constexpr int LICENSE_COUNT = {len(license_list)};\n")
|
||||||
|
|
||||||
f.write("const char *const LICENSE_NAMES[] = {\n")
|
file.write("inline constexpr const char *LICENSE_NAMES[] = {\n")
|
||||||
for license in license_list:
|
for license in license_list:
|
||||||
f.write('\t"' + escape_string(license[0]) + '",\n')
|
file.write(f'\t"{methods.to_escaped_cstring(license[0])}",\n')
|
||||||
f.write("};\n\n")
|
file.write("};\n\n")
|
||||||
|
|
||||||
f.write("const char *const LICENSE_BODIES[] = {\n\n")
|
file.write("inline constexpr const char *LICENSE_BODIES[] = {\n\n")
|
||||||
for license in license_list:
|
for license in license_list:
|
||||||
|
to_raw = []
|
||||||
for line in license[1:]:
|
for line in license[1:]:
|
||||||
if line == ".":
|
if line == ".":
|
||||||
f.write('\t"\\n"\n')
|
to_raw += [""]
|
||||||
else:
|
else:
|
||||||
f.write('\t"' + escape_string(line) + '\\n"\n')
|
to_raw += [line]
|
||||||
f.write('\t"",\n\n')
|
file.write(f"{methods.to_raw_cstring(to_raw)},\n\n")
|
||||||
f.write("};\n\n")
|
file.write("};\n\n")
|
||||||
|
|
||||||
f.write("#endif // LICENSE_GEN_H\n")
|
|
||||||
|
@ -1,52 +1,37 @@
|
|||||||
import zlib
|
import methods
|
||||||
|
|
||||||
|
|
||||||
def run(target, source, env):
|
def run(target, source, env):
|
||||||
src = str(source[0])
|
buffer = methods.get_buffer(str(source[0]))
|
||||||
dst = str(target[0])
|
decomp_size = len(buffer)
|
||||||
with open(src, "rb") as f, open(dst, "w", encoding="utf-8", newline="\n") as g:
|
buffer = methods.compress_buffer(buffer)
|
||||||
buf = f.read()
|
|
||||||
decomp_size = len(buf)
|
|
||||||
|
|
||||||
# Use maximum zlib compression level to further reduce file size
|
|
||||||
# (at the cost of initial build times).
|
|
||||||
buf = zlib.compress(buf, zlib.Z_BEST_COMPRESSION)
|
|
||||||
|
|
||||||
g.write(
|
|
||||||
"""/* THIS FILE IS GENERATED DO NOT EDIT */
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
|
with methods.generated_wrapper(str(target[0])) as file:
|
||||||
|
file.write(f"""\
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
|
|
||||||
#include "core/io/compression.h"
|
#include "core/io/compression.h"
|
||||||
#include "core/io/file_access.h"
|
#include "core/io/file_access.h"
|
||||||
#include "core/string/ustring.h"
|
#include "core/string/ustring.h"
|
||||||
|
|
||||||
"""
|
inline constexpr int _gdextension_interface_data_compressed_size = {len(buffer)};
|
||||||
)
|
inline constexpr int _gdextension_interface_data_uncompressed_size = {decomp_size};
|
||||||
|
inline constexpr unsigned char _gdextension_interface_data_compressed[] = {{
|
||||||
|
{methods.format_buffer(buffer, 1)}
|
||||||
|
}};
|
||||||
|
|
||||||
g.write("static const int _gdextension_interface_data_compressed_size = " + str(len(buf)) + ";\n")
|
class GDExtensionInterfaceDump {{
|
||||||
g.write("static const int _gdextension_interface_data_uncompressed_size = " + str(decomp_size) + ";\n")
|
public:
|
||||||
g.write("static const unsigned char _gdextension_interface_data_compressed[] = {\n")
|
static void generate_gdextension_interface_file(const String &p_path) {{
|
||||||
for i in range(len(buf)):
|
Ref<FileAccess> fa = FileAccess::open(p_path, FileAccess::WRITE);
|
||||||
g.write("\t" + str(buf[i]) + ",\n")
|
ERR_FAIL_COND_MSG(fa.is_null(), vformat("Cannot open file '%s' for writing.", p_path));
|
||||||
g.write("};\n")
|
Vector<uint8_t> data;
|
||||||
|
data.resize(_gdextension_interface_data_uncompressed_size);
|
||||||
g.write(
|
int ret = Compression::decompress(data.ptrw(), _gdextension_interface_data_uncompressed_size, _gdextension_interface_data_compressed, _gdextension_interface_data_compressed_size, Compression::MODE_DEFLATE);
|
||||||
"""
|
ERR_FAIL_COND_MSG(ret == -1, "Compressed file is corrupt.");
|
||||||
class GDExtensionInterfaceDump {
|
fa->store_buffer(data.ptr(), data.size());
|
||||||
public:
|
}};
|
||||||
static void generate_gdextension_interface_file(const String &p_path) {
|
}};
|
||||||
Ref<FileAccess> fa = FileAccess::open(p_path, FileAccess::WRITE);
|
|
||||||
ERR_FAIL_COND_MSG(fa.is_null(), vformat("Cannot open file '%s' for writing.", p_path));
|
|
||||||
Vector<uint8_t> data;
|
|
||||||
data.resize(_gdextension_interface_data_uncompressed_size);
|
|
||||||
int ret = Compression::decompress(data.ptrw(), _gdextension_interface_data_uncompressed_size, _gdextension_interface_data_compressed, _gdextension_interface_data_compressed_size, Compression::MODE_DEFLATE);
|
|
||||||
ERR_FAIL_COND_MSG(ret == -1, "Compressed file is corrupt.");
|
|
||||||
fa->store_buffer(data.ptr(), data.size());
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // TOOLS_ENABLED
|
#endif // TOOLS_ENABLED
|
||||||
"""
|
""")
|
||||||
)
|
|
||||||
|
@ -2,18 +2,22 @@
|
|||||||
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
|
import methods
|
||||||
|
|
||||||
|
|
||||||
def make_default_controller_mappings(target, source, env):
|
def make_default_controller_mappings(target, source, env):
|
||||||
dst = str(target[0])
|
with methods.generated_wrapper(str(target[0])) as file:
|
||||||
with open(dst, "w", encoding="utf-8", newline="\n") as g:
|
file.write("""\
|
||||||
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
|
#include "core/input/default_controller_mappings.h"
|
||||||
g.write('#include "core/typedefs.h"\n')
|
|
||||||
g.write('#include "core/input/default_controller_mappings.h"\n')
|
#include "core/typedefs.h"
|
||||||
|
|
||||||
|
""")
|
||||||
|
|
||||||
# ensure mappings have a consistent order
|
# ensure mappings have a consistent order
|
||||||
platform_mappings: dict = OrderedDict()
|
platform_mappings = OrderedDict()
|
||||||
for src_path in source:
|
for src_path in map(str, source):
|
||||||
with open(str(src_path), "r", encoding="utf-8") as f:
|
with open(src_path, "r", encoding="utf-8") as f:
|
||||||
# read mapping file and skip header
|
# read mapping file and skip header
|
||||||
mapping_file_lines = f.readlines()[2:]
|
mapping_file_lines = f.readlines()[2:]
|
||||||
|
|
||||||
@ -32,28 +36,28 @@ def make_default_controller_mappings(target, source, env):
|
|||||||
line_parts = line.split(",")
|
line_parts = line.split(",")
|
||||||
guid = line_parts[0]
|
guid = line_parts[0]
|
||||||
if guid in platform_mappings[current_platform]:
|
if guid in platform_mappings[current_platform]:
|
||||||
g.write(
|
file.write(
|
||||||
"// WARNING: DATABASE {} OVERWROTE PRIOR MAPPING: {} {}\n".format(
|
"// WARNING: DATABASE {} OVERWROTE PRIOR MAPPING: {} {}\n".format(
|
||||||
src_path, current_platform, platform_mappings[current_platform][guid]
|
src_path, current_platform, platform_mappings[current_platform][guid]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
platform_mappings[current_platform][guid] = line
|
platform_mappings[current_platform][guid] = line
|
||||||
|
|
||||||
platform_variables = {
|
PLATFORM_VARIABLES = {
|
||||||
"Linux": "#ifdef LINUXBSD_ENABLED",
|
"Linux": "LINUXBSD",
|
||||||
"Windows": "#ifdef WINDOWS_ENABLED",
|
"Windows": "WINDOWS",
|
||||||
"Mac OS X": "#ifdef MACOS_ENABLED",
|
"Mac OS X": "MACOS",
|
||||||
"Android": "#ifdef ANDROID_ENABLED",
|
"Android": "ANDROID",
|
||||||
"iOS": "#ifdef IOS_ENABLED",
|
"iOS": "IOS",
|
||||||
"Web": "#ifdef WEB_ENABLED",
|
"Web": "WEB",
|
||||||
}
|
}
|
||||||
|
|
||||||
g.write("const char* DefaultControllerMappings::mappings[] = {\n")
|
file.write("const char *DefaultControllerMappings::mappings[] = {\n")
|
||||||
for platform, mappings in platform_mappings.items():
|
for platform, mappings in platform_mappings.items():
|
||||||
variable = platform_variables[platform]
|
variable = PLATFORM_VARIABLES[platform]
|
||||||
g.write("{}\n".format(variable))
|
file.write(f"#ifdef {variable}_ENABLED\n")
|
||||||
for mapping in mappings.values():
|
for mapping in mappings.values():
|
||||||
g.write('\t"{}",\n'.format(mapping))
|
file.write(f'\t"{mapping}",\n')
|
||||||
g.write("#endif\n")
|
file.write(f"#endif // {variable}_ENABLED\n")
|
||||||
|
|
||||||
g.write("\tnullptr\n};\n")
|
file.write("\tnullptr\n};\n")
|
||||||
|
36
editor/SCsub
36
editor/SCsub
@ -5,7 +5,6 @@ Import("env")
|
|||||||
|
|
||||||
env.editor_sources = []
|
env.editor_sources = []
|
||||||
|
|
||||||
import glob
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import editor_builders
|
import editor_builders
|
||||||
@ -17,17 +16,16 @@ if env.editor_build:
|
|||||||
def doc_data_class_path_builder(target, source, env):
|
def doc_data_class_path_builder(target, source, env):
|
||||||
paths = dict(sorted(source[0].read().items()))
|
paths = dict(sorted(source[0].read().items()))
|
||||||
data = "\n".join([f'\t{{"{key}", "{value}"}},' for key, value in paths.items()])
|
data = "\n".join([f'\t{{"{key}", "{value}"}},' for key, value in paths.items()])
|
||||||
with methods.generated_wrapper(target) as file:
|
with methods.generated_wrapper(str(target[0])) as file:
|
||||||
file.write(
|
file.write(
|
||||||
f"""\
|
f"""\
|
||||||
static const int _doc_data_class_path_count = {len(paths)};
|
|
||||||
|
|
||||||
struct _DocDataClassPath {{
|
struct _DocDataClassPath {{
|
||||||
const char *name;
|
const char *name;
|
||||||
const char *path;
|
const char *path;
|
||||||
}};
|
}};
|
||||||
|
|
||||||
static const _DocDataClassPath _doc_data_class_paths[{len(env.doc_class_path) + 1}] = {{
|
inline constexpr int _doc_data_class_path_count = {len(paths)};
|
||||||
|
inline constexpr _DocDataClassPath _doc_data_class_paths[{len(env.doc_class_path) + 1}] = {{
|
||||||
{data}
|
{data}
|
||||||
{{nullptr, nullptr}},
|
{{nullptr, nullptr}},
|
||||||
}};
|
}};
|
||||||
@ -42,7 +40,7 @@ static const _DocDataClassPath _doc_data_class_paths[{len(env.doc_class_path) +
|
|||||||
exp_inc = "\n".join([f'#include "platform/{p}/export/export.h"' for p in platforms])
|
exp_inc = "\n".join([f'#include "platform/{p}/export/export.h"' for p in platforms])
|
||||||
exp_reg = "\n".join([f"\tregister_{p}_exporter();" for p in platforms])
|
exp_reg = "\n".join([f"\tregister_{p}_exporter();" for p in platforms])
|
||||||
exp_type = "\n".join([f"\tregister_{p}_exporter_types();" for p in platforms])
|
exp_type = "\n".join([f"\tregister_{p}_exporter_types();" for p in platforms])
|
||||||
with methods.generated_wrapper(target) as file:
|
with methods.generated_wrapper(str(target[0])) as file:
|
||||||
file.write(
|
file.write(
|
||||||
f"""\
|
f"""\
|
||||||
#include "register_exporters.h"
|
#include "register_exporters.h"
|
||||||
@ -83,7 +81,6 @@ void register_exporter_types() {{
|
|||||||
docs += Glob(d + "/*.xml") # Custom.
|
docs += Glob(d + "/*.xml") # Custom.
|
||||||
|
|
||||||
docs = sorted(docs)
|
docs = sorted(docs)
|
||||||
env.Depends("#editor/doc_data_compressed.gen.h", docs)
|
|
||||||
env.CommandNoCache(
|
env.CommandNoCache(
|
||||||
"#editor/doc_data_compressed.gen.h",
|
"#editor/doc_data_compressed.gen.h",
|
||||||
docs,
|
docs,
|
||||||
@ -97,40 +94,31 @@ void register_exporter_types() {{
|
|||||||
# Generated with `make include-list` for each resource.
|
# Generated with `make include-list` for each resource.
|
||||||
|
|
||||||
# Editor translations
|
# Editor translations
|
||||||
tlist = glob.glob(env.Dir("#editor/translations/editor").abspath + "/*.po")
|
|
||||||
env.Depends("#editor/editor_translations.gen.h", tlist)
|
|
||||||
env.CommandNoCache(
|
env.CommandNoCache(
|
||||||
"#editor/editor_translations.gen.h",
|
"#editor/editor_translations.gen.h",
|
||||||
tlist,
|
Glob("#editor/translations/editor/*"),
|
||||||
env.Run(editor_builders.make_editor_translations_header),
|
env.Run(editor_builders.make_translations_header),
|
||||||
)
|
)
|
||||||
|
|
||||||
# Property translations
|
# Property translations
|
||||||
tlist = glob.glob(env.Dir("#editor/translations/properties").abspath + "/*.po")
|
|
||||||
env.Depends("#editor/property_translations.gen.h", tlist)
|
|
||||||
env.CommandNoCache(
|
env.CommandNoCache(
|
||||||
"#editor/property_translations.gen.h",
|
"#editor/property_translations.gen.h",
|
||||||
tlist,
|
Glob("#editor/translations/properties/*"),
|
||||||
env.Run(editor_builders.make_property_translations_header),
|
env.Run(editor_builders.make_translations_header),
|
||||||
)
|
)
|
||||||
|
|
||||||
# Documentation translations
|
# Documentation translations
|
||||||
tlist = glob.glob(env.Dir("#doc/translations").abspath + "/*.po")
|
|
||||||
env.Depends("#editor/doc_translations.gen.h", tlist)
|
|
||||||
env.CommandNoCache(
|
env.CommandNoCache(
|
||||||
"#editor/doc_translations.gen.h",
|
"#editor/doc_translations.gen.h",
|
||||||
tlist,
|
Glob("#doc/translations/*"),
|
||||||
env.Run(editor_builders.make_doc_translations_header),
|
env.Run(editor_builders.make_translations_header),
|
||||||
)
|
)
|
||||||
|
|
||||||
# Extractable translations
|
# Extractable translations
|
||||||
tlist = glob.glob(env.Dir("#editor/translations/extractable").abspath + "/*.po")
|
|
||||||
tlist.extend(glob.glob(env.Dir("#editor/translations/extractable").abspath + "/extractable.pot"))
|
|
||||||
env.Depends("#editor/extractable_translations.gen.h", tlist)
|
|
||||||
env.CommandNoCache(
|
env.CommandNoCache(
|
||||||
"#editor/extractable_translations.gen.h",
|
"#editor/extractable_translations.gen.h",
|
||||||
tlist,
|
Glob("#editor/translations/extractable/*"),
|
||||||
env.Run(editor_builders.make_extractable_translations_header),
|
env.Run(editor_builders.make_translations_header),
|
||||||
)
|
)
|
||||||
|
|
||||||
env.add_source_files(env.editor_sources, "*.cpp")
|
env.add_source_files(env.editor_sources, "*.cpp")
|
||||||
|
@ -2,141 +2,95 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
import shutil
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import tempfile
|
import tempfile
|
||||||
import uuid
|
import uuid
|
||||||
import zlib
|
|
||||||
|
|
||||||
from methods import print_warning
|
import methods
|
||||||
|
|
||||||
|
|
||||||
def make_doc_header(target, source, env):
|
def make_doc_header(target, source, env):
|
||||||
dst = str(target[0])
|
buffer = b"".join([methods.get_buffer(src) for src in map(str, source)])
|
||||||
with open(dst, "w", encoding="utf-8", newline="\n") as g:
|
decomp_size = len(buffer)
|
||||||
buf = ""
|
buffer = methods.compress_buffer(buffer)
|
||||||
docbegin = ""
|
|
||||||
docend = ""
|
|
||||||
for src in source:
|
|
||||||
src = str(src)
|
|
||||||
if not src.endswith(".xml"):
|
|
||||||
continue
|
|
||||||
with open(src, "r", encoding="utf-8") as f:
|
|
||||||
content = f.read()
|
|
||||||
buf += content
|
|
||||||
|
|
||||||
buf = (docbegin + buf + docend).encode("utf-8")
|
with methods.generated_wrapper(str(target[0])) as file:
|
||||||
decomp_size = len(buf)
|
file.write(f"""\
|
||||||
|
inline constexpr const char *_doc_data_hash = "{hash(buffer)}";
|
||||||
# Use maximum zlib compression level to further reduce file size
|
inline constexpr int _doc_data_compressed_size = {len(buffer)};
|
||||||
# (at the cost of initial build times).
|
inline constexpr int _doc_data_uncompressed_size = {decomp_size};
|
||||||
buf = zlib.compress(buf, zlib.Z_BEST_COMPRESSION)
|
inline constexpr const unsigned char _doc_data_compressed[] = {{
|
||||||
|
{methods.format_buffer(buffer, 1)}
|
||||||
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
|
}};
|
||||||
g.write("#ifndef _DOC_DATA_RAW_H\n")
|
""")
|
||||||
g.write("#define _DOC_DATA_RAW_H\n")
|
|
||||||
g.write('static const char *_doc_data_hash = "' + str(hash(buf)) + '";\n')
|
|
||||||
g.write("static const int _doc_data_compressed_size = " + str(len(buf)) + ";\n")
|
|
||||||
g.write("static const int _doc_data_uncompressed_size = " + str(decomp_size) + ";\n")
|
|
||||||
g.write("static const unsigned char _doc_data_compressed[] = {\n")
|
|
||||||
for i in range(len(buf)):
|
|
||||||
g.write("\t" + str(buf[i]) + ",\n")
|
|
||||||
g.write("};\n")
|
|
||||||
|
|
||||||
g.write("#endif")
|
|
||||||
|
|
||||||
|
|
||||||
def make_translations_header(target, source, env, category):
|
def make_translations_header(target, source, env):
|
||||||
dst = str(target[0])
|
category = os.path.basename(str(target[0])).split("_")[0]
|
||||||
|
sorted_paths = sorted([src.abspath for src in source], key=lambda path: os.path.splitext(os.path.basename(path))[0])
|
||||||
|
|
||||||
with open(dst, "w", encoding="utf-8", newline="\n") as g:
|
xl_names = []
|
||||||
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
|
msgfmt = env.Detect("msgfmt")
|
||||||
g.write("#ifndef _{}_TRANSLATIONS_H\n".format(category.upper()))
|
if not msgfmt:
|
||||||
g.write("#define _{}_TRANSLATIONS_H\n".format(category.upper()))
|
methods.print_warning("msgfmt not found, using .po files instead of .mo")
|
||||||
|
|
||||||
sorted_paths = sorted([str(x) for x in source], key=lambda path: os.path.splitext(os.path.basename(path))[0])
|
with methods.generated_wrapper(str(target[0])) as file:
|
||||||
|
for path in sorted_paths:
|
||||||
msgfmt_available = shutil.which("msgfmt") is not None
|
name = os.path.splitext(os.path.basename(path))[0]
|
||||||
|
|
||||||
if not msgfmt_available:
|
|
||||||
print_warning("msgfmt is not found, using .po files instead of .mo")
|
|
||||||
|
|
||||||
xl_names = []
|
|
||||||
for i in range(len(sorted_paths)):
|
|
||||||
name = os.path.splitext(os.path.basename(sorted_paths[i]))[0]
|
|
||||||
# msgfmt erases non-translated messages, so avoid using it if exporting the POT.
|
# msgfmt erases non-translated messages, so avoid using it if exporting the POT.
|
||||||
if msgfmt_available and name != category:
|
if msgfmt and name != category:
|
||||||
mo_path = os.path.join(tempfile.gettempdir(), uuid.uuid4().hex + ".mo")
|
mo_path = os.path.join(tempfile.gettempdir(), uuid.uuid4().hex + ".mo")
|
||||||
cmd = "msgfmt " + sorted_paths[i] + " --no-hash -o " + mo_path
|
cmd = f"{msgfmt} {path} --no-hash -o {mo_path}"
|
||||||
try:
|
try:
|
||||||
subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE).communicate()
|
subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE).communicate()
|
||||||
with open(mo_path, "rb") as f:
|
buffer = methods.get_buffer(mo_path)
|
||||||
buf = f.read()
|
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
print_warning(
|
methods.print_warning(
|
||||||
"msgfmt execution failed, using .po file instead of .mo: path=%r; [%s] %s"
|
"msgfmt execution failed, using .po file instead of .mo: path=%r; [%s] %s"
|
||||||
% (sorted_paths[i], e.__class__.__name__, e)
|
% (path, e.__class__.__name__, e)
|
||||||
)
|
)
|
||||||
with open(sorted_paths[i], "rb") as f:
|
buffer = methods.get_buffer(path)
|
||||||
buf = f.read()
|
|
||||||
finally:
|
finally:
|
||||||
try:
|
try:
|
||||||
os.remove(mo_path)
|
if os.path.exists(mo_path):
|
||||||
|
os.remove(mo_path)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
# Do not fail the entire build if it cannot delete a temporary file.
|
# Do not fail the entire build if it cannot delete a temporary file.
|
||||||
print_warning(
|
methods.print_warning(
|
||||||
"Could not delete temporary .mo file: path=%r; [%s] %s" % (mo_path, e.__class__.__name__, e)
|
"Could not delete temporary .mo file: path=%r; [%s] %s" % (mo_path, e.__class__.__name__, e)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
with open(sorted_paths[i], "rb") as f:
|
buffer = methods.get_buffer(path)
|
||||||
buf = f.read()
|
|
||||||
|
|
||||||
if name == category:
|
if name == category:
|
||||||
name = "source"
|
name = "source"
|
||||||
|
|
||||||
decomp_size = len(buf)
|
decomp_size = len(buffer)
|
||||||
# Use maximum zlib compression level to further reduce file size
|
buffer = methods.compress_buffer(buffer)
|
||||||
# (at the cost of initial build times).
|
|
||||||
buf = zlib.compress(buf, zlib.Z_BEST_COMPRESSION)
|
|
||||||
|
|
||||||
g.write("static const unsigned char _{}_translation_{}_compressed[] = {{\n".format(category, name))
|
file.write(f"""\
|
||||||
for j in range(len(buf)):
|
inline constexpr const unsigned char _{category}_translation_{name}_compressed[] = {{
|
||||||
g.write("\t" + str(buf[j]) + ",\n")
|
{methods.format_buffer(buffer, 1)}
|
||||||
|
}};
|
||||||
|
|
||||||
g.write("};\n")
|
""")
|
||||||
|
|
||||||
xl_names.append([name, len(buf), str(decomp_size)])
|
xl_names.append([name, len(buffer), decomp_size])
|
||||||
|
|
||||||
|
file.write(f"""\
|
||||||
|
struct {category.capitalize()}TranslationList {{
|
||||||
|
const char* lang;
|
||||||
|
int comp_size;
|
||||||
|
int uncomp_size;
|
||||||
|
const unsigned char* data;
|
||||||
|
}};
|
||||||
|
|
||||||
|
inline constexpr {category.capitalize()}TranslationList _{category}_translations[] = {{
|
||||||
|
""")
|
||||||
|
|
||||||
g.write("struct {}TranslationList {{\n".format(category.capitalize()))
|
|
||||||
g.write("\tconst char* lang;\n")
|
|
||||||
g.write("\tint comp_size;\n")
|
|
||||||
g.write("\tint uncomp_size;\n")
|
|
||||||
g.write("\tconst unsigned char* data;\n")
|
|
||||||
g.write("};\n\n")
|
|
||||||
g.write("static {}TranslationList _{}_translations[] = {{\n".format(category.capitalize(), category))
|
|
||||||
for x in xl_names:
|
for x in xl_names:
|
||||||
g.write(
|
file.write(f'\t{{ "{x[0]}", {x[1]}, {x[2]}, _{category}_translation_{x[0]}_compressed }},\n')
|
||||||
'\t{{ "{}", {}, {}, _{}_translation_{}_compressed }},\n'.format(
|
|
||||||
x[0], str(x[1]), str(x[2]), category, x[0]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
g.write("\t{nullptr, 0, 0, nullptr}\n")
|
|
||||||
g.write("};\n")
|
|
||||||
|
|
||||||
g.write("#endif")
|
file.write("""\
|
||||||
|
{ nullptr, 0, 0, nullptr },
|
||||||
|
};
|
||||||
def make_editor_translations_header(target, source, env):
|
""")
|
||||||
make_translations_header(target, source, env, "editor")
|
|
||||||
|
|
||||||
|
|
||||||
def make_property_translations_header(target, source, env):
|
|
||||||
make_translations_header(target, source, env, "property")
|
|
||||||
|
|
||||||
|
|
||||||
def make_doc_translations_header(target, source, env):
|
|
||||||
make_translations_header(target, source, env, "doc")
|
|
||||||
|
|
||||||
|
|
||||||
def make_extractable_translations_header(target, source, env):
|
|
||||||
make_translations_header(target, source, env, "extractable")
|
|
||||||
|
@ -42,7 +42,7 @@
|
|||||||
Vector<String> get_editor_locales() {
|
Vector<String> get_editor_locales() {
|
||||||
Vector<String> locales;
|
Vector<String> locales;
|
||||||
|
|
||||||
EditorTranslationList *etl = _editor_translations;
|
const EditorTranslationList *etl = _editor_translations;
|
||||||
while (etl->data) {
|
while (etl->data) {
|
||||||
const String &locale = etl->lang;
|
const String &locale = etl->lang;
|
||||||
locales.push_back(locale);
|
locales.push_back(locale);
|
||||||
@ -56,7 +56,7 @@ Vector<String> get_editor_locales() {
|
|||||||
void load_editor_translations(const String &p_locale) {
|
void load_editor_translations(const String &p_locale) {
|
||||||
const Ref<TranslationDomain> domain = TranslationServer::get_singleton()->get_or_add_domain("godot.editor");
|
const Ref<TranslationDomain> domain = TranslationServer::get_singleton()->get_or_add_domain("godot.editor");
|
||||||
|
|
||||||
EditorTranslationList *etl = _editor_translations;
|
const EditorTranslationList *etl = _editor_translations;
|
||||||
while (etl->data) {
|
while (etl->data) {
|
||||||
if (etl->lang == p_locale) {
|
if (etl->lang == p_locale) {
|
||||||
Vector<uint8_t> data;
|
Vector<uint8_t> data;
|
||||||
@ -84,7 +84,7 @@ void load_editor_translations(const String &p_locale) {
|
|||||||
void load_property_translations(const String &p_locale) {
|
void load_property_translations(const String &p_locale) {
|
||||||
const Ref<TranslationDomain> domain = TranslationServer::get_singleton()->get_or_add_domain("godot.properties");
|
const Ref<TranslationDomain> domain = TranslationServer::get_singleton()->get_or_add_domain("godot.properties");
|
||||||
|
|
||||||
PropertyTranslationList *etl = _property_translations;
|
const PropertyTranslationList *etl = _property_translations;
|
||||||
while (etl->data) {
|
while (etl->data) {
|
||||||
if (etl->lang == p_locale) {
|
if (etl->lang == p_locale) {
|
||||||
Vector<uint8_t> data;
|
Vector<uint8_t> data;
|
||||||
@ -112,7 +112,7 @@ void load_property_translations(const String &p_locale) {
|
|||||||
void load_doc_translations(const String &p_locale) {
|
void load_doc_translations(const String &p_locale) {
|
||||||
const Ref<TranslationDomain> domain = TranslationServer::get_singleton()->get_or_add_domain("godot.documentation");
|
const Ref<TranslationDomain> domain = TranslationServer::get_singleton()->get_or_add_domain("godot.documentation");
|
||||||
|
|
||||||
DocTranslationList *dtl = _doc_translations;
|
const DocTranslationList *dtl = _doc_translations;
|
||||||
while (dtl->data) {
|
while (dtl->data) {
|
||||||
if (dtl->lang == p_locale) {
|
if (dtl->lang == p_locale) {
|
||||||
Vector<uint8_t> data;
|
Vector<uint8_t> data;
|
||||||
@ -140,7 +140,7 @@ void load_doc_translations(const String &p_locale) {
|
|||||||
void load_extractable_translations(const String &p_locale) {
|
void load_extractable_translations(const String &p_locale) {
|
||||||
const Ref<TranslationDomain> domain = TranslationServer::get_singleton()->get_or_add_domain("godot.editor");
|
const Ref<TranslationDomain> domain = TranslationServer::get_singleton()->get_or_add_domain("godot.editor");
|
||||||
|
|
||||||
ExtractableTranslationList *etl = _extractable_translations;
|
const ExtractableTranslationList *etl = _extractable_translations;
|
||||||
while (etl->data) {
|
while (etl->data) {
|
||||||
if (etl->lang == p_locale) {
|
if (etl->lang == p_locale) {
|
||||||
Vector<uint8_t> data;
|
Vector<uint8_t> data;
|
||||||
@ -166,7 +166,7 @@ void load_extractable_translations(const String &p_locale) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Vector<Vector<String>> get_extractable_message_list() {
|
Vector<Vector<String>> get_extractable_message_list() {
|
||||||
ExtractableTranslationList *etl = _extractable_translations;
|
const ExtractableTranslationList *etl = _extractable_translations;
|
||||||
Vector<Vector<String>> list;
|
Vector<Vector<String>> list;
|
||||||
|
|
||||||
while (etl->data) {
|
while (etl->data) {
|
||||||
|
@ -1,71 +1,47 @@
|
|||||||
"""Functions used to generate source files during build time"""
|
"""Functions used to generate source files during build time"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from io import StringIO
|
|
||||||
|
|
||||||
from methods import to_raw_cstring
|
import methods
|
||||||
|
|
||||||
|
|
||||||
# See also `scene/theme/icons/default_theme_icons_builders.py`.
|
# See also `scene/theme/icons/default_theme_icons_builders.py`.
|
||||||
def make_editor_icons_action(target, source, env):
|
def make_editor_icons_action(target, source, env):
|
||||||
dst = str(target[0])
|
icons_names = []
|
||||||
svg_icons = source
|
icons_raw = []
|
||||||
|
icons_med = []
|
||||||
|
icons_big = []
|
||||||
|
|
||||||
with StringIO() as icons_string, StringIO() as s:
|
for idx, svg in enumerate(source):
|
||||||
for svg in svg_icons:
|
path = str(svg)
|
||||||
with open(str(svg), "r") as svgf:
|
with open(path, encoding="utf-8", newline="\n") as file:
|
||||||
icons_string.write("\t%s,\n" % to_raw_cstring(svgf.read()))
|
icons_raw.append(methods.to_raw_cstring(file.read()))
|
||||||
|
|
||||||
s.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
|
name = os.path.splitext(os.path.basename(path))[0]
|
||||||
s.write("#ifndef _EDITOR_ICONS_H\n")
|
icons_names.append(f'"{name}"')
|
||||||
s.write("#define _EDITOR_ICONS_H\n")
|
|
||||||
s.write("static const int editor_icons_count = {};\n".format(len(svg_icons)))
|
|
||||||
s.write("static const char *editor_icons_sources[] = {\n")
|
|
||||||
s.write(icons_string.getvalue())
|
|
||||||
s.write("};\n\n")
|
|
||||||
s.write("static const char *editor_icons_names[] = {\n")
|
|
||||||
|
|
||||||
# this is used to store the indices of thumbnail icons
|
if name.endswith("MediumThumb"):
|
||||||
thumb_medium_indices = []
|
icons_med.append(str(idx))
|
||||||
thumb_big_indices = []
|
elif name.endswith(("BigThumb", "GodotFile")):
|
||||||
index = 0
|
icons_big.append(str(idx))
|
||||||
for f in svg_icons:
|
|
||||||
fname = str(f)
|
|
||||||
|
|
||||||
# Trim the `.svg` extension from the string.
|
icons_names_str = ",\n\t".join(icons_names)
|
||||||
icon_name = os.path.basename(fname)[:-4]
|
icons_raw_str = ",\n\t".join(icons_raw)
|
||||||
# some special cases
|
|
||||||
if icon_name.endswith("MediumThumb"): # don't know a better way to handle this
|
|
||||||
thumb_medium_indices.append(str(index))
|
|
||||||
if icon_name.endswith("BigThumb"): # don't know a better way to handle this
|
|
||||||
thumb_big_indices.append(str(index))
|
|
||||||
if icon_name.endswith("GodotFile"): # don't know a better way to handle this
|
|
||||||
thumb_big_indices.append(str(index))
|
|
||||||
|
|
||||||
s.write('\t"{0}"'.format(icon_name))
|
with methods.generated_wrapper(str(target[0])) as file:
|
||||||
|
file.write(f"""\
|
||||||
|
inline constexpr int editor_icons_count = {len(icons_names)};
|
||||||
|
inline constexpr const char *editor_icons_sources[] = {{
|
||||||
|
{icons_raw_str}
|
||||||
|
}};
|
||||||
|
|
||||||
if fname != svg_icons[-1]:
|
inline constexpr const char *editor_icons_names[] = {{
|
||||||
s.write(",")
|
{icons_names_str}
|
||||||
s.write("\n")
|
}};
|
||||||
|
|
||||||
index += 1
|
inline constexpr int editor_md_thumbs_count = {len(icons_med)};
|
||||||
|
inline constexpr int editor_md_thumbs_indices[] = {{ {", ".join(icons_med)} }};
|
||||||
|
|
||||||
s.write("};\n")
|
inline constexpr int editor_bg_thumbs_count = {len(icons_big)};
|
||||||
|
inline constexpr int editor_bg_thumbs_indices[] = {{ {", ".join(icons_big)} }};
|
||||||
if thumb_medium_indices:
|
""")
|
||||||
s.write("\n\n")
|
|
||||||
s.write("static const int editor_md_thumbs_count = {};\n".format(len(thumb_medium_indices)))
|
|
||||||
s.write("static const int editor_md_thumbs_indices[] = {")
|
|
||||||
s.write(", ".join(thumb_medium_indices))
|
|
||||||
s.write("};\n")
|
|
||||||
if thumb_big_indices:
|
|
||||||
s.write("\n\n")
|
|
||||||
s.write("static const int editor_bg_thumbs_count = {};\n".format(len(thumb_big_indices)))
|
|
||||||
s.write("static const int editor_bg_thumbs_indices[] = {")
|
|
||||||
s.write(", ".join(thumb_big_indices))
|
|
||||||
s.write("};\n")
|
|
||||||
|
|
||||||
s.write("#endif\n")
|
|
||||||
|
|
||||||
with open(dst, "w", encoding="utf-8", newline="\n") as f:
|
|
||||||
f.write(s.getvalue())
|
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
"""Functions used to generate source files during build time"""
|
"""Functions used to generate source files during build time"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from io import StringIO
|
|
||||||
|
import methods
|
||||||
|
|
||||||
|
|
||||||
def parse_template(inherits, source, delimiter):
|
def parse_template(inherits, source, delimiter):
|
||||||
@ -36,54 +37,36 @@ def parse_template(inherits, source, delimiter):
|
|||||||
script_template["script"].replace('"', '\\"').lstrip().replace("\n", "\\n").replace("\t", "_TS_")
|
script_template["script"].replace('"', '\\"').lstrip().replace("\n", "\\n").replace("\t", "_TS_")
|
||||||
)
|
)
|
||||||
return (
|
return (
|
||||||
'{ String("'
|
f'{{ String("{script_template["inherits"]}"), '
|
||||||
+ script_template["inherits"]
|
+ f'String("{script_template["name"]}"), '
|
||||||
+ '"), String("'
|
+ f'String("{script_template["description"]}"), '
|
||||||
+ script_template["name"]
|
+ f'String("{script_template["script"]}") }},'
|
||||||
+ '"), String("'
|
|
||||||
+ script_template["description"]
|
|
||||||
+ '"), String("'
|
|
||||||
+ script_template["script"]
|
|
||||||
+ '")'
|
|
||||||
+ " },\n"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def make_templates(target, source, env):
|
def make_templates(target, source, env):
|
||||||
dst = str(target[0])
|
delimiter = "#" # GDScript single line comment delimiter by default.
|
||||||
with StringIO() as s:
|
if source:
|
||||||
s.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n\n")
|
ext = os.path.splitext(str(source[0]))[1]
|
||||||
s.write("#ifndef _CODE_TEMPLATES_H\n")
|
if ext == ".cs":
|
||||||
s.write("#define _CODE_TEMPLATES_H\n\n")
|
delimiter = "//"
|
||||||
s.write('#include "core/object/object.h"\n')
|
|
||||||
s.write('#include "core/object/script_language.h"\n')
|
|
||||||
|
|
||||||
delimiter = "#" # GDScript single line comment delimiter by default.
|
parsed_templates = []
|
||||||
if source:
|
|
||||||
ext = os.path.splitext(str(source[0]))[1]
|
|
||||||
if ext == ".cs":
|
|
||||||
delimiter = "//"
|
|
||||||
|
|
||||||
parsed_template_string = ""
|
for filepath in source:
|
||||||
number_of_templates = 0
|
filepath = str(filepath)
|
||||||
|
node_name = os.path.basename(os.path.dirname(filepath))
|
||||||
|
parsed_templates.append(parse_template(node_name, filepath, delimiter))
|
||||||
|
|
||||||
for filepath in source:
|
parsed_template_string = "\n\t".join(parsed_templates)
|
||||||
filepath = str(filepath)
|
|
||||||
node_name = os.path.basename(os.path.dirname(filepath))
|
|
||||||
parsed_template = parse_template(node_name, filepath, delimiter)
|
|
||||||
parsed_template_string += "\t" + parsed_template
|
|
||||||
number_of_templates += 1
|
|
||||||
|
|
||||||
s.write("\nstatic const int TEMPLATES_ARRAY_SIZE = " + str(number_of_templates) + ";\n")
|
with methods.generated_wrapper(str(target[0])) as file:
|
||||||
s.write(
|
file.write(f"""\
|
||||||
"\nstatic const struct ScriptLanguage::ScriptTemplate TEMPLATES[" + str(number_of_templates) + "] = {\n"
|
#include "core/object/object.h"
|
||||||
)
|
#include "core/object/script_language.h"
|
||||||
|
|
||||||
s.write(parsed_template_string)
|
inline constexpr int TEMPLATES_ARRAY_SIZE = {len(parsed_templates)};
|
||||||
|
static const struct ScriptLanguage::ScriptTemplate TEMPLATES[TEMPLATES_ARRAY_SIZE] = {{
|
||||||
s.write("};\n")
|
{parsed_template_string}
|
||||||
|
}};
|
||||||
s.write("\n#endif\n")
|
""")
|
||||||
|
|
||||||
with open(dst, "w", encoding="utf-8", newline="\n") as f:
|
|
||||||
f.write(s.getvalue())
|
|
||||||
|
@ -3,17 +3,14 @@ from misc.utility.scons_hints import *
|
|||||||
|
|
||||||
Import("env")
|
Import("env")
|
||||||
|
|
||||||
import glob
|
|
||||||
|
|
||||||
import editor_theme_builders
|
import editor_theme_builders
|
||||||
|
|
||||||
# Fonts
|
# Fonts
|
||||||
flist = glob.glob(env.Dir("#thirdparty").abspath + "/fonts/*.ttf")
|
flist = Glob("#thirdparty/fonts/*.ttf")
|
||||||
flist.extend(glob.glob(env.Dir("#thirdparty").abspath + "/fonts/*.otf"))
|
flist.extend(Glob("#thirdparty/fonts/*.otf"))
|
||||||
flist.extend(glob.glob(env.Dir("#thirdparty").abspath + "/fonts/*.woff"))
|
flist.extend(Glob("#thirdparty/fonts/*.woff"))
|
||||||
flist.extend(glob.glob(env.Dir("#thirdparty").abspath + "/fonts/*.woff2"))
|
flist.extend(Glob("#thirdparty/fonts/*.woff2"))
|
||||||
flist.sort()
|
flist.sort()
|
||||||
env.Depends("#editor/themes/builtin_fonts.gen.h", flist)
|
|
||||||
env.CommandNoCache(
|
env.CommandNoCache(
|
||||||
"#editor/themes/builtin_fonts.gen.h",
|
"#editor/themes/builtin_fonts.gen.h",
|
||||||
flist,
|
flist,
|
||||||
|
@ -2,28 +2,20 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
import methods
|
||||||
|
|
||||||
|
|
||||||
def make_fonts_header(target, source, env):
|
def make_fonts_header(target, source, env):
|
||||||
dst = str(target[0])
|
with methods.generated_wrapper(str(target[0])) as file:
|
||||||
|
for src in map(str, source):
|
||||||
|
# Saving uncompressed, since FreeType will reference from memory pointer.
|
||||||
|
buffer = methods.get_buffer(src)
|
||||||
|
name = os.path.splitext(os.path.basename(src))[0]
|
||||||
|
|
||||||
with open(dst, "w", encoding="utf-8", newline="\n") as g:
|
file.write(f"""\
|
||||||
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
|
inline constexpr int _font_{name}_size = {len(buffer)};
|
||||||
g.write("#ifndef _EDITOR_FONTS_H\n")
|
inline constexpr unsigned char _font_{name}[] = {{
|
||||||
g.write("#define _EDITOR_FONTS_H\n")
|
{methods.format_buffer(buffer, 1)}
|
||||||
|
}};
|
||||||
|
|
||||||
# Saving uncompressed, since FreeType will reference from memory pointer.
|
""")
|
||||||
for i in range(len(source)):
|
|
||||||
file = str(source[i])
|
|
||||||
with open(file, "rb") as f:
|
|
||||||
buf = f.read()
|
|
||||||
|
|
||||||
name = os.path.splitext(os.path.basename(file))[0]
|
|
||||||
|
|
||||||
g.write("static const int _font_" + name + "_size = " + str(len(buf)) + ";\n")
|
|
||||||
g.write("static const unsigned char _font_" + name + "[] = {\n")
|
|
||||||
for j in range(len(buf)):
|
|
||||||
g.write("\t" + str(buf[j]) + ",\n")
|
|
||||||
|
|
||||||
g.write("};\n")
|
|
||||||
|
|
||||||
g.write("#endif")
|
|
||||||
|
@ -17,7 +17,6 @@ if env["steamapi"] and env.editor_build:
|
|||||||
if env["tests"]:
|
if env["tests"]:
|
||||||
env_main.Append(CPPDEFINES=["TESTS_ENABLED"])
|
env_main.Append(CPPDEFINES=["TESTS_ENABLED"])
|
||||||
|
|
||||||
env_main.Depends("#main/splash.gen.h", "#main/splash.png")
|
|
||||||
env_main.CommandNoCache(
|
env_main.CommandNoCache(
|
||||||
"#main/splash.gen.h",
|
"#main/splash.gen.h",
|
||||||
"#main/splash.png",
|
"#main/splash.png",
|
||||||
@ -25,14 +24,12 @@ env_main.CommandNoCache(
|
|||||||
)
|
)
|
||||||
|
|
||||||
if env_main.editor_build and not env_main["no_editor_splash"]:
|
if env_main.editor_build and not env_main["no_editor_splash"]:
|
||||||
env_main.Depends("#main/splash_editor.gen.h", "#main/splash_editor.png")
|
|
||||||
env_main.CommandNoCache(
|
env_main.CommandNoCache(
|
||||||
"#main/splash_editor.gen.h",
|
"#main/splash_editor.gen.h",
|
||||||
"#main/splash_editor.png",
|
"#main/splash_editor.png",
|
||||||
env.Run(main_builders.make_splash_editor),
|
env.Run(main_builders.make_splash_editor),
|
||||||
)
|
)
|
||||||
|
|
||||||
env_main.Depends("#main/app_icon.gen.h", "#main/app_icon.png")
|
|
||||||
env_main.CommandNoCache(
|
env_main.CommandNoCache(
|
||||||
"#main/app_icon.gen.h",
|
"#main/app_icon.gen.h",
|
||||||
"#main/app_icon.png",
|
"#main/app_icon.png",
|
||||||
|
@ -1,60 +1,42 @@
|
|||||||
"""Functions used to generate source files during build time"""
|
"""Functions used to generate source files during build time"""
|
||||||
|
|
||||||
|
import methods
|
||||||
|
|
||||||
|
|
||||||
def make_splash(target, source, env):
|
def make_splash(target, source, env):
|
||||||
src = str(source[0])
|
buffer = methods.get_buffer(str(source[0]))
|
||||||
dst = str(target[0])
|
|
||||||
|
|
||||||
with open(src, "rb") as f:
|
with methods.generated_wrapper(str(target[0])) as file:
|
||||||
buf = f.read()
|
|
||||||
|
|
||||||
with open(dst, "w", encoding="utf-8", newline="\n") as g:
|
|
||||||
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
|
|
||||||
g.write("#ifndef BOOT_SPLASH_H\n")
|
|
||||||
g.write("#define BOOT_SPLASH_H\n")
|
|
||||||
# Use a neutral gray color to better fit various kinds of projects.
|
# Use a neutral gray color to better fit various kinds of projects.
|
||||||
g.write("static const Color boot_splash_bg_color = Color(0.14, 0.14, 0.14);\n")
|
file.write(f"""\
|
||||||
g.write("static const unsigned char boot_splash_png[] = {\n")
|
static const Color boot_splash_bg_color = Color(0.14, 0.14, 0.14);
|
||||||
for i in range(len(buf)):
|
inline constexpr const unsigned char boot_splash_png[] = {{
|
||||||
g.write(str(buf[i]) + ",\n")
|
{methods.format_buffer(buffer, 1)}
|
||||||
g.write("};\n")
|
}};
|
||||||
g.write("#endif")
|
""")
|
||||||
|
|
||||||
|
|
||||||
def make_splash_editor(target, source, env):
|
def make_splash_editor(target, source, env):
|
||||||
src = str(source[0])
|
buffer = methods.get_buffer(str(source[0]))
|
||||||
dst = str(target[0])
|
|
||||||
|
|
||||||
with open(src, "rb") as f:
|
with methods.generated_wrapper(str(target[0])) as file:
|
||||||
buf = f.read()
|
|
||||||
|
|
||||||
with open(dst, "w", encoding="utf-8", newline="\n") as g:
|
|
||||||
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
|
|
||||||
g.write("#ifndef BOOT_SPLASH_EDITOR_H\n")
|
|
||||||
g.write("#define BOOT_SPLASH_EDITOR_H\n")
|
|
||||||
# The editor splash background color is taken from the default editor theme's background color.
|
# The editor splash background color is taken from the default editor theme's background color.
|
||||||
# This helps achieve a visually "smoother" transition between the splash screen and the editor.
|
# This helps achieve a visually "smoother" transition between the splash screen and the editor.
|
||||||
g.write("static const Color boot_splash_editor_bg_color = Color(0.125, 0.145, 0.192);\n")
|
file.write(f"""\
|
||||||
g.write("static const unsigned char boot_splash_editor_png[] = {\n")
|
static const Color boot_splash_editor_bg_color = Color(0.125, 0.145, 0.192);
|
||||||
for i in range(len(buf)):
|
inline constexpr const unsigned char boot_splash_editor_png[] = {{
|
||||||
g.write(str(buf[i]) + ",\n")
|
{methods.format_buffer(buffer, 1)}
|
||||||
g.write("};\n")
|
}};
|
||||||
g.write("#endif")
|
""")
|
||||||
|
|
||||||
|
|
||||||
def make_app_icon(target, source, env):
|
def make_app_icon(target, source, env):
|
||||||
src = str(source[0])
|
buffer = methods.get_buffer(str(source[0]))
|
||||||
dst = str(target[0])
|
|
||||||
|
|
||||||
with open(src, "rb") as f:
|
with methods.generated_wrapper(str(target[0])) as file:
|
||||||
buf = f.read()
|
# Use a neutral gray color to better fit various kinds of projects.
|
||||||
|
file.write(f"""\
|
||||||
with open(dst, "w", encoding="utf-8", newline="\n") as g:
|
inline constexpr const unsigned char app_icon_png[] = {{
|
||||||
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
|
{methods.format_buffer(buffer, 1)}
|
||||||
g.write("#ifndef APP_ICON_H\n")
|
}};
|
||||||
g.write("#define APP_ICON_H\n")
|
""")
|
||||||
g.write("static const unsigned char app_icon_png[] = {\n")
|
|
||||||
for i in range(len(buf)):
|
|
||||||
g.write(str(buf[i]) + ",\n")
|
|
||||||
g.write("};\n")
|
|
||||||
g.write("#endif")
|
|
||||||
|
125
methods.py
125
methods.py
@ -6,6 +6,8 @@ import os
|
|||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
import textwrap
|
||||||
|
import zlib
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from io import StringIO, TextIOBase
|
from io import StringIO, TextIOBase
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@ -144,30 +146,36 @@ def get_version_info(module_version_string="", silent=False):
|
|||||||
if not silent:
|
if not silent:
|
||||||
print_info(f"Using version status '{version_info['status']}', overriding the original '{version.status}'.")
|
print_info(f"Using version status '{version_info['status']}', overriding the original '{version.status}'.")
|
||||||
|
|
||||||
|
return version_info
|
||||||
|
|
||||||
|
|
||||||
|
def get_git_info():
|
||||||
|
os.chdir(base_folder_path)
|
||||||
|
|
||||||
# Parse Git hash if we're in a Git repo.
|
# Parse Git hash if we're in a Git repo.
|
||||||
githash = ""
|
git_hash = ""
|
||||||
gitfolder = ".git"
|
git_folder = ".git"
|
||||||
|
|
||||||
if os.path.isfile(".git"):
|
if os.path.isfile(".git"):
|
||||||
with open(".git", "r", encoding="utf-8") as file:
|
with open(".git", "r", encoding="utf-8") as file:
|
||||||
module_folder = file.readline().strip()
|
module_folder = file.readline().strip()
|
||||||
if module_folder.startswith("gitdir: "):
|
if module_folder.startswith("gitdir: "):
|
||||||
gitfolder = module_folder[8:]
|
git_folder = module_folder[8:]
|
||||||
|
|
||||||
if os.path.isfile(os.path.join(gitfolder, "HEAD")):
|
if os.path.isfile(os.path.join(git_folder, "HEAD")):
|
||||||
with open(os.path.join(gitfolder, "HEAD"), "r", encoding="utf8") as file:
|
with open(os.path.join(git_folder, "HEAD"), "r", encoding="utf8") as file:
|
||||||
head = file.readline().strip()
|
head = file.readline().strip()
|
||||||
if head.startswith("ref: "):
|
if head.startswith("ref: "):
|
||||||
ref = head[5:]
|
ref = head[5:]
|
||||||
# If this directory is a Git worktree instead of a root clone.
|
# If this directory is a Git worktree instead of a root clone.
|
||||||
parts = gitfolder.split("/")
|
parts = git_folder.split("/")
|
||||||
if len(parts) > 2 and parts[-2] == "worktrees":
|
if len(parts) > 2 and parts[-2] == "worktrees":
|
||||||
gitfolder = "/".join(parts[0:-2])
|
git_folder = "/".join(parts[0:-2])
|
||||||
head = os.path.join(gitfolder, ref)
|
head = os.path.join(git_folder, ref)
|
||||||
packedrefs = os.path.join(gitfolder, "packed-refs")
|
packedrefs = os.path.join(git_folder, "packed-refs")
|
||||||
if os.path.isfile(head):
|
if os.path.isfile(head):
|
||||||
with open(head, "r", encoding="utf-8") as file:
|
with open(head, "r", encoding="utf-8") as file:
|
||||||
githash = file.readline().strip()
|
git_hash = file.readline().strip()
|
||||||
elif os.path.isfile(packedrefs):
|
elif os.path.isfile(packedrefs):
|
||||||
# Git may pack refs into a single file. This code searches .git/packed-refs file for the current ref's hash.
|
# Git may pack refs into a single file. This code searches .git/packed-refs file for the current ref's hash.
|
||||||
# https://mirrors.edge.kernel.org/pub/software/scm/git/docs/git-pack-refs.html
|
# https://mirrors.edge.kernel.org/pub/software/scm/git/docs/git-pack-refs.html
|
||||||
@ -176,26 +184,26 @@ def get_version_info(module_version_string="", silent=False):
|
|||||||
continue
|
continue
|
||||||
(line_hash, line_ref) = line.split(" ")
|
(line_hash, line_ref) = line.split(" ")
|
||||||
if ref == line_ref:
|
if ref == line_ref:
|
||||||
githash = line_hash
|
git_hash = line_hash
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
githash = head
|
git_hash = head
|
||||||
|
|
||||||
version_info["git_hash"] = githash
|
|
||||||
# Fallback to 0 as a timestamp (will be treated as "unknown" in the engine).
|
|
||||||
version_info["git_timestamp"] = 0
|
|
||||||
|
|
||||||
# Get the UNIX timestamp of the build commit.
|
# Get the UNIX timestamp of the build commit.
|
||||||
|
git_timestamp = 0
|
||||||
if os.path.exists(".git"):
|
if os.path.exists(".git"):
|
||||||
try:
|
try:
|
||||||
version_info["git_timestamp"] = subprocess.check_output(
|
git_timestamp = subprocess.check_output(
|
||||||
["git", "log", "-1", "--pretty=format:%ct", "--no-show-signature", githash]
|
["git", "log", "-1", "--pretty=format:%ct", "--no-show-signature", git_hash], encoding="utf-8"
|
||||||
).decode("utf-8")
|
)
|
||||||
except (subprocess.CalledProcessError, OSError):
|
except (subprocess.CalledProcessError, OSError):
|
||||||
# `git` not found in PATH.
|
# `git` not found in PATH.
|
||||||
pass
|
pass
|
||||||
|
|
||||||
return version_info
|
return {
|
||||||
|
"git_hash": git_hash,
|
||||||
|
"git_timestamp": git_timestamp,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def get_cmdline_bool(option, default):
|
def get_cmdline_bool(option, default):
|
||||||
@ -1417,6 +1425,11 @@ def generate_vs_project(env, original_args, project_name="godot"):
|
|||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# FILE GENERATION & FORMATTING
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
|
||||||
def generate_copyright_header(filename: str) -> str:
|
def generate_copyright_header(filename: str) -> str:
|
||||||
MARGIN = 70
|
MARGIN = 70
|
||||||
TEMPLATE = """\
|
TEMPLATE = """\
|
||||||
@ -1450,15 +1463,14 @@ def generate_copyright_header(filename: str) -> str:
|
|||||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
"""
|
"""
|
||||||
filename = filename.split("/")[-1].ljust(MARGIN)
|
if len(filename := os.path.basename(filename).ljust(MARGIN)) > MARGIN:
|
||||||
if len(filename) > MARGIN:
|
|
||||||
print_warning(f'Filename "{filename}" too large for copyright header.')
|
print_warning(f'Filename "{filename}" too large for copyright header.')
|
||||||
return TEMPLATE % filename
|
return TEMPLATE % filename
|
||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def generated_wrapper(
|
def generated_wrapper(
|
||||||
path, # FIXME: type with `Union[str, Node, List[Node]]` when pytest conflicts are resolved
|
path: str,
|
||||||
guard: Optional[bool] = None,
|
guard: Optional[bool] = None,
|
||||||
) -> Generator[TextIOBase, None, None]:
|
) -> Generator[TextIOBase, None, None]:
|
||||||
"""
|
"""
|
||||||
@ -1466,26 +1478,11 @@ def generated_wrapper(
|
|||||||
for generated scripts. Meant to be invoked via `with` statement similar to
|
for generated scripts. Meant to be invoked via `with` statement similar to
|
||||||
creating a file.
|
creating a file.
|
||||||
|
|
||||||
- `path`: The path of the file to be created. Can be passed a raw string, an
|
- `path`: The path of the file to be created.
|
||||||
isolated SCons target, or a full SCons target list. If a target list contains
|
|
||||||
multiple entries, produces a warning & only creates the first entry.
|
|
||||||
- `guard`: Optional bool to determine if `#pragma once` should be added. If
|
- `guard`: Optional bool to determine if `#pragma once` should be added. If
|
||||||
unassigned, the value is determined by file extension.
|
unassigned, the value is determined by file extension.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Handle unfiltered SCons target[s] passed as path.
|
|
||||||
if not isinstance(path, str):
|
|
||||||
if isinstance(path, list):
|
|
||||||
if len(path) > 1:
|
|
||||||
print_warning(
|
|
||||||
f"Attempting to use generated wrapper with multiple targets; will only use first entry: {path[0]}"
|
|
||||||
)
|
|
||||||
path = path[0]
|
|
||||||
if not hasattr(path, "get_abspath"):
|
|
||||||
raise TypeError(f'Expected type "str", "Node" or "List[Node]"; was passed {type(path)}.')
|
|
||||||
path = path.get_abspath()
|
|
||||||
|
|
||||||
path = str(path).replace("\\", "/")
|
|
||||||
if guard is None:
|
if guard is None:
|
||||||
guard = path.endswith((".h", ".hh", ".hpp", ".hxx", ".inc"))
|
guard = path.endswith((".h", ".hh", ".hpp", ".hxx", ".inc"))
|
||||||
|
|
||||||
@ -1503,6 +1500,50 @@ def generated_wrapper(
|
|||||||
file.write("\n")
|
file.write("\n")
|
||||||
|
|
||||||
|
|
||||||
|
def get_buffer(path: str) -> bytes:
|
||||||
|
with open(path, "rb") as file:
|
||||||
|
return file.read()
|
||||||
|
|
||||||
|
|
||||||
|
def compress_buffer(buffer: bytes) -> bytes:
|
||||||
|
# Use maximum zlib compression level to further reduce file size
|
||||||
|
# (at the cost of initial build times).
|
||||||
|
return zlib.compress(buffer, zlib.Z_BEST_COMPRESSION)
|
||||||
|
|
||||||
|
|
||||||
|
def format_buffer(buffer: bytes, indent: int = 0, width: int = 120, initial_indent: bool = False) -> str:
|
||||||
|
return textwrap.fill(
|
||||||
|
", ".join(str(byte) for byte in buffer),
|
||||||
|
width=width,
|
||||||
|
initial_indent="\t" * indent if initial_indent else "",
|
||||||
|
subsequent_indent="\t" * indent,
|
||||||
|
tabsize=4,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# CSTRING PARSING
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
C_ESCAPABLES = [
|
||||||
|
("\\", "\\\\"),
|
||||||
|
("\a", "\\a"),
|
||||||
|
("\b", "\\b"),
|
||||||
|
("\f", "\\f"),
|
||||||
|
("\n", "\\n"),
|
||||||
|
("\r", "\\r"),
|
||||||
|
("\t", "\\t"),
|
||||||
|
("\v", "\\v"),
|
||||||
|
# ("'", "\\'"), # Skip, as we're only dealing with full strings.
|
||||||
|
('"', '\\"'),
|
||||||
|
]
|
||||||
|
C_ESCAPE_TABLE = str.maketrans(dict((x, y) for x, y in C_ESCAPABLES))
|
||||||
|
|
||||||
|
|
||||||
|
def to_escaped_cstring(value: str) -> str:
|
||||||
|
return value.translate(C_ESCAPE_TABLE)
|
||||||
|
|
||||||
|
|
||||||
def to_raw_cstring(value: Union[str, List[str]]) -> str:
|
def to_raw_cstring(value: Union[str, List[str]]) -> str:
|
||||||
MAX_LITERAL = 16 * 1024
|
MAX_LITERAL = 16 * 1024
|
||||||
|
|
||||||
@ -1540,4 +1581,8 @@ def to_raw_cstring(value: Union[str, List[str]]) -> str:
|
|||||||
|
|
||||||
split += [segment]
|
split += [segment]
|
||||||
|
|
||||||
return " ".join(f'R"<!>({x.decode()})<!>"' for x in split)
|
if len(split) == 1:
|
||||||
|
return f'R"<!>({split[0].decode()})<!>"'
|
||||||
|
else:
|
||||||
|
# Wrap multiple segments in parenthesis to suppress `string-concatenation` warnings on clang.
|
||||||
|
return "({})".format(" ".join(f'R"<!>({segment.decode()})<!>"' for segment in split))
|
||||||
|
@ -17,8 +17,9 @@ Export("env_modules")
|
|||||||
|
|
||||||
# Header with MODULE_*_ENABLED defines.
|
# Header with MODULE_*_ENABLED defines.
|
||||||
def modules_enabled_builder(target, source, env):
|
def modules_enabled_builder(target, source, env):
|
||||||
with methods.generated_wrapper(target) as file:
|
modules = sorted(source[0].read())
|
||||||
for module in source[0].read():
|
with methods.generated_wrapper(str(target[0])) as file:
|
||||||
|
for module in modules:
|
||||||
file.write(f"#define MODULE_{module.upper()}_ENABLED\n")
|
file.write(f"#define MODULE_{module.upper()}_ENABLED\n")
|
||||||
|
|
||||||
|
|
||||||
@ -29,14 +30,26 @@ modules_enabled = env.CommandNoCache(
|
|||||||
|
|
||||||
def register_module_types_builder(target, source, env):
|
def register_module_types_builder(target, source, env):
|
||||||
modules = source[0].read()
|
modules = source[0].read()
|
||||||
mod_inc = "\n".join([f'#include "{p}/register_types.h"' for p in modules.values()])
|
mod_inc = "\n".join([f'#include "{value}/register_types.h"' for value in modules.values()])
|
||||||
mod_init = "\n".join(
|
mod_init = "\n".join(
|
||||||
[f"#ifdef MODULE_{n.upper()}_ENABLED\n\tinitialize_{n}_module(p_level);\n#endif" for n in modules.keys()]
|
[
|
||||||
|
f"""\
|
||||||
|
#ifdef MODULE_{key.upper()}_ENABLED
|
||||||
|
initialize_{key}_module(p_level);
|
||||||
|
#endif"""
|
||||||
|
for key in modules.keys()
|
||||||
|
]
|
||||||
)
|
)
|
||||||
mod_uninit = "\n".join(
|
mod_uninit = "\n".join(
|
||||||
[f"#ifdef MODULE_{n.upper()}_ENABLED\n\tuninitialize_{n}_module(p_level);\n#endif" for n in modules.keys()]
|
[
|
||||||
|
f"""\
|
||||||
|
#ifdef MODULE_{key.upper()}_ENABLED
|
||||||
|
uninitialize_{key}_module(p_level);
|
||||||
|
#endif"""
|
||||||
|
for key in modules.keys()
|
||||||
|
]
|
||||||
)
|
)
|
||||||
with methods.generated_wrapper(target) as file:
|
with methods.generated_wrapper(str(target[0])) as file:
|
||||||
file.write(
|
file.write(
|
||||||
f"""\
|
f"""\
|
||||||
#include "register_module_types.h"
|
#include "register_module_types.h"
|
||||||
@ -88,9 +101,10 @@ for name, path in env.module_list.items():
|
|||||||
if env["tests"]:
|
if env["tests"]:
|
||||||
|
|
||||||
def modules_tests_builder(target, source, env):
|
def modules_tests_builder(target, source, env):
|
||||||
with methods.generated_wrapper(target) as file:
|
headers = sorted([os.path.relpath(src.path, methods.base_folder_path).replace("\\", "/") for src in source])
|
||||||
for header in source:
|
with methods.generated_wrapper(str(target[0])) as file:
|
||||||
file.write('#include "{}"\n'.format(os.path.normpath(header.path).replace("\\", "/")))
|
for header in headers:
|
||||||
|
file.write(f'#include "{header}"\n')
|
||||||
|
|
||||||
env.CommandNoCache("modules_tests.gen.h", test_headers, env.Run(modules_tests_builder))
|
env.CommandNoCache("modules_tests.gen.h", test_headers, env.Run(modules_tests_builder))
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
from misc.utility.scons_hints import *
|
from misc.utility.scons_hints import *
|
||||||
|
|
||||||
|
import methods
|
||||||
|
|
||||||
Import("env")
|
Import("env")
|
||||||
Import("env_modules")
|
Import("env_modules")
|
||||||
|
|
||||||
@ -8,28 +10,21 @@ env_text_server_adv = env_modules.Clone()
|
|||||||
|
|
||||||
|
|
||||||
def make_icu_data(target, source, env):
|
def make_icu_data(target, source, env):
|
||||||
dst = target[0].srcnode().abspath
|
buffer = methods.get_buffer(str(source[0]))
|
||||||
|
with methods.generated_wrapper(str(target[0])) as file:
|
||||||
|
file.write(f"""\
|
||||||
|
/* (C) 2016 and later: Unicode, Inc. and others. */
|
||||||
|
/* License & terms of use: https://www.unicode.org/copyright.html */
|
||||||
|
|
||||||
with open(dst, "w", encoding="utf-8", newline="\n") as g:
|
#include <unicode/utypes.h>
|
||||||
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
|
#include <unicode/udata.h>
|
||||||
g.write("/* (C) 2016 and later: Unicode, Inc. and others. */\n")
|
#include <unicode/uversion.h>
|
||||||
g.write("/* License & terms of use: https://www.unicode.org/copyright.html */\n")
|
|
||||||
g.write("#ifndef _ICU_DATA_H\n")
|
|
||||||
g.write("#define _ICU_DATA_H\n")
|
|
||||||
g.write('#include "unicode/utypes.h"\n')
|
|
||||||
g.write('#include "unicode/udata.h"\n')
|
|
||||||
g.write('#include "unicode/uversion.h"\n')
|
|
||||||
|
|
||||||
with open(source[0].srcnode().abspath, "rb") as f:
|
extern "C" U_EXPORT const size_t U_ICUDATA_SIZE = {len(buffer)};
|
||||||
buf = f.read()
|
extern "C" U_EXPORT const unsigned char U_ICUDATA_ENTRY_POINT[] = {{
|
||||||
|
{methods.format_buffer(buffer, 1)}
|
||||||
g.write('extern "C" U_EXPORT const size_t U_ICUDATA_SIZE = ' + str(len(buf)) + ";\n")
|
}};
|
||||||
g.write('extern "C" U_EXPORT const unsigned char U_ICUDATA_ENTRY_POINT[] = {\n')
|
""")
|
||||||
for i in range(len(buf)):
|
|
||||||
g.write("\t" + str(buf[i]) + ",\n")
|
|
||||||
|
|
||||||
g.write("};\n")
|
|
||||||
g.write("#endif")
|
|
||||||
|
|
||||||
|
|
||||||
# Thirdparty source files
|
# Thirdparty source files
|
||||||
|
@ -18,10 +18,10 @@ def export_icon_builder(target, source, env):
|
|||||||
platform = src_path.parent.parent.stem
|
platform = src_path.parent.parent.stem
|
||||||
with open(str(source[0]), "r") as file:
|
with open(str(source[0]), "r") as file:
|
||||||
svg = file.read()
|
svg = file.read()
|
||||||
with methods.generated_wrapper(target) as file:
|
with methods.generated_wrapper(str(target[0])) as file:
|
||||||
file.write(
|
file.write(
|
||||||
f"""\
|
f"""\
|
||||||
static const char *_{platform}_{src_name}_svg = {methods.to_raw_cstring(svg)};
|
inline constexpr const char *_{platform}_{src_name}_svg = {methods.to_raw_cstring(svg)};
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ def register_platform_apis_builder(target, source, env):
|
|||||||
api_inc = "\n".join([f'#include "{p}/api/api.h"' for p in platforms])
|
api_inc = "\n".join([f'#include "{p}/api/api.h"' for p in platforms])
|
||||||
api_reg = "\n".join([f"\tregister_{p}_api();" for p in platforms])
|
api_reg = "\n".join([f"\tregister_{p}_api();" for p in platforms])
|
||||||
api_unreg = "\n".join([f"\tunregister_{p}_api();" for p in platforms])
|
api_unreg = "\n".join([f"\tunregister_{p}_api();" for p in platforms])
|
||||||
with methods.generated_wrapper(target) as file:
|
with methods.generated_wrapper(str(target[0])) as file:
|
||||||
file.write(
|
file.write(
|
||||||
f"""\
|
f"""\
|
||||||
#include "register_platform_apis.h"
|
#include "register_platform_apis.h"
|
||||||
|
@ -9,7 +9,6 @@ env.add_source_files(env.scene_sources, "*.cpp")
|
|||||||
|
|
||||||
SConscript("icons/SCsub")
|
SConscript("icons/SCsub")
|
||||||
|
|
||||||
env.Depends("#scene/theme/default_font.gen.h", "#thirdparty/fonts/OpenSans_SemiBold.woff2")
|
|
||||||
env.CommandNoCache(
|
env.CommandNoCache(
|
||||||
"#scene/theme/default_font.gen.h",
|
"#scene/theme/default_font.gen.h",
|
||||||
"#thirdparty/fonts/OpenSans_SemiBold.woff2",
|
"#thirdparty/fonts/OpenSans_SemiBold.woff2",
|
||||||
|
@ -1,30 +1,21 @@
|
|||||||
"""Functions used to generate source files during build time"""
|
"""Functions used to generate source files during build time"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import os.path
|
|
||||||
|
import methods
|
||||||
|
|
||||||
|
|
||||||
def make_fonts_header(target, source, env):
|
def make_fonts_header(target, source, env):
|
||||||
dst = str(target[0])
|
with methods.generated_wrapper(str(target[0])) as file:
|
||||||
|
for src in map(str, source):
|
||||||
|
# Saving uncompressed, since FreeType will reference from memory pointer.
|
||||||
|
buffer = methods.get_buffer(src)
|
||||||
|
name = os.path.splitext(os.path.basename(src))[0]
|
||||||
|
|
||||||
with open(dst, "w", encoding="utf-8", newline="\n") as g:
|
file.write(f"""\
|
||||||
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
|
inline constexpr int _font_{name}_size = {len(buffer)};
|
||||||
g.write("#ifndef _DEFAULT_FONTS_H\n")
|
inline constexpr unsigned char _font_{name}[] = {{
|
||||||
g.write("#define _DEFAULT_FONTS_H\n")
|
{methods.format_buffer(buffer, 1)}
|
||||||
|
}};
|
||||||
|
|
||||||
# Saving uncompressed, since FreeType will reference from memory pointer.
|
""")
|
||||||
for i in range(len(source)):
|
|
||||||
file = str(source[i])
|
|
||||||
with open(file, "rb") as f:
|
|
||||||
buf = f.read()
|
|
||||||
|
|
||||||
name = os.path.splitext(os.path.basename(file))[0]
|
|
||||||
|
|
||||||
g.write("static const int _font_" + name + "_size = " + str(len(buf)) + ";\n")
|
|
||||||
g.write("static const unsigned char _font_" + name + "[] = {\n")
|
|
||||||
for j in range(len(buf)):
|
|
||||||
g.write("\t" + str(buf[j]) + ",\n")
|
|
||||||
|
|
||||||
g.write("};\n")
|
|
||||||
|
|
||||||
g.write("#endif")
|
|
||||||
|
@ -1,51 +1,35 @@
|
|||||||
"""Functions used to generate source files during build time"""
|
"""Functions used to generate source files during build time"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from io import StringIO
|
|
||||||
|
|
||||||
from methods import to_raw_cstring
|
import methods
|
||||||
|
|
||||||
|
|
||||||
# See also `editor/icons/editor_icons_builders.py`.
|
# See also `editor/icons/editor_icons_builders.py`.
|
||||||
def make_default_theme_icons_action(target, source, env):
|
def make_default_theme_icons_action(target, source, env):
|
||||||
dst = str(target[0])
|
icons_names = []
|
||||||
svg_icons = [str(x) for x in source]
|
icons_raw = []
|
||||||
|
|
||||||
with StringIO() as icons_string, StringIO() as s:
|
for src in map(str, source):
|
||||||
for svg in svg_icons:
|
with open(src, encoding="utf-8", newline="\n") as file:
|
||||||
with open(svg, "r") as svgf:
|
icons_raw.append(methods.to_raw_cstring(file.read()))
|
||||||
icons_string.write("\t%s,\n" % to_raw_cstring(svgf.read()))
|
|
||||||
|
|
||||||
s.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n\n")
|
name = os.path.splitext(os.path.basename(src))[0]
|
||||||
s.write('#include "modules/modules_enabled.gen.h"\n\n')
|
icons_names.append(f'"{name}"')
|
||||||
s.write("#ifndef _DEFAULT_THEME_ICONS_H\n")
|
|
||||||
s.write("#define _DEFAULT_THEME_ICONS_H\n")
|
|
||||||
s.write("static const int default_theme_icons_count = {};\n\n".format(len(svg_icons)))
|
|
||||||
s.write("#ifdef MODULE_SVG_ENABLED\n")
|
|
||||||
s.write("static const char *default_theme_icons_sources[] = {\n")
|
|
||||||
s.write(icons_string.getvalue())
|
|
||||||
s.write("};\n")
|
|
||||||
s.write("#endif // MODULE_SVG_ENABLED\n\n")
|
|
||||||
s.write("static const char *default_theme_icons_names[] = {\n")
|
|
||||||
|
|
||||||
index = 0
|
icons_names_str = ",\n\t".join(icons_names)
|
||||||
for f in svg_icons:
|
icons_raw_str = ",\n\t".join(icons_raw)
|
||||||
fname = str(f)
|
|
||||||
|
|
||||||
# Trim the `.svg` extension from the string.
|
with methods.generated_wrapper(str(target[0])) as file:
|
||||||
icon_name = os.path.basename(fname)[:-4]
|
file.write(f"""\
|
||||||
|
#include "modules/modules_enabled.gen.h"
|
||||||
|
|
||||||
s.write('\t"{0}"'.format(icon_name))
|
inline constexpr int default_theme_icons_count = {len(icons_names)};
|
||||||
|
inline constexpr const char *default_theme_icons_sources[] = {{
|
||||||
|
{icons_raw_str}
|
||||||
|
}};
|
||||||
|
|
||||||
if fname != svg_icons[-1]:
|
inline constexpr const char *default_theme_icons_names[] = {{
|
||||||
s.write(",")
|
{icons_names_str}
|
||||||
s.write("\n")
|
}};
|
||||||
|
""")
|
||||||
index += 1
|
|
||||||
|
|
||||||
s.write("};\n")
|
|
||||||
|
|
||||||
s.write("#endif\n")
|
|
||||||
|
|
||||||
with open(dst, "w", encoding="utf-8", newline="\n") as f:
|
|
||||||
f.write(s.getvalue())
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user