-
Notifications
You must be signed in to change notification settings - Fork 15.3k
[libc] Add some integration features into newhdrgen #114272
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This adds some command-line switches to the newhdrgen script that facilitate more generalized build system integration. These enable the use of the script in Fuchsia's GN build. The --write-if-changed switch avoids touching the .h output file if it's unchanged, which is beneficial to incremental rebuilds. The --depfile switch writes out a make/ninja-compatible depfile describing the inputs and outputs. This is crucial for build system integration when using the following new feature. When the new --libc-dir switch is given, the YAML file argument is optional. Instead, the --h_def_file input file path must have the --libc-dir path as a prefix and the yaml file is found in its corresponding place in the libc source tree.
|
✅ With the latest revision this PR passed the Python code formatter. |
|
@llvm/pr-subscribers-libc Author: Roland McGrath (frobtech) ChangesThis adds some command-line switches to the newhdrgen script The --write-if-changed switch avoids touching the .h output file The --depfile switch writes out a make/ninja-compatible depfile When the new --libc-dir switch is given, the YAML file argument Full diff: https://github.com/llvm/llvm-project/pull/114272.diff 1 Files Affected:
diff --git a/libc/newhdrgen/yaml_to_classes.py b/libc/newhdrgen/yaml_to_classes.py
index a295058f7dc821..460bc4a87452c3 100644
--- a/libc/newhdrgen/yaml_to_classes.py
+++ b/libc/newhdrgen/yaml_to_classes.py
@@ -219,15 +219,36 @@ def increase_indent(self, flow=False, indentless=False):
def main():
parser = argparse.ArgumentParser(description="Generate header files from YAML")
parser.add_argument(
- "yaml_file", help="Path to the YAML file containing header specification"
+ "yaml_file",
+ help="Path to the YAML file containing header specification",
+ type=Path,
+ nargs="?",
)
parser.add_argument(
"--output_dir",
help="Directory to output the generated header file",
+ type=Path,
)
parser.add_argument(
"--h_def_file",
help="Path to the .h.def template file (required if not using --export_decls)",
+ type=Path,
+ )
+ parser.add_argument(
+ "--libc-dir",
+ help="Path to llvm-libc source tree",
+ type=Path,
+ default=Path(__file__).parents[1],
+ )
+ parser.add_argument(
+ "--depfile",
+ help="Path to write a depfile",
+ type=argparse.FileType("w"),
+ )
+ parser.add_argument(
+ "--write-if-changed",
+ help="Don't touch the output .h file if it's unchanged",
+ action="store_true",
)
parser.add_argument(
"--add_function",
@@ -252,30 +273,62 @@ def main():
)
args = parser.parse_args()
+ def write_to_file(path, contents):
+ if (
+ not args.write_if_changed
+ or not path.exists()
+ or path.read_text() != contents
+ ):
+ path.write_text(contents)
+
+ yaml_file = args.yaml_file
+ if args.h_def_file and not yaml_file:
+ libc_include_dir = args.libc_dir / "include"
+ libc_yaml_dir = args.libc_dir / "newhdrgen" / "yaml"
+ yaml_file = libc_yaml_dir / args.h_def_file.with_suffix("").with_suffix(
+ ".yaml"
+ ).relative_to(libc_include_dir)
+
+ if args.output_dir:
+ output_file_path = args.output_dir
+ if output_file_path.is_dir():
+ if not args.yaml_file:
+ libc_yaml_dir = args.libc_dir / "newhdrgen" / "yaml"
+ output_file_path /= args.yaml_file.relative_to(
+ libc_yaml_dir
+ ).with_suffix(".h")
+ else:
+ output_file_path /= f"{Path(args.yaml_file).stem}.h"
+ output_file_path.parent.mkdir(parents=True, exist_ok=True)
+ else:
+ output_file_path = args.yaml_file.with_suffix(".h")
+
+ if args.depfile and args.h_def_file:
+ args.depfile.write(f"{output_file_path}: {args.h_def_file} {args.yaml_file}\n")
+ args.depfile.close()
+
if args.add_function:
add_function_to_yaml(yaml_file, args.add_function)
header_class = GpuHeader if args.export_decls else HeaderFile
header = load_yaml_file(args.yaml_file, header_class, args.entry_points)
+ if args.add_function:
+ add_function_to_yaml(yaml_file, args.add_function)
+
header_str = str(header)
+ header_class = GpuHeader if args.export_decls else HeaderFile
+ header = load_yaml_file(args.yaml_file, header_class, args.entry_points)
- if args.output_dir:
- output_file_path = Path(args.output_dir)
- if output_file_path.is_dir():
- output_file_path /= f"{Path(args.yaml_file).stem}.h"
- else:
- output_file_path = Path(f"{Path(args.yaml_file).stem}.h")
+ header_str = str(header)
if not args.export_decls and args.h_def_file:
with open(args.h_def_file, "r") as f:
h_def_content = f.read()
final_header_content = fill_public_api(header_str, h_def_content)
- with open(output_file_path, "w") as f:
- f.write(final_header_content)
else:
- with open(output_file_path, "w") as f:
- f.write(header_str)
+ final_header_content = str
+ write_to_file(output_file_path, final_header_content)
if __name__ == "__main__":
|
michaelrj-google
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code changes overall LGTM, make sure to update the docs where necessary: https://github.com/llvm/llvm-project/blob/main/libc/docs/dev/header_generation.rst?plain=1
That does not currently include any explanation of the file-related command line switches. It's not really documentation for the tool as a tool. It's more a few examples of things to try and what might happen. |
fabio-d
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it'd be great if the two blocks that decide yaml_file and output_file_path had some comment explaining the various cases with examples, because the code alone was a bit hard to follow to me
| else: | ||
| with open(output_file_path, "w") as f: | ||
| f.write(header_str) | ||
| final_header_content = str |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
final_header_content = header_str?
| header_class = GpuHeader if args.export_decls else HeaderFile | ||
| header = load_yaml_file(args.yaml_file, header_class, args.entry_points) | ||
|
|
||
| if args.add_function: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this repetition (see 5 lines above) on purpose?
michaelrj-google
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall LGTM, but you need to fix the paths before landing.
| output_file_path = args.output_dir | ||
| if output_file_path.is_dir(): | ||
| if not args.yaml_file: | ||
| libc_yaml_dir = args.libc_dir / "newhdrgen" / "yaml" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also needs to be updated.
| yaml_file = args.yaml_file | ||
| if args.h_def_file and not yaml_file: | ||
| libc_include_dir = args.libc_dir / "include" | ||
| libc_yaml_dir = args.libc_dir / "newhdrgen" / "yaml" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this needs to be updated since headergen has been moved to the hdrgen directory.
| def write_to_file(path, contents): | ||
| if ( | ||
| not args.write_if_changed | ||
| or not path.exists() | ||
| or path.read_text() != contents | ||
| ): | ||
| path.write_text(contents) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
given that this is only used in one place at the moment, would it make more sense to inline this function?
|
I'm going to abandon this and do some more basic refactoring to get towards a good CLI for both programmatic and human use. It will be in several smaller steps. |
This adds some command-line switches to the newhdrgen script
that facilitate more generalized build system integration.
These enable the use of the script in Fuchsia's GN build.
The --write-if-changed switch avoids touching the .h output file
if it's unchanged, which is beneficial to incremental rebuilds.
The --depfile switch writes out a make/ninja-compatible depfile
describing the inputs and outputs. This is crucial for build
system integration when using the following new feature.
When the new --libc-dir switch is given, the YAML file argument
is optional. Instead, the --h_def_file input file path must have
the --libc-dir path as a prefix and the yaml file is found in its
corresponding place in the libc source tree.