ziglang / zig

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

Unable to link GLFW static library #20569

Closed matkve closed 1 month ago

matkve commented 1 month ago

Zig Version

0.14.0-dev.185+c40708a2c

Steps to Reproduce and Observed Behavior

I am trying to use zig as a build system for my c++ project. I want to use the library GLFW. At first I tried to link with a prebuilt GLFW static library from https://www.glfw.org/download, and this worked fine. The prebuilt libglfw3.a was supposedly built with MinGW-w64 (version 13.2.0-win32-dwarf-msvcrt). However, I wanted to have GLFW as a git submodule in my project, and build it myself. I installed a MinGW-w64 version similar to the one used for the prebuilt libglfw3.a; i686-13.2.0-release-win32-dwarf-msvcrt-rt_v11-rev1.7z from https://github.com/niXman/mingw-builds-binaries/releases. Here is my build.zig:

const std = @import("std");

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

    const exe = b.addExecutable(.{
        .name = "Minesweeper",
        .target = target,
        .optimize = optimize,
    });
    exe.linkLibCpp();
    exe.addCSourceFiles(.{
        .root = b.path("src"),
        .files = &.{"main.cpp"},
        .flags = &.{"-std=c++20"},
    });

    // Build GLFW as static lib
    const generate_glfw_makefile = b.addSystemCommand(&.{
        "cmake",
        "-G",
        "MinGW Makefiles",
        "-S",
        "deps\\glfw",
    });
    const glfw_build_dir = generate_glfw_makefile.addPrefixedOutputDirectoryArg("-B", "build");
    generate_glfw_makefile.addArgs(&.{
        "-DGLFW_BUILD_DOCS:BOOL=0",
        "-DGLFW_BUILD_TESTS:BOOL=0",
        "-DGLFW_BUILD_EXAMPLES:BOOL=0",
        "-DCMAKE_BUILD_TYPE=Release",
    });
    const build_glfw = b.addSystemCommand(&.{
        "cmake",
        "--build",
    });
    build_glfw.addDirectoryArg(glfw_build_dir);
    build_glfw.addArg("-j");

    // Link the static library libglfw3.a that will be created by the build_glfw step
    exe.addLibraryPath(glfw_build_dir.path(b, "src"));
    exe.linkSystemLibrary2("gdi32", .{ .preferred_link_mode = .static, .use_pkg_config = .no });
    exe.linkSystemLibrary2("glfw3", .{ .preferred_link_mode = .static, .use_pkg_config = .no });
    exe.addIncludePath(b.path("deps\\glfw\\include"));

    exe.step.dependOn(&build_glfw.step);
    b.installArtifact(exe);
}

main.cpp:

#include "GLFW/glfw3.h"
int main(int argc, char **argv) {
    glfwInit();
    return 0;
}

When I run zig build I get a linker error:

error: lld-link: undefined symbol: glfwInit
    note: referenced by C:\CppDev\Projects\Minesweeper\src\main.cpp:3
    note:               C:\CppDev\Projects\Minesweeper\.zig-cache\o\3964f28f84789df326d85735ec363016\main.obj:(main)
error: the following command failed with 1 compilation errors:
C:\ZigDev\zig-windows-x86_64-0.14.0-dev.185+c40708a2c\zig.exe build-exe -cflags -std=c++20 -- C:\CppDev\Projects\Minesweeper\src\main.cpp -search_paths_first_static -lgdi32 -lglfw3 -ODebug -I C:\CppDev\Projects\Minesweeper\deps\glfw\include -L C:\CppDev\Projects\Minesweeper\.zig-cache\o\39ad8182ed0103a8cfbc7de01ac2c9f2\build\src -Mroot -lc++ --cache-dir C:\CppDev\Projects\Minesweeper\.zig-cache --global-cache-dir C:\Users\matkve01\AppData\Local\zig --name Minesweeper --listen=-

When I build with the following g++ command directly in the terminal, I am able to link with the libglfw3.a that I built myself in the zig build system: g++ -I <path/to/glfw/include/dir> main.cpp -L <path/to/dir/containing/libglfw3> -lglfw3 -lgdi32 -o test It is the same main.cpp as above.

Expected Behavior

I expected to be able to link the libglfw3.a that I built myself, seeing as I was able to link it when invoking g++ directly. I was also able to link with the prebuilt libglfw3.a that was built using pretty much the same MinGW-w64 version as I am using, so why is it not working with the one I build myself?

matkve commented 1 month ago

I finally got it working thanks to https://github.com/ziglang/zig/issues/5735#issuecomment-886069293. It seems like you need a very specific MinGW-w64 version for it to work with zig cc. The one that worked for me was mingw-x86_64-clang from msys2. I tried a bunch of different versions before this that did not work, for example one with the following build-info:

version : MinGW-W64-builds-5.0.0
user    : runneradmin
date    : 10.16.2023- 5:22:12 PM
args    : --mode=gcc-13.2.0 --buildroot=/c/buildroot --jobs=4 --rev=1 --with-default-msvcrt=msvcrt --rt-version=v11 --threads=posix --exceptions=seh --arch=x86_64 --bin-compress --enable-languages=c,c++,fortran
PATH    : /mingw64/bin:/usr/local/bin:/usr/bin:/bin:/c/Windows/System32:/c/Windows:/c/Windows/System32/Wbem:/c/Windows/System32/WindowsPowerShell/v1.0/:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl
CFLAGS  : -O2 -pipe -fno-ident
CXXFLAGS: -O2 -pipe -fno-ident
CPPFLAGS: 
LDFLAGS : -pipe -fno-ident