Error in makefile *** missing separator. Stop - linux

The code snippet is as follows:
$(shell javac $(MY_PATH)/test/TestFile.java)
$(shell java -cp $(MY_PATH)/test/ TestFile)
There is no space or tab in the start. The error i am getting is
* missing separator. Stop.
The error is coming in second line only and not in the first line.
Basically my TestFile is not in java path.
I have tried all the solutions here but none helped me out. I guess the error has something to do with the directory path I provided. The same code snippet works with cmd prompt in windows but not in linux machine. Can't figure the exact problem. Kindly help. Thanks.

This is how makefiles supposed to be used:
.PHONY: run
JAVAC:=javac
JAVA:=java
TARGET:=TestFile
SOURCES:=TestFile.java
OBJS:=$(patsubst %.java, %.class, $(SOURCES))
$(TARGET): $(OBJS)
%.class: %.java
$(JAVAC) $^
run: $(TARGET)
$(JAVA) $(TARGET)
make run will compile and run. make will only compile. Of course it all could be set to one target, but better don't do that.

Related

why "cmd_$#" is the previous command when build linux kernel

within linux kernel source repo, there is Makefile.build under /scripts, which is called many times when building src. there is some target : prerequisite like this:
$(obj)/%.i: $(src)/%.c FORCE
$(call if_changed_dep,cpp_i_c)
and if_changed_dep is
if_changed_dep = $(if $(newer-prereqs)$(cmd-check),$(cmd_and_fixdep),#:)
newer-prereqs is quite straightforward but cmd-check is a bit obsecure.
cmd-check = $(filter-out $(subst $(space),$(space_escape),$(strip $(cmd_$#))), \
$(subst $(space),$(space_escape),$(strip $(cmd_$1))))
I know that $(cmd_$1) will be expanded to cmd_cpp_i_c, which is the current compiling command
and $(cmd_$#) will be expanded to $(cmd_$(obj)/%.i). for instance if it compiles i2c-core-base.c, it will be $(cmd_i2c-core-base.i) (I omit $(obj))
https://flylib.com/books/en/2.860.1.84/1/ says it is the previous command when compiling.
my question is where I am able to find the evidence since I could not find where cmd_$# is defined.
Thanks a lot for any comments.
After executing the command, the macro cmd_and_savecmd, records the command line into the file ..cmd.
In /scripts/Kbuild.include
cmd_and_savecmd = \
$(cmd); \
printf '%s\n' 'cmd_$# := $(make-cmd)' > $(dot-target).cmd
As make is invoked again during a rebuild, it will include those .*.cmd files.
In /Makefile
-include $(foreach f,$(existing-targets),$(dir $(f)).$(notdir $(f)).cmd)
So, cmd_$# is used to keep tracks of what command has already been done last time when building a file.

Standard error file when there is no error

I'm new to Linux & shell and I'm struggling with checking if the compilation is successful.
g++ code.cpp -o code.o 2>error.txt
if [ ! -e error.txt ]
then
do something
else
echo "Failed to compile"
I guess an error file is created even if the compilation is successful. What is the content of the error file when there is no error? I need to change the if condition to check if the compilation is successful.
It's just the order of things. What happens when the shell parses the string g++ code.cpp -o code.o 2>error.txt is:
The shell creates error.txt, truncating the file if that name already exists.
g++ is called with its error output redirected to the new file.
If g++ does not write any data, then the file remains as it was (empty) at the end of step 1.
You probably aren't so much interested in the error file as you are the return value. You probably ought to just do:
if g++ code.cpp -o code; then : do something; done
or even just:
g++ code .cpp -o code && : do something
but if really want to do something else with the errors, you can do:
if g++ code.cpp -o code.o 2> error.txt; then
rm error.txt
: do something
else
echo >&2 Failed to compile code.cpp.\ See "$(pwd)"/error.txt for details.
fi
Make sure you escape at least one of the spaces after the . so that you get 2 spaces after the period (or just quote the whole argument to echo). Although it's become fashionable lately to claim that you only need one space, all of those arguments rely on the use of variable width fonts and any command line tool worth using will be used most often in an environment where fixed width fonts are still dominant. This last point is totally unrelated to your question, but is worth remembering.

How to let MAKEFILE retain the backslash sequences within a string when used in a make rule?

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.

Makefile, Run environment check target before user run any targets

I want to run following environment check target checkenv before any of other targets,
all: build_sub_target1 build_target2
clean: clean_sub_target1 clean_target2
...
...
checkenv:
$(if $(PROJECT_ROOT), , \
$(error $(shell echo -e '\033[41;33mFATAL: Please load project settings first. \
Run "source PROJECT_ROOT_DIR/envsetup.sh"\033[0m')) \
)
I want every other target run checkenv target before they actually do their task, how can I do this? Any other way except that I add checkenv to the depends list of each targets?
Since I have many targets in this file, and I think it's not cool to add into each targets... Should there be any potential rules to do this?
Thanks a lot for your help!
You could use make conditionals for that, so that this condition is checked while the makefile is being read and before targets get evaluated:
ifndef PROJECT_ROOT
$(error "Please load project settings first. Run source PROJECT_ROOT_DIR/envsetup.sh")
endif

Make ignores the rule when run for the first time

SO
I can't find out why these lines are not called for the first time I run 'make' but are called the next time:
sb_path = sb
sb_src := $(sb_path)/src
sb_build := $(sb_path)/build
ifndef DO_NOT_GENERATE_COMMIT_INFO
commit_sb: | $(sb_bin)
#$(sb_build)/generate-commit-info $(sb_path)
$(sb_src)/last_git_commit_info.h: | commit_sb ;
endif
I'm just curious because there is no file generate-commit-info file and make crashes when I call it for the second time, but it compiles my program ok for the first try.
I use script on my local machine to copy sources over ssh to another machine and to run compile.sh script there:
...
scp -r $sbfolder/build $sbfolder/Makefile "$buildserver:$root/$curdate"
check_retcode
scp -r $sbfolder/sb/Makefile "$buildserver:$root/$curdate/sb/"
...
ssh $buildserver "$root/compile.sh $curdate $debug"
compile.sh:
# fix Makefile: we don't have git installed here
#DO_NOT_GENERATE_COMMIT_INFO=true
#now we can compile sb
curdir="/home/tmp/kamyshev/sb_new/$1"
cd $curdir
check_retcode
t_path=$curdir
debug=$2
config=RELEASE
if [[ debug -eq 1 ]]; then
config=DEBUG
fi
echo "building sb... CONFIG=$config"
make -j2 CONFIG=$config
check_retcode
As you see DO_NOT_GENERATE_COMMIT_INFO=true is commented out. So I just don't see a reason why the code is not run when I call a make or the script for the first time (either from the remote script or myselft from command line).
Do you have any clues?
UPDATE on Etan Reisner comment:
commit_sb target is checked, it does not exist, so it's rule is being run and it updates last_git_commit_info.h. Thus it forces to update the .h file. It also gives me a .PHONY target commit_sb so I could do it directly by calling make commit_sb.
The generate-commit-info also creates a file in a $(sb_bin) folder.
My another guess is that you are talking about a better way to organize this code.
I can update last_git_commit_info.h directly with a such rule:
commit_sb $(sb_src)/last_git_commit_info.h: FORCE | $(sb_bin)
#$(sb_build)/generate-commit-info $(sb_path)
FORCE:
Thanks to the commenters on my question I've done some additional research: I've tried to make a minimal complete example. And this led me to the answer.
My code generates dependency files (look at -MMD command in SB_CXXFLAGS):
# just example - in real Makefile these are calculated on the fly
sb_deps := file1.d file2.d [...]
# rules with dependances of .o files against .h files
-include $(sb_deps)
SB_CXXFLAGS = $(CXXFLAGS) [...] -MMD
# compile and generate dependency info;
$(sb_obj)/%.o:$(sb_src)/%.cpp
$(CXX) $(SB_CXXFLAGS) $< -o $#
And when I run make for the first time there no *.d files, so no *.cpp depends on last_git_commit_info.h file and the rule is not applied.
On the subsequent runs the dependency rule appears in one of *.d files, the rule is executed and I get the error.
UPDATE: This does not concern the question directly, but this is the better way to write these rules:
ifndef DO_NOT_GENERATE_COMMIT_INFO
commit_sb $(sb_src)/last_git_commit_info.h: FORCE | $(sb_bin)
#$(sb_build)/generate-commit-info $(sb_path)
FORCE:
endif

Resources