Skip to content

Splitting out pybind11/stl/filesystem.h. #3077

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

Merged
merged 5 commits into from
Jul 8, 2021
Merged

Splitting out pybind11/stl/filesystem.h. #3077

merged 5 commits into from
Jul 8, 2021

Conversation

rwgk
Copy link
Collaborator

@rwgk rwgk commented Jul 6, 2021

Unfortunately PR #2730 forces users of pybind11/stl.h to link against -lstdc++fs (or similar, depending on the platform) even if they don't actually use the new type caster. This issue is resolved here by moving the new type caster to pybind11/stl/filesystem.h. The std::filessytem-related link options will be needed only if the new header is included.

Further refinements of the cmake files (see PR comments) is beyond the scope of this PR and left for follow-on PRs.

Example breakage due to PR #2730: https://github.com/deepmind/open_spiel/runs/2999582108

This PR is mostly following the suggestion here: #2730 (comment)

Except using pybind11/stl/filesystem.h instead of pybind11/stlfs.h, as decided via chat.

stl.h restored to the exact state before merging PR #2730 via:

git checkout 733f8de24feed964f96b639a0a44247f46bed868 stl.h

NOTE: The #2730 change log entry was edited after this PR was merged.

To solve breakages like: https://github.com/deepmind/open_spiel/runs/2999582108

Mostly following the suggestion here: pybind#2730 (comment)

Except using pybind11/stl/filesystem.h instead of pybind11/stlfs.h, as decided via chat.

stl.h restored to the exact state before merging PR pybind#2730 via:
```
git checkout 733f8de stl.h
```
@rwgk rwgk requested a review from henryiii as a code owner July 6, 2021 19:15
Comment on lines +9 to +15
#ifdef __has_include
# if defined(PYBIND11_CPP17) && __has_include(<filesystem>) && \
PY_VERSION_HEX >= 0x03060000
# include <filesystem>
# define PYBIND11_HAS_FILESYSTEM 1
# endif
#endif
Copy link
Collaborator

Choose a reason for hiding this comment

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

Just a thought, do we need this PYBIND11_HAS_FILESYSTEM now? If I include <stl/filesystem.h> do I want it to silently not cast things instead of getting a compile-time error?

Copy link
Collaborator

Choose a reason for hiding this comment

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

(If not, it should be moved to the include in the test ;) )

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

(If not, it should be moved to the include in the test ;) )

Copying my question from the slack channel here:

In this first pass, I simply kept the #ifdef block defining PYBIND11_HAS_FILESYSTEM in the header file. Does that still make sense? Would it be better to move that to the test? — It seem useful to keep it in the header, so others can easily use it if available without having to do anything much otherwise, but I'm not sure how this shakes out best.

Ideally we'd give people a choice? Bail out with a compile-time error or have them handle the runtime error.

It's not really great if we lead users down the path of copy-pasting the __has_include logic from the test.

Copy link
Collaborator

@henryiii henryiii Jul 6, 2021

Choose a reason for hiding this comment

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

But do users want "works if available" behavior for this? (The answer may be yes) It seems a little weird if your package only accepts pathlib.Path arguments if it was compiled in C++17 mode on some compilers. And only allows you to return std::filesystem on Python 3 (though that I'm less worried about). I'm guessing there will be some extra work most users will have to do to make sure this works (including requiring macOS 10.15+), so forcing the user to explicit might be better.

That is, I expect most users will either make an effort to support std::filesystem/pathlib everywhere, or they will not support it, but very few will support it if available. But could easily be wrong. I don't find the "auto" selection of C++ level all that useful either (setuptools helpers), but some users want it.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm okay to leave it as is, a user (who looks at the source) can check PYBIND11_HAS_FILESYSTEM if they want. But I'm also okay to (re)move it to the tests.

Copy link
Collaborator

@henryiii henryiii Jul 7, 2021

Choose a reason for hiding this comment

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

__has_include is not actually a C++17 feature, it's a C++20 one. Though I think all major compilers added it very early, but still, maybe it's best to remove this and just #include filesystem and let the failure happen if it's not available, rather than calling #error. This then makes PYBIND11_HAS_FILESYSTEM rather weird, though.

Copy link
Collaborator

Choose a reason for hiding this comment

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

@henryiii This page suggest it is a C++17 feature though? https://en.cppreference.com/w/cpp/preprocessor/include

Copy link
Collaborator

Choose a reason for hiding this comment

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

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

__has_include currently appears in 10 source code locations on master (see below).

If think for this PR it's important to stay focused on the one problem we want to solve as soon as possible: users shouldn't be forced to work on the link options if they don't actually want to use the new caster. I'll update the PR description accordingly.

include/pybind11/cast.h:#  if defined(__has_include)
include/pybind11/cast.h:#    if __has_include(<string_view>)
include/pybind11/stl.h:#ifdef __has_include
include/pybind11/stl.h:#  if defined(PYBIND11_CPP17) && __has_include(<optional>)
include/pybind11/stl.h:#  if defined(PYBIND11_CPP14) && (__has_include(<experimental/optional>) && \
include/pybind11/stl.h:                                 !__has_include(<optional>))
include/pybind11/stl.h:#  if defined(PYBIND11_CPP17) && __has_include(<variant>)
include/pybind11/stl.h:#  if defined(PYBIND11_CPP17) && __has_include(<filesystem>) && \
include/pybind11/detail/common.h:#if defined(__has_include)
include/pybind11/detail/common.h:#  if __has_include(<version>)

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes, @Skylion007 is correct, I was muddling has_include with feature test macros - probably shouldn't comment on things while in a conference. :)

This plans seems fine, we need to fix this, then we can polish and or document a bit more later if needed.

if (PyErr_Occurred()) {
PyErr_Clear();
return false;
} else {
Copy link
Collaborator

Choose a reason for hiding this comment

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

else after return is not ideal style.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes, it's called "guard" style to put the short returning branch at the top without an else, and it's preferable.

Copy link
Collaborator

Choose a reason for hiding this comment

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

@henryiii Plan on enabling a clang-tidy check for this soon.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

else after return is not ideal style.

Done.

@Skylion007
Copy link
Collaborator

Need to fix some of the pip tests.

@henryiii
Copy link
Collaborator

henryiii commented Jul 6, 2021

There's a place or two where this needs to be added to the Python build system too. I'd do a quick git grep stl.h or maybe a rarer file and see where there are lists. Possibly only in tests, maybe in setup.py somewhere.

Copy link
Collaborator

@Skylion007 Skylion007 left a comment

Choose a reason for hiding this comment

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

Edit the lists as @henryiii suggested.

if (PyErr_Occurred()) {
PyErr_Clear();
return false;
} else {
Copy link
Collaborator

Choose a reason for hiding this comment

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

@henryiii Plan on enabling a clang-tidy check for this soon.

@rwgk
Copy link
Collaborator Author

rwgk commented Jul 6, 2021

There's a place or two where this needs to be added to the Python build system too. I'd do a quick git grep stl.h or maybe a rarer file and see where there are lists. Possibly only in tests, maybe in setup.py somewhere.

I tried that already but apparently I need to do something more involved because stl is a new subdirectory. Working on it.

@henryiii
Copy link
Collaborator

henryiii commented Jul 6, 2021

One Python 2 failure is our random known flake, the other is just the packaging test (which happens to be Python 2 as well), which tests the file list.

We already have some directories (like detail) so whatever we do for that should work?

This now passes interactively:
```
pytest tests/extra_python_package/
```
@rwgk
Copy link
Collaborator Author

rwgk commented Jul 6, 2021

One Python 2 failure is our random known flake, the other is just the packaging test (which happens to be Python 2 as well), which tests the file list.

We already have some directories (like detail) so whatever we do for that should work?

No good deed gets unpunished ... I think I finally figured it out. (I overlooked the tools directory longer than I'd like to admit.)

rwgk added 3 commits July 6, 2021 13:37
iwyuh.py -c -std=c++17 -DPYBIND11_TEST_BOOST -Ipybind11/include -I/usr/include/python3.9 -I/usr/include/eigen3 include/pybind11/stl/filesystem.h
@rwgk
Copy link
Collaborator Author

rwgk commented Jul 6, 2021

Happy day, the mac os straggler made it :-)

@henryiii I hope this PR is final now, could you please review and approve if this looks good to you?

@jagerman
Copy link
Member

jagerman commented Jul 7, 2021

I don't think any of the CI's are going to catch this, but with clang before 9 and gcc before 9 (or any clang with stdlibc++ before before 9) you also need to link with -lstdc++fs (stdlibc++) or -lc++fs (clang+llvm). Might be worth documenting that, or perhaps providing some opt-in cmake machinery to help with setting up the linking?

https://github.com/oxen-io/lokinet/blob/dev/cmake/check_for_std_filesystem.cmake

is some cmake code we wrote to deal with figuring out the linking mess.

@Skylion007
Copy link
Collaborator

@henryiii
Copy link
Collaborator

henryiii commented Jul 7, 2021

Might be worth documenting that, or perhaps providing some opt-in cmake machinery to help with setting up the linking?

This is why I liked just making it an error if pybind11/std/filesystem.h is included but the filesystem library is not available, either due to linking requirements, macOS target settings, or for other reasons. Having a "try to use it if available" makes us responsible for deciding that correctly (which is hard), and for providing tools to make it optionally available elsewhere. The current, undocumented, tiny bit of code that enables this is not too bad, since we aren't advertising it.

It's not our responsibility to provide support for filesystem for the user, just for allowing conversion if a user already supports it. IMO. But docs on how to use it, including links to CMake modules that do the linking, etc, are fine and useful. (and the above caveats).

@rwgk
Copy link
Collaborator Author

rwgk commented Jul 7, 2021

Having a "try to use it if available" makes us responsible for deciding that correctly (which is hard),

Yes exactly. This is the issue meant to be solved by this PR.

It's not our responsibility to provide support for filesystem for the user, just for allowing conversion if a user already supports it. IMO. But docs on how to use it, including links to CMake modules that do the linking, etc, are fine and useful. (and the above caveats).

These could be nice follow-on PRs.

@rwgk rwgk merged commit 6d1b197 into pybind:master Jul 8, 2021
@github-actions github-actions bot added the needs changelog Possibly needs a changelog entry label Jul 8, 2021
@rwgk rwgk deleted the stlfs branch July 8, 2021 16:03
@rwgk rwgk removed the needs changelog Possibly needs a changelog entry label Jul 8, 2021
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.

4 participants