-
Notifications
You must be signed in to change notification settings - Fork 1.4k
plugins: Build command plugin dependencies for the host, not the target #6791
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
plugins: Build command plugin dependencies for the host, not the target #6791
Conversation
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.
Can we come up with a test for it in SwiftToolTests.swift
?
When cross-compiling, SwiftPM plugins and their dependencies run on the host and so must be compiled for the host OS and architecture, not the cross-compiled target OS and architecture. SwiftPM will compile a command plugin for the host but if the plugin depends on an executable it will cross-compile the executable for the target, so the plugin will not be able to run it: error: Error Domain=NSPOSIXErrorDomain Code=8 "Exec format error" Command plugin dependencies are already handled specially in PluginCommand.run; this commit makes that special build step use the host toolchain instead of the target toolchain. swiftlang#6060 handled the equivalent problem for build tool plugins.
f5162c8
to
75b18db
Compare
I think regression testing for the normal case where we are not cross-compiling is already covered. I have been testing locally with a test case which turns out to be very similar to One difference is that my local test also has a top-level target which we can check is cross-compiled, in addition to the command plugin which should be built for the host. However I don't think we yet have testing infrastructure to set up a cross-compiler. Is there a way to fake enough of a cross-compliation SDK to show that I'd be happy to add my test but I think it would just duplicate what's already there. |
@swift-ci smoke test |
For reference, here is the test I've been using locally: CommandPluginDependencies.zip If you run the plugin without a cross-compilation SDK you should see the following output:
If you run it with a cross-compilation SDK without the fix in this PR, it will fail because
This is because both
If you apply the fix in this PR, the build will succeed.
|
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.
Thanks for fixing this! SGTM as it was tested manually. We certainly should improve SwiftTool
testing infrastructure to cover cross-compilation in the future.
…the target Since swiftlang#7164, dependencies of command plugins are once again being built for the _target_ rather than the host. This causes problem when cross compiling because the host needs to be able to run the plugin dependencies, but finds target binaries instead. This problem was fixed before in swiftlang#6791 by forcing command plugin dependencies to be built for the host by overriding the default build parameters in swiftTool.createBuildSystem(). The same solution still works in this commit, but a better long-term option would be to rework BuildOperation.plan() to handle command plugin dependencies specially, as it already does for build plugin dependencies. At present, BuildOperation.plan calls graph.invokeBuildToolPlugins to process sources. invokeBuildToolPlugins finds all build tool dependecies and builds them separately, using a specially-created BuildOperation instance: https://github.com/apple/swift-package-manager/blob/34efc0bfe9d40d9a019644ac8fcd0b852c491dfe/Sources/SPMBuildCore/Plugins/PluginInvocation.swift#L409 There is no equivalent step for command plugin dependencies, so they are built for the host architecture. Ideally we should rework BuildOperation.plan to build command and build plugin dependencies in the same way.
…the target Since swiftlang#7164, dependencies of command plugins are once again being built for the _target_ rather than the host. This causes problem when cross compiling because the host needs to be able to run the plugin dependencies, but finds target binaries instead. This problem was fixed before in swiftlang#6791 by forcing command plugin dependencies to be built for the host by overriding the default build parameters in swiftTool.createBuildSystem(). The same solution still works in this commit, but a better long-term option would be to rework BuildOperation.plan() to handle command plugin dependencies specially, as it already does for build plugin dependencies. At present, BuildOperation.plan calls graph.invokeBuildToolPlugins to process sources. invokeBuildToolPlugins finds all build tool dependecies and builds them separately, using a specially-created BuildOperation instance: https://github.com/apple/swift-package-manager/blob/34efc0bfe9d40d9a019644ac8fcd0b852c491dfe/Sources/SPMBuildCore/Plugins/PluginInvocation.swift#L409 There is no equivalent step for command plugin dependencies, so they are built for the host architecture. Ideally we should rework BuildOperation.plan to build command and build plugin dependencies in the same way.
…the target Since swiftlang#7164, dependencies of command plugins are once again being built for the _target_ rather than the host. This causes problem when cross compiling because the host needs to be able to run the plugin dependencies, but finds target binaries instead. This problem was fixed before in swiftlang#6791 by forcing command plugin dependencies to be built for the host by overriding the default build parameters in swiftTool.createBuildSystem(). The same solution still works in this commit, but a better long-term option would be to rework BuildOperation.plan() to handle command plugin dependencies specially, as it already does for build plugin dependencies. At present, BuildOperation.plan calls graph.invokeBuildToolPlugins to process sources. invokeBuildToolPlugins finds all build tool dependecies and builds them separately, using a specially-created BuildOperation instance: https://github.com/apple/swift-package-manager/blob/34efc0bfe9d40d9a019644ac8fcd0b852c491dfe/Sources/SPMBuildCore/Plugins/PluginInvocation.swift#L409 There is no equivalent step for command plugin dependencies, so they are built for the host architecture. Ideally we should rework BuildOperation.plan to build command and build plugin dependencies in the same way.
…the target (#7280) Always build command line plugin dependencies for the host triple. ### Motivation: Since #7164, dependencies of command plugins are once again being built for the _target_ rather than the host. This causes problem when cross compiling because the host needs to be able to run the plugin dependencies, but finds target binaries instead. This problem was fixed before in #6791 by forcing command plugin dependencies to be built for the host by overriding the default build parameters in swiftTool.createBuildSystem(). The same solution still works in this commit, but a better long-term option would be to rework BuildOperation.plan() to handle command plugin dependencies specially, as it already does for build plugin dependencies. ### Modifications: At present, BuildOperation.plan calls graph.invokeBuildToolPlugins to process sources. invokeBuildToolPlugins finds all build tool dependecies and builds them separately, using a specially-created BuildOperation instance: https://github.com/apple/swift-package-manager/blob/34efc0bfe9d40d9a019644ac8fcd0b852c491dfe/Sources/SPMBuildCore/Plugins/PluginInvocation.swift#L409 There is no equivalent step for command plugin dependencies, so they are built for the host architecture. Ideally we should rework BuildOperation.plan to build command and build plugin dependencies in the same way. This commit forces all plugin dependencies to be built for the host - this is similar to what was done in #6791 and #7273. ### Testing: An integration test checks that any targets depended on by a command plugin are built for the host, not for the target. * A new CommandPluginTestStub plugin has a dependency on a target executable which will be built automatically when the plugin is run. The test checks that the dependency is built for the host architecture, no matter which target architecture is selected using '--triple'. * The plugin also asks SwiftPM to build the 'placeholder' main target. The test checks that the dependency is built for the target architecture. The test is restricted to macOS because we can be sure of having a viable cross-compilation environment (arm64 to x86_64 and vice versa). The standard Linux build environments can't cross compile to other architectures. ### Result: Command plugins can be used again when cross-compiling.
Motivation:
When cross-compiling, SwiftPM plugins and their dependencies run on the host and so must be compiled for the host OS and architecture, not the cross-compiled target OS and architecture. SwiftPM will
compile a command plugin for the host but if the plugin depends on an executable it will cross-compile the executable for the target so the plugin will not be able to run it:
This problem does not affect
binaryTarget
dependencies, which are handled by a different code path which correctly selects the the binary for the host system from the archive.Modifications:
Command plugin dependencies are already handled specially in
PluginCommand.run
; this commit makes that special build step use the host toolchain instead of the target toolchain.#6060 handled the equivalent problem for build tool plugins.
Result:
Executables which are are dependencies of command plugins will be built for the host OS and architecture, so the plugins will be able to run them.