-
Notifications
You must be signed in to change notification settings - Fork 120
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
Add support for swift #89
Add support for swift #89
Conversation
78500d0
to
b7ab9ae
Compare
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.
@xinzhengzhang, thanks so much for all your work here, for taking the lead, and for simplifying, unifying the implementations, and posting this. And sorry again for my holiday slowness. You can expect me to be faster in the future.
I'll comment on things that jump out to me as being worth discussing in this first round. Thanks for being great!
refresh_compile_commands.bzl
Outdated
@@ -100,6 +102,7 @@ _expand_template = rule( | |||
"labels_to_flags": attr.string_dict(mandatory = True), # string keys instead of label_keyed because Bazel doesn't support parsing wildcard target patterns (..., *, :all) in BUILD attributes. | |||
"exclude_external_sources": attr.bool(default = False), | |||
"exclude_headers": attr.string(values = ["all", "external", ""]), # "" needed only for compatibility with Bazel < 3.6.0 | |||
"enable_swift": attr.bool(default = False), |
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.
What do you think about just always having swift enabled, eliminating the need for configuration and branching?
I'm asking because swift extraction should be really fast, right, since there's no need for header extraction. Normal clangd doesn't crash or otherwise error out if there are swift commands, right?
You're the expert here, but it seems from the outside like this is worth having on all the time :)
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 flag designed for some other tools like infer
In bilibili we are using it for static analysis and it didn't support swift yet...
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.
Ah! Got it. And to confirm, the static analysis tools crash, rather than gracefully ignoring the swift files? Bummer.
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.
How about it we at least turn swift on by default?
Perhaps "exclude_swift" defaulting to False?
(We should make sure to eventually document this in the README and file docstring)
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.
It might also be worth submitting bugs to the tools that crash on swift files? They're going to see more and more of those inputs as the years roll on, I think.
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 you are right, other tools should not transfer the problem to this compatibility to increase the cost of using.
I will add a filter in my case and remove this flag
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.
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.
Sounds good. But if it removes the need for the file filter, I'd still be happy with keeping an exclude_swift
flag (off by default) for you, until those tools become tolerant to swift files?
(They do crash, yes, or otherwise issue errors that interfere with their use?)
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.
refresh.template.py
Outdated
@@ -683,7 +694,36 @@ def _get_apple_active_clang(): | |||
# Unless xcode-select has been invoked (like for a beta) we'd expect, e.g., '/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang' or '/Library/Developer/CommandLineTools/usr/bin/clang'. | |||
|
|||
|
|||
def _apple_platform_patch(compile_args: typing.List[str]): | |||
@functools.lru_cache(maxsize=None) | |||
def _get_apple_active_swiftc(): |
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.
Just checking my understanding: Does sourcekit-lsp have problems if we don't unwrap the main executable? I (I'm not sure if it's ever executed, like with query-driver in clangd--or how tolerant they are of unknown flags.)
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 tried and it does seem to work without unpacking the main executable in sourcekit-lsp but it can not tolerant other unknown flags like -Xwrapped-swift
error: unknown argument: \'-Xwrapped-swift=-debug-prefix-pwd-is-dot\'error: unknown argument: \'-Xwrapped-swift=-ephemeral-module-cache\'")) Code: -32001
And it is still necessary for c&cpp because we need to extract header information.
To be on the safe side, I think it's better to unwrap it
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.
Main executable: After some more thought, I think we should just set it to 'swiftc', rather than finding the full path via xcrun--assuming that works.
Why? This'll keep things more open for Swift on other platforms down the line that don't have xcrun (like Linux, Swift for servers). If a tool does try to resolve swiftc, it should work just fine without xcrun, resolving to the same system default via the path, so we're stripping out unnecessary complexity. This works for clang, too, so I've removed the xcrun call for clang on the main branch in a797a78. Sorry for leading you down an unnecessarily complex path to start; thanks for helping make this tool better all around.
Flags: Just to make sure I'm on the same page, these are red-squiggly errors in the editor, right? Makes total sense that we'll need to remove/replace them, then.
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.
Here we should set clang
in else branch or just assert the main executable has to be one of ['swiftc' , 'external/local_config_cc/wrapped_clang'] ?
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 have rebased the branch.
Here is the implementation
if compile_args[0].endswith('swiftc'):
compile_args[0] = 'swiftc'
else:
compile_args[0] = 'clang'
compile_args.insert(match + 1, os.environ["BUILD_WORKSPACE_DIRECTORY"] + "=.") | ||
|
||
# Remove other -Xwrapped-swift arguments like `-ephemeral-module-cache` `-global-index-store-import-path` | ||
# We could override index-store by config sourcekit-lsp |
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.
What's our plan for integrating their indexing during build?
(Eventually we'll need to document how to configure things in the README, but that can wait until the end.)
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.
We can analyze commands in aquery
and pre build .swiftmodule by striping -emit-object
in swift but that looks like it's going to be the second super slow header extractor...
For some small project fully build the target and cache the results by bazel ecosystem seems the best way but for some super huge project like bilibili it is impossible to wait a fully build before writing code. So I am doing another set of rules and a vscode plugin for integrating indexing with building. I will sync that once there is any progress
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.
For clarity: I wasn't meaning to propose that we force a full swift build up front when it isn't needed, but we should help people get sourcekit-lsp configured correctly, via instructions in the readme.
I'm guessing part of that will be pointing source kit-lsp to pick up the indexing output generated during bazel builds? And configuring bazel builds to generate that output if they don't already?
I'd love to learn more about what you're working on with the plugin!
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.
Here is my implementation.
I have wrapped the hedron_refresh_compile_commands
and collect all the module info which depended by the target into outputs.
Not as painful as rebuilding .d file for find headers, we can share module objects with compiling and indexing in this way.
"""De-Bazel(rule_swift) the command into something sourcekit-lsp can parse.""" | ||
|
||
# Remove build_bazel_rules_swift/tools/worker/worker | ||
compile_args.pop(0) |
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.
Could you explain/doc a little bit more about what's happening here and below? I assume these are things built into the wrapper scripts, maybe with a persistent worker? (Sorry for my ignorance--I just haven't worked much with Bazel&swift)
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.
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.
Got it. Is there a case we need to worry about where the user disables persistent workers?
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.
At least in the current rules_apple version we don't need.
The worker has wrapped both.
@@ -703,7 +748,7 @@ def _apple_platform_patch(compile_args: typing.List[str]): | |||
# We also have to manually figure out the values of SDKROOT and DEVELOPER_DIR, since they're missing from the environment variables Bazel provides. | |||
# Filed Bazel issue about the missing environment variables: https://github.com/bazelbuild/bazel/issues/12852 | |||
compile_args = [arg.replace('__BAZEL_XCODE_DEVELOPER_DIR__', _get_apple_DEVELOPER_DIR()) for arg in compile_args] | |||
apple_platform = _get_apple_platform(compile_args) | |||
apple_platform = _get_apple_platform(compile_args, environmentVariables) |
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.
Ooh, are the environment variables specified correctly for the swift toolchain? If so, this'd be interesting to report on the issue linked above, since they'd been asking about whether it was cc specific.
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.
Of course correct, the environment is resolved by the apple_common provider in
https://bazel.build/rules/lib/apple_common#apple_host_system_env
https://bazel.build/rules/lib/apple_common#target_apple_env
refresh.template.py
Outdated
match = next((i for i,v in enumerate(compile_args) if v == "-Xwrapped-swift=-debug-prefix-pwd-is-dot"), None) | ||
if match: | ||
compile_args[match] = "-debug-prefix-map" | ||
compile_args.insert(match + 1, os.environ["BUILD_WORKSPACE_DIRECTORY"] + "=.") |
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.
Like with clang, might be able to just strip this out, since the commands are (conceptually) happening in place, not that we're actually running/debugging with them anyway.
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.
Yes, indeed we are not running but I found that there are a few options for specify index store path and I guess it may be can share the cache with that in build phase if the same store-path was specified.
sourcekit-lsp -h
-index-store-path <index-store-path>
Override index-store-path from the build system
-index-db-path <index-db-path>
Override index-database-path from the build system
So I do everything possible to keep the two consistent though not being validated
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.
Those flags look handy for configuring sourcekit-lsp! (like in #89 (comment))
But I just meant that it might make sense just omit that particular flag, -debug-prefix-map, since I don't think it'll impact analysis--nor compilation if it's just the cwd.
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.
Separate question: Do you know how source kit lsp gets its clangd? |
clangd was found by searching the bin path |
…/89\#discussion_r1037771523 refresh.template.py: omit warn_missing_generated and rename _file_exists to _warn_if_file_doesnt_exist
…/89#discussion_r1037776844 refresh.template.py: using endwith api
…/89#discussion_r1037780681 refresh.template.py: do not suppress error when locate xcrun toolchain
…/89#discussion_r1037781502 refresh.template.py: add some more explain for why need to remove the worker
…/89\#discussion_r1037771523 refresh.template.py: omit warn_missing_generated and rename _file_exists to _warn_if_file_doesnt_exist
…/89#discussion_r1037776844 refresh.template.py: using endwith api
…/89#discussion_r1037780681 refresh.template.py: do not suppress error when locate xcrun toolchain
…/89#discussion_r1037781502 refresh.template.py: add some more explain for why need to remove the worker
https://github.com/hedronvision/bazel-compile-commands-extractor/pull/89\#discussion_r1037771523 refresh.template.py: omit warn_missing_generated and rename _file_exists to _warn_if_file_doesnt_exist hedronvision#89 (comment) refresh.template.py: using endwith api hedronvision#89 (comment) refresh.template.py: do not suppress error when locate xcrun toolchain hedronvision#89 (comment) refresh.template.py: add some more explain for why need to remove the worker
e96bbbe
to
facd48e
Compare
for more information, see https://pre-commit.ci
Hi Chris~ |
Hey @xinzhengzhang! Could I ask you to take one more pass through, seeing if there are further ways to simplify the refresh.template.py changes and generally improving things in any way you see? I'm wondering if it might simplify things to unify the swift code path further with the cc codepath, just conditioning on action.mnemonic when needed rather than routing--or if they're actually different enough that they should be more fully separate. I'm not sure how many args patches are really shared. It'll be harder for C++ users to update things if the codepaths are too unified, but if they should share most logic, then we want to unify them so swift gets more future improvements. Your call, but I think we should definitely go more to one extreme or the other or at least document things so that we're clear. Please let me know what you think. Let's also rename We're also going to at least need some docs to merge. If you want to just outline them, I can flesh them out, since I think I've got comparative advantage on English. (Not meaning any offense; your English is far better than I would be in any other language.) In particular, I think it'd be good to get instructions for pointing sourcekit-lsp into the accumulating index from building. I can dive in more tomorrow, but it's getting late enough here that I'd better go to sleep for tonight. Cheers, |
Sorry, maybe I misunderstood before #1 (comment) , I thought you wanted to make commands_extractor more general and adapt to more languages. Honestly, there is not much difference between the two implementations except where to find the source files. I will try to write another version and try not to break the original implementation of refresh.template.py. |
Ah, no sorry. Miscommunication somewhere, maybe. (About to go to sleep but want to catch you fast so I don't waste your time.) |
To make sure we're on the same page: Let's keep things in one file. Definitely looking to generalize things! I was just wondering if maybe the codepaths could benefit from being merged further. (Truly wondering; unsure how much of the cc flag patching applies to swift.) |
But there are indeed multiple sources in one swift compile action. |
Because it was re-implemented, I re-opened a PR #96 for the convenience of review |
Add support for
SwiftCompile
in rule_swiftIt extracts swift compile commands into
compile_commands.json
providing to sourcekit-lspVSCode setup
Examples: