mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-06-07 21:17:07 +09:00
Meta: Add build command to ladybird.py
This commit is contained in:
parent
85842c1739
commit
c9624d5118
Notes:
github-actions[bot]
2025-05-21 17:37:14 +00:00
Author: https://github.com/ayeteadoe
Commit: c9624d5118
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/4742
Reviewed-by: https://github.com/ADKaster
Reviewed-by: https://github.com/R-Goc
Reviewed-by: https://github.com/trflynn89
5 changed files with 309 additions and 0 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -59,3 +59,5 @@ Meta/CMake/vcpkg/user-variables.cmake
|
|||
|
||||
# Keep last to ensure .DS_Store is never tracked, even if otherwise allowed by any exception above.
|
||||
.DS_Store
|
||||
|
||||
__pycache__
|
||||
|
|
|
@ -55,14 +55,18 @@
|
|||
{
|
||||
"hidden": true,
|
||||
"name": "windows_ci",
|
||||
"binaryDir": "${fileDir}/Build/release",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
|
||||
"ENABLE_WINDOWS_CI": "ON"
|
||||
}
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"name": "windows_dev",
|
||||
"binaryDir": "${fileDir}/Build/debug",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"ENABLE_WINDOWS_CI": "OFF"
|
||||
}
|
||||
},
|
||||
|
|
1
Meta/__init__.py
Normal file
1
Meta/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
# NOTE: Provided so ladybird.py can import the BuildVcpkg script as a module
|
301
Meta/ladybird.py
Executable file
301
Meta/ladybird.py
Executable file
|
@ -0,0 +1,301 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import shutil
|
||||
import multiprocessing
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
from enum import IntEnum
|
||||
|
||||
|
||||
class HostArchitecture(IntEnum):
|
||||
Unsupported = 0
|
||||
x86_64 = 1
|
||||
AArch64 = 2
|
||||
|
||||
|
||||
class HostSystem(IntEnum):
|
||||
Unsupported = 0
|
||||
Linux = 1
|
||||
macOS = 2
|
||||
Windows = 3
|
||||
|
||||
|
||||
class Platform:
|
||||
def __init__(self):
|
||||
import platform
|
||||
self.system = platform.system()
|
||||
if self.system == 'Windows':
|
||||
self.host_system = HostSystem.Windows
|
||||
elif self.system == 'Darwin':
|
||||
self.host_system = HostSystem.macOS
|
||||
elif self.system == 'Linux':
|
||||
self.host_system = HostSystem.Linux
|
||||
else:
|
||||
self.host_system = HostSystem.Unsupported
|
||||
|
||||
self.architecture = platform.machine().lower()
|
||||
if self.architecture in ('x86_64', 'amd64'):
|
||||
self.host_architecture = HostArchitecture.x86_64
|
||||
elif self.architecture in ('aarch64', 'arm64'):
|
||||
self.host_architecture = HostArchitecture.AArch64
|
||||
else:
|
||||
self.host_architecture = HostArchitecture.Unsupported
|
||||
|
||||
|
||||
def main(platform):
|
||||
if platform.host_system == HostSystem.Unsupported:
|
||||
print(f'Unsupported host system {platform.system}', file=sys.stderr)
|
||||
sys.exit(1)
|
||||
if platform.host_architecture == HostArchitecture.Unsupported:
|
||||
print(f'Unsupported host architecture {platform.architecture}', file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
parser = argparse.ArgumentParser(description='Ladybird')
|
||||
subparsers = parser.add_subparsers(dest='command')
|
||||
|
||||
preset_parser = argparse.ArgumentParser(add_help=False)
|
||||
preset_parser.add_argument(
|
||||
'--preset',
|
||||
required=False,
|
||||
default=os.environ.get('BUILD_PRESET',
|
||||
'windows_dev_ninja' if platform.host_system == HostSystem.Windows else 'default'),
|
||||
)
|
||||
|
||||
# FIXME: Validate that the cc/cxx combination is compatible (e.g. don't allow CC=gcc and CXX=clang++)
|
||||
# FIXME: Migrate find_compiler.sh for more explicit compiler validation
|
||||
compiler_parser = argparse.ArgumentParser(add_help=False)
|
||||
compiler_parser.add_argument(
|
||||
'--cc',
|
||||
required=False,
|
||||
default=os.environ.get('CC', 'clang-cl' if platform.host_system == HostSystem.Windows else 'cc'))
|
||||
compiler_parser.add_argument(
|
||||
'--cxx',
|
||||
required=False,
|
||||
default=os.environ.get('CXX', 'clang-cl' if platform.host_system == HostSystem.Windows else 'c++')
|
||||
)
|
||||
|
||||
target_parser = argparse.ArgumentParser(add_help=False)
|
||||
target_parser.add_argument('--target', required=False, default='Ladybird')
|
||||
|
||||
build_parser = subparsers.add_parser('build', help='Compiles the target binaries',
|
||||
parents=[preset_parser, compiler_parser, target_parser])
|
||||
build_parser.add_argument('args', nargs=argparse.REMAINDER,
|
||||
help='Additional arguments passed through to the build system')
|
||||
|
||||
args = parser.parse_args()
|
||||
kwargs = vars(args)
|
||||
command = kwargs.pop('command', None)
|
||||
|
||||
if not command:
|
||||
parser.print_help()
|
||||
sys.exit(1)
|
||||
|
||||
if platform.host_system != HostSystem.Windows and os.geteuid() == 0:
|
||||
print('Do not run ladybird.py as root, your Build directory will become root-owned', file=sys.stderr)
|
||||
sys.exit(1)
|
||||
elif platform.host_system == HostSystem.Windows and 'VCINSTALLDIR' not in os.environ:
|
||||
print('ladybird.py must be run from a Visual Studio enabled environment', file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
if command == 'build':
|
||||
build_dir = _configure_main(platform, **kwargs)
|
||||
_build_main(build_dir, **kwargs)
|
||||
|
||||
|
||||
def _configure_main(platform, **kwargs):
|
||||
cmake_args = []
|
||||
|
||||
host_system = platform.host_system
|
||||
if host_system == HostSystem.Linux and platform.host_architecture == HostArchitecture.AArch64:
|
||||
cmake_args.extend(_configure_skia_jemalloc())
|
||||
|
||||
lb_source_dir, build_preset_dir, build_env_cmake_args = _configure_build_env(**kwargs)
|
||||
if build_preset_dir.joinpath('build.ninja').exists() or build_preset_dir.joinpath('ladybird.sln').exists():
|
||||
return build_preset_dir
|
||||
|
||||
_build_vcpkg()
|
||||
_validate_cmake_version()
|
||||
|
||||
cmake_args.extend(build_env_cmake_args)
|
||||
config_args = [
|
||||
'cmake',
|
||||
'--preset',
|
||||
kwargs.get('preset'),
|
||||
'-S',
|
||||
lb_source_dir,
|
||||
'-B',
|
||||
build_preset_dir,
|
||||
]
|
||||
config_args.extend(cmake_args)
|
||||
|
||||
# FIXME: Improve error reporting for vcpkg install failures
|
||||
# https://github.com/LadybirdBrowser/ladybird/blob/master/Documentation/BuildInstructionsLadybird.md#unable-to-find-a-build-program-corresponding-to-ninja
|
||||
try:
|
||||
subprocess.check_call(config_args)
|
||||
except subprocess.CalledProcessError as e:
|
||||
_print_process_stderr(e, 'Unable to configure ladybird project')
|
||||
sys.exit(1)
|
||||
return build_preset_dir
|
||||
|
||||
|
||||
def _configure_skia_jemalloc():
|
||||
import resource
|
||||
page_size = resource.getpagesize()
|
||||
gn = shutil.which('gn') or None
|
||||
# https://github.com/LadybirdBrowser/ladybird/issues/261
|
||||
if page_size != 4096 and gn is None:
|
||||
print('GN not found! Please build GN from source and put it in $PATH', file=sys.stderr)
|
||||
sys.exit(1)
|
||||
pkg_config = shutil.which('pkg-config') or None
|
||||
cmake_args = []
|
||||
if pkg_config:
|
||||
cmake_args.append(f'-DPKG_CONFIG_EXECUTABLE={pkg_config}')
|
||||
|
||||
user_vars_cmake_module = Path('Meta/CMake/vcpkg/user-variables.cmake')
|
||||
user_vars_cmake_module.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
with open(user_vars_cmake_module, 'w') as f:
|
||||
f.writelines([
|
||||
f'set(PKGCONFIG {pkg_config})',
|
||||
f'set(GN {gn})',
|
||||
'',
|
||||
])
|
||||
|
||||
return cmake_args
|
||||
|
||||
|
||||
def _configure_build_env(**kwargs):
|
||||
preset = kwargs.get('preset')
|
||||
cc = kwargs.get('cc')
|
||||
cxx = kwargs.get('cxx')
|
||||
cmake_args = []
|
||||
cmake_args.extend([
|
||||
f'-DCMAKE_C_COMPILER={cc}',
|
||||
f'-DCMAKE_CXX_COMPILER={cxx}',
|
||||
])
|
||||
_ensure_ladybird_source_dir()
|
||||
lb_source_dir = Path(os.environ.get('LADYBIRD_SOURCE_DIR'))
|
||||
|
||||
build_root_dir = lb_source_dir / 'Build'
|
||||
|
||||
known_presets = {
|
||||
'default': build_root_dir / 'release',
|
||||
'windows_ci_ninja': build_root_dir / 'release',
|
||||
'windows_dev_ninja': build_root_dir / 'debug',
|
||||
'windows_dev_msbuild': build_root_dir / 'debug',
|
||||
'Debug': build_root_dir / 'debug',
|
||||
'Sanitizer': build_root_dir / 'sanitizers',
|
||||
'Distribution': build_root_dir / 'distribution',
|
||||
}
|
||||
if preset not in known_presets:
|
||||
print(f'Unknown build preset "{preset}"', file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
build_preset_dir = known_presets.get(preset)
|
||||
vcpkg_root = str(build_root_dir / 'vcpkg')
|
||||
os.environ['VCPKG_ROOT'] = vcpkg_root
|
||||
os.environ['PATH'] += os.pathsep + str(lb_source_dir.joinpath('Toolchain', 'Local', 'cmake', 'bin'))
|
||||
os.environ['PATH'] += os.pathsep + str(vcpkg_root)
|
||||
return lb_source_dir, build_preset_dir, cmake_args
|
||||
|
||||
|
||||
def _build_vcpkg():
|
||||
sys.path.append(str(Path(__file__).parent.joinpath('..', 'Toolchain')))
|
||||
# FIXME: Rename main() in BuildVcpkg.py to build_vcpkg() and call that from the scripts __main__
|
||||
from BuildVcpkg import main as build_vcpkg
|
||||
build_vcpkg()
|
||||
|
||||
|
||||
def _validate_cmake_version():
|
||||
# FIXME: This 3.25+ CMake version check may not be needed anymore due to vcpkg downloading a newer version
|
||||
cmake_pls_install_msg = 'Please install CMake version 3.25 or newer.'
|
||||
|
||||
try:
|
||||
cmake_version_output = subprocess.check_output(
|
||||
[
|
||||
'cmake',
|
||||
'--version',
|
||||
],
|
||||
text=True
|
||||
).strip()
|
||||
|
||||
version_match = re.search(r'version\s+(\d+)\.(\d+)\.(\d+)?', cmake_version_output)
|
||||
if version_match:
|
||||
major = int(version_match.group(1))
|
||||
minor = int(version_match.group(2))
|
||||
patch = int(version_match.group(3))
|
||||
if major < 3 or (major == 3 and minor < 25):
|
||||
print(f'CMake version {major}.{minor}.{patch} is too old. {cmake_pls_install_msg}', file=sys.stderr)
|
||||
sys.exit(1)
|
||||
else:
|
||||
print(f'Unable to determine CMake version. {cmake_pls_install_msg}', file=sys.stderr)
|
||||
sys.exit(1)
|
||||
except subprocess.CalledProcessError as e:
|
||||
_print_process_stderr(e, f'CMake not found. {cmake_pls_install_msg}\n')
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def _ensure_ladybird_source_dir():
|
||||
ladybird_source_dir = os.environ.get('LADYBIRD_SOURCE_DIR', None)
|
||||
ladybird_source_dir = Path(ladybird_source_dir) if ladybird_source_dir else None
|
||||
|
||||
if not ladybird_source_dir or not ladybird_source_dir.is_dir():
|
||||
try:
|
||||
top_dir = subprocess.check_output(
|
||||
[
|
||||
'git',
|
||||
'rev-parse',
|
||||
'--show-toplevel',
|
||||
],
|
||||
text=True
|
||||
).strip()
|
||||
|
||||
ladybird_source_dir = Path(top_dir)
|
||||
os.environ['LADYBIRD_SOURCE_DIR'] = str(ladybird_source_dir)
|
||||
except subprocess.CalledProcessError as e:
|
||||
_print_process_stderr(e, 'Unable to determine LADYBIRD_SOURCE_DIR:')
|
||||
sys.exit(1)
|
||||
return ladybird_source_dir
|
||||
|
||||
|
||||
def _build_main(build_dir, **kwargs):
|
||||
build_args = [
|
||||
'cmake',
|
||||
'--build',
|
||||
str(build_dir),
|
||||
'--parallel',
|
||||
os.environ.get('MAKEJOBS', str(multiprocessing.cpu_count())),
|
||||
]
|
||||
build_target = kwargs.get('target', '')
|
||||
if build_target:
|
||||
build_args.extend([
|
||||
'--target',
|
||||
build_target,
|
||||
])
|
||||
build_system_args = kwargs.get('args', [])
|
||||
if build_system_args:
|
||||
build_args.append('--')
|
||||
build_args.extend(build_system_args)
|
||||
try:
|
||||
subprocess.check_call(build_args)
|
||||
except subprocess.CalledProcessError as e:
|
||||
msg = 'Unable to build ladybird '
|
||||
if build_target:
|
||||
msg += f'target "{build_target}"'
|
||||
else:
|
||||
msg += 'project'
|
||||
_print_process_stderr(e, msg)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def _print_process_stderr(e, msg):
|
||||
err_details = f': {e.stderr}' if e.stderr else ''
|
||||
print(f'{msg}{err_details}', file=sys.stderr)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(Platform())
|
1
Toolchain/__init__.py
Normal file
1
Toolchain/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
# NOTE: Provided so ladybird.py can import the BuildVcpkg script as a module
|
Loading…
Add table
Add a link
Reference in a new issue