7

I want to use GNUMake to run a rule-based makefile which builds a set of C files in a directory structure (on a Windows file system).

The root directory, some sub-directories and some files contain spaces.

Example file: "C:\Documents and Settings\<username>\My Documents\Test Dir\Build Me.c"

GNUMake doesn't really work when the file paths contain spaces. I've read about the possible ways of working around this issue (removing the spaces from my filenames, using the 8.3 format, substituting spaces with ? or \\ etc.) but none of them are perfect (or are they?)

Is there a silver bullet that will solve this problem?

BTW I am stuck with GNUMake, I can't use a different make tool.

demoncodemonkey
  • 11,730
  • 10
  • 61
  • 103

6 Answers6

3

The easiest thing is indeed to fix the file names.

Failing that, though, write your commands to put double quotes around the file names. The easiest and safest thing is to put all the file names into macros; the trick there is that you have to escape the double quotes, which Make is otherwise going to want to eat up itself.

So: FN="\"C:\My Documents\myfiles.c\"" FN2="C:\My Documents\myfile2.c"

or use $(CC) $(CFLAGS) "$(FN2)"

The trick here is to echo your command line with echo

echo $(CC) $(CFLAGS) "$(FN2)"

or use make -d to get all the details of what make is trying to do.

You may need to hack about with this a bit, in particular, you may need to double up the escapes

Charlie Martin
  • 110,348
  • 25
  • 193
  • 263
  • 11
    "Fix the file names"? The names are not broken. Tools that can't handle spaces are broken. The example path is a MS standard, even (I suspect this was a tactic to push developers to fix their broken tools that can't handle spaces.) – Qwertie May 01 '12 at 17:21
  • 1
    Nah, it's tools that use file names that don't match the UNIX standard that are broken. Also operating systems. – Charlie Martin May 02 '12 at 18:29
  • Operating systems and tools that *allow* spaces are broken?! – Qwertie Jun 06 '12 at 19:06
  • 2
    Yeah. And you kids get off my lawn. – Charlie Martin Jun 07 '12 at 21:54
2

I found a great inspiration at http://www.mail-archive.com/help-make@gnu.org/msg05201.html which got me going. My own test application consists of a directory of WW2-era Jazz FLV files downloaded from YouTube and an audio subdirectory into which I'd like to store the OGA audio versions of each one. And, of course, the file names contain spaces. I would then like to run ffmpeg2theora to

Here is the GNUMake Makefile that I've hacked together to work. Thanks to all of the hints on this site and also the referenced site above!

sq = $(subst $(sp),?,$1)
qs = $(subst ?,$(sp),$1)

e :=
sp := $(e) $(e)

FLVS := $(foreach file,var,$(call sq,$(wildcard *.flv)))
FLVS := $(subst .flv?,.flv ,$(FLVS))

AUDIOS := $(patsubst %.flv,audio/%.oga,$(FLVS))

.PHONY: audios show

audios: $(AUDIOS)

$(AUDIOS) : $(FLVS)
    ffmpeg2theora --novideo -o "$(call qs,$@)" "$(call qs,$(notdir $(patsubst %.oga,audio/%.flv,$@)))"

show:
    echo $(FLVS)
    echo $(AUDIOS)
Brian Yoder
  • 186
  • 6
  • Or you can substitute other characters and convert them back to spaces when needed. `s+ = $(subst \ ,+,$1)` `+s = $(subst +,\ ,$1)` `$(call s+,foo bar): $(call s+,bar baz)` `@echo Making $(call +s,$@) from $(call +s,$<)` – Mr_Moneybags Feb 01 '15 at 19:53
2

You may be able to escape the spaces in your makefile, i.e.:

$(CC) $(CFLAGS) 'C:\Documents\ and\ Settings\<username>\My\ Documents\Test\ Dir\Build Me.c'

I've added the single quotes just in case, but I don't know if this works if you're using the windows terminal (rather than cygwin etc).

Dana the Sane
  • 14,762
  • 8
  • 58
  • 80
  • May be able, as it I don't have a windows install handy to test with to be sure. I can't think of a reason why this won't work though. – Dana the Sane May 23 '12 at 18:03
1

I've typically used what is sort of a combination of Dana the Sane's answer and Brian Yoder's answer.

You just use the $(subst) function to replace all occurances of spaces with escaped spaces. EG:

empty := 
space := $(empty) $(empty)
program_files := $(subst $(space),\$(space),$(ProgramFiles))

(Note that with some older versions of make on Windows you would also need to use another $(subst) to change path backslashes to slashes)

T.E.D.
  • 44,016
  • 10
  • 73
  • 134
0

I simply add 'single quotes' around the offending string:- '$(TARGET_DIR)'

Example: (this helped me get erlang.mk to work correctly on windows!)

app:: $(C_SRC_ENV)
    @mkdir -p priv/
    $(c_src_verbose) $(CC) $(CFLAGS) $(C_SRC_DIR)/*.c -fPIC -shared -o $(C_SRC_OUTPUT) \
        -I '$(ERTS_INCLUDE_DIR)' $(C_SRC_OPTS)

'$(ERTS_INCLUDE_DIR)' now correctly expands to 'c:/Program Files/erl7.0/erts-7.0/include/'

using make -d also helps reveal invalid paths

Charles Okwuagwu
  • 10,538
  • 16
  • 87
  • 157
0

If the spaces are only in the "root" part of the pathname, you can mount that directory on a path without blanks. There are multiple ways of doing this: from the command line ("net use" or "subst") or from Explorer (Tools > Map Network Drive). So C:\Documents and Settings\\My Documents\Test Dir" might become X:\BuildMe.c

However, if there are blanks in the file names, or in directories below the "root" build directory, then there probably aren't any perfect solutions. I've used the other suggestions you mentioned (8.3 names, replacing blanks with a different character) and these work but they have their own problems.

jdigital
  • 11,926
  • 4
  • 34
  • 51
  • It needs to work in all cases. i.e. when the root directory contains a space, as well as the subdirectories themselves, and also the filenames themselves. – demoncodemonkey Mar 25 '09 at 11:12