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
Related
I'm using GNU Make to build a dynamic web site but I need to build two versions. As a net result currently I run my makefile using two command line incantations. This is inefficient and can result in errors (I don't always remember to run both versions or make a typing error and they fail) thus I want to make it one build.
The Command Line incantations are:
sudo make release build=test
sudo make release build=release
The two incantations activate ifeq blocks that set the path and modify some files.
Part of the much simplified (to help readability) top level makefile:
subs = today tomorrow
files = index.php foot.php
ifeq ($(build),test)
export path = /var/www/html/cgi-test
$(shell cp -f head-test.php head.php)
$(shell sed -i '/"DB"/c\ define("DB", "db_test");' subs.php)
else ifeq ($(build),release)
export path = /var/www/html/cgi-new
$(shell cp -f head-release.php head.php)
$(shell sed -i '/"DB"/c\ define("DB", "db_new");' subs.php)
endif
.PHONY: all go
all:
$(MAKE) go
#for ALL in $(subs);\
do $(MAKE) -C $$ALL all || exit $$?;\
done;
go:
cp $(files) $(path)/.
The sub-makefiles have a very similar structure but don't need the ifeq blocks because the files and paths have already been setup.
I think I can simply move the shell commands into the .PHONY rules but I can't do that with the exports because I get errors "export: : bad variable name".
I could do it with a batch file and call the makefile twice but that sidesteps the problem rather than cures it and I wish to learn from the process.
So can anybody show me the way to do this in a makefile?
Thanks to Tripleee here is the answer that finally worked back ported to match my starting post. The one major change is that I have gone back to 'all' as the rule I expect to start the build habits die hard! - Thanks
.PHONY: all both rel-test rel-release
cgi-test := cgi-test
db-test := db_test
cgi-release := cgi-new
db-release := db_new
subs = today tomorrow
files = index.php foot.php
all: both
both: rel-test rel-release
rel-test rel-release: rel-%:
cp -f head-$*.php head.php
sed -i '/"DB"/c\ define("DB", "$(db-$*)");' subs.php
$(MAKE) go path=/var/www/html/strutts/$(cgi-$*)
#for ALL in $(subs);\
do $(MAKE) build=$* path=/var/www/html/strutts/$(cgi-$*) -C $$ALL all || exit $$?;\
done;
Something like this?
.PHONY: both rel-test rel-release
both: rel-test rel-release
cgi-test := cgi-test
db-test := db_test
cgi-release := cgi-new
db-release := db_new
rel-%:
cp -f head-$*.php head.php
sed -i '/"DB"/c\ define("DB", "$(db-$*)")' subs.php
$(MAKE) release build=$* path=/var/www/html/$(cgi-$*)
The reason the export can't be moved into a recipe is that you are using the export command of make itself, not the shell's command with the same name.
You absolutely should not use sudo unless you specifically require the output files to be owned and only writable by root. Even then, running as much as possible as a regular user would be proper hygiene; maybe add a sudo command inside the Makefile to copy the files to their final location.
Can someone let me know what these two flags do in this makefile? I've googled 'till my fingures hurt, but cannot find any info. The GNU documentation doesn't seem have this info.
Thanks!
(-ln) and (-fs)
$(MAKE) -C wiringPi $#
$(MAKE) -C devLib $#
-ln -fs libwiringPiDev.so.2.0 devLib/libwiringPiDev.so
-ln -fs libwiringPi.so.2.0 wiringPi/libwiringPi.so
$(MAKE) -C gpio 'INCLUDE=-I../devLib -I../wiringPi' 'LDFLAGS=-L../devLib -L../wiringPi' $#
The ln -fs foo bar command creates a link named bar pointing to file foo. The -f option forces the creation: if a bar already exists it is overwritten (except if it is a directory). The -s option tells ln to create a symbolic link instead of the default hard link. See man ln to know more about this command.
The - on front of the command tells make that it should not abort if the command fails. If you are using GNU make see the make manual section about errors in recipes.
Thanks Eugene. Without the '-' I was able to find more info.
So I think the ln with the (-fs) is checking, then removing a existing file (if there is one) then making a symbolic link. cool.
I'm sure this was / is obvious to the experienced out there.
Thanks,
oc.
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.
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
I have a makefile that uses a source file from the internet. There are two locations where the file resides, neither of which I consider very dependable, so I also keep a local copy. So the relevant lines of my makefile look like:
src.c:
wget -nv http://location.com/$# || wget -nv http://otherplace.com/$# || cp local/$# .
src.o: src.c
$(CC) -o $# $<
Is this the "right way" to do this? What if there are multiple steps in each different way of creating the target - how do I tell make "Try A. If A fails, try B. If B fails, ..."?
The right thing to do is this:
.PHONY: phony
src.c: phony
if (wget -nv http://location.com/$# -O $#.temp) && ! diff $#.temp $# >/dev/null; then \
mv $#.temp $#; \
fi
I shortened your command to a single wget but you can put whatever you want there, including a sequence of ||s to achieve "try this, if not, try that etc". Just make sure it outputs to a temporary file (and does not hang indefinitely !) .
It is in fact important to use phony here, and not only .PHONY. Can you see why?
Also, with this method, there is no longer a need to keep another "local" copy and/or use cp. Your target src.c is your "local copy" - the latest one you were able to successfully get from the Internet.