premake / premake-core

Premake
https://premake.github.io/
BSD 3-Clause "New" or "Revised" License
3.22k stars 619 forks source link

Make with Clang fails to find `ar` on Windows #1742

Open ghost opened 2 years ago

ghost commented 2 years ago

I am working on a GnuMake based Build-System for a GameEngine. I got clang installed and set toolset("clang"). At the Moment I am able to compile GLFW, but it dosn't link. Is there a way to set the toolset for the linker?

This is the premake5.lua I use:

workspace ("VoidSpaceProject")
    systemversion ("latest")
    architecture ("x86", "x64")
    configurations
    {
        "debugwin32", "debugwin64",
        "devwin32", "devwin64",
        "releasewin32", "releasewin64"
    }
    toolset ("clang")

    cppdialect ("C++17")

    location (".")

    --===========================================================
    --  Path Variables
    --===========================================================

    pathGLFW = (".ext/GLFW/")
    pathEngine = ("Engine/")
    pathTestbed = ("Testbed/")

    pathObj = (".bin/.int/%{prj.name}/%{cfg.buildcfg}/")
    pathOut = (".bin/%{prj.name}/%{cfg.buildcfg}/")

    --===========================================================
    --  GLFW Project
    --===========================================================
    project ("GLFW")
        language ("C")
        kind ("StaticLib")

        location (".ext/GLFW")

        targetdir (pathOut)
        objdir (pathObj)

        --===========================================================
        --  CrossPlatform Settings
        staticruntime "On"
        includedirs
        {
            "%{prj.location}/src/"
        }
        files
        {
            "%{prj.location}/include/GLFW/glfw3.h",
            "%{prj.location}/include/GLFW/glfw3native.h",
            "%{prj.location}/src/glfw_config.h",
            "%{prj.location}/src/context.c",
            "%{prj.location}/src/init.c",
            "%{prj.location}/src/input.c",
            "%{prj.location}/src/monitor.c",
            "%{prj.location}/src/vulkan.c",
            "%{prj.location}/src/window.c"
        }
        -- filter {}
        --  CrossPlatform Settings
        --===========================================================

        --===========================================================
        --  Win32 Settings
        filter ("configurations:*win32")
            system ("windows")
            architecture ("x86")
            files
            {
                "%{prj.location}/src/win32_init.c",
                "%{prj.location}/src/win32_joystick.c",
                "%{prj.location}/src/win32_monitor.c",
                "%{prj.location}/src/win32_time.c",
                "%{prj.location}/src/win32_thread.c",
                "%{prj.location}/src/win32_window.c",
                "%{prj.location}/src/wgl_context.c",
                "%{prj.location}/src/egl_context.c",
                "%{prj.location}/src/osmesa_context.c"
            }
            defines
            {
                ("_GLFW_WIN32"),
                ("_CRT_SECURE_NO_WARNINGS")
            }
        filter {}
        --  Win32 Settings
        --===========================================================

        --===========================================================
        --  Win64 Settings
        filter ("configurations:*win64")
            system ("windows")
            architecture ("x64")
            files
            {
                "%{prj.location}/src/win32_init.c",
                "%{prj.location}/src/win32_joystick.c",
                "%{prj.location}/src/win32_monitor.c",
                "%{prj.location}/src/win32_time.c",
                "%{prj.location}/src/win32_thread.c",
                "%{prj.location}/src/win32_window.c",
                "%{prj.location}/src/wgl_context.c",
                "%{prj.location}/src/egl_context.c",
                "%{prj.location}/src/osmesa_context.c"
            }
            defines
            {
                "_GLFW_WIN32",
                "_CRT_SECURE_NO_WARNINGS"
            }
        filter {}
        --  Win64 Settings
        --===========================================================

        --===========================================================
        --  Configurations
        filter ("configurations:DebugWin32")
            defines {"VSE_DEBUG"}
            runtime ("Debug")
            symbols ("On")

        filter ("configurations:DebugWin64")
            defines {"VSE_DEBUG"}
            runtime ("Debug")
            symbols ("On")

        filter ("configurations:DevWin32")
            defines {"VSE_DEV"}
            runtime ("Release")
            optimize "Speed"

        filter ("configurations:DevWin64")
            defines {"VSE_DEV"}
            runtime ("Release")
            optimize "Speed"

        filter ("configurations:ReleaseWin32")
            defines {"VSE_RELEASE"}
            runtime ("Release")
            optimize "Speed"

        filter ("configurations:ReleaseWin64")
            defines {"VSE_RELEASE"}
            runtime ("Release")
            optimize "Speed"
        filter {}
        --  Configurations
        --===========================================================
nickclark2016 commented 2 years ago

Can you share the premake file that you use for GLFW and the premake file for the project that fails to link?

ghost commented 2 years ago

Can you share the premake file that you use for GLFW and the premake file for the project that fails to link?

It is updated, hope this is enough 😅 I really appreciate your help 😋

nickclark2016 commented 2 years ago

Can you share the premake file that you use for GLFW and the premake file for the project that fails to link?

It is updated, hope this is enough 😅 I really appreciate your help 😋

Can you share the project premake file you're trying to link to as well?

ghost commented 2 years ago

It is already there, It get's compiled tut not finish. This is the Compiler output I get:

Creating ../../.bin/.int/GLFW/debugwin32
context.c
egl_context.c
init.c
input.c
monitor.c
osmesa_context.c
vulkan.c
wgl_context.c
win32_init.c
win32_joystick.c
win32_monitor.c
win32_thread.c
win32_time.c
win32_window.c
window.c
Creating ../../.bin/GLFW/debugwin32
Linking GLFW
process_begin: CreateProcess(NULL, ar -rcs ../../.bin/GLFW/debugwin32/GLFW.lib ../../.bin/.int/GLFW/debugwin32/context.o ../../.bin/.int/GLFW/debugwin32/egl_context.o ../../.bin/.int/GLFW/debugwin32/init.o ../../.bin/.int/GLFW/debugwin32/input.o ../../.bin/.int/GLFW/debugwin32/monitor.o ../../.bin/.int/GLFW/debugwin32/osmesa_context.o ../../.bin/.int/GLFW/debugwin32/vulkan.o ../../.bin/.int/GLFW/debugwin32/wgl_context.o ../../.bin/.int/GLFW/debugwin32/win32_init.o ../../.bin/.int/GLFW/debugwin32/win32_joystick.o ../../.bin/.int/GLFW/debugwin32/win32_monitor.o ../../.bin/.int/GLFW/debugwin32/win32_thread.o ../../.bin/.int/GLFW/debugwin32/win32_time.o ../../.bin/.int/GLFW/debugwin32/win32_window.o ../../.bin/.int/GLFW/debugwin32/window.o, ...) failed.
make (e=2): Das System kann die angegebene Datei nicht finden.
make[1]: *** [Makefile:150: ../../.bin/GLFW/debugwin32/GLFW.lib] Error 2
make: *** [makefile:54: GLFW] Error 2
nickclark2016 commented 2 years ago

Ahh, I'm following now. GLFW itself isn't linking. Are you using mingw for Makefile on windows?

ghost commented 2 years ago

I use Clang from LLVM

nickclark2016 commented 2 years ago

Yes, but how are you running Make?

ghost commented 2 years ago

From the Terminal inside vsCode 😅

nickclark2016 commented 2 years ago

Windows or Linux?

ghost commented 2 years ago

Windows

nickclark2016 commented 2 years ago

Is "ar" located on your path? I've had no problem with Clang + gmake2 on Linux (just trying to figure out if we're having issues with out exporter on Windows).

ghost commented 2 years ago

I don't know what "ar" is 😅 I want to use clang for linking. If you want you can run it yourself, it is on my Engine Repository

nickclark2016 commented 2 years ago

Ahh, I don't have the tooling installed on my machine for that. It looks like we only use llvm-ar if LTO is enabled. If not, we fall back on the GCC archive tool (ar).

nickclark2016 commented 2 years ago

https://github.com/premake/premake-core/wiki/flags

Try adding the LinkTimeOptimization flag to your premake file.

ghost commented 2 years ago

Thx, it seems to have worked :yum:

nickclark2016 commented 2 years ago

Awesome. @starkos is this something that we want to continue being the default behavior?

ghost commented 2 years ago

I think it is better to try using the linker of the compiler or add a toolset-linker() function

nickclark2016 commented 2 years ago

We use the linker of the compiler for every toolset but this weird edge case.

ghost commented 2 years ago

Hmm... so it is like a bug thing?

nickclark2016 commented 2 years ago

I don't think so, as it is intended and has been there for a while. That said, I think a discussion needs to be had on whether or not this should continue to be the desired behavior.

starkos commented 2 years ago

I guess the question is how much of an "edge" is this edge case? Poking around the open questions on StackOverflow, there a number of "my project won't link library X" topics out there. Maybe related?

Is there any reason not to default to llvm-ar when Clang is the toolset? I'm not familiar enough with the distribution.

(Also it would lovely if the error message said which file it can't find; not terribly helpful as is but I guess that's out of scope here.)

nickclark2016 commented 2 years ago

Just from familiarity with winapi, I believe it is "ar" that cannot be found.

starkos commented 2 years ago

Just from familiarity with winapi, I believe it is "ar" that cannot be found.

Right, I get that, I was just poking fun at the not useful error message. Anyway, my vote would be to switch the Clang adapter to always use the LLVM linker, if that's a valid option.

nickclark2016 commented 2 years ago

I think that's valid, as if you have Clang you should have LLVM-ar. I'm slightly worried about a wholesale swap of the linkers without some verification, because I don't know if all the flags for GCC's linker will map to LLVM's linker correctly.

starkos commented 2 years ago

Tried to replace with ar with llvm-ar. Worked fine on my macOS boxes, but the CI build failed because llvm-ar isn't found on those servers. Guess that answers the question? I guess the only way to fix this properly is to actually write logic into the makefile to look for and use llvm-ar is possible, and fall back to ar if not? (Or vice versa, but that feels like there right ordering to me.)

nickclark2016 commented 2 years ago

Just wanted to circle back on this now that I've got a bit of time. I think we can do something like this for Unix operating systems:

ifeq (, $(shell which llvm-ar))
   LINKER := ar
else
   LINKER := llvm-ar
endif

For windows, we may be a little trickier. We'd need to know if the command was being executed from a powershell or a command line environment. We could explicitly invoke into an environment like this:

powershell Get-Command llvm-ar

I'd need more research to figure out how to actually do this in Windows, as I'm not very familiar with using Makefiles in a windows environment.

projectitis commented 2 years ago

An additional note if you are working on this.

I just make the same 'forced' fix to get llvm-ar on windows (i.e. flags { "LinkTimeOptimization" }) After premake generated the makefile I had to make a manual fix to the xxx.make file for a successful link:

### OLD
LINKCMD = $(AR) -rcs "$@" $(OBJECTS)

### NEW
LINKCMD = $(AR) -rcs $@ $(OBJECTS)

The quotes around the output file name cause a problem.

Example (I am building Rive):

llvm-ar -rcs "windows/bin/release/rive.lib" windows/obj/release/aabb.o windows/obj/release/animation_base.o ...
### Results in 
llvm-ar.exe: error: windows/obj/release/t: no such file or directory
make[1]: *** [rive.make:523: windows/bin/release/rive.lib] Error 1

llvm-ar -rcs windows/bin/release/rive.lib windows/obj/release/aabb.o windows/obj/release/animation_base.o ...
### Works as expected