views:

240

answers:

3

An example to illustrate my question:

Top level makefile

rootdir = $(realpath .)
export includedir = $(rootdir)/include
default:
    @$(MAKE) --directory=$(rootdir)/src/libs/libfoo

Makefile for src/libfoo

currentdir = $(realpath .)
includedir = $(function or magic to make a relative path
               from $(currentdir) to $(includedir),
               which in this example would be ../../../include)

Another example:

current dir = /home/username/projects/app/trunk/src/libs/libfoo/ 
destination = /home/username/projects/app/build/libfoo/ 
relative    = ../../../../build/libfoo

How can this be done, while trying to be as portable as possible?

+2  A: 

Doing what you want does not look easy. It may be possible using a lot of combined $(if in the makefile but not portable (gmake only) and cumbersome.

IMHO, you are trying to solve a problem that you create yourself. Why don't you send the correct value of includedir as a relative path from the Top-level Makefile? It can be done very easily as follows:

rootdir = $(realpath .)
default:
    @$(MAKE) --directory=$(rootdir)/src/libs/libfoo includedir=../../../include

Then you can use $(includedir) in the sub-makefiles. It is already defined as relative.

Didier Trosset
This meta-answer is the best one -- avoid the problem! Note also that `--directory` isn't portable: `cd $(rootdir)/src/libs/libfoo; $(MAKE) ...` would be more reliable.
Norman Gray
@Norman Gray: what's wrong with `$(MAKE) -C ...`?
Beta
I don't think I'd go as far as _wrong_, but not all `make` commands support it (and it's not in [posix](http://www.opengroup.org/onlinepubs/009695399/utilities/make.html), for example), so if this makefile is for distribution, then it might create problems. In any case, I tend to think that `cd foo; $(MAKE)...` expresses the intention more clearly.
Norman Gray
+1  A: 

Python is portable! So, I would suggest you this simple example in your submakefile

With current_dir and destination_dir paths os.path.relpath() does the job for you so you do not have to re-invent the wheel.

submakefile.mk

current_dir=$(CURDIR)
makefile_target:
    (echo "import os"; echo "print os.path.relpath('$(current_dir)', '$(destination_dir)')" )| python
djondal
+1  A: 

Didier's answer is the best one, but the following might give you some ideas:

includedir=/a/b/c/d
currentdir=/a/b/e/f/g
up=; while ! expr $includedir : $currentdir >/dev/null; do up=../$up; currentdir=`dirname $currentdir`; done; relative=$up`expr $includedir : $currentdir'/*\(.*\)'`
echo "up=$up  currentdir=$currentdir, relative=$relative"

Sorted!

(no-one said it had to be pretty...)

Norman Gray