blob: 51f111a8127419aaa4567e59919b79739bbd0711 [file] [log] [blame] [edit]
#!/usr/bin/env python3
#
# Copyright 2021 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import enum
import os
from pathlib import Path
import shlex
import shutil
import subprocess
import sys
from typing import List, Union
import zipfile
NINJA_SRC = Path(__file__).parent.parent
TOP = NINJA_SRC.parent.parent
@enum.unique
class Host(enum.Enum):
"""Enumeration of supported hosts."""
Darwin = 'darwin'
Linux = 'linux'
Windows = 'windows'
def get_default_host() -> Host:
"""Returns the Host matching the current machine."""
if sys.platform.startswith('linux'):
return Host.Linux
if sys.platform.startswith('darwin'):
return Host.Darwin
if sys.platform.startswith('win'):
return Host.Windows
raise RuntimeError(f'Unsupported host: {sys.platform}')
def create_new_dir(path: Path) -> None:
if path.exists():
shutil.rmtree(path)
path.mkdir(parents=True)
def run_cmd(args: List[Union[str, Path]], cwd: Path = None) -> None:
if cwd is not None:
print(f'cd {cwd}')
str_args = [str(arg) for arg in args]
if get_default_host() == Host.Windows:
print(subprocess.list2cmdline(str_args))
else:
print(' '.join([shlex.quote(arg) for arg in str_args]))
sys.stdout.flush()
subprocess.run(str_args, cwd=cwd, check=True)
def zip_dir(root: Path, out_file: Path) -> None:
"""Zip a folder with archive paths relative to the root"""
with zipfile.ZipFile(out_file, 'w', zipfile.ZIP_DEFLATED) as zip_obj:
for parent, _, files in os.walk(root):
for file in files:
install_file = Path(parent) / file
rel_file = install_file.relative_to(root)
zip_obj.write(install_file, rel_file)
def main() -> None:
host = get_default_host()
exe = '.exe' if host == Host.Windows else ''
out = TOP / 'out/ninja'
create_new_dir(out)
create_new_dir(out / 'build')
create_new_dir(out / 'artifact')
prebuilt_cmake = TOP / f'prebuilts/cmake/{host.value}-x86/bin/cmake{exe}'
prebuilt_ninja = TOP / f'prebuilts/ninja/{host.value}-x86/ninja{exe}'
cmake_conf_args: List[Union[str, Path]] = [
prebuilt_cmake,
NINJA_SRC,
'-B', out / 'build',
]
cmake_build_args: List[Union[str, Path]] = [
prebuilt_cmake,
'--build', out / 'build',
'--parallel',
'--config', 'Release',
]
if host == Host.Windows:
cmake_conf_args += ['-G', 'Visual Studio 17 2022', '-A', 'x64']
else:
# Use the Multi-Config generator for consistency with MSVC, which is also multi-config.
# (e.g. "--config Release" replaces CMAKE_BUILD_TYPE, and there is a "Release" subdir.)
cmake_conf_args += [
'-G', 'Ninja Multi-Config',
f'-DCMAKE_MAKE_PROGRAM={prebuilt_ninja}',
]
if host == Host.Linux:
ldflags = '-static-libstdc++'
cmake_conf_args += [
f'-DCMAKE_EXE_LINKER_FLAGS={ldflags}',
f'-DCMAKE_SHARED_LINKER_FLAGS={ldflags}',
]
elif host == Host.Darwin:
cmake_conf_args += [
'-DCMAKE_OSX_DEPLOYMENT_TARGET=10.9',
'-DCMAKE_OSX_ARCHITECTURES=x86_64;arm64',
]
run_cmd(cmake_conf_args)
run_cmd(cmake_build_args)
ninja_bin = out / f'build/Release/ninja{exe}'
if host != Host.Windows:
run_cmd(['strip', ninja_bin])
create_new_dir(out / 'install')
shutil.copy2(ninja_bin, out / 'install')
# The LICENSE file is a symlink to COPYING. Avoid copying it directly because Kokoro uses Cygwin
# git, which produces a Cygwin symlink that non-Cygwin Python treats as a small binary file.
shutil.copy2(NINJA_SRC / 'COPYING', out / 'install/LICENSE')
build_id = os.getenv('KOKORO_BUILD_ID', 'dev')
zip_dir(out / 'install', out / f'artifact/ninja-{host.value}-{build_id}.zip')
run_cmd([sys.executable, TOP / 'toolchain/ndk-kokoro/gen_manifest.py',
'--root', TOP, '-o', out / f'artifact/manifest-{build_id}.xml'])
# The ninja tests complete in just a few seconds, so run them during the build. Wait until the
# end so we can collect artifacts if a test fails.
run_cmd([out / f'build/Release/ninja_test{exe}'], cwd=out / 'build')
if __name__ == '__main__':
main()