Skip to content

make: normalize backslashes in env-imported variable values#376

Open
Peter0x44 wants to merge 1 commit into
skeeto:masterfrom
Peter0x44:make_normalize_environment
Open

make: normalize backslashes in env-imported variable values#376
Peter0x44 wants to merge 1 commit into
skeeto:masterfrom
Peter0x44:make_normalize_environment

Conversation

@Peter0x44
Copy link
Copy Markdown
Collaborator

@Peter0x44 Peter0x44 commented May 1, 2026

On Windows, the VULKAN_SDK environment variable, as set by the Vulkan SDK qt ifw installer contain backslash-separated paths. When GNU Make expands these into recipe lines passed to a unixy shell, the backslashes make it over to the shell command, where they are treated as escape characters, mangling the paths.

As a result, using make -f llama.mak would fail to build, if invoked from powershell, on a system with the vulkan SDK installed.

Normalize backslashes to forward slashes in all variable values imported from the Windows environment at startup, when a "unixy" shell is being used. This is the same thing that BusyBox-w32 ash does in setwinxp() on shell startup.

On Windows, the VULKAN_SDK environment variable, as set by the Vulkan
SDK qt ifw installer contain backslash-separated paths. When GNU Make
expands these into recipe lines passed to a unixy shell, the backslashes
make it over to the shell command, where they are treated as escape
characters, mangling the paths.

As a result, using `make -f llama.mak -j32` would fail to build, if
invoked from powershell.

Normalize backslashes to forward slashes in all variable values imported
from the Windows environment at startup, when a "unixy" shell is being
used.  This is the same thing that BusyBox-w32 ash does in setwinxp() on
shell startup.
@Peter0x44
Copy link
Copy Markdown
Collaborator Author

Peter0x44 commented May 1, 2026

I've found powershell to be quite useful for running agents, so I noticed this issue when I went to build llama.mak. I figured it would be sensible to do the same change busybox-w32 does to the environment variables expanded into recipes when SHELL is "unixy". But I'm a little unsure if it could have other consequences, so opened as a PR instead of pushing it.

@skeeto
Copy link
Copy Markdown
Owner

skeeto commented May 2, 2026

But I'm a little unsure if it could have other consequences, so opened as a PR instead of pushing it.

I appreciate it. I too am a little worried about edge cases a dumb conversion might break. The conversion in busybox-w32 breaks some things (which is why we need etc/profile), but there's no precedent of it not breaking these things. We'll merge this after the GCC 16 release and let it "cook" for awhile on master. Try to exercise some builds with GNU Make, perhaps even by using -G 'MinGW Makefiles' (what an awful name) in CMake.

@Peter0x44
Copy link
Copy Markdown
Collaborator Author

This shouldn't affect -G "MinGW Makefiles" because it uses SHELL=cmd (you can see this in the generated makefiles)
It could affect Unix Makefiles, which do work under BusyBox-w32

@Peter0x44
Copy link
Copy Markdown
Collaborator Author

@skeeto worth merging now?

To summarize, this will make no difference if you invoke make from within w64devkit.exe, as busybox-w32 already did the transformation in the environment variables. It will make no difference if you invoke make SHELL=cmd from a cmd shell. It will only make a difference if you invoke make from a non-busybox-w32 shell and depend on the backslashes being preserved for some reason.

@skeeto
Copy link
Copy Markdown
Owner

skeeto commented May 18, 2026

A real use case, here in a contrived example:

SHELL = cmd
DIR = .
example:
        dir $(DIR)

Where this currently works:

$ make DIR='\windows'

But would no longer work after these changes, as /windows looks like an option to lots of Windows-only software. This particular case illustrates why the shell doesn't actually matter either, but rather the receiving program, e.g. information unknown to Make. My tiny bugfix in 9cbd374 has proven disruptive, and this is a bigger change than that.

I'd love a solution like the one in u-config where path variables are escaped for the receiving shell when interpolated. However, Make doesn't have the luxury of knowing which variables are paths and which are shell fragments that should be passed through unmodified, e.g. CFLAGS='-Wall -Wextra'.

Perhaps we still merge this to try it out, but it might be reverted before the next release.

@Peter0x44
Copy link
Copy Markdown
Collaborator Author

Yeah, it ultimately is a hack, but it is one I find useful occasionally. For cmd, this is not a major issue, as \ isn't used to escape things (that's ^ or ` I forgot) and nobody really designs cli arguments around \ (since it's also a path separator, for which / works equally well in the vast majority of contexts)

That's why I think it's a good idea. And since BusyBox is already doing this translation, doing it in make too would only be more consistent, not less. I could put it behind an env var or add a way to disable it if that would make it any better.

I could also just fix my environment variables anyway.

@skeeto
Copy link
Copy Markdown
Owner

skeeto commented May 19, 2026

Alright, let's try it out for awhile.

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.

2 participants