|  | #!/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") | 
|  |  | 
|  | 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()) |