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

Windows ARM64 support #1339

Merged
merged 1 commit into from
Aug 16, 2021
Merged

Windows ARM64 support #1339

merged 1 commit into from
Aug 16, 2021

Conversation

Alovchin91
Copy link
Contributor

@Alovchin91 Alovchin91 commented Aug 9, 2021

// 'function': incompatible types - from 'uint32_t *' to 'Limb *'
// 'function': incompatible types - from 'fiat_p256_felem' to 'const Limb *'
// etc.
#pragma warning(disable: 4133)
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 is probably a bad idea, as I'm not sure if it's okay to use 32-bit math on ARM64 in this module

Copy link
Owner

Choose a reason for hiding this comment

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

Yes, we shouldn't disable these warnings. When the code is correct, then there will be no warnings. These warnings help us ensure we're not accidentally using 32-bit integer types instead of 32-bit integer types or vice versa. If there are cases we need to do conversions then we should add explicit casts for those specific instances.

Copy link
Contributor Author

@Alovchin91 Alovchin91 Aug 9, 2021

Choose a reason for hiding this comment

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

Okay, it looks like we have a problem then because we don't have the __uint128_t type, and we also don't have a OPENSSL_USE_NISTZ256 implementation 😅

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@briansmith What do you think about including a bigint library? For example boost's cpp_int or calccrypto? That could solve all the issues with math at once, and we could only include it on Windows ARM64.

Copy link
Owner

Choose a reason for hiding this comment

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

Okay, it looks like we have a problem then because we don't have the __uint128_t type, and we also don't have a OPENSSL_USE_NISTZ256 implementation.

If I understand what you're saying correctly, there is another PR that adds the fallback bn_mul_mont implementation that would be needed for supporting MSVC to work.

HOWEVER, that code will be much slower than using the uint128_t-based arithmetic from Fiat Crypto that using clang would provide.

So, with that in mind, maybe we should first get this working with TARGET_CC=clang and then worry about supporting MSVC as the C compiler in a separate PR?

@briansmith What do you think about including a bigint library? For example boost's cpp_int or calccrypto? That could solve all the issues with math at once, and we could only include it on Windows ARM64.

It would be very unlikely that we'd add an external dependency for the math.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

One of the main goals for me is to make sure Rustup can compile with rustls-tls feature enabled. If we can somehow specify in build.rs that we want to use clang.exe as the C compiler, and that setting can be dragged into Rustup, I'm generally happy 🙂

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@briansmith Okay, before I change a ton of #if defined(__GNUC__) to #if defined(__GNUC__) || defined(__clang__) in this context:

#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic ignored "-Wsign-conversion"
#pragma GCC diagnostic ignored "-Wconversion"
#endif

-- is this an expected change? 🙃

Copy link
Owner

Choose a reason for hiding this comment

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

There is some code that does that in ring, because BoringSSL does that. But only code that we share with BoringSSL is supposed to do that, ideally.

For code not shared with BoringSSL, we should be using explicit casts and avoid disabling the warnings.

If you're going to hand this off to me, then go ahead and disable whatever warnings and then I'll fix that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tried to be as conservative as I could when introducing those #if ... defined(__clang__) 🙂 It now builds on my SPX and all the tests run. I'm going to try cross-compiling everything from an x64 machine now, and if that succeeds, I think my job here is largely done 🙂 I'd prefer to leave the code itself to you since it likely has nothing to do with Windows ARM64 target but rather with the logic itself, and I don't trust myself there as I have zero knowledge of crypto 😬

{ \
Limb tmp = (_a) - (_borrow); \
*(_r) = tmp - (_b); \
(_ret) = ((_a) < tmp) | ((*(_r)) > tmp); \
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I did my best, you know the rest... Please validate this math

Copy link
Owner

Choose a reason for hiding this comment

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

AFAICT, these macros are just doing what the #else branches below already do, so we can just undo this change if you take my suggestion above.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's not possible to use the #else branches below unfortunately because they use 128-bit __uint128_t type which is not available on MSVC 🤷

Copy link
Owner

Choose a reason for hiding this comment

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

It's not possible to use the #else branches below unfortunately because they use 128-bit __uint128_t type which is not available on MSVC 🤷

Thanks. I forgot about that. I will think about what to do. Probably it makes sense to change the #else branches so that they don't require __uint128_t and then are shared across MSVC and non-MSVC targets, if that doesn't negatively affect the performance.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll leave this decision up to you if you don't mind 🙂

Copy link
Owner

Choose a reason for hiding this comment

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

There are three aspects of this:

  1. Get something working. If we can rely on clang as the C compiler, then this is less much less work than what's in this PR.
  2. Get it working with MSVC as the C compiler.
  3. Unifying, if practical, the MSVC and non-MSVC code paths.

If we want to have, for expediency, a separate MSVC-only code path for now, then we "just" need to convert your #define macros into true inline functions, since we don't do that #define stuff except as a last resort.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I thought I'd leave the crypto/fipsmodule/bn/internal.h changes as is because they're present upstream in BoringSSL, but if you'd prefer to revert that file, please let me know 🙂

src/cpu.rs Show resolved Hide resolved
@awakecoding
Copy link
Contributor

@Alovchin91 I have improved the build.rs script to add dynamic detection of nasm.exe / clang.exe within the PATH + a few extra paths, which solves the annoying issue of having to copy nasm.exe inside the target folder every time. Next on my list is to figure out how the pregeneration works, I think one issue could be that both x64 and ARM object files use the same names currently:

target\aarch64-pc-windows-msvc\debug\build\ring-bf8b835a0b88012d\out\aes_nohw.obj : fatal error LNK1112: module machine type 'ARM64' conflicts with target machine type 'x64'

build.rs Outdated Show resolved Hide resolved
@Alovchin91
Copy link
Contributor Author

@awakecoding Hmm, I don't think the issue is the file name but rather the lack of "target arch" parameter in clang.exe invocation.

@awakecoding
Copy link
Contributor

@awakecoding Hmm, I don't think the issue is the file name but rather the lack of "target arch" parameter in clang.exe invocation.

I think you are correct, it doesn't hurt to explicitly specify it anyway, otherwise you rely on defaults (and that's never good).

@awakecoding
Copy link
Contributor

ok, I fixed it - I can build the tests now if I copy the "tests" folder inside the "target" folder to avoid the incorrect path issue

@awakecoding
Copy link
Contributor

For some odd reason, I don't seem to have the issue with compiling the test code anymore. I did a "git clean -fdx" and I didn't copy the tests directory, and it still builds. In other words, the latest code on your branch just builds correctly for me

@Alovchin91
Copy link
Contributor Author

Alovchin91 commented Aug 9, 2021

For some odd reason, I don't seem to have the issue with compiling the test code anymore. I did a "git clean -fdx" and I didn't copy the tests directory, and it still builds. In other words, the latest code on your branch just builds correctly for me

I think it's important to call both cargo build and cargo test either with a --target parameter, or without, but not mixing them. I think the reason is indeed the preassemble flag which likely builds assembly just once and then tries to reuse it. If you mix the calls with and without flag then, you get a difference of a target's folder and that's why it likely fails.

@awakecoding
Copy link
Contributor

My next step is to add proper detection for the MSVC clang distribution (the one installed as an MSVC component) because I think this is what @briansmith would rather use. the llvm.org clang distribution has an installer that can add clang to the PATH, but the clang.exe installed via MSVC doesn't, so it'll need a bit more work to detect and find properly. The proper modern way might be to call vswhere.exe to find it, unless there's already something better available to do this detection.

image

@Alovchin91
Copy link
Contributor Author

Alovchin91 commented Aug 9, 2021

@awakecoding I think you might want to use cc for that:

https://docs.rs/cc/1.0.69/cc/windows_registry/fn.find_tool.html

BTW could you please also upgrade cc to 1.0.69? This version contains fixes to find MSVC tools on Windows ARM.

@awakecoding
Copy link
Contributor

@Alovchin91 sure, I absolutely hate vswhere.exe, so if cc has some helpers, I'm all for it!

@awakecoding
Copy link
Contributor

I'm trying to call cc::windows_registry::find_tool(&msvc_target, "clang.exe") with "x86", "x64" and "ARM64" as the msvc_target, but nothing appears to work. I'm not sure if I'm calling it right?

@Alovchin91
Copy link
Contributor Author

The name of the parameter is a bit confusing, but it means that it should be an *-msvc Rust target. So you need to just pass the target to it, e.g. aarch64-pc-windows-msvc.

@awakecoding
Copy link
Contributor

yeah, I tried all of those and even looked at the source code for CC, it just doesn't seem to want to find it. Even if I could get a proper result, it returns a Command, and there doesn't seem to be a stable feature right now to extract the path to the executable? That could be a problem

@Alovchin91
Copy link
Contributor Author

Alovchin91 commented Aug 9, 2021

find_tool should return a Tool type that contains a path to the executable: https://docs.rs/cc/1.0.69/cc/struct.Tool.html#method.path

@awakecoding
Copy link
Contributor

It appears to be broken, maybe you can have better luck than I do. I think I'll try a different method, I've been on it for an hour already:

image

@awakecoding
Copy link
Contributor

I can call cc::windows_registry::find_tool to find link.exe and other tools, but I think it is unfortunately limited to just the executable in the "primary" tools directory you get with the visual studio command prompt. maybe that's why it doesn't find clang.exe? The thing is that we can find clang.exe through the PATH in the visual studio command prompt.

@Alovchin91
Copy link
Contributor Author

I think you're right: https://github.com/alexcrichton/cc-rs/blob/4a6e8b7c7522392de0cda0325d4041f536745fe0/src/windows_registry.rs#L420

A good idea for extending the library then! 🙂

@Alovchin91
Copy link
Contributor Author

Alovchin91 commented Aug 9, 2021

As a workaround you could ask it to find devenv.exe and given that it has a well-known path, build a new path based on it: https://github.com/alexcrichton/cc-rs/blob/4a6e8b7c7522392de0cda0325d4041f536745fe0/src/windows_registry.rs#L841

Something like this could work:

cc::windows_registry::find_tool("x86_64-pc-windows-msvc", "devenv.exe")
    .map(|tool| tool.path().parent().join(r"..\..\VC\Tools\Llvm\x64\bin\clang.exe"));

Copy link
Owner

@briansmith briansmith left a comment

Choose a reason for hiding this comment

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

I took a quick look at the patch and

build.rs Outdated
@@ -287,6 +295,24 @@ fn read_env_var(name: &'static str) -> Result<String, std::env::VarError> {
std::env::var(name)
}

// Find executable in PATH with optional extra search directories
fn find_in_path(path: &Path, extra: Vec<&Path>) -> Option<PathBuf> {
Copy link
Owner

Choose a reason for hiding this comment

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

I would prefer to avoid this. The goal of the original design is to ensure we're using a known-good version of build tools during packaging and not just whatever happens to be around. When ring is packaged on crates.io, the code is pre-assembled and the object files are included in the crate. The previous way nasm was found, in a specific directory, ensures we don't accidentally use a different version of nasm that happens to be around, when packaging.

Copy link
Contributor

Choose a reason for hiding this comment

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

I understand your point, so may I suggest to modify it such that specific directories are searched before checking the PATH instead? This would ensure that target/tools/windows/nasm/nasm.exe always gets picked up even if nasm.exe is also present in the PATH. Requiring a specific copy of a tool within a custom directory is particularly painful for everybody else. I have nasm installed in my CI environment for other dependencies that require it, I just make sure to make it available in my system PATH so they can pick it up.

Copy link
Contributor

Choose a reason for hiding this comment

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

@briansmith I think you need to mark this comment as "resolved"

build.rs Outdated
@@ -365,7 +391,7 @@ fn pregenerate_asm_main() {
let srcs = asm_srcs(perlasm_src_dsts);
for src in srcs {
let obj_path = obj_path(&pregenerated, &src, MSVC_OBJ_EXT);
run_command(nasm(&src, asm_target.arch, &obj_path, &pregenerated));
run_command(win_asm(&src, asm_target.arch, &obj_path, &pregenerated));
Copy link
Owner

Choose a reason for hiding this comment

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

It seems like this should be made consistent with the code below that does this:

let cmd = if target.os != WINDOWS || (ext != "asm" && ext != "S") {
            cc(p, ext, target, warnings_are_errors, &out_path, out_dir)
        } else {
            win_asm(p, &target.arch, &out_path, out_dir)
        };

Probably factor out this conditonal into a function (named asm perhaps) and use it here and below.

In particular, it is confusing how win_asm is used for .S files here (IIUC) but not used for .S files below.

Copy link
Owner

Choose a reason for hiding this comment

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

Disregard this. This was leftover feedback that was building on some other feedback I deleted before posting.

Copy link
Owner

Choose a reason for hiding this comment

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

I believe the refactoring in recent PRs will allow us to avoid making any changes here in this PR.

build.rs Outdated Show resolved Hide resolved
build.rs Outdated
}
}

fn find_nasm() -> Option<PathBuf> {
Copy link
Owner

Choose a reason for hiding this comment

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

Especially since this PR doesn't actually use NASM, we don't need to change the way NASM is found in this PR. If we want to be more flexible with NASM then let's discuss that in another issue/PR.

// 'function': incompatible types - from 'uint32_t *' to 'Limb *'
// 'function': incompatible types - from 'fiat_p256_felem' to 'const Limb *'
// etc.
#pragma warning(disable: 4133)
Copy link
Owner

Choose a reason for hiding this comment

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

Yes, we shouldn't disable these warnings. When the code is correct, then there will be no warnings. These warnings help us ensure we're not accidentally using 32-bit integer types instead of 32-bit integer types or vice versa. If there are cases we need to do conversions then we should add explicit casts for those specific instances.

crypto/limbs/limbs.inl Outdated Show resolved Hide resolved
@@ -90,6 +109,8 @@ static inline Carry limb_sbb(Limb *r, Limb a, Limb b, Carry borrow_in) {
Carry ret;
#if defined(RING_CORE_SUBBORROW_INTRINSIC)
ret = RING_CORE_SUBBORROW_INTRINSIC(borrow_in, a, b, r);
#elif defined(RING_CORE_SUBBORROW)
RING_CORE_SUBBORROW(borrow_in, a, b, r, ret);
Copy link
Owner

Choose a reason for hiding this comment

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

ditto.

crypto/limbs/limbs.inl Outdated Show resolved Hide resolved
src/cpu.rs Show resolved Hide resolved
crypto/fipsmodule/bn/internal.h Outdated Show resolved Hide resolved
@briansmith
Copy link
Owner

Hi, I took a quick look at the PR and offered some suggested changes. I am impressed with your ability to get this mostly sorted out already on your own.

Could you please also extend the GitHub Actions configuration to include Windows AAarch64 as a build-but-don't-test target? This would make it clear how one gets clang and make it easy for me to test this locally, since I'd just need to run the same scripts as GitHub Actions uses.

@briansmith
Copy link
Owner

find_tool should return a Tool type that contains a path to the executable: https://docs.rs/cc/1.0.69/cc/struct.Tool.html#method.path

Again, I wouldn't worry about trying to search for clang (or nasm) right now. When I package ring on crates.io then the assembly will be packaged in .obj files in the packaged crate and the user won't need clang or nasm.

@codecov
Copy link

codecov bot commented Aug 9, 2021

Codecov Report

Merging #1339 (f8aa6ba) into main (8fe3633) will increase coverage by 0.00%.
The diff coverage is 100.00%.

❗ Current head f8aa6ba differs from pull request most recent head e8e9a67. Consider uploading reports for the commit e8e9a67 to get more accurate results
Impacted file tree graph

@@           Coverage Diff           @@
##             main    #1339   +/-   ##
=======================================
  Coverage   92.81%   92.82%           
=======================================
  Files         117      117           
  Lines       17826    17841   +15     
  Branches      195      195           
=======================================
+ Hits        16546    16561   +15     
+ Misses       1246     1245    -1     
- Partials       34       35    +1     
Impacted Files Coverage Δ
crypto/curve25519/curve25519.c 99.70% <ø> (ø)
crypto/fipsmodule/ec/ecp_nistz384.inl 100.00% <ø> (ø)
crypto/fipsmodule/ec/p256.c 100.00% <ø> (ø)
crypto/poly1305/poly1305.c 98.95% <ø> (ø)
src/cpu.rs 95.65% <100.00%> (+0.53%) ⬆️
crypto/cpu-intel.c 67.21% <0.00%> (-3.28%) ⬇️
crypto/internal.h 88.09% <0.00%> (ø)
crypto/fipsmodule/aes/aes_nohw.c 0.00% <0.00%> (ø)
crypto/fipsmodule/ec/p256-x86_64.c 96.89% <0.00%> (ø)
src/aead/aes.rs 82.96% <0.00%> (+0.43%) ⬆️
... and 1 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 8fe3633...e8e9a67. Read the comment docs.

@awakecoding
Copy link
Contributor

find_tool should return a Tool type that contains a path to the executable: https://docs.rs/cc/1.0.69/cc/struct.Tool.html#method.path

Again, I wouldn't worry about trying to search for clang (or nasm) right now. When I package ring on crates.io then the assembly will be packaged in .obj files in the packaged crate and the user won't need clang or nasm.

The concern is not limited to the way ring is packaged for crates.io, but how one can rebuild it entirely from source, including for the assembly files. You mentioned that you'd rather use the MSVC clang, and that's the only thing missing right now - properly detecting its install path so we can pick it up. If you don't care about detection then I guess you can manually add it the PATH in your build environment? We're just trying to make it simpler with minimal custom operations, such that all one needs to do is either install MSVC clang or llvm.org clang to rebuild everything.

@briansmith
Copy link
Owner

The concern is not limited to the way ring is packaged for crates.io, but how one can rebuild it entirely from source, including for the assembly files. You mentioned that you'd rather use the MSVC clang, and that's the only thing missing right now - properly detecting its install path so we can pick it up. If you don't care about detection then I guess you can manually add it the PATH in your build environment? We're just trying to make it simpler with minimal custom operations, such that all one needs to do is either install MSVC clang or llvm.org clang to rebuild everything.

I understand. I would prefer to deal with it in a separate PR though. For a long time the crates.io distribution is the only one I "support." I am open to changing that but I'd rather deal with all the things that are involved in changing that policy separately.

@awakecoding
Copy link
Contributor

The concern is not limited to the way ring is packaged for crates.io, but how one can rebuild it entirely from source, including for the assembly files. You mentioned that you'd rather use the MSVC clang, and that's the only thing missing right now - properly detecting its install path so we can pick it up. If you don't care about detection then I guess you can manually add it the PATH in your build environment? We're just trying to make it simpler with minimal custom operations, such that all one needs to do is either install MSVC clang or llvm.org clang to rebuild everything.

I understand. I would prefer to deal with it in a separate PR though. For a long time the crates.io distribution is the only one I "support." I am open to changing that but I'd rather deal with all the things that are involved in changing that policy separately.

No problem, we can trim and remove some of the detection code and expect clang.exe to be already present in the PATH, and avoid touching nasm.exe to keep it all for a separate PR. Just to make sure you understand, we're not going to implement MSVC clang detection in this PR, mostly because it's quite painful and we've been on it for hours already, but also because it would bring even more complex detection code in the current PR. The most sensible way to detect it would be to implement calling vswhere.exe like in the screenshot below. I pointed to the x86 and x64 versions of the MSVC-distributed clang.exe:

image

@awakecoding
Copy link
Contributor

@briansmith @Alovchin91 I removed the dynamic nasm/clang detection from the current branch. From the build system point of view, it should be good for the current PR (excluding the update to the CI environment). I am done for now, let me know if you need anything, I think the rest has to do with the math and the lack of a uint128_t data type in MSVC for ARM64.

@awakecoding
Copy link
Contributor

It turns out #1343 introduced some conflicts with this story. Shall we maybe go ahead and merge it if everyone's happy before we continue working on build.rs? 🤔

My goal with the other PRs I have submitted (and will submit) is to reduce this PR to just the cpu.rs changes and the CI/CD changes, or close to that. The work I've been doing yesterday and today is to clarify build.rs in response to some of the parts of this PR that I found confusing or where I want to do things a different way. For example, my change to always use ".o" for the object file extension was done after having difficulty reviewing the logic regarding that in this PR. As another example, instead of having to create a separate clang() function in build.rs to force compilation with clang, we can use the existing cc() function so that Windows Aarch64 and other non-Windows assembly stuff is processed exactly the same way.

If you want to keep rebasing this PR on top of my other ones, go ahead. Or if you want to wait until the other changes are done, that could be less work.

I was worried that cleanup in other PRs for specific things like the cc handling of clangs, and clang-related improvements, would ultimately create conflicts with the current PR. Can we keep it a minimum such that we can merge this PR sooner than later, and complete the improvements after the current PR has been merged? It would likely result in a lot less conflicts.

@briansmith
Copy link
Owner

I was worried that cleanup in other PRs for specific things like the cc handling of clangs, and clang-related improvements, would ultimately create conflicts with the current PR. Can we keep it a minimum such that we can merge this PR sooner than later, and complete the improvements after the current PR has been merged? It would likely result in a lot less conflicts.

There are parts of this PR that I don't want to maintain, and which are hard for me to verify the correctness of, including the clang() function separate from the cc() function for example.

Keep in mind that most people who contribute to ring are not interested in Windows AAarch64, so we have to optimize for those people, by minimizing the amount of Windows-AAarch64-specific logic.

In any case, I expect the work to be done today.

@Alovchin91
Copy link
Contributor Author

Alovchin91 commented Aug 13, 2021

@briansmith I'm sorry, I've made a comment about conflicts after I saw an email about #1343 but before I read your previous message 😅 Please go ahead, I totally support your argument that supporting Windows AArch64 shouldn't require (too much) additional effort compared to other architectures, especially given that API-wise it's just WIN64.

As another example, instead of having to create a separate clang() function in build.rs to force compilation with clang, we can use the existing cc() function so that Windows Aarch64 and other non-Windows assembly stuff is processed exactly the same way.

I was hoping that would be possible, indeed 😄

@briansmith My only concern is that I hope that we could merge this PR before we enable compilation with MSVC, so there still will be some hardcoded if aarch64 { c.compiler("clang-cl") } code for now. Is that okay?

I'm also not sure if you can support both clang and clang-cl without branching between the two, since AFAIK clang-cl exists specifically to mimic MSVC's command line arguments. Okay, I found the PR you've mentioned, totally love what you've done there!

@Alovchin91
Copy link
Contributor Author

Discussion from #1346:

but whether it's in $PATH or not, or what that compiler is named (clang vs clang-12, for example) wouldn't be hard-coded in.

I'm afraid that would make usage of ring unnecessarily over-complicated on Windows AArch64. I'd probably still suggest to hardcode clang-cl for now, for better compatibility and for simpler usage.

At the same time, if you don't want to release a new ring version before it's compilable under MSVC on AArch64, and given that one still needs additional setup (Clang in the $PATH), maybe it doesn't really matter much. 🤔

I guess I don't have a strong opinion but am slightly inclined to hardcode clang-cl with a FIXME comment.

@awakecoding
Copy link
Contributor

Discussion from #1346:

but whether it's in $PATH or not, or what that compiler is named (clang vs clang-12, for example) wouldn't be hard-coded in.

I'm afraid that would make usage of ring unnecessarily over-complicated on Windows AArch64. I'd probably still suggest to hardcode clang-cl for now, for better compatibility and for simpler usage.

At the same time, if you don't want to release a new ring version before it's compilable under MSVC on AArch64, and given that one still needs additional setup (Clang in the $PATH), maybe it doesn't really matter much. 🤔

I guess I don't have a strong opinion but am slightly inclined to hardcode clang-cl with a FIXME comment.

I suggest we just make sure that it can be built for Windows ARM64, and then we could make further clang detection and flexibility improvements in a separate PR to handle clang vs clang-cl, and clang-12 vs clang, etc, if need be.

@Alovchin91
Copy link
Contributor Author

and then we could make further clang detection and flexibility improvements in a separate PR to handle clang vs clang-cl, and clang-12 vs clang, etc, if need be.

@awakecoding To be honest, I don't think ring should know anything about where to find clang and which clang to use. I'd remove any knowledge of these specifics as soon as MSVC support is there. My suggestion to default to clang is just because I think it's easier to comprehend "clang-cl was not found" error message than something cryptic about int128_t 😅

Maybe we can do something like "if the target arch is aarch64 and the env is msvc and no compiler has been set then default to whataever clang there is on the path." In the products I work on we will set TARGET_AARCH64_PC_WINDOWS_MSVC_CC or similar to a specific version of clang.

I suggest the following course of action, which seems ideal to me:
PR 1. Merge this.
PR 2. Make a PR to get the build working when $TARGET_AARCH64_PC_WINDOWS_MSVC_CC points to VS2019's clang, either a full path or "clang" when it is in $PATH.
PR 3. Change the code to compile with VS2019's cl.exe (or clang or clang-cl).

@briansmith Sounds reasonable to me 🙂

build.rs Outdated
@@ -365,7 +391,7 @@ fn pregenerate_asm_main() {
let srcs = asm_srcs(perlasm_src_dsts);
for src in srcs {
let obj_path = obj_path(&pregenerated, &src, MSVC_OBJ_EXT);
run_command(nasm(&src, asm_target.arch, &obj_path, &pregenerated));
run_command(win_asm(&src, asm_target.arch, &obj_path, &pregenerated));
Copy link
Owner

Choose a reason for hiding this comment

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

I believe the refactoring in recent PRs will allow us to avoid making any changes here in this PR.

build.rs Outdated Show resolved Hide resolved
build.rs Outdated Show resolved Hide resolved
build.rs Outdated Show resolved Hide resolved
build.rs Show resolved Hide resolved
@Alovchin91
Copy link
Contributor Author

I can't seem to build it with clang-cl anymore:

  running "clang-cl" "-nologo" "-MD" "-Z7" "-Brepro" "--target=aarch64-pc-windows-msvc" "-I" "include" "-I" "pregenerated" "-W4" "-fmsc-version=1900" "/GS" "/Gy" "/EHsc" "/GR-" "/Zc:wchar_t" "/Zc:forScope" "/Zc:inline" "/Zc:rvalueCast" "/sdl" "/Wall" "/wd4127" "/wd4464" "/wd4514" "/wd4710" "/wd4711" "/wd4820" "/wd5045" "/Od" "/RTCsu" "-DNDEBUG" "-WX" "-c" "/Fopregenerated\\aesv8-armx-win64.o" "pregenerated\\tmp\\aesv8-armx-win64.S"
  In file included from pregenerated\tmp\aesv8-armx-win64.S:14:
  include\ring-core/arm_arch.h(104,9): error: macro name is a reserved identifier [-Werror,-Wreserved-id-macro]
  #define __ARM_MAX_ARCH__ 8
          ^
  1 error generated.

@Alovchin91
Copy link
Contributor Author

@briansmith Please take a look at the changes I've made to build.rs. As mentioned earlier, I cannot compile the code with clang-cl now (for whatever reason) so maybe I'll try to figure out why later.

@Alovchin91
Copy link
Contributor Author

I cannot compile the code with clang-cl now (for whatever reason) so maybe I'll try to figure out why later.

Hmm, forget about clang-cl I guess. The reason why I cannot compile with it now is because now it's also being used to compile assembly code which was not the case before. I'm not sure if we should worry about it or not.

@Alovchin91
Copy link
Contributor Author

Okay, so unless we care about the ability to compile assembly code with clang-cl, we should be good to go now @briansmith

I agree to license my contributions to each file under the terms given at the top of each file I changed.

Co-authored-by: Marc-André Moreau <marcandre.moreau@gmail.com>
@awakecoding
Copy link
Contributor

Okay, so unless we care about the ability to compile assembly code with clang-cl, we should be good to go now @briansmith

I don't think we care about building the assembly code with clang-cl, mostly because we really intend to use clang for it, and I'm not even sure that clang-cl can compile the assembly code in question with the MSVC-style arguments.

@Alovchin91
Copy link
Contributor Author

I don't think we care about building the assembly code with clang-cl, mostly because we really intend to use clang for it, and I'm not even sure that clang-cl can compile the assembly code in question with the MSVC-style arguments.

I'm not even sure it tries to compile it using a cl-driver when it sees a .S file 😅
In any case, if I assume pre-generated ASM, both clang-cl and clang now work for Windows AArch64 target 🙂

@Alovchin91
Copy link
Contributor Author

I must admit I'm pretty happy with the result! 🙂

@briansmith
Copy link
Owner

BTW could you please also upgrade cc to 1.0.69? This version contains fixes to find MSVC tools on Windows ARM.

Done in PR #1354.

@briansmith
Copy link
Owner

Here's how I tested this on the device:

  1. I copied
    C:\Program\ Files\apps-x86\Microsoft\ Visual\ Studio/2019\BuildTools\VC\Redist\MSVC\14.29.30133\arm64\Microsoft.VC142.CRT\vcruntime140.dll into the working copy of the device via scp.

rm -Rf target/aarch64-pc-windows-msvc/release
cargo test --no-run --release --target=aarch64-pc-windows-msvc
find target/aarch64-pc-windows-msvc/release -name "*.exe" | xargs -i scp "{}" username@surfaceprox:
ssh username@surfaceprox

On the Surface Pro X:

for %i in (*.exe) do %i

I also tested the debug builds in an analogous way.

@awakecoding
Copy link
Contributor

Here's how I tested this on the device:

  1. I copied
    C:\Program\ Files\apps-x86\Microsoft\ Visual\ Studio/2019\BuildTools\VC\Redist\MSVC\14.29.30133\arm64\Microsoft.VC142.CRT\vcruntime140.dll into the working copy of the device via scp.
rm -Rf target/aarch64-pc-windows-msvc/release
cargo test --no-run --release --target=aarch64-pc-windows-msvc
find target/aarch64-pc-windows-msvc/release -name "*.exe" | xargs -i scp "{}" username@surfaceprox:
ssh username@surfaceprox

On the Surface Pro X:

for %i in (*.exe) do %i

I also tested the debug builds in an analogous way.

Nice! If you want to get rid of the annoying vcruntime140.dll, you can use RUSTFLAGS='-C target-feature=+crt-static' as documented here.

@briansmith briansmith merged commit ceb5b90 into briansmith:main Aug 16, 2021
@briansmith
Copy link
Owner

@Alovchin91, @awakecoding Thanks for all your effort on this! I especially appreciate the effort you put in after the extra PR to make this easier to maintain (I hope) for people who don't have access to an aarch64-pc-windows-msvc device.

@Alovchin91 Alovchin91 deleted the alovchin91/win-arm64 branch August 16, 2021 19:46
@Alovchin91
Copy link
Contributor Author

@briansmith Thanks for all your help along the way! 😊 That was a lot of fun gentlemen 😀

NilsIrl added a commit to NilsIrl/MozWire that referenced this pull request Sep 20, 2021
@awakecoding
Copy link
Contributor

@briansmith it's been a year to the day that these Windows ARM64 build fixes are been merged on the main branch, but no release has been done since then, and we're still unable to build some of our Rust dependencies for all platforms because of this. We're getting closer to a first possible Windows ARM64 build of Remote Desktop Manager, so it's becoming a more pressing issue that we get a working build.

I have tried backporting the fixes back on top of 0.16.20 (there is no release tag on GitHub, so finding the right commit is tricky) and force it to work for Windows ARM64, but that version of build.rs was already quite different from the version on top of which the fixes were made. I wasted a few hours on it, and I'm stick figuring out how the static library is built assuming a .a extension, and why it still wants to build a bunch of linux64 assembly files.

I tried using the version of ring right after this pull request got merged, and edited Cargo.toml to make a fake 0.16.20 release out of it, such that it would get picked up by other crates like webpki, but then I hit "expected struct Reader, found struct untrusted::reader::Reader" issues. The latest ring release uses untrusted 0.9.0, while webpki is still on 0.7.1, and trying to change it to 0.9.0 causes a whole lot of other issues that I'm not familiar with.

What I need is a version of ring that can be built for Windows ARM64 and webpki, and I guess this means updating webpki to an newer version of the untrusted crate matching the latest version of ring. What would be the simplest way to get this unblocked? Is a ring 0.16.20 backport the only option, or is a new release of compatible crates coming soon?

@tr3ysmith
Copy link

@briansmith What can we do to get a new release out for the main branch? Rust is basically unusable on Windows ARM I you're relying on major libraries like Reqwest, Rustls, OAuth, etc.

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.

5 participants