在makefile中,如何获取从一个绝对路径到另一个绝对路径的相对路径?
一个例子来说明我的问题:
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)
另一个例子:
current dir = /home/username/projects/app/trunk/src/libs/libfoo/
destination = /home/username/projects/app/build/libfoo/
relative = ../../../../build/libfoo
如何做到这一点,同时尝试尽可能可移植?
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
您可以使用shell函数,并使用realpath(1)(它是coreutils的一部分)和--relative-标记。
下面是一个示例:
您甚至可以通过一次调用 realpath(1) 来处理整个文件列表,因为它知道如何处理许多文件名。
这是一个例子:
You can use the shell function, and use realpath(1) (which is part of coreutils) and the --relative-to flag.
Here is an example:
You can even process a whole list of files with one invocation of realpath(1) since it knows how to process many file names.
Here is an example:
做你想做的事情看起来并不容易。可能可以在 makefile 中使用大量组合
$(if
但不可移植(仅限 gmake)并且很麻烦。恕我直言,您正在尝试解决您自己创建的问题。为什么不呢您将
includedir
的正确值作为顶级 Makefile 的相对路径发送吗?这可以很容易地完成,如下所示:然后您可以在中使用
$(includedir)
子 makefile 已被定义为相对的。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:Then you can use
$(includedir)
in the sub-makefiles. It is already defined as relative.Python 是可移植的!因此,我建议您在子makefile中使用这个简单的示例,
使用
current_dir
和destination_dir
路径os.path.relpath()
为您完成这项工作所以你不必重新发明轮子。submakefile.mk
Python is portable! So, I would suggest you this simple example in your submakefile
With
current_dir
anddestination_dir
pathsos.path.relpath()
does the job for you so you do not have to re-invent the wheel.submakefile.mk
具有纯 Make 的强大嵌入式解决方案:
测试用例:
预期结果:
Robust drop-in solution with pure Make:
Test cases:
Expected results:
Didier 的答案是最好的,但以下内容可能会给您一些想法:
排序!
(没有人说它必须很漂亮......)
Didier's answer is the best one, but the following might give you some ideas:
Sorted!
(no-one said it had to be pretty...)
这是一个仅使用 GNU make 函数的解决方案。尽管它是递归的,但它应该比调用外部程序更有效。这个想法非常简单:相对路径将为零或更多..向上到最常见的祖先,然后是后缀向下到第二个目录。困难的部分是找到两条路径中最长的公共前缀。
我最近将一大套递归 makefile 翻译成整个项目 make,因为众所周知,递归 make 很糟糕,因为它没有公开整个依赖关系图 (
Here's a solution that only uses GNU make functions. Even though it's recursive, it ought to be more efficient than calling an external program. The idea is pretty straight forward: the relative path will be zero or more .. to go up to the most common ancestor, then a suffix to go down to the 2nd directory. The hard part is finding the longest common prefix in both paths.
I recently translated a large set of recursive makefiles into a whole project make as it's well known that recursive make is bad due to not exposing the entire dependence graph (http://aegis.sourceforge.net/auug97.pdf). All source code and library paths are defined relative to the current makefile directory. Instead of defining a fixed number of generic % build rules, I create a set of rules for every (source code directory, output directory) pair, which avoids the ambiguity of using vpath. When creating the build rules, I need a canonical path for each source code directory. Although the absolute path can be used, it's usually too long and less portable (I happened to be using Cygwin GNU make where absolute paths have a /cygdrive prefix and aren't recognized by Windows programs). Therefore, I use this function heavily for generating canonical paths.
Perl 是可移植的!下面是使用核心 Perl 模块 File::Spec(或 File::Spec::Functions)中的 abs2rel 函数的解决方案:
Perl is portable! Here's a solution using the abs2rel function from the core Perl module File::Spec (resp. File::Spec::Functions):
这是我基于诺曼·格雷的想法的解决方案:
This is my solution based on the Norman Gray's idea: