WINAVR not finding file in include path with whitespace - makefile

When I supply an path for EXTRAINCDIRS (in the Makefile, following the sample provided by WINAVR) without whitespace, the compiler is able to find my header file, but when I use a path containing whitespace (enclosed in quotation marks, as the comments in the Makefile direct), it raises: error: No such file or directory.
"d:/dev/avr/atmega/shared/" # will search files in this dir
"d:/dev/avr/atmega/sha ed/" # will not search this dir for files
I mean, the comments say:
# List any extra directories to look for include files here.
# Each directory must be seperated by a space.
# Use forward slashes for directory separators.
# For a directory that has spaces, enclose it in quotes.
Any idea how to get WINAVR to handle this correctly?
I'm using Programmer's Notepad (WINAVR) on Windows XP. Here's the command line command:
avr-g++ -c -mmcu=atmega328p -I. -gdwarf-2 -DF_CPU=UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=./main.lst -I"d:/dev/avr/atmega/shared/" -I"d:/dev/avr/atmega/sha -Ied/" -std=gnu99 -MMD -MP -MF .dep/main.o.d main.c -o main.o

What is happening is that I'm guessing somewhere else in the makefile there is a line that does something like the following:
INCLUDES = $(addprefix -I, $(INCDIRS))
When that happens addprefix treats any spaces in the $(INCDIRS) variable as a seperator to the next variable and will add the -I there. What you could do is use a special character for spaces say '\\' and then before the command is generated call a substitute function to resubstitute spaces. Something like the below example:
SPACE = \\
INCDIRS = /home/posey/test$(SPACE)dir
INCLUDES = $(addprefix -I, $(INCDIRS))
REAL_INCLUDES = $(subst $(SPACE), ,$(INCLUDES))
.PHONY : all
all:
$(info $(REAL_INCLUDES))
If this doesn't make sense you can post the entire makefile and we can show you exactly what's going on. Once the space has been substituted back into the variable you cannot run it through any further make functions that work with space delimiters without the same behavior occurring.

Related

make: gcc: Command not found with include in makefile

I am trying to a create a makefile architecture so I have one global makefile at the top which call another in a subdirectory.
Global makefile :
CC = gcc
CFLAGS = -W -Wall -pedantic
LDFLAGS =
PROJECT = proj
SOURCES =
PATH = $(PROJECT)
include $(PATH)/Makefile
all : $(PROJECT).exe
$(PROJECT).exe :
$(CC) $(CFLAGS) $(LDFLAGS) $(DEFINES) $(INCLUDES) $(SOURCES) -o $#
clean :
rm -rf *.exe
Subdirectory makefile :
CC = gcc
CFLAGS = -W -Wall -pedantic
LDFLAGS =
SOURCES += $(PATH)/main.c
When I "make" in the top directory I have the following error :
gcc -W -Wall -pedantic proj/main.c -o proj.exe
make: gcc: Command not found
make: *** [Makefile:17: FK16_jake.exe] Error 127
But when i type exactly the same command (gcc -W -Wall -pedantic proj/main.c -o proj.exe) in my terminal, it's building.
And if I remove the makefile include, he recognize gcc but don't build because no sources (normal behavior).
You are overriding PATH, which is used to determine where to look for executables. Change this variable and it should work.
In the UNIX shell, the environment variable PATH specifies the set of directories to search for executables when you run a command.
The GNU Make manual says:
When make runs a recipe, variables defined in the makefile are
placed into the environment of each shell. This allows you to pass
values to sub-make invocations (see Recursive Use of make). By default, only variables that came from the environment
or the command line are passed to recursive invocations.
Because PATH is a shell variable and is defined in the environment of make, it is "came from the environment". That means when you modify the value with PATH = $(PROJECT) the updated value will be set in the environment of the shell that runs the recipe for $(PROJECT).exe. That means the shell runs with a bad value for the PATH and so cannot find gcc.
To avoid this confusion, do not use PATH as a makefile variable. Use another name which is not the same as an environment variable that the shell depends on. You could call it PROJECT_PATH instead, or just use $(PROJECT) instead of $(PATH).

Why aren't my variables expanding in my makefile?

I'm using mingw32-make to run my makefile. The contents of the Makefile are the following:
#OBJS specifies which files to compile as part of the project
OBJS = SDLpp.o SDLpp_exception.o SDLpp_window.o
#CC specifies which compiler we're using
CC = g++
#INCLUDE_PATHS specifies the additional include paths we'll need
INCLUDE_PATHS = -IC:\mingw_dev_lib\include\SDL2 \
-IC:\mingw_dev_lib\include\SDL_image \
-IC:\mingw_dev_lib\include\SDLpp
#LIBRARY_PATHS specifies the additional library paths we'll need
LIBRARY_PATHS = -LC:\mingw_dev_lib\lib
#COMPILER_FLAGS specifies the additional compilation options we're using
# -w suppresses all warnings
# -Wall includes all warnings
# -Wl,-subsystem,windows gets rid of the console window
COMPILER_FLAGS = -Wall
#LINKER_FLAGS specifies the libraries we're linking against
LINKER_FLAGS = -lmingw32 -lSDL2main -lSDL2 -lSDL2_image
#LIB_NAME specifies the name of our library
LIB_NAME = libSDLcpp.a
#This is the target that compiles our executable
all : $(OBJS)
ar rvs $(LIB_NAME) $(OBJS)
%.o : %.c
$(CC) $< $(INCLUDE_PATHS) $(LIBRARY_PATHS) $(COMPILER_FLAGS) -c $(LINKER_FLAGS) -o $#
^(the white-space before the commands are tabs)^
When run, the shell outputs
g++ -c -o SDLpp.o SDLpp.cpp
which indicates that the other variables are not being expanding in the first pattern rule. Oddly, only CC is expanding into g++. Why is this happening?
The issue is not one of non-expanding variables. Rather, the makefile is using the default rule instead of the one you provided.
The reason may be that your rule uses *.c, while you likely have *.cpp files, IIRC.

Makefile For Loop Pattern Substitution

In the following makefile for loop, how can I edit the string, that the i variable represents, with a pattern substitution in the middle of the string? In my case, I wish to replace any / character in the string with a _ character.
for i in $(MODULES:%.cpp=%); do \
g++ -c Sources/$$i.cpp -o Build/$$i.o; \
done
For example if MODULES = Directory/File.cpp then the inner line should expand to
g++ -c Sources/Directory/File.cpp -o Build/Directory_File.o
This answer is valid only with GNU make and bash.
Simple bash substitution (${parameter/pattern/string}) in the context of a make recipe (double $):
for i in $(MODULES:%.cpp=%); do \
g++ -c Sources/$$i.cpp -o Build/$${i//\//_}.o; \
done
Warning: this works only if the shell used by make is bash. So, add maybe a:
SHELL := bash
at the beginning of your Makefile.
Explanation:
${i/X/_} expands as the value of variable i in which the first occurrence of X is replaced by _.
${i//X/_} expands as the value of variable i in which all occurrences of X are replaced by _.
In your case X is the / character and it must be escaped (\/): ${i//\//_}.
Note that there is probably a less bash and more make way to do the same. Something like:
SRCS := $(shell find Sources -type f -name *.cpp)
OBJS :=
define OBJ_rule
obj := Build/$$(subst /,_,$$(patsubst Sources/%.cpp,%,$(1))).o
OBJS += $$(obj)
$$(obj): $(1)
g++ -c $$< -o $$#
endef
$(foreach s,$(SRCS),$(eval $(call OBJ_rule,$(s))))
.PHONY: objs
objs: $(OBJS)
Which instantiates one rule per module and should do the same... with the significant advantage that, when you type make objs, only the outdated object files are rebuilt. But it's a bit more tricky.

What does "$(#:%.o=%.d)" mean in a makefile?

I see below command options for GCC in a makefile:
... -MMD -MP -MF "$(#:%.o=%.d)" -MT "$(#:%.o=%.d)" -o "$#" "$<"
How to interpret it?
I searched through the makefile document, but no luck so far.
(This is not just about Automatic Variables)
$(:=) performs a string replacement.
$# is the name of the file being generated (the target).
So $(#:%.o=%.d) is the name of the file, with the .o extension changed to .d.
This command line generates one .d dependency file for each .o file.
(Thanks to #Quentin's clue. I just found it!)
It is called Substitution Reference
Some quote:
A substitution reference substitutes the value of a variable with
alterations that you specify. It has the form ‘$(var:a=b)’ (or
‘${var:a=b}’) and its meaning is to take the value of the variable
var, replace every a at the end of a word with b in that value, and
substitute the resulting string.
When we say “at the end of a word”, we mean that a must appear either
followed by whitespace or at the end of the value in order to be
replaced; other occurrences of a in the value are unaltered. For
example:
foo := a.o b.o c.o
bar := $(foo:.o=.c)
sets ‘bar’ to ‘a.c b.c c.c’. See Setting Variables.
A substitution reference is actually an abbreviation for use of the
patsubst expansion function (see Functions for String Substitution and
Analysis). We provide substitution references as well as patsubst for
compatibility with other implementations of make.
So, the full interpretation of the following command:
... -MMD -MP -MF "$(#:%.o=%.d)" -MT "$(#:%.o=%.d)" -o "$#" "$<"
is:
Use gcc to compile the 1st prerequisite file ($<) and generate the
output file named after the current rule target's name (%#). And by
the way, generate a makefile named as *.d containing a rule to describe the dependency of current rule target. And change the name of rule target in the
generated *.d makefile from *.o to *.d.

% not matching zero or more characters in rule?

According to the manual on Defining and Redefining Pattern Rules (and if I am reading it correctly):
‘%’ character matching any sequence of zero or more characters...
But the following is not matching both bench.cpp and bench2.cpp:
bench%.o : bench%.cpp
$(CXX) $(CXXFLAGS) -DCRYPTOPP_DATA_DIR='"$(PREFIX)/share/cryptopp"' -c $<
%.o : %.cpp
$(CXX) $(CXXFLAGS) -c $<
Here's what I see when running make:
$ rm bench*.o
$ make static dynamic cryptest.exe PREFIX=/usr/local
make: Nothing to be done for `static'.
make: Nothing to be done for `dynamic'.
g++ -DNDEBUG -g -O2 -fPIC -march=native -pipe -c bench.cpp
g++ -DNDEBUG -g -O2 -fPIC -march=native -pipe -DCRYPTOPP_DATA_DIR='"/usr/local/share/cryptopp"' -c bench2.cpp
Above, both bench.cpp and bench2.cpp should have -DCRYPTOPP_DATA_DIR='"/usr/local/share/cryptopp"'. I also tried using the asterisk (*) with no joy.
How do I craft a rule that matches both bench.cpp and bench2.cpp?
According to the link you provided
A pattern rule contains the character ‘%’ (exactly one of them) in the
target; otherwise, it looks exactly like an ordinary rule. The target
is a pattern for matching file names; the ‘%’ matches any nonempty
substring, while other characters match only themselves.
So % doesn't match empty strings.
‘%’ character matching any sequence of zero or more characters...
refers to the definition of vpath which is totally different.
I'm afraid you'll have to use bench1 instead of bench. Alternatively you can use macro to defines 2 rules but write it only once.
Well, I happened to stumble across the proper section of the documentation on this.
According to 4.4 Using Wildcard Characters in File Names, I should probably use an asterisk in this case.
And according to Stallman and the GNUMake manual, % is not a wildcard for specifying file names:
A single file name can specify many files using wildcard characters.
The wildcard characters in make are ‘*’, ‘?’ and ‘[…]’ ...

Resources