Search code examples
makefileln

Symbolic link in 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.


Solution

  • 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.