Skip to content

SwiftDriver: initial (incomplete) windows port #878

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 1 commit into from
Oct 21, 2021

Conversation

compnerd
Copy link
Member

This is sufficient to build on Windows, and the resulting driver is able
to somewhat function. The tests are still not usable due to assumptions
about path which do not hold and the insufficiency of the path
representation in tools-support-core. This is likely best approached by
replacing the use of Path from t-s-c with the representation in
system. However, this allows some attempt to validate the swift-driver
which is increasingly becoming required for s-p-m, and thus unblocks
further work.

@compnerd
Copy link
Member Author

@artemcm - the big problem with this change is that there are a few places where I cannot reliably make a distinction for the executable names (i.e. extensions - .exe). Do you have thoughts on how to handle this? I'm leaning towards adding a freestanding function:

func executable(_ name: String) -> String {
#if os(Windows)
  guard name.suffix(from: name.index(name.endIndex, offsetBy: -4))) == ".exe" else {
    return "\(name).exe"
  }
  return name
#else
  return name
#endif
}

@compnerd
Copy link
Member Author

I'm aware that there was a previous port that attempted to add support for Windows, however, I feel that this is more complete and more closely reflects the C++ driver. This is sufficient for getting a fair number of the tests to pass. This is a pretty simplistic mapping for the tools, but it establishes a beachhead so that we can move forward.

@compnerd compnerd marked this pull request as ready for review October 16, 2021 19:51
@compnerd
Copy link
Member Author

@swift-ci please test

@compnerd
Copy link
Member Author

@swift-ci please test macOS platform

@compnerd
Copy link
Member Author

@swift-ci please test

@compnerd
Copy link
Member Author

Locally, Im still seeing ~30% of the tests fail, which I've not yet dug into, but once this is merged, we should have a baseline to work from.

@compnerd compnerd requested review from artemcm and cltnschlosser and removed request for artemcm October 18, 2021 22:02
@artemcm
Copy link
Contributor

artemcm commented Oct 18, 2021

@artemcm - the big problem with this change is that there are a few places where I cannot reliably make a distinction for the executable names (i.e. extensions - .exe). Do you have thoughts on how to handle this? I'm leaning towards adding a freestanding function:

func executable(_ name: String) -> String {
#if os(Windows)
  guard name.suffix(from: name.index(name.endIndex, offsetBy: -4))) == ".exe" else {
    return "\(name).exe"
  }
  return name
#else
  return name
#endif
}

I think this is an entirely reasonable approach.

@compnerd
Copy link
Member Author

compnerd commented Oct 18, 2021

@artemcm - the big problem with this change is that there are a few places where I cannot reliably make a distinction for the executable names (i.e. extensions - .exe). Do you have thoughts on how to handle this? I'm leaning towards adding a freestanding function:

func executable(_ name: String) -> String {
#if os(Windows)
  guard name.suffix(from: name.index(name.endIndex, offsetBy: -4))) == ".exe" else {
    return "\(name).exe"
  }
  return name
#else
  return name
#endif
}

I think this is an entirely reasonable approach.

Okay; just wanted to make sure that someone doesn't have a better idea (I can propose and implement and still dislike my idea right? :-D). There is some duplication - I'd like to move the function to a different file if I could get a bit of guidance as to where such a utility function should reside.

Copy link
Contributor

@cltnschlosser cltnschlosser left a comment

Choose a reason for hiding this comment

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

For the most part looks good, obviously lots of TODOs/FIXMEs for the future.

BTW is there a good "Beginners guide to Swift on Windows"?

@@ -131,6 +142,9 @@ extension Toolchain {
private func envVarName(for toolName: String) -> String {
let lookupName = toolName
.replacingOccurrences(of: "-", with: "_")
// FIXME(compnerd) we should extract the extension for generating the
// toolname rather than assuming that we can convert the tool name blindly
.replacingOccurrences(of: ".", with: "_")
Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, I guess it would be nice if the environment variables were consistent across platforms. So windows doesn't always have an extra _EXE in its variables.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, I think that we will need to resolve this, but I think that doing that subsequently is better than trying to address everything immediately.

@@ -104,7 +115,7 @@ public protocol Toolchain {

extension Toolchain {
public var searchPaths: [AbsolutePath] {
getEnvSearchPaths(pathString: env["PATH"], currentWorkingDirectory: fileSystem.currentWorkingDirectory)
getEnvSearchPaths(pathString: ProcessEnv.path, currentWorkingDirectory: fileSystem.currentWorkingDirectory)
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this break tests or something? Where an (arbitrary) env might have been injected in.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, it was breaking both tests as well as use of the driver.

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh I meant the change. Since it isn’t using the passed in env anymore. But if it’s not breaking anything, then 🤷‍♂️

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh, the tests and the driver seem to be behaving fine with the change. They should be equivalent in that ProcessEnv.path will map to env["PATH"] on Darwin and Linux, but env["Path"] on Windows.

Copy link
Contributor

Choose a reason for hiding this comment

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

It's not using this env, which is where I could see problems maybe arising, but if not, then roll with it :)

public protocol Toolchain {
  init(env: [String: String], executor: DriverExecutor, fileSystem: FileSystem, compilerExecutableDir: AbsolutePath?, toolDirectory: AbsolutePath?)
  var env: [String: String] { get }

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not convinced this won't potentially break downstream driver clients. Toolchain.env comes all the way from a Driver.init argument, which defaults to ProcessEnv.vars, but can also be invoked with a custom environment when the driver is used as a library.

Can we instead continue using env and disambiguate "Path" or "PATH" based on the platform like TSC does?

Comment on lines 121 to 124
// FIXME(compnerd) we should capitalise the OS name, e.g. windows ->
// Windows; we get away with this for now as Windows has a
// case-insensitive file system.
let os: String = target.os?.rawValue ?? "none"
Copy link
Contributor

Choose a reason for hiding this comment

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

You can probably capitalize the rawValue of this enum for Windows.

Is "none" a better value than just returning nil here?

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah, I think I see what you are proposing. I think that the returning nil actually could work and be better. I'll make that change. The capitalization though I don't know how to handle :-(.

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Member Author

Choose a reason for hiding this comment

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

It's both. The component is 'windows', the enum entry is 'win32'.

@compnerd
Copy link
Member Author

For the most part looks good, obviously lots of TODOs/FIXMEs for the future.

Yeah, porting everything is going to take quite some time. This should at least put some of the paths in place.

BTW is there a good "Beginners guide to Swift on Windows"?

Hmm, from the driver perspective it should mostly be identical to macOS with the following differences:

  • you need VS and WinSDK installed (for MSVCRT and WinSDK headers and import libraries respectively)
  • you need to explicitly specify -sdk as there is no xcrun equivalent

For a user, at this point, its "install visual studio, install Swift using the installer from swift.org". Mostly everything else is now in place so that is all that should be needed. If there is something that needs documentation, I'm happy to try to write that up.

@compnerd
Copy link
Member Author

@swift-ci please test

Copy link
Contributor

@artemcm artemcm left a comment

Choose a reason for hiding this comment

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

I have just one concern about the Toolchain's use of environment variables, but other than that this is great!

@@ -104,7 +115,7 @@ public protocol Toolchain {

extension Toolchain {
public var searchPaths: [AbsolutePath] {
getEnvSearchPaths(pathString: env["PATH"], currentWorkingDirectory: fileSystem.currentWorkingDirectory)
getEnvSearchPaths(pathString: ProcessEnv.path, currentWorkingDirectory: fileSystem.currentWorkingDirectory)
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not convinced this won't potentially break downstream driver clients. Toolchain.env comes all the way from a Driver.init argument, which defaults to ProcessEnv.vars, but can also be invoked with a custom environment when the driver is used as a library.

Can we instead continue using env and disambiguate "Path" or "PATH" based on the platform like TSC does?

@compnerd
Copy link
Member Author

I think that we really should find something better for this - what happens if some OS uses something different? I think that changing this for now is fine, but for longer term, we really should be looking to abstract this using other libraries.

This is sufficient to build on Windows, and the resulting driver is able
to somewhat function.  The tests are still not usable due to assumptions
about path which do not hold and the insufficiency of the path
representation in tools-support-core.  This is likely best approached by
replacing the use of `Path` from t-s-c with the representation in
system.  However, this allows some attempt to validate the swift-driver
which is increasingly becoming required for s-p-m, and thus unblocks
further work.
@compnerd
Copy link
Member Author

@swift-ci please test

@compnerd compnerd merged commit 6401fbb into swiftlang:main Oct 21, 2021
@compnerd compnerd deleted the windows branch October 21, 2021 04:36
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