| #!/usr/bin/env python3 |
| # Copyright 2022 The IREE Authors |
| # |
| # Licensed under the Apache License v2.0 with LLVM Exceptions. |
| # See https://llvm.org/LICENSE.txt for license information. |
| # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| |
| # This scans the IREE source tree for long path lengths, which are problematic |
| # on Windows: https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation |
| # |
| # We ultimately care that the build system is happy, but CMake on Windows in |
| # particular does not actually give early or easy to understand error messages, |
| # and developers/CI using Linux may still want to see warnings. We'll use |
| # relative directory path length as a reasonable heuristic for "will the build |
| # system be happy?", since CMake tends to create paths like this: |
| # `iree/compiler/.../Foo/CMakeFiles/iree_compiler_Foo_Foo.objects.dir/bar.obj`. |
| # Note that 'Foo' appears three times in that path, so that's typically the best |
| # place to trim characters (and not file names). |
| # |
| # To check that all relative paths are shorter than the default limit: |
| # python check_path_lengths.py |
| # |
| # To check that all relative paths are shorter than a custom limit: |
| # python check_path_lengths.py --limit=50 |
| |
| import argparse |
| import os |
| import pathlib |
| import sys |
| |
| |
| def parse_arguments(): |
| parser = argparse.ArgumentParser(description="Path length checker") |
| # The default limit was selected based on repository state when this script |
| # was added. If the max path length decreases, consider lowering this too. |
| parser.add_argument( |
| "--limit", help="Path length limit (inclusive)", type=int, default=75 |
| ) |
| parser.add_argument( |
| "--include_tests", |
| help="Includes /test directories. False by default as these don't usually generate problematic files during the build", |
| action="store_true", |
| default=False, |
| ) |
| parser.add_argument( |
| "--verbose", |
| help="Outputs detailed information about path lengths", |
| action="store_true", |
| default=False, |
| ) |
| args = parser.parse_args() |
| return args |
| |
| |
| def main(args): |
| repo_root = pathlib.Path(__file__).parent.parent.parent |
| |
| # Just look at the compiler directory for now, since it has historically had |
| # by far the longest paths. |
| walk_root = os.path.join(repo_root, "compiler") |
| |
| longest_path_length = -1 |
| long_paths = [] |
| short_paths = [] |
| for dirpath, dirnames, _ in os.walk(walk_root): |
| # Don't descend into test directories, since they typically don't generate |
| # object files or binaries that could trip up the build system. |
| if not args.include_tests and "test" in dirnames: |
| dirnames.remove("test") |
| # Skip build directories (should really anything be covered by .gitignore). |
| if "build" in dirnames: |
| dirnames.remove("build") |
| |
| path = pathlib.Path(dirpath).relative_to(repo_root).as_posix() |
| if len(path) > args.limit: |
| long_paths.append(path) |
| else: |
| short_paths.append(path) |
| longest_path_length = max(longest_path_length, len(path)) |
| long_paths.sort(key=len) |
| short_paths.sort(key=len) |
| |
| if args.verbose and short_paths: |
| print(f"These paths are shorter than the limit of {args.limit} characters:") |
| for path in short_paths: |
| print("{:3d}, {}".format(len(path), path)) |
| |
| if long_paths: |
| print(f"These paths are longer than the limit of {args.limit} characters:") |
| for path in long_paths: |
| print("{:3d}, {}".format(len(path), path)) |
| print( |
| f"Error: {len(long_paths)} source paths are longer than {args.limit} characters." |
| ) |
| print(" Long paths can be problematic when building on Windows.") |
| print(" Please look at the output above and trim the paths.") |
| sys.exit(1) |
| else: |
| print(f"All path lengths are under the limit of {args.limit} characters.") |
| |
| |
| if __name__ == "__main__": |
| main(parse_arguments()) |