I created a makefile to build some code and when adding --trace option to debug/make sure everything is good, I noticed that there is a print saying some target is not found, even if it is there and it executes it. So I created a more simple example to point this and ask around why this is happening.
My makefile:
APP_NAME = apl
ODIR = obj
all: $(APP_NAME)
$(ODIR):
#mkdir -p $(ODIR)
$(APP_NAME): $(ODIR)
If I execute it with make all it creates the obj folder.
If I add the --trace option at the end it says that the obj target does not exist and it creates the folder:
$ make all --trace
makefile:7: target 'obj' does not exist
mkdir -p obj
$ ll
drwxrwxr-x. 2 user user 4096 Aug 17 10:44 obj
I have a linux machine with fedora installed. Can anyone help me understand why that message?
The trace message...
makefile:7: target 'obj' does not exist
is simply informational. It's telling you why the mkdir -p obj was executed. If you specify some dependency for $(OBJ) and arrange for that dependency to be newer than $(OBJ) then the message would be something like...
makefile:7: update target 'obj' due to: <dependency name>
Related
I am trying to run build with some new changes in makefile where new folder needs to be created and place some files in that folder.
Here is my target placed in my make file:
tools_mvv32: $(RELEASE_FILES) ## Which has files pointing to TGTTEST32
define file_copy
mkdir -p $(#D)
cp -f $< $#
endef
TGTTEST32 := /home_test/workspace/copy/limited_projects/src/main/scp/build/Linux/project/primary/ktl
$(TGTTEST32)/tools/bin/%: $(TGTTEST32)/bin/%
$(file_copy)
When i try to run build by placing the target i.e. with specific file name with hardcoded as follows, It works fine
/home_test/workspace/copy/limited_projects/src/main/scp/build/Linux/project/primary/ktl/tools/bin/mpf: /home_test/workspace/copy/limited_projects/src/main/scp/build/Linux/project/primary/ktl/bin/mpf
$(file_copy)
May i know if any syntax is incorrect in my generic target ?
I am hitting below issue with my generic target:
gmake: *** No rule to make target /home_test/workspace/copy/limited_projects/src/main/scp/build/Linux/project/primary/ktl/tools/mpf
I have searched for hours for an answer to this. I am new to gcc and Makefiles.
I have a Makefile in some source code that looks like this:
CC=gcc
SRCDIR=src
BINDIR=../bin
CFLAGS= -flag
LIBS= -lthing
...
$(BINDIR)/program_name: $(SRCDIR)/program_name.c
$(CC) $(CFLAGS) $(SRCDIR)/program_name.c -o $(BINDIR)/program_name $(LIBS)
I understand what all of this means except what ../ in BINDIR is meant to do. When I make the Makefile, I get the error message:
/usr/bin/ld: cannot open output file ../bin/program_name: No such file or directory
collect2: error: ld returned 1 exit status
Makefile:20: recipe for target '../bin/program_name' failed
make: *** [../bin/program_name] Error 1
My guess is that the original author of this Makefile meant that the bin folder should go in the parent directory of where the Makefile is located. I know when using the Linux CLI command cd that the dot dot means go up a directory. Is that what this is trying to achieve?
To automatically create the $(BINDIR) directory before it is actually needed you must declare it as a prerequisite (dependence) of any target that uses it. But each time its content changes its timestamp also changes. So, declaring it as a regular prerequisite is not the best thing to do because the targets depending on it would be re-built without real reason, just because the content of $(BINDIR) changed.
This is why make also supports order-only prerequisites (OOPs):
$(BINDIR)/program_name: $(SRCDIR)/program_name.c | $(BINDIR)
$(CC) $(CFLAGS) $< -o $# $(LIBS)
$(BINDIR):
mkdir -p $#
Note the | that introduces the list of OOPs. An OOP is built if it does not exist, which causes the targets depending on it to be (re-)built too. But if it exists make does not even consider its last modification time. Even if some target depending on it is older, it is not rebuilt just because of that.
Note: I also used the $< and $# automatic variables. In the rule's recipe they expand as the first prerequisite ($(SRCDIR)/program_name.c) and the target ($(BINDIR)/program_name), respectively. They are highly recommended: less typing, less errors prone, more generic rules... they have many good properties.
Your makefile is missing a rule to create the BINDIR directory - if it doesn't exist, your link line won't be able to put the resulting binary there! A rule like this one should do it:
$(BINDIR):
mkdir -p $(BINDIR)
Just make sure that any other rules (like the one in your question) also depend on this directory!
I'd like a set of makefile rules that create a symlink to one of several code modules before building the project. The name of the make target would determine the file to which the symlink points. For example:
The user invokes 'make R3000'
Make sees that 'data.asm' doesn't exist yet, so a symlink is created from 'data_R3000.asm' to 'data.asm'
The build process continues, using data.asm
How can I set up make rules to do this?
Maybe something like:
MODULES := $(patsubst data_%.asm,%,$(wildcard data_*.asm))
all:
...
data.asm:
[ -n "$(filter $(MAKECMDGOALS),$(MODULES))" ] || { echo unknown module: $(MAKECMDGOALS) ; exit 1; }
ln -s $(filter $(MAKECMDGOALS),$(MODULES)) $#
Then make sure data.asm is listed as a prerequisite in the appropriate rules.
I would do something like this:
.PHONY mklink
mklink:
test -e data_$(MAKECMDGOALS).asm || exit 1
ln -s data_$(MAKECMDGOALS).asm data.asm
and then make all (and other targets) dependent on mklink. The reason you shouldn't make data.asm your target in the rule is that if you run make R3000, then data.asm will be created, and then if you run make L2000, the data.asm file will be pointing to the wrong directory, and will not be overwritten (I'll assuming this is not what you want). The test line checks if the link target exists, and if not, it exits with 1, causing the target to fail. You should also add a check that MAKECMDGOALS is exactly one element as well.
When I tried my makefile, I got error saying that No such file or directory, but my directory is right there, what do I do wrong? Thanks.
my project structure :
dev |--- ev
|--- display
|--- install ( makefile is here, try to call makefiles in ev and display folder)
My makefile :
MODULES :=ev display
SRC_DIR :=$(addprefix ../, $(MODULES))
BUILD_DIR:=$(addsuffix /build, $(SRC_DIR))
x:=../ev ------> add temporarily just for test,
------> the same error if x:=$(HOME)/dev/ev
INSTALL_DIR:=EX Frameworks Add-ons
INSTALL_DIR:=$(addprefix $(HOME)/EX/, $(INSTALL_DIR))
vpath %.cpp %.java $(SRC_DIR)
.PHONY: all clean
checkdirs: $(INSTALL_DIR)
$(INSTALL_DIR):
#echo "INSTALL DIR"
#mkdir -p $#
define make-goal
$1:
#echo "start building each part"
cd $# && make -f Makefile_new.osx clean
cd $# && make -f Makefile_new.osx package
endef
clean:
#echo "clean up"
#echo "BUILD_DIR IS $(BUILD_DIR)"
#rm -rf $(BUILD_DIR)
all:
#echo "start build subdirectory"
#echo "SRC_DIR IS $(SRC_DIR)"
#echo "x is $(x)"
$(call make-goal, $(x))) ----> when it comes to here, I got error message
The error messages:
x is ../ev
../x:
make: ../ev:: No such file or directory.
I guess it is about relative path, because I call this makefile from Install folder, then $(x) can't be found from Install folder, but when I tried to make a folder named ev (Install/ev), I still got the same error.
I think it must be something basic I missed here, but what it is.
Thanks.
Update:
I am trying to build a project which includes several sub-projects. the structure is:
dev |---- ev
|---- edf
|----- dt
|------af
|------Install
Inside of Install, I have a makefile, which is at the top level. The makefile in Install folder will call makefiles in other folders to build different subjects,
Ideally, I want to build every sub projects without touching sources. My sources include c++ and java code.
It's not clear what you're trying to do. Also due to some indentation hiccups I can't be sure, but you appear to be defining a variable make-goal that contains a template for a make rule, then using it with $(call ...) inside the recipe for the all target. That cannot work: you cannot create a make rule inside the recipe for another make rule!
The reason this fails is that the $(call ...) is expanding to content which is added to the recipe of the all target, so instead of creating a new make rule it's treating the result as a shell script. The first line is $1:, and you passed in ../ev, so make is trying to run the command ../ev: just as the error shows you.
If you describe what you want to do at a higher level we can give you some ideas on how to do it.
ETA:
If you just want your all target to also build a subdirectory, there's no need for all this complex GNU make advanced capabilities. That stuff is only needed when you get to guru-level makefile creation. Simple "build a target after another target is finished" is the exact thing make was designed to do: nothing special is needed to do that.
For example:
.PHONY: all $(SRC_DIR)
all: $(SRC_DIR)
$(SRC_DIR):
#echo "start building $#"
cd $# && $(MAKE) -f Makefile_new.osx clean
cd $# && $(MAKE) -f Makefile_new.osx package
This is still a pretty non-standard setup but I think it will work the way you want. Remember you'll have to either move the all target up to be the first one in the makefile, or you'll have to run make all explicitly: make only builds the first target in the makefile unless you give it specific targets on the command line.
It is clear that the target is newer than the source from these two ls
comands:
[metaperl#andLinux ~/edan/pkg/gist.el] ls -l ../../wares/gist.el/gist.elc #target
-rw-r--r-- 1 metaperl metaperl 10465 Jul 18 10:56 ../../wares/gist.el/gist.elc
[metaperl#andLinux ~/edan/pkg/gist.el] ls -l yank/gist.el/gist.el #source
-rw-r--r-- 1 metaperl metaperl 13025 Jul 18 10:57 yank/gist.el/gist.el
[metaperl#andLinux ~/edan/pkg/gist.el]
However when I run makepp -v I am told that this rule depends not only
on the listed target, but also on the cd and mv commands.
makepplog: Targets
/home/metaperl/edan/wares/gist.el/gist.elc'
depend on/usr/local/bin/emacs',
/home/metaperl/edan/pkg/gist.el/yank/gist.el/gist.el',
/bin/mv'
What aspect of make logic dictates that the actions to produce the
target are part of the dependency chain of deciding on whether to make
the target?
To my mind, only the listed sources should affect whether or not the
target is rebuilt.
The entire makepp -v output is quite long, and exists at:
http://gist.github.com/480468
My makepp file:
include main.makepp
#VER
PKG := gist.el
URL := http://github.com/defunkt/$(PKG).git
TARGET := $(WARES)gist.el/gist.elc
$(TARGET) : yank/gist.el/gist.el
cd $(dir $(input)) && $(BYTECOMPILE) gist.el
mv $(dir $(input)) $(WARES)
perl {{
print 'github username: ';
my $username = <STDIN>;
print 'github API token: ';
my $api_token = <STDIN>;
system "git config --global github.user $username";
system "git config --global github.token $api_token";
use File::Butler;
my $lines = Butler('init.el', 'read');
my $loc = sprintf '%s%s', $EDAN_PKG, "$PKG/";
$lines =~ s/__LOC__/$loc/g;
$lines =~ s/__PKG__/$PKG/g;
Butler( $EDAN_EL, prepend => \$lines );
}}
yank/gist.el/gist.el : yank
cd yank && git clone http://github.com/defunkt/gist.el.git
yank:
mkdir yank
$(phony clean):
$(RM) -rf $(dir $(TARGET)) yank
With a standard make, the contents of the commands to make a target are not taken into account when deciding whether to rebuild the target. Only the dependencies are taken into account; this can go beyond the source if you have dependencies declared elsewhere.
You don't show your makeppfile, so I can't be sure, but the Parsing command... messages from makepp -v make me suspect that makepp behaves differently from standard make on this count.
makepp will rebuild a target if any of the dependencies have changed or if the command has changes. In your case, I suspect that either some of the variables that you use in the rule to make $(TARGET) have changed or that makepp is seeing that the commands are constructed dynamically and is automatically rebuilding the target. Try using the -m target_newer option to makepp to force it to use the old GNU make method (that is, only re-build if the source is newer than the target).
Link