ziglang / zig

General-purpose programming language and toolchain for maintaining robust, optimal, and reusable software.
https://ziglang.org
MIT License
34.3k stars 2.51k forks source link

linking issue with xinput DLL #1763

Open andrewrk opened 5 years ago

andrewrk commented 5 years ago

@errpr reports the following problem:

<errpr> I'm having a problem. My program never halts if I link to window's xinput1_4 DLL
<errpr> this is my code
const std = @import("std");

const XINPUT_GAMEPAD = struct {
    wButtons: c_ushort,
    bLeftTrigger: u8,
    bRightTrigger: u8,
    sThumbLX: c_short,
    sThumbLY: c_short,
    sThumbRX: c_short,
    sThumbRY: c_short,
};

const XINPUT_STATE = struct {
    dwPacketNumber: c_ulong,
    Gamepad: XINPUT_GAMEPAD,
};

extern "xinput1_4" stdcallcc fn XInputGetState(dwUserIndex: c_ulong, pState: *XINPUT_STATE) c_ulong;

pub const HINSTANCE__ = extern struct {
    unused: c_int,
};
pub const HINSTANCE = ?*HINSTANCE__;

pub export fn WinMain(Instance: HINSTANCE, PrevInstance: HINSTANCE, lpCmdLine: ?[*]u8, nCmdShow: c_int) c_int 
{
    var ControllerState: XINPUT_STATE = undefined;
    const errorcode = XInputGetState(0, &ControllerState);

    return 0;
}

We determined, using --verbose-link to find out the linker line, and replacing LLD with link.exe, that the problem goes away with microsoft's linker. So this appears to be an LLD issue.

We need to create a nice bug report for LLD upstream so that they fix it. The sooner the better, to maximize the chance that the fix comes out in 8.0.0, in time for zig 0.4.0.

This issue will remain open until the problem is solved in Zig master branch.

jhark commented 4 months ago

Doesn't reproduce with Zig 0.13.0-dev.351+64ef45eb0, Windows 10.

The test program also gets pad state as expected.

zig build-exe -lc -lXInput1_4 main.zig

Updated code:

const std = @import("std");

pub const XINPUT_GAMEPAD = extern struct {
    wButtons: c_ushort,
    bLeftTrigger: u8,
    bRightTrigger: u8,
    sThumbLX: c_short,
    sThumbLY: c_short,
    sThumbRX: c_short,
    sThumbRY: c_short,
};

pub const XINPUT_STATE = extern struct {
    dwPacketNumber: c_ulong,
    Gamepad: XINPUT_GAMEPAD,
};

pub extern fn XInputGetState(c_ulong, [*c]XINPUT_STATE) c_ulong;

pub fn main() void {
    var state = std.mem.zeroes(XINPUT_STATE);
    const err = XInputGetState(0, &state);
    std.debug.print("state: {}\nerr: {}\n", .{ state, err });
}

(using @cImport(@cInclude("XInput.h")); also works just fine)