[K/N] Option to build smaller LLVM distribution.

Also add a few adjustments to `package.py`:
* Enable threading in LLVM
* Replace `--archive-path` with `--pack` to avoid naming divergence.
This commit is contained in:
Sergey Bogolepov
2021-08-09 11:37:07 +07:00
committed by Space
parent 74e26126df
commit 75215fcb97
2 changed files with 62 additions and 29 deletions
+21 -5
View File
@@ -18,24 +18,42 @@ python3 package.py
``` ```
It will create a `llvm-distribution` folder which contains LLVM distribution. It will create a `llvm-distribution` folder which contains LLVM distribution.
Note that build will take a lot of time and all your machine cores. 😈 Note that build will take a lot of time and all your machine cores. 😈
See [HACKING.md](../../HACKING.md#using-different-llvm-distributions-as-part-of-kotlinnative-compilation-pipeline) on how to use freshly built distribution. See [HACKING.md](../../HACKING.md#using-different-llvm-distributions-as-part-of-kotlinnative-compilation-pipeline)
on how to use freshly built distribution.
### Building distribution for end-users
By default, `package.py` installs a lot of LLVM components that is not really required to use Kotlin/Native compiler.
To build only essential parts, run the following command:
```
python3 package.py --build-targets install-distribution --distribution-components $DISTRIBUTION_COMPONENTS
```
Set of required `$DISTRIBUTION_COMPONENTS` is depends on OS:
| OS | Distribution components |
| --- | --- |
|Windows | `clang libclang lld llvm-cov llvm-profdata llvm-ar clang-resource-headers` |
|macOS | `clang libclang lld llvm-cov llvm-profdata llvm-ar clang-resource-headers` |
|Linux | `clang libclang lld llvm-cov llvm-profdata llvm-ar clang-resource-headers compiler_rt` |
### Tuning ### Tuning
Run `python3 package.py -h` to check how one can tune script's behavior. Run `python3 package.py -h` to check how one can tune script's behavior.
Some examples: Some examples:
* `--archive-path` creates an archive (`zip` on Windows, `tar.gz` on macOS and Linux) with distribution * `--pack` creates an archive (`zip` on Windows, `tar.gz` on macOS and Linux) with distribution
alongside with its SHA256. alongside with its SHA256.
* `--install-path` allows overriding distribution's output directory. * `--install-path` allows overriding distribution's output directory.
* `--num-stages` specifies number of steps in build. Passing 2 or more makes bootstrap build which * `--num-stages` specifies number of steps in build. Passing 2 or more makes bootstrap build which
means that LLVM will build itself by using distribution from the previous step. means that LLVM will build itself by using distribution from the previous step.
* `--stage0` allows using existing LLVM toolchain for bootstrapping. * `--stage0` allows using existing LLVM toolchain for bootstrapping.
* `--build-targets` specifies what targets will be passed to Ninja.
* `--distribution-components` is a list of components that will be installed with `install-distribution` build target.
### Docker ### Docker
You can use Docker to build LLVM for Linux: You can use Docker to build LLVM for Linux:
```shell ```shell
docker build -t kotlin-llvm-builder . docker build -t kotlin-llvm-builder .
docker run --rm -it -v <HOST_PATH>:/output kotlin-llvm-builder --archive-path /output/llvm-11.1.0-linux-x64 docker run --rm -it -v <HOST_PATH>:/output kotlin-llvm-builder --install-path /output/llvm-11.1.0-linux-x64 --pack
``` ```
@@ -43,5 +61,3 @@ docker run --rm -it -v <HOST_PATH>:/output kotlin-llvm-builder --archive-path /o
1. Bootstrap build is not working on macOS for default git branch. 1. Bootstrap build is not working on macOS for default git branch.
2. `libcxx` and `compiler-rt` are built as projects, not runtimes. 2. `libcxx` and `compiler-rt` are built as projects, not runtimes.
3. No way to run LLVM tests out of the box. 3. No way to run LLVM tests out of the box.
4. No way to override default `install` task out of the box.
+41 -24
View File
@@ -92,13 +92,31 @@ def construct_cmake_flags(
install_path: str = None, install_path: str = None,
projects: List[str] = None, projects: List[str] = None,
runtimes: List[str] = None, runtimes: List[str] = None,
targets: List[str] = None targets: List[str] = None,
distribution_components: List[str] = None
) -> List[str]: ) -> List[str]:
building_bootstrap = bootstrap_llvm_path is None building_bootstrap = bootstrap_llvm_path is None
c_compiler, cxx_compiler, linker, ar = None, None, None, None c_compiler, cxx_compiler, linker, ar = None, None, None, None
c_flags, cxx_flags, linker_flags = None, None, None c_flags, cxx_flags, linker_flags = None, None, None
cmake_args = [
'-DCMAKE_BUILD_TYPE=Release',
'-DLLVM_ENABLE_ASSERTIONS=OFF',
'-DLLVM_ENABLE_TERMINFO=OFF',
'-DLLVM_INCLUDE_GO_TESTS=OFF',
'-DLLVM_ENABLE_Z3_SOLVER=OFF',
'-DCOMPILER_RT_BUILD_BUILTINS=ON',
'-DLLVM_ENABLE_THREADS=ON',
'-DLLVM_OPTIMIZED_TABLEGEN=ON'
]
if not building_bootstrap: if not building_bootstrap:
if distribution_components:
cmake_args.append('-DLLVM_DISTRIBUTION_COMPONENTS=' + ';'.join(distribution_components))
# These links are actually copies on windows, so they're wasting precious disk space.
cmake_args.append("-DCLANG_LINKS_TO_CREATE=clang++")
cmake_args.append("-DLLD_SYMLINKS_TO_CREATE=ld.lld;wasm-ld")
if host_is_windows(): if host_is_windows():
# CMake is not tolerant to backslashes # CMake is not tolerant to backslashes
c_compiler = f'{bootstrap_llvm_path}/bin/clang-cl.exe'.replace('\\', '/') c_compiler = f'{bootstrap_llvm_path}/bin/clang-cl.exe'.replace('\\', '/')
@@ -120,14 +138,6 @@ def construct_cmake_flags(
cxx_flags = ['-isysroot', isysroot, '-stdlib=libc++'] cxx_flags = ['-isysroot', isysroot, '-stdlib=libc++']
linker_flags = ['-stdlib=libc++'] linker_flags = ['-stdlib=libc++']
cmake_args = [
'-DCMAKE_BUILD_TYPE=Release',
'-DLLVM_ENABLE_ASSERTIONS=OFF',
'-DLLVM_ENABLE_TERMINFO=OFF',
'-DLLVM_INCLUDE_GO_TESTS=OFF',
'-DLLVM_ENABLE_Z3_SOLVER=OFF',
'-DCOMPILER_RT_BUILD_BUILTINS=ON'
]
if host_is_darwin(): if host_is_darwin():
cmake_args.append('-DLLVM_ENABLE_LIBCXX=ON') cmake_args.append('-DLLVM_ENABLE_LIBCXX=ON')
@@ -186,7 +196,7 @@ def construct_cmake_flags(
# Also not working for Linux and macOS because of signal chaining. # Also not working for Linux and macOS because of signal chaining.
# TODO: Enable after LLVM distribution patching. # TODO: Enable after LLVM distribution patching.
if not host_is_windows(): if not host_is_windows():
cmake_args.append("-LLVM_BUILD_LLVM_DYLIB=OFF") cmake_args.append("-DLLVM_BUILD_LLVM_DYLIB=OFF")
cmake_args.append("-DLLVM_LINK_LLVM_DYLIB=OFF") cmake_args.append("-DLLVM_LINK_LLVM_DYLIB=OFF")
return cmake_args return cmake_args
@@ -221,11 +231,11 @@ def force_create_directory(parent, name) -> Path:
def llvm_build_commands( def llvm_build_commands(
install_path, bootstrap_path, llvm_src, targets, ninja_target, projects, runtimes install_path, bootstrap_path, llvm_src, targets, build_targets, projects, runtimes, distribution_components
) -> List[List[str]]: ) -> List[List[str]]:
cmake_flags = construct_cmake_flags(bootstrap_path, install_path, projects, runtimes, targets) cmake_flags = construct_cmake_flags(bootstrap_path, install_path, projects, runtimes, targets, distribution_components)
cmake_command = [cmake, "-G", "Ninja"] + cmake_flags + [os.path.join(llvm_src, "llvm")] cmake_command = [cmake, "-G", "Ninja"] + cmake_flags + [os.path.join(llvm_src, "llvm")]
ninja_command = [ninja, ninja_target] ninja_command = [ninja] + build_targets
return [cmake_command, ninja_command] return [cmake_command, ninja_command]
@@ -250,12 +260,18 @@ def default_num_stages():
def build_parser() -> argparse.ArgumentParser: def build_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(description="Build LLVM toochain for Kotlin/Native") parser = argparse.ArgumentParser(description="Build LLVM toolchain for Kotlin/Native")
# Output configuration. # Output configuration.
parser.add_argument("--install-path", type=str, default="llvm-distribution", required=False, parser.add_argument("--install-path", type=str, default="llvm-distribution", required=False,
help="Where final LLVM distribution will be installed") help="Where final LLVM distribution will be enabled")
parser.add_argument("--archive-path", default=None, parser.add_argument("--pack", action='store_true',
help="Create an archive and its sha256 for final distribution at given path") help="Create an archive and its sha256 for final distribution at `--install-path`")
parser.add_argument("--build-targets", default=["install"],
nargs="+",
help="What components should be installed")
parser.add_argument("--distribution-components", default=None,
nargs="+",
help="What components should be installed with `install-distribution` target")
# Build configuration # Build configuration
parser.add_argument("--stage0", type=str, default=None, parser.add_argument("--stage0", type=str, default=None,
help="Path to existing LLVM toolchain") help="Path to existing LLVM toolchain")
@@ -280,7 +296,7 @@ def build_parser() -> argparse.ArgumentParser:
parser.add_argument("--isysroot", type=str, default=None, parser.add_argument("--isysroot", type=str, default=None,
help="(macOS only) Override path to macOS SDK") help="(macOS only) Override path to macOS SDK")
# Misc. # Misc.
parser.add_argument("--save-temporary-files", type=bool, default=False, parser.add_argument("--save-temporary-files", action='store_true',
help="Should intermediate build results be saved?") help="Should intermediate build results be saved?")
return parser return parser
@@ -312,16 +328,16 @@ def build_distribution(args):
else: else:
# None targets means all available targets. # None targets means all available targets.
targets = None targets = None
if building_final: if building_final:
install_path = args.install_path install_path = args.install_path
build_targets = args.build_targets
else: else:
install_path = force_create_directory(current_dir, f"llvm-stage-{stage}") install_path = force_create_directory(current_dir, f"llvm-stage-{stage}")
intermediate_build_results.append(install_path) intermediate_build_results.append(install_path)
build_targets = ["install"]
projects = ["clang", "lld", "libcxx", "libcxxabi", "compiler-rt"] projects = ["clang", "lld", "libcxx", "libcxxabi", "compiler-rt"]
runtimes = None runtimes = None
ninja_target = "install"
build_dir = force_create_directory(current_dir, f"llvm-stage-{stage}-build") build_dir = force_create_directory(current_dir, f"llvm-stage-{stage}-build")
intermediate_build_results.append(build_dir) intermediate_build_results.append(build_dir)
@@ -330,9 +346,10 @@ def build_distribution(args):
bootstrap_path=absolute_path(bootstrap_path), bootstrap_path=absolute_path(bootstrap_path),
llvm_src=absolute_path(args.llvm_src), llvm_src=absolute_path(args.llvm_src),
targets=targets, targets=targets,
ninja_target=ninja_target, build_targets=build_targets,
projects=projects, projects=projects,
runtimes=runtimes runtimes=runtimes,
distribution_components=args.distribution_components
) )
os.chdir(build_dir) os.chdir(build_dir)
@@ -404,8 +421,8 @@ def main():
temporary_llvm_repo = clone_llvm_repository(args.repo, args.branch, args.llvm_repo_destination) temporary_llvm_repo = clone_llvm_repository(args.repo, args.branch, args.llvm_repo_destination)
args.llvm_src = temporary_llvm_repo args.llvm_src = temporary_llvm_repo
final_dist = build_distribution(args) final_dist = build_distribution(args)
if args.archive_path is not None: if args.pack:
archive = create_archive(final_dist, args.archive_path) archive = create_archive(final_dist, args.install_path)
create_checksum_file(archive, f"{archive}.sha256") create_checksum_file(archive, f"{archive}.sha256")
if not args.save_temporary_files and temporary_llvm_repo is not None: if not args.save_temporary_files and temporary_llvm_repo is not None:
print(f"Removing temporary directory: {temporary_llvm_repo}") print(f"Removing temporary directory: {temporary_llvm_repo}")