Symbolic link in makefile - makefile

Consider the following makefile:
SHELL = /bin/sh
MY_DIR := $(realpath ./)
BASE_DIR := $(realpath ../..)
BASE_SRC_DIR = $(BASE_DIR)/src
BASE_INC_DIR = $(BASE_DIR)/include
HUL_DIR = $(MY_DIR)/hul
JNI_DIR = $(HUL_DIR)/jni
JNI_SRC_DIR = $(JNI_DIR)/src
JNI_INC_DIR = $(JNI_DIR)/include
dirs: $(JNI_SRC_DIR) $(JNI_INC_DIR)
$(JNI_SRC_DIR): $(JNI_DIR)
ln -s $(BASE_SRC_DIR) $#
$(JNI_INC_DIR): $(JNI_DIR)
ln -s $(BASE_INC_DIR) $#
$(JNI_DIR):
mkdir -p $(JNI_DIR)
This makefile creates two symbolic links (JNI_SRC_DIR and JNI_INC_DIR) and sets a JNI_DIR as a dependency for those. All is fine except one thing: calling make dirs twice creates the links and then links inside those folders. I know this is the standard ln behaviour when symlinking folders that already exist, I just don't know of any ln option flag to prevent it without an error (-n does it but with an error). Anyway, what I'd like to change is make running the rules for the second time. Apparently it also follows the symlinks, but I just want it to check whether they are there:
Here's a sample output, with three calls:
$ make dirs
mkdir -p /Users/fratelli/Documents/hul/platform/android/hul/jni
ln -s /Users/fratelli/Documents/hul/src /Users/fratelli/Documents/hul/platform/android/hul/jni/src
ln -s /Users/fratelli/Documents/hul/include /Users/fratelli/Documents/hul/platform/android/hul/jni/include
$ make dirs
ln -s /Users/fratelli/Documents/hul/src /Users/fratelli/Documents/hul/platform/android/hul/jni/src
ln -s /Users/fratelli/Documents/hul/include /Users/fratelli/Documents/hul/platform/android/hul/jni/include
$ make dirs
make: Nothing to be done for `dirs'.
I'd like the second time to behave as the third, as the symlinks are already there.

What's happening is that when the symlinks are created by the first make dirs invocation, the modification time of the directory gets updated. Because you have a dependency on the directory, that means the next time you run make dirs, make decides the targets are out of date.
You can change the dependency on $(JNI_DIR) to be an order-only prerequisite instead, like this:
$(JNI_SRC_DIR): | $(JNI_DIR)
ln -s $(BASE_SRC_DIR) $#
$(JNI_INC_DIR): | $(JNI_DIR)
ln -s $(BASE_INC_DIR) $#
This tells make to create $(JNI_DIR) if it doesn't exist, but it won't recreate the links if the directory has been updated.

Related

bash shell generates a link that was not specified

I wrote a simple bash script (in /homedir) to run an executable and then move the outputs to /workdir. I also made a soft link of /workdir named work to /homedir for me to switch easily between folders.
All steps are working well, except that an unspecified soft link named 'grids' is created in /workdir to itself. I can't delete it otherwise all outputs are gone as well.
How can this happen?
#!/bin/bash
cd ..
expname=`basename "$PWD"`
echo 'experiment name: '$expname
homedir=/home/b/b380963/icon_foehn/$expname/grids/
workdir=/work/bb1096/b380963/icon_foehn/$expname/grids/
if [ ! -d ${workdir} ]; then
mkdir -p ${workdir}
fi
cd $homedir
ln -s ${workdir} work
cd /home/b/b380963/nwp/dwd_icon_tools_v2/icontools/
./icongridgen --nml $homedir/gridgen_MCH_july.nml
mv ICON_1E_* $workdir/
mv base_grid* $workdir/
It's quite easy to see in your code:
workdir=/work/bb1096/b380963/icon_foehn/$expname/grids/
...
ln -s ${workdir} work
The command ln -s is the command, creating the symlink.
If you don't like the creation of that symlink, you might put that line in comment (don't delete it: in case you're not satisfied, it's easier to uncomment it).
You can solve your issue, using this command:
ln -sTf ...
This removes the existing destination files beforehand.

Makefile - Execute a rule for every field in a variable

I have my project binary located at my repository's root, along with a Makefile used to build it.
This binary uses many of my self-made libraries, located in my lib/ folder
For the purpose of building (and cleaning) my repository's binary, I want to implement the following execution :
Instead of hardcoding the following lines,
clean_binaries:
make -C clean lib/folder1 -s
make -C clean lib/folder2 -s
make -C clean lib/another_folder -s
I created the BIN_PATH variable, containing the previous paths.
BIN_PATHS = lib/folder1 \
lib/folder2 \
lib/another_folder
And made a simple rule like this one :
clean_binaries: $(BIN_PATHS)
make -C clean $< -s
BUT it only executes the line for the first field of the variable (lib/folder1), which is not what I want to do.
I thought about using implicit rules(?), just like I compile the .c files, but I couldn't get it right.
In the end, I simply wonder how to execute a rule for every field of a given variable, and this inside a Makefile, if there is any way to do so.
Thank you for your answers :]
The way you get GNU make to generate a sequence of commands that vary by the
fields in a variable is to use the foreach function, e.g.
Makefile
BIN_PATHS := lib/folder1 lib/folder2 lib/another_folder
.PHONY: clean_binaries
clean_binaries:
$(foreach path,$(BIN_PATHS),make -C $(path) clean ;)
which runs like:
$ make
make -C lib/folder1 clean -s; make -C lib/folder2 clean -s; make -C lib/another_folder clean -s;
not requiring a shell-loop.
Note also that you need to correct:
make -C clean <directory>
to:
make -C <directory> clean

Incrementing Makefile Variable When Executing Rule

My dilemma is the following: I need to create a symbolic link to a different serial port for each of the items in the Makefile variable 'LINKS'. I have the following code.
LINK_PATH = ~/some/path/
LINKS = $(LINK_PATH)/SomeLinkName $(LINK_PATH)/AnotherLinkName $(LINK_PATH)/TheseLinkNamesUnchangeable
COUNT = 0
install: $(LINKS)
#Do other stuff
$(LINKS): $(LINK_PATH)
ln -s /dev/ttyS$(COUNT) $#
$(LINK_PATH):
mkdir -p $#
I know that, as it is now, it will just create a bunch of links pointing to /dev/ttyS0. But I need them to be different, preferably sequential. Any ideas? Thanks.
if all of the serial ports are defined ahead of time, you can enumerate them and store that list in another variable then use that variable as a target dependency:
LINKS=/path/to/bar /path/to/baz /path/to/woz
COUNTS=$(shell v=`echo $(LINKS) | wc -w`; echo `seq 0 $$(expr $$v - 1)`)
install: $(COUNTS)
$(COUNTS):
#echo ln -s /dev/ttyS$# $(shell v=($(LINKS)); echo $${v[$#]})
then, when run:
[user#host: ~]$ make install
ln -s /dev/ttyS0 /path/to/bar
ln -s /dev/ttyS1 /path/to/baz
ln -s /dev/ttyS2 /path/to/woz

ln command creates broken links

I'm having trouble using the ln command in a makefile.
This is a part of my makefile for creating a dynamic library:
NAME := Net
DDIR := dynamic_library
DLIB := $(DDIR)/lib$(NAME).so
MAJOR := 1
MINOR := 0
VERSION := $(MAJOR).$(MINOR)
$(DLIB).$(VERSION): $(OBJD)
g++ -shared -Wl,-soname,$(DLIB).$(MAJOR) $^ -o $#
$(DLIB): $(DLIB).$(VERSION)
ln -sf $(DLIB).$(VERSION) $(DLIB)
ln -sf $(DLIB).$(VERSION) $(DLIB).$(MAJOR)
OBJD are my .o files.
I'm trying to create the links next to libNet.so.1.0 which is in dynamic_library/ .
The ln commands create broken links with incomplete target addresses but in the correct destination.
I've tried adding ./ and / before the sources but they don't work.
Any help would be appreciated
EDIT
found the answer through trial and error
apparently we're supposed to add ../ before the sources. I have no idea why though.
if anybody has a better way, please answer.
Some of the variations of ln command are:
ln -s abs_path_to_link_target rel_path_from_current_dir_to_link_source
ln -s rel_path_from_link_src_to_target rel_path_from_current_dir_to_link_source
But the following, which you were trying to use, is not one of them:
ln -s rel_path_from_current_dir_to_link_target ...
Your makefile has another subtle error, namely, the link source, does not depend on the changes to the link target, it only depends on the existence of the link target.
And another problem, is that you have a "side effect", when you are making $(DLIB) target. I am guessing you are a software eng, so you know that side effects are bad for parallelism, cause race conditions, and make code hard to read.
Also, one should always use automatic variables such as $#, and depend everything on the Makefile.
Finally, I am hoping that you know why you are using -f. Some of the responses above, including mine :), do not use it. It is very important in the Makefile context, don't drop it.
Bearing these points in mind, the cleanest and correct way to do this would be:
$(DLIB) $(DLIB).$(MAJOR): Makefile | $(DLIB).$(VERSION)
ln -sf $(abspath $|) $#
g++ -shared -Wl,-soname,$(DLIB).$(MAJOR) $^ -o $#
Isn't it supposed to be -Wl,-soname,$(DLIB).$(VERSION)?
ln -s creates a link at the destination location with a link target of your source path (not the full path the path you give the ln command). If your link destination is a directory below your source directory and you aren't using full paths to the source then you need the ../ so that the link target is ../source.file instead of source.file as that would make the link point to a file in the same directory.
Compare:
$ ln -s bar foo
$ readlink foo
bar
$ readlink -f foo
/tmp/bar
$ ln -s ../bar foo
$ readlink foo
../bar
$ readlink -f foo
/foo
$ ln -s /tmp/bar foo
$ readlink foo
/tmp/bar
$ readlink -f foo
/tmp/bar

How to get current relative directory of your Makefile?

I have a several Makefiles in app specific directories like this:
/project1/apps/app_typeA/Makefile
/project1/apps/app_typeB/Makefile
/project1/apps/app_typeC/Makefile
Each Makefile includes a .inc file in this path one level up:
/project1/apps/app_rules.inc
Inside app_rules.inc I'm setting the destination of where I want the binaries to be placed when built. I want all binaries to be in their respective app_type path:
/project1/bin/app_typeA/
I tried using $(CURDIR), like this:
OUTPUT_PATH = /project1/bin/$(CURDIR)
but instead I got the binaries buried in the entire path name like this: (notice the redundancy)
/project1/bin/projects/users/bob/project1/apps/app_typeA
What can I do to get the "current directory" of execution so that I can know just the app_typeX in order to put the binaries in their respective types folder?
The shell function.
You can use shell function: current_dir = $(shell pwd).
Or shell in combination with notdir, if you need not absolute path:
current_dir = $(notdir $(shell pwd)).
Update.
Given solution only works when you are running make from the Makefile's current directory.
As #Flimm noted:
Note that this returns the current working directory, not the parent directory of the Makefile. For example, if you run cd /; make -f /home/username/project/Makefile, the current_dir variable will be /, not /home/username/project/.
Code below will work for Makefiles invoked from any directory:
mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
current_dir := $(notdir $(patsubst %/,%,$(dir $(mkfile_path))))
As taken from here;
ROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
Shows up as;
$ cd /home/user/
$ make -f test/Makefile
/home/user/test
$ cd test; make Makefile
/home/user/test
If you are using GNU make, $(CURDIR) is actually a built-in variable. It is the location where the Makefile resides the current working directory, which is probably where the Makefile is, but not always.
OUTPUT_PATH = /project1/bin/$(notdir $(CURDIR))
See Appendix A Quick Reference in http://www.gnu.org/software/make/manual/make.html
THIS_DIR := $(dir $(abspath $(firstword $(MAKEFILE_LIST))))
I like the chosen answer, but I think it would be more helpful to actually show it working than explain it.
/tmp/makefile_path_test.sh
#!/bin/bash -eu
# Create a testing dir
temp_dir=/tmp/makefile_path_test
proj_dir=$temp_dir/dir1/dir2/dir3
mkdir -p $proj_dir
# Create the Makefile in $proj_dir
# (Because of this, $proj_dir is what $(path) should evaluate to.)
cat > $proj_dir/Makefile <<'EOF'
path := $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST)))))
cwd := $(shell pwd)
all:
#echo "MAKEFILE_LIST: $(MAKEFILE_LIST)"
#echo " path: $(path)"
#echo " cwd: $(cwd)"
#echo ""
EOF
# See/debug each command
set -x
# Test using the Makefile in the current directory
cd $proj_dir
make
# Test passing a Makefile
cd $temp_dir
make -f $proj_dir/Makefile
# Cleanup
rm -rf $temp_dir
Output:
+ cd /tmp/makefile_path_test/dir1/dir2/dir3
+ make
MAKEFILE_LIST: Makefile
path: /private/tmp/makefile_path_test/dir1/dir2/dir3
cwd: /tmp/makefile_path_test/dir1/dir2/dir3
+ cd /tmp/makefile_path_test
+ make -f /tmp/makefile_path_test/dir1/dir2/dir3/Makefile
MAKEFILE_LIST: /tmp/makefile_path_test/dir1/dir2/dir3/Makefile
path: /tmp/makefile_path_test/dir1/dir2/dir3
cwd: /tmp/makefile_path_test
+ rm -rf /tmp/makefile_path_test
NOTE: The function $(patsubst %/,%,[path/goes/here/]) is used to strip the trailing slash.
I tried many of these answers, but on my AIX system with gnu make 3.80 I needed to do some things old school.
Turns out that lastword, abspath and realpath were not added until 3.81. :(
mkfile_path := $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
mkfile_dir:=$(shell cd $(shell dirname $(mkfile_path)); pwd)
current_dir:=$(notdir $(mkfile_dir))
As others have said, not the most elegant as it invokes a shell twice, and it still has the spaces issues.
But as I don't have any spaces in my paths, it works for me regardless of how I started make:
make -f ../wherever/makefile
make -C ../wherever
make -C ~/wherever
cd ../wherever; make
All give me wherever for current_dir and the absolute path to wherever for mkfile_dir.
The simple, correct, modern way:
For GNU make >= 3.81, which was introduced in 2006
ROOT_DIR := $(dir $(realpath $(lastword $(MAKEFILE_LIST))))
MAKEFILE_LIST changes as include files come in and out of scope. The last item is the current file.
lastword plucks the last item (Makefile name, relative to pwd)
realpath is built-in to make, and resolves to a canonical path from filesystem root
dir trims off the filename, leaving just the directory.
Here is one-liner to get absolute path to your Makefile file using shell syntax:
SHELL := /bin/bash
CWD := $(shell cd -P -- '$(shell dirname -- "$0")' && pwd -P)
And here is version without shell based on #0xff answer:
CWD := $(abspath $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST))))))
Test it by printing it, like:
cwd:
#echo $(CWD)
As far as I'm aware this is the only answer here that works correctly with spaces:
space:=
space+=
CURRENT_PATH := $(subst $(lastword $(notdir $(MAKEFILE_LIST))),,$(subst $(space),\$(space),$(shell realpath '$(strip $(MAKEFILE_LIST))')))
It essentially works by escaping space characters by substituting ' ' for '\ ' which allows Make to parse it correctly, and then it removes the filename of the makefile in MAKEFILE_LIST by doing another substitution so you're left with the directory that makefile is in. Not exactly the most compact thing in the world but it does work.
You'll end up with something like this where all the spaces are escaped:
$(info CURRENT_PATH = $(CURRENT_PATH))
CURRENT_PATH = /mnt/c/Users/foobar/gDrive/P\ roje\ cts/we\ b/sitecompiler/
Example for your reference, as below:
The folder structure might be as:
Where there are two Makefiles, each as below;
sample/Makefile
test/Makefile
Now, let us see the content of the Makefiles.
sample/Makefile
export ROOT_DIR=${PWD}
all:
echo ${ROOT_DIR}
$(MAKE) -C test
test/Makefile
all:
echo ${ROOT_DIR}
echo "make test ends here !"
Now, execute the sample/Makefile, as;
cd sample
make
OUTPUT:
echo /home/symphony/sample
/home/symphony/sample
make -C test
make[1]: Entering directory `/home/symphony/sample/test'
echo /home/symphony/sample
/home/symphony/sample
echo "make test ends here !"
make test ends here !
make[1]: Leaving directory `/home/symphony/sample/test'
Explanation, would be that the parent/home directory can be stored in the environment-flag, and can be exported, so that it can be used in all the sub-directory makefiles.
use {} instead of ()
cur_dir=${shell pwd}
parent_dir=${shell dirname ${shell pwd}}}
Solution found here : https://sourceforge.net/p/ipt-netflow/bugs-requests-patches/53/
The solution is : $(CURDIR)
You can use it like that :
CUR_DIR = $(CURDIR)
## Start :
start:
cd $(CUR_DIR)/path_to_folder
update 2018/03/05
finnaly I use this:
shellPath=`echo $PWD/``echo ${0%/*}`
# process absolute path
shellPath1=`echo $PWD/`
shellPath2=`echo ${0%/*}`
if [ ${shellPath2:0:1} == '/' ] ; then
shellPath=${shellPath2}
fi
It can be executed correct in relative path or absolute path.
Executed correct invoked by crontab.
Executed correct in other shell.
show example, a.sh print self path.
[root#izbp1a7wyzv7b5hitowq2yz /]# more /root/test/a.sh
shellPath=`echo $PWD/``echo ${0%/*}`
# process absolute path
shellPath1=`echo $PWD/`
shellPath2=`echo ${0%/*}`
if [ ${shellPath2:0:1} == '/' ] ; then
shellPath=${shellPath2}
fi
echo $shellPath
[root#izbp1a7wyzv7b5hitowq2yz /]# more /root/b.sh
shellPath=`echo $PWD/``echo ${0%/*}`
# process absolute path
shellPath1=`echo $PWD/`
shellPath2=`echo ${0%/*}`
if [ ${shellPath2:0:1} == '/' ] ; then
shellPath=${shellPath2}
fi
$shellPath/test/a.sh
[root#izbp1a7wyzv7b5hitowq2yz /]# ~/b.sh
/root/test
[root#izbp1a7wyzv7b5hitowq2yz /]# /root/b.sh
/root/test
[root#izbp1a7wyzv7b5hitowq2yz /]# cd ~
[root#izbp1a7wyzv7b5hitowq2yz ~]# ./b.sh
/root/./test
[root#izbp1a7wyzv7b5hitowq2yz ~]# test/a.sh
/root/test
[root#izbp1a7wyzv7b5hitowq2yz ~]# cd test
[root#izbp1a7wyzv7b5hitowq2yz test]# ./a.sh
/root/test/.
[root#izbp1a7wyzv7b5hitowq2yz test]# cd /
[root#izbp1a7wyzv7b5hitowq2yz /]# /root/test/a.sh
/root/test
[root#izbp1a7wyzv7b5hitowq2yz /]#
old:
I use this:
MAKEFILE_PATH := $(PWD)/$({0%/*})
It can show correct if executed in other shell and other directory.
One line in the Makefile should be enough:
DIR := $(notdir $(CURDIR))

Resources