What is the most reliable way of using GNUMake wit

2019-02-17 02:24发布

问题:

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.

回答1:

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



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



回答3:

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)


回答4:

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)



回答5:

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.



回答6:

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