premake-core icon indicating copy to clipboard operation
premake-core copied to clipboard

Make with Clang fails to find `ar` on Windows

Open ghost opened this issue 4 years ago • 27 comments

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
		--===========================================================

ghost avatar Nov 01 '21 14:11 ghost

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

nickclark2016 avatar Nov 01 '21 15:11 nickclark2016

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 😋

ghost avatar Nov 01 '21 16:11 ghost

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?

nickclark2016 avatar Nov 01 '21 16:11 nickclark2016

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

ghost avatar Nov 01 '21 17:11 ghost

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

nickclark2016 avatar Nov 01 '21 17:11 nickclark2016

I use Clang from LLVM

ghost avatar Nov 01 '21 17:11 ghost

Yes, but how are you running Make?

nickclark2016 avatar Nov 01 '21 17:11 nickclark2016

From the Terminal inside vsCode 😅

ghost avatar Nov 01 '21 17:11 ghost

Windows or Linux?

nickclark2016 avatar Nov 01 '21 17:11 nickclark2016

Windows

ghost avatar Nov 01 '21 17:11 ghost

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).

nickclark2016 avatar Nov 01 '21 17:11 nickclark2016

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

ghost avatar Nov 01 '21 17:11 ghost

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 avatar Nov 01 '21 17:11 nickclark2016

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

Try adding the LinkTimeOptimization flag to your premake file.

nickclark2016 avatar Nov 01 '21 17:11 nickclark2016

Thx, it seems to have worked :yum:

ghost avatar Nov 01 '21 17:11 ghost

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

nickclark2016 avatar Nov 01 '21 17:11 nickclark2016

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

ghost avatar Nov 01 '21 17:11 ghost

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

nickclark2016 avatar Nov 01 '21 17:11 nickclark2016

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

ghost avatar Nov 01 '21 17:11 ghost

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.

nickclark2016 avatar Nov 01 '21 17:11 nickclark2016

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.)

starkos avatar Nov 02 '21 10:11 starkos

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

nickclark2016 avatar Nov 06 '21 22:11 nickclark2016

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.

starkos avatar Nov 07 '21 20:11 starkos

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.

nickclark2016 avatar Nov 07 '21 21:11 nickclark2016

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.)

starkos avatar Nov 26 '21 15:11 starkos

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.

nickclark2016 avatar Jan 12 '22 19:01 nickclark2016

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

projectitis avatar Aug 14 '22 09:08 projectitis