I am new to makefile, I am trying to add a make debug mode.
I have the following:
CXXFLAGS=-Wall -c
debug: $(EXECUTABLE)
CXXFLAGS+=-pg
all:
....
for some reason it assigns it and when I put make debug it give me
CXXFLAGS+=-pg
/bin/sh: CXXFLAGS+=-pg: not found
make: *** [debug] Error 127
Is there any way to do and avoid writing the entire all command again in the debug except with -pg flags?
I tried to remove debug: target
and CXXFLAGS was concatenated with -pg flags successfully
If you are using gnumake, just add:
debug: CXXFLAGS += -pg
debug: $(EXECUTABLE)
Note that it is typical to define all first so that it is the default. If the rules for debug appear before all in the Makefile, debug becomes the default (if it is first).
All tab-indented lines below a target are piped directly to shell subprocesses, but your CXXFLAGS line is using Makefile syntax, not valid shell syntax.
Worse, even if you used shell syntax, setting the variable wouldn't carry over to lines executed under a different target; they would only affect shell commands under the same target, and then, only if all the lines are joined with \ escape characters.
Make will read the values from environment variables, so you could set the environment variable as you run make, e.g. (Bourne-family shells):
myprompt$ CXXFLAGS=" -pg $CXXFLAGS" make
Related
I have a makefile in a directory of mine which builds scripts with certain environment variables set. What if I want to create another makefile in the same directory with different environment variables set? How should I name the two make files? Does makefile.1 and makefile.2 work? How do I call them?
You can give sensible names to the files like makefile.win and makefile.nix and use them:
make -f makefile.win
make -f makefile.nix
or have a Makefile that contains:
win:
make -f makefile.win
nix:
make -f makefile.nix
and use make win or make nix
You can name makefile whatever you want. I usually name it like somename.mk. To use it later you need to tell make what makefile you want. Use -f option for this:
make -f somename.mk
Actually you can have two set of environment variables in the same make file. for example
COMPILER = gcc
CCFLAGS1 = -g
CCFLAGS2 = -Wall
a: main.c
${COMPILER} ${CCFLAGS1} main.c
b: test.c
${COMPILER} ${CCFLAGS2} test.c
then you can just say make a or make b. Depending on what you want.
Also it is possible with -f flag to call which makefile you want to call.
You can do something like this rather than using multiple makefiles for the same purpose. You can pass the environment or set a flag to the same makefile. For eg:
ifeq ($(ENV),ENV1)
ENV_VAR = THIS
else
ENV_VAR = THAT
endif
default : test
.PHONY : test
test:
#echo $(ENV_VAR)
Then you can simply run the make command with arguments
make ENV=ENV1
I have two makefiles in the same directory. Many of the recipes have identical names and here are two solutions:
1. Prefix in make
proja_hello:
#echo "hello A"
projb_hello:
#echo "hello N"
2. Keep two separate files
Project A has makefile. Type make hello.
Project B has a separate make file called projb.mk. Type bmake hello.
This works since I've added alias bmake ='make -f projb.mk to my .bashrc. Note! This command can be called anywhere but only works where projb.mk exists.
Note! You lose autocompletion of make with the alias and typing make -f projb.mk hello is not better than typing make projb_hello.
This is my first question on Stackoverflow so forgive me if I ask anything ridiculous :D.
Problem:
Suppose I want to compile a program that is in the directory "my dir/" with a space in it. Say the pathname of the program is "my dir/test.c".
Here is the sample makefile that I was trying out:
CC = gcc
DIR = my\ dir
$(DIR)/test.out: $(DIR)/test.c
# $(CC) $< -o $#
$(CC) $(DIR)/test.c -o $(DIR)/test.out
As you can see that in the last line(line-5) I have written the pathnames of the source and the output files directly as written in the prerequisite and the target, respectively. Doing this works fine because it yields the command:gcc my\ dir/test.c -o my\ dir/test.outwhich a syntactically correct way of passing filenames(with spaces) to gcc or any other shell command.
The second last line(line-4) is where the problem is(commented line). I've used automatic variables $# (Target) and $< (First and the only Prerequisite) to produce the filename arguments for gcc which I expected to bemy\ dir/test.out and my\ dir/test.c, respectively. But here, for some reason, the produced filenames are my dir/test.out and my dir/test.c and hence the yielded command is: gcc my dir/test.c -o my dir/test.out
Now here, gcc considers my and dir/test.c as different two different input filenames and the command generates errors.
Here is a screenshot of the generated error output when I uncomment line-4 and comment line-5 of the above Makefile:
My Question:
Is there any way to retain those backslashes even by using automatic variables the way I did? Or is there any alternative that will achieve the same goal as using automatic variables and also solve my problem? Because flexibility is important here.
Thanks in advance for your help!!!
Use double or single quotes for the automatic variables.
Use single quotes, if you want to avoid shell expansion of the values referenced by the automatic variables:
$(DIR)/test.out: $(DIR)/test.c
$(CC) '$<' -o '$#'
Double quotes allow shell expansion. For example, if there was a dollar sign in DIR:
DIR := $$my\ dir
then "$#" would expand to "$my dir", and the shell would interpret $my as variable.
What is the reason for having both a CCFLAGS and a SHCCFLAGS variable in the SCons environment?
I am trying to modify a large program build that I did not write myself. When I add the command:
env.Append(CCFLAGS=["-I%s" % amber_dir, "-DAMBER"])
the compiler runs without the flags I added. But when I do
env.Append(SHCCFLAGS=["-I%s" % amber_dir, "-DAMBER"])
the compiler adds my flags as wanted. Somewhere in SCons' innards, CCFLAGS are is not passed to SHCCFLAGS. But why have a CCFLAGS and a SHCCFLAGS to begin with?
This is taken from the SCons User's Guide: SCons Construction Variable
CCFLAGS
General options that are passed to the C and C++ compilers.
CPPFLAGS
User-specified C preprocessor options. These will be included in any
command that uses the C preprocessor, including not just compilation
of C and C++ source files via the $CCCOM, $SHCCCOM, $CXXCOM and
$SHCXXCOM command lines, but also the $FORTRANPPCOM, $SHFORTRANPPCOM,
$F77PPCOM and $SHF77PPCOM command lines used to compile a Fortran
source file, and the $ASPPCOM command line used to assemble an
assembly language source file, after first running each file through
the C preprocessor. Note that this variable does not contain -I (or
similar) include search path options that scons generates
automatically from $CPPPATH. See $_CPPINCFLAGS, below, for the
variable that expands to those options.
SHCCFLAGS
Options that are passed to the C and C++ compilers to generate
shared-library objects.
SHCCCOM
The command line used to compile a C source file to a shared-library
object file. Any options specified in the $SHCFLAGS, $SHCCFLAGS and
$CPPFLAGS construction variables are included on this command line.
The most interesting of the 4 mentioned above are the SHCCCOM and CPPFLAGS variables. Try your test again setting CPPFLAGS instead of CCFLAGS.
A general comment about the flags you are setting: with SCons, its generally better to set include paths with the CPPPATH variable, and to set defines with the CPPDEFINES. When using these variable, you dont need to include the -I, nor the -D flags, SCons will add it for you in a platform-independent manner. Here's an example:
env.Append(CPPPATH=amber_dir)
env.Append(CPPDEFINES='AMBER')
You'll need to test this to see if the SharedObject() and/or SharedLibrary() builders use those, I would imagine they would.
Answers to questions in comment below:
SHCCCOM is just used to see what the command line looks like, sometimes you may need to use it without using the SCons builders directly. SHCCFLAGS is a super-set of CPPFLAGS and others and should be used when you have flags that you only want to pass to SharedLibrary() or SharedObject(). CPPFLAGS applies to both static and shared compilations.
I use scons (V1.1.0) for a project that contains a build step that involves the flex tool.
The definition for the flex command in the scons default rules is:
env["LEX"] = env.Detect("flex") or "lex"
env["LEXFLAGS"] = SCons.Util.CLVar("")
env["LEXCOM"] = "$LEX $LEXFLAGS -t $SOURCES > $TARGET"
which I don't want to change.
However, since -t causes #line directives to be created in the output file that refer to the file "<stdout>", this confuses the subsequent gcov processing.
As a solution, I found that -o can be used to override the file name flex produces into the #line directives (it still produces its output on stdout due to the -t option which apparently has precedence).
To achieve that, I added this in the project's SConscript file:
env.AppendUnique(LEXFLAGS = ['-o $TARGET','-c'],delete_existing=1)
I added the -c option (which does nothing) only to show the difference between how it is treated compared to -o.
An according debug print in the SConscript file results in the following (as expected):
repr(env["LEXFLAGS"]) = ['-o $TARGET', '-c']
This results in the following command line, according to the scons log:
flex "-o build/myfile.cpp" -c -t src/myfile.ll > build/myfile.cpp
So the -c option gets into the command line as desired, but the -o option and its filename parameter has double quotes around it, that must have been created by scons when expanding the LEXFLAGS variable.
When I use this definition for LEXFLAGS instead:
env.AppendUnique(LEXFLAGS = ['--outfile=$TARGET','-c'],delete_existing=1)
the resulting command line works as desired:
flex --outfile=build/myfile.cpp -c -t src/myfile.ll > build/myfile.cpp
So one could speculate that the blank in the -o case caused the double quotes to be used, maybe in an attempt to bind the content together into one logical parameter for the command.
So while my immediate problem is solved by using --outfile, my question is still is it possible to rid of the double quotes in the -o case?
Thanks,
Andy
SCons 1.1.0 is extremely old at this point. I'd recommend trying 2.3.0. But your analysis is correct; if an option (a single option, that is) has a space in it, SCons will quote it so it stays a single option. But you don't have a single option; you really have two, '-o' and '$TARGET'. Just break it up like that and it'll work.
I have a environment variable set with name $MY_ENV_VARIABLE.
How do I use this variable inside my makefile to (for example) include some source files?
LOCAL_SRC_FILES = $(MY_ENV_VARIABLE)/libDEMO.so
Something like above doesn't seem to work.
Note: in my case this is needed for building with the Android NDK but I guess this applies to make in general.
Just to add some information...
The syntax to access the environment variable in make is like other variables in make...
#export the variable. e.g. in the terminal,
export MY_ENV_VARIABLE="hello world"
...
#in the makefile (replace before call)
echo $(MY_ENV_VARIABLE)
This performs the substitution before executing the commmand. If you instead, want the substitution to happen during the command execution, you need to escape the $ (For example, echo $MY_ENV_VARIABLE is incorrect and will attempt to substitute the variable M in make, and append it to Y_ENV_VARIABLE)...
#in the makefile (replace during call)
echo $$MY_ENV_VARIABLE
Make sure you exported the variable from your shell. Running:
echo $MY_ENV_VARIABLE
shows you whether it's set in your shell. But to know whether you've exported it so that subshells and other sub-commands (like make) can see it try running:
env | grep MY_ENV_VARIABLE
If it's not there, be sure to run export MY_ENV_VARIABLE before running make.
That's all you need to do: make automatically imports all environment variables as make variables when it starts up.
I just had a similar issue (under Cygwin):
Running echo $OSTYPE on the shell prints the value, but
running env | grep OSTYPE doesn't give any output.
As I can't guarantee that this variable is exported on all machines I want to run that makefile on, I used the following to get the variable from within the makefile:
OSTYPE = $(shell echo $$OSTYPE)
Which of course can also be used within a condition like the following:
ifeq ($(shell echo $$OSTYPE),cygwin)
# ...do something...
else
# ...do something else...
endif
EDIT:
Some things I found after experimenting with the info from jozxyqk's answer, all from within the makefile:
If I run #echo $$OSTYPE or #echo "$$OSTYPE" in a recipe, the variable is successfully expanded into cygwin.
However, using that in a condition like ifeq ($$OSTYPE,cygwin) or ifeq ("$$OSTYPE","cygwin") doesn't expand it.
Thus it is logical that first setting a variable like TEST = "$$OSTYPE" will lead to echo $(TEST) printing cygwin (the expansion is done by the echo call) but that doesn't work in a condition - ifeq ($(TEST),cygwin) is false.