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

fix: Replicates SPM default behavior for publicHeadersPath: If this is nil, the directory is set to include #1429

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

0xLucasMarcal
Copy link
Contributor

Match SPM's default behavior for public headers path

When SPM processes a target without an explicit publicHeadersPath, it follows these rules:

  1. If publicHeadersPath is nil and an include/ directory exists, use include/ as the public headers path
  2. This makes all headers in the include/ directory visible to dependent targets

This PR replicates this canonical behavior by:

  • Checking for the existence of include/ directory when publicHeadersPath is not set
  • Using include/ as the public headers path if it exists
  • Making all headers in include/*.h visible to clang targets

https://developer.apple.com/documentation/packagedescription/target/publicheaderspath

@brentleyjones
Copy link
Collaborator

Does this fix a certain use case? If so, can we add or adjust an example to show it?

@0xLucasMarcal
Copy link
Contributor Author

0xLucasMarcal commented Jan 6, 2025

Does this fix a certain use case? If so, can we add or adjust an example to show it?

It was causing tree-sitter build to fail, but after fixing the header not found by patching rules_swift_package_manager, the build started failing with a new error, that tree-sitter wasn't exposing all the source files to SPM. So I sent a PR fixing that and explicitly setting include as publicHeadersPath. So now, I have no fully running example 😓

What do you suggest in this case?

if public_hdrs_path == None:
if repository_files.path_exists(repository_ctx, paths.join(abs_target_path, "include")):
public_includes.append(paths.join(abs_target_path, "include"))

Copy link
Owner

Choose a reason for hiding this comment

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

So, we have support for magical public header directories here. Do you understand why this is not working for the tree-sitter case?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This search runs on the public headers list. Without this patch, the list was empty, so there were no headers to check if it was in a magical directory.

Copy link
Contributor Author

@0xLucasMarcal 0xLucasMarcal Jan 6, 2025

Choose a reason for hiding this comment

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

All the other Clang libraries that I used defined modulemaps to expose the headers and define modules.

Copy link
Owner

Choose a reason for hiding this comment

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

Sorry, I don't understand. If there are no header files in the include directory, why does the build fail?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here's a small project with instructions to reproduce the failure: https://github.com/0xLucasMarcal/rules_spm_implicit_include_dir_issue

Copy link
Contributor Author

@0xLucasMarcal 0xLucasMarcal Jan 7, 2025

Choose a reason for hiding this comment

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

Basically what happens is that when the clang target doesn’t have publicHeadersDir set and also doesn’t have a modulemap, the rspm doesn’t reach the headers inside of include dir

Copy link
Owner

Choose a reason for hiding this comment

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

Thank you for providing the repro! Let's add your repro package to the pkg_manifest_minimal example. That will be a good test.

@0xLucasMarcal 0xLucasMarcal requested a review from cgrindel January 7, 2025 23:26
if public_hdrs_path == None:
if repository_files.path_exists(repository_ctx, paths.join(abs_target_path, "include")):
public_includes.append(paths.join(abs_target_path, "include"))

Copy link
Owner

Choose a reason for hiding this comment

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

Thank you for providing the repro! Let's add your repro package to the pkg_manifest_minimal example. That will be a good test.

if public_hdrs_path == None:
if repository_files.path_exists(repository_ctx, paths.join(abs_target_path, "include")):
public_includes.append(paths.join(abs_target_path, "include"))

Copy link
Owner

Choose a reason for hiding this comment

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

Suggested change
# If public includes were specified, use them.
# Else if the Swift package manifest does not specify a public headers path,
# use the default "include" directory, if it exists.
# This copies the behavior of the canonical Swift Package Manager implementation.
# https://developer.apple.com/documentation/packagedescription/target/publicheaderspath
public_includes = []
if public_hdrs_path != None:
public_includes.append(
paths.normalize(paths.join(abs_target_path, public_hdrs_path)),
)
elif repository_files.path_exists(
repository_ctx,
paths.join(abs_target_path, "include"),
):
public_includes.append(paths.join(abs_target_path, "include"))

Copy link
Owner

Choose a reason for hiding this comment

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

This suggested code combines the previous if statement with your new logic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants