Skip to content
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

std.Build: fix Compile.installHeader behavior, add WriteFile.addCopyDirectory #19167

Merged
merged 11 commits into from
Apr 7, 2024

Conversation

castholm
Copy link
Contributor

@castholm castholm commented Mar 3, 2024

Fixes #17204
Closes #19139

The intent for Compile.installHeader and friends has always been to bundle the headers alongside an artifact, have them be installed together with the artifact and get automatically added to the include search paths of modules that link with the artifact.

Currently, however, these functions modify the default install top-level step of the builder, which can lead to a number of unexpected results such as installing or not installing the headers depending on which top-level build steps are invoked.

This PR changes it so that installed headers are added to the compile step itself instead of modifying the top-level install step. To handle the construction of the include search path for dependent linking modules, an intermediary WriteFile step responsible for constructing the appropriate include tree is created and set up the first time a module links to an artifact.

The standalone test install_headers has been added to verify the correctness of the installation and linking behavior.

Summary of changes:

  • [Breaking] Compile.installHeader now takes a LazyPath.
  • [Breaking] Compile.installConfigHeader has had its second argument removed and now uses the value of include_path as its sub path, for parity with Module.addConfigHeader. Use artifact.installHeader(config_h.getOutput(), "foo.h") if you want to set the sub path to something different.
  • [Breaking] Compile.installHeadersDirectory/installHeadersDirectoryOptions have been consolidated into Compile.installHeadersDirectory, which takes a LazyPath and allows exclude/include filters just like InstallDir.
  • [Breaking] b.addInstallHeaderFile now takes a LazyPath.
  • [Breaking] As a workaround for resurrect emit-h #9698, the generated -femit-h header is now never emitted even when the user specifies an override for h_dir. If you absolutely need the emitted header, you now need to do install_artifact.emitted_h = artifact.getEmittedH() until -femit-h is fixed.
  • added WriteFile.addCopyDirectory, which functions very similar to InstallDir.
  • InstallArtifact has been updated to install the bundled headers alongide the artifact. The bundled headers are installed to the directory specified by h_dir (which is zig-out/include by default).

Comment on lines +269 to +277
for (wf.directories.items) |dir| {
man.hash.addBytes(dir.source.getPath2(b, step));
man.hash.addBytes(dir.sub_path);
for (dir.options.exclude_extensions) |ext| man.hash.addBytes(ext);
if (dir.options.include_extensions) |incs| for (incs) |inc| man.hash.addBytes(inc);
}
Copy link
Contributor Author

@castholm castholm Mar 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit iffy and won't necessarily catch up with changes to files within the directory, only changes to the installation options. Directory args to Step.Run (which I based this on) have similar issues.

I'm not sure if this is a problem that needs solving or if it's an acceptable tradeoff for not having to recursively hash every single file in a directory tree, but it might be nice to find a solution for this in the future.

@castholm
Copy link
Contributor Author

castholm commented Mar 3, 2024

Additional thoughts: we now have three more or less copy/pasted implementations for "copy directory tree with exclude/include filters" in InstallDir, InstallArtifact and WriteFiles.addCopyDirectory. Maybe this should be extracted out to the standard library? I'm pretty sure I've seen people asking how to recursively copy a directory multiple times both on Ziggit and on Discord, so I'm sure people would find it useful outside of the context of the build system as well.

Comment on lines +264 to +277
// 'path' lazy paths are relative to the build root of some step, inferred from the step
// in which they are used. This means that we can't dupe such paths, because they may
// come from dependencies with their own build roots and duping the paths as is might
// cause the build script to search for the file relative to the wrong root.
// As a temporary workaround, we convert build root-relative paths to absolute paths.
// If/when the build-root relative paths are updated to encode which build root they are
// relative to, this workaround should be removed.
const duped_source: LazyPath = switch (self.source) {
.path => |root_rel| .{ .cwd_relative = b.pathFromRoot(root_rel) },
else => self.source.dupe(b),
};
Copy link
Contributor Author

@castholm castholm Mar 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested this with a simple local project where

  • package a exported a static library lib bundling build root-relative header a.h,
  • package b depended on a, and
  • package b built and installed an executable exe with a main.c root source file that uses symbols from a.h and which did both exe.linkLibrary(lib) and exe.installLibraryHeaders(lib).

That repro failed with an "unable to update file" error prior to this workaround, but passes now.

If #19313 is accepted and implemented, this workaround can be reverted.
(Thanks @MasterQ32 for indirectly bringing this flaw to my attention.)

castholm and others added 11 commits April 7, 2024 15:32
Previously, `Step.Compile.installHeader` and friends would incorrectly
modify the default `install` top-level step, when the intent was for
headers to get bundled with and installed alongside an artifact. This
change set implements the intended behavior.

This carries with it some breaking changes; `installHeader` and
`installConfigHeader` both have new signatures, and
`installHeadersDirectory` and `installHeadersDirectoryOptions` have been
merged into `installHeaders`.
This is no longer needed after the installed headers refactoring.
Added test coverage for `installLibraryHeaders`
Also renames `addHeaders` to `addHeadersDirectory` for clarity.
This is a temporary workaround that can be revered if/when 'path'
lazy paths are updated to encode which build root they are relative to.
@andrewrk
Copy link
Member

andrewrk commented Apr 7, 2024

Thanks for keeping this updated. Great work. Let's move forward with this and then address any problems in follow-up changes.

#19313 is marked as accepted and moved to the 0.12 milestone.

@andrewrk andrewrk merged commit fdd6c31 into ziglang:master Apr 7, 2024
10 checks passed
@andrewrk andrewrk added breaking Implementing this issue could cause existing code to no longer compile or have different behavior. zig build system std.Build, the build runner, `zig build` subcommand, package management release notes This PR should be mentioned in the release notes. labels Apr 7, 2024
@castholm castholm deleted the installHeader branch April 8, 2024 14:37
linusg added a commit to linusg/bdwgc that referenced this pull request Apr 10, 2024
linusg added a commit to linusg/bdwgc that referenced this pull request Apr 14, 2024
@andrewrk andrewrk added this to the 0.12.0 milestone Apr 18, 2024
@andrewrk
Copy link
Member

Follow-up issue: #20571

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking Implementing this issue could cause existing code to no longer compile or have different behavior. release notes This PR should be mentioned in the release notes. zig build system std.Build, the build runner, `zig build` subcommand, package management
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Step.Compile.installHeader and related functions don't install headers as intended
2 participants