Skip to content

Conversation

@rofferom
Copy link
Contributor

@rofferom rofferom commented Nov 26, 2025

Description

Based on #3100 and #3116, here is an dirty implementation of cross compilation for Windows (tested from a Debian 12).

I chose to base my work on v20 branch to make sure I have a stable environment, which allow me to excursively focus on the build system.

Also, the build.rs files don't seem to be very cross-compilation friendly. Since I don't have a good knowledge of alvr build system, I decided to implement an alternative codepath with a lot of code duplication, just to create a proof of concept that can be a base for discussion. I'm pretty sure I missed a lot of details, but at least I managed to have something working.

At the very end, I'm able to build with this simple command:

cargo xtask build-streamer --release windows

It requires some environment variables at first (more details bellow), but I managed to plug it in the existing command flow.

Known limitations

  • build.rs for Dashboard hasn't been updated. Which means that the executable doesn't have its icon correctly configured.
  • No ffmpeg build for now. So no x264 support
  • package command not patched

Environment requirements

  • Rust target x86_64-pc-windows-msvc installed
  • clang-cl as a toolchain since it is compilant with Windows C++ ABI
  • https://github.com/mstorsjo/msvc-wine to get the required MSVC/Windows SDK files

How to build (only tested on Debian 12)

Install required Windows components

Where: in msvc-wine folder.

VS_ROOT_DIR=<msvcinstallpath>

./vsdownload.py \
    --accept-license \
    --dest $VS_ROOT_DIR \
    --host-arch x64 \
    Microsoft.VisualStudio.Component.VC.14.44.17.14.x86.x64 \
    Microsoft.Component.VC.Runtime.UCRTSDK \
    Microsoft.VisualStudio.Component.VC.Redist.14.Latest \
    Microsoft.VisualStudio.Component.Windows11SDK.26100

./install.sh $VS_ROOT_DIR

Note this may be improved, I discovered msvc-wine while working on this PR.

Setup build env

VS_ROOT_DIR=<msvcinstallpath>

export CXX=clang-cl-19
export AR=llvm-lib-19
export TARGET_CC=clang-cl-19
export CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_LINKER=lld-link-19

MSVC_ROOT=$VS_ROOT_DIR/vc/tools/msvc/14.44.35207
WINSDK_INCLUDE=$VS_ROOT_DIR/kits/10/include/10.0.26100.0
WINSDK_LIB=$VS_ROOT_DIR/kits/10/lib/10.0.26100.0

export INCLUDE="$MSVC_ROOT/include;$WINSDK_INCLUDE/shared;$WINSDK_INCLUDE/um;$WINSDK_INCLUDE/ucrt;$WINSDK_INCLUDE/winrt"
export LIB="$MSVC_ROOT/lib/x64;$WINSDK_LIB/ucrt/x64;$WINSDK_LIB/um/x64"

Build

cargo xtask build-streamer --release windows

Output

build
└── alvr_streamer_windows
    ├── ALVR Dashboard.exe
    ├── bin
    │   └── win64
    │       ├── alvr_server_openvr.pdb
    │       ├── driver_alvr_server.dll
    │       ├── openvr_api.dll
    │       └── vcruntime140_1.dll
    └── driver.vrdrivermanifest

rofferom and others added 3 commits November 24, 2025 18:23
…tion (alvr-org#3100)

Standardize all Windows API header includes to use lowercase filenames.
This ensures compatibility when cross-compiling on case-sensitive
filesystems (Linux with MinGW).

(cherry picked from commit a992688)
* fix(server_openvr): Fix inputColorAdjust type

Fixes this build error with clang-cl 19.1.7
cpp/platform/win32/FrameRender.cpp(787,15): error: non-constant-expression cannot be narrowed from type 'int' to 'uint32_t' (aka 'unsigned int') in initializer list [-Wc++11-narrowing]

* fix(server_openvr): Remove useless D3D9Types.h include

* fix(server_openvr): Normalize Windows link libraries to lowercase for cross-compilation

Standardize all Windows API libraries to use lowercase filenames.
This ensures compatibility when cross-compiling on case-sensitive
filesystems (Linux with MinGW).

* fix(server_openvr): Force usage of UuidFromStringA()

RPC_CSTR isn't a wide string, so it the A version of UuidFromString()
can be called explicitly.

Fixes this build error with clang-cl 19.1.7
cpp/platform/win32/shared/d3drender.cpp(93,4): error: no matching function for call to 'UuidFromStringW'
     93 |                         UuidFromString( ( RPC_CSTR ) "8c8f13b1-60eb-4b6a-a433-de86104115ac", &guid );
        |                         ^~~~~~~~~~~~~~
  .../kits/10/include/10.0.26100.0/shared/rpcdce.h(2775,24): note: expanded from macro 'UuidFromString'
   2775 | #define UuidFromString UuidFromStringW
        |                        ^~~~~~~~~~~~~~~
  .../kits/10/include/10.0.26100.0/shared/rpcdce.h(2769,1): note: candidate function not viable: no known conversion from 'RPC_CSTR' (aka 'unsigned char *') to 'RPC_WSTR' (aka 'unsigned short *') for 1st argument
   2769 | UuidFromStringW (
        | ^
   2770 |     _In_opt_ RPC_WSTR StringUuid,
        |              ~~~~~~~~~~~~~~~~~~~

(cherry picked from commit aa72497)
Requires clang-cl and Windows SDK.

The implementation introduces an alternative codepath
with a lot of code duplication. The goal is to show
that seems to be required to make the build system
able to cross compile.
Copy link
Member

@zmerp zmerp left a comment

Choose a reason for hiding this comment

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

This is a preliminary review.
You should rebase your branch because some changes were already merged.
Also, I think you could avoid duplicating the build code, making use of std::env:consts::OS, which should point to the destination compilation target, not the host

pub vulkan_layer_manifest_dir: PathBuf,
pub launcher_root: Option<PathBuf>,

pub platform: Option<&'static str>,
Copy link
Member

Choose a reason for hiding this comment

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

Why should this be an Option?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

See my comment bellow. There is no valid reason, I just wanted to keep the existing build system untouched.

In this specific case, it allows me to override the defaut behavior of openvr_driver_lib_dir() with a new constructor new_cross_windows().

alvr_filesystem::deps_dir().join("linux/x264/alvr_build")
}

fn cross_windows_build() {
Copy link
Member

Choose a reason for hiding this comment

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

if possible I would like to not duplicate the build code

@rofferom
Copy link
Contributor Author

making use of std::env:consts::OS, which should point to the destination compilation target, not the host

I'm not familiar with this part of Rust, but actually this seems not to be true in build.rs. As it is an host tool, its target is the host OS, not the --target specified on cargo call. Which mean that cfg!(...) have an "unexpected" behavior. I attached a code example bellow.

I should have been more explicit about this part in the MR description. This is why I chose to create an alternate codepath to make it work, since I think some preliminary changes in the build system could be required at first. During my first try to add cross compilation support, I was triggering all the Linux build codepath, and I want tweaking all the conditional build tests, which lead to heavy changes.

You should rebase your branch because some changes were already merged.

I can open a new PR targeting master (since the name of my current branch is explicit about v20.14.1), but I suggest we can discuss about the correct strategy to remove code duplication. Then I'll be able to provide a PR targeting master, with a correct implementation.

build.rs behavior tests

build.rs example

fn main() {
    println!("cargo:warning=In build.rs");

    println!("cargo:warning=std::env:consts::OS={}", std::env::consts::OS);

    if cfg!(windows) {
        println!("cargo:warning=cfg!(windows)");
    } else if cfg!(target_os = "linux") {
        println!("cargo:warning=cfg!(target_os = \"linux\")");
    }
}

Linux build

$ cargo build
warning: [email protected]: In build.rs
warning: [email protected]: std::env:consts::OS=linux
warning: [email protected]: cfg!(target_os = "linux")

Linux -> Windows build

$ cargo build --target "x86_64-pc-windows-msvc"
   Compiling rusttest v0.1.0 (/mnt/kyber/rusttest)
warning: [email protected]: In build.rs
warning: [email protected]: std::env:consts::OS=linux
warning: [email protected]: cfg!(target_os = "linux")

@zmerp
Copy link
Member

zmerp commented Nov 29, 2025

Ah I see, so env::var("CARGO_CFG_TARGET_OS") is the only good way to do this. I would say that interleaving the code is not that bad, as I see that significant portions of the code are duplicated. you can use many small if-else wherever you need instead.

@The-personified-devil The-personified-devil changed the base branch from v20 to master November 30, 2025 18:38
@The-personified-devil The-personified-devil changed the base branch from master to v20 November 30, 2025 18:39
@The-personified-devil
Copy link
Collaborator

You'll have to rebase this on top of master so that we can actually do anything with it, tho I can do that for you if you think that's too much for you.

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