GNU Make - 如何处理目标文件中的路径

时间:2014-09-24 18:28:26

标签: makefile gnu makefile-project

我正在编写一个更大的makefile,它将处理源文件的递归结构,并将它们放在目标目录中的相同递归结构中。基本上你可以假设这个makefile:

DESTINATION_DIR = out
SOURCE_DIR = src
OBJECTS = out/abc.o out/subdir/test.o out/subdir/subdir/xyz.o

.PHONY: all
all: $(OBJECTS)

$(DESTINATION_DIR)/%.o: $(SOURCE_DIR)/%.c
    @echo "$@ --- $<"

正如您所看到的,我正在尝试用依赖项中的$(SOURCE_DIR)替换$(DESTINATION_DIR),但这不起作用。我怎么解决这个问题?我甚至试图以这种方式使用替换脚本:

%.o: $(shell myreplacementscript.py "%.c" "$(DESTINATION_DIR)" "$(SOURCE_DIR)")
    @echo "$@ --- $<"

但百分号将传递给我的脚本而无需替换。那么我怎么能告诉它输出依赖于源文件动态?我需要将子目录保存在OBJECTS变量中,我不能压扁结构。子目录是动态的,而不是预定义的。

我已经搜索过其他有相同问题的人,但他们要么有平坦的OBJECTS,要么有递归的make,在我的情况下由于根据依赖关系的目录之间的互连而不适合。

摘要/错误消息:

它不会用src /替换OBJECTS中的/。所以错误信息是“Keine Regel vorhanden,um das Target»out / abc.o«,benötigtvon»all«,zu erstellen.Schluss。”这是典型的错误“没有规则来制定目标......”。

完整的makefile可以在这里看到: Full Makefile

每当我在左侧留下%.html的冒号的右侧边缘时它就可以工作,但我需要将源文件作为依赖项来获得有效的增量构建(希望不创建依赖文件)。

亲切的问候,

丹尼尔

2 个答案:

答案 0 :(得分:1)

使用GNU make扩展的解决方案不是一个好方法。我建议不要使用任何GNU Make特定功能。首先,它不便携。其次,它的语法很糟糕。使用有史以来发明的标准工具和技术。你的解决方案是 - 壳牌。您可以将Makefile包装到shell脚本中,并使用常见的shell语言进行所有计算和字符串操作。请看以下示例:

src_files="file1.c file2.c file3.c"

cat > Makefile <<EOF
-
-
YOUR MAKEFILE STATIC STUFF GOES HERE
-

all: $(OBJECTS)

EOF

for file in $src_files; do
  src="src/$file"
  obj=`echo $file | sed 's/\.c$/\.o/'`
  sources="$sources $src"
  objects="$objects out/$obj"

  cat >>Makefile <<EOF
$obj: $src
    YOUR CODE HERE
EOF
done

cat >>Makefile <<EOF
SOURCES = $sources
OBJECTS = $objects

EOF

为脚本命名&#39; mkmf&#39;并运行./mkmf。它将生成Makefile。您可以对其进行参数化,使其非常强大和智能。不需要使用少量和脏的gnu make扩展。

答案 1 :(得分:0)

MichaelGrünewald的回答和MadScientist的网站,我决定采用VPATH的方式。但是因此我必须首先切换到输出目录并删除OBJECTS的out /前缀(通过对makefile的递归调用)。以上简短示例将如下修改:

ROOTDIR = $(abspath ./)

DESTINATION_DIR = out
SOURCE_DIR = src

DESTINATION_DIRABS = $(abspath $(shell cd $(ROOTDIR); cd $(DESTINATION_DIR); pwd))
SOURCE_DIRABS = $(abspath $(shell cd $(ROOTDIR); cd $(SOURCE_DIR); pwd))

ifneq ($(abspath ./),$(DESTINATION_DIRABS))
# we are not in the destination directory, so we first need to change to it
OBJECTS     = 
else
# without out/ prefix!
OBJECTS     = abc.o subdir/test.o subdir/subdir/xyz.o
# set the VPATH for the source files
VPATH       = $(SOURCE_DIRABS)
endif

.PHONY: all
all: $(OBJECTS)
ifneq ($(abspath ./),$(DESTINATION_DIRABS))
    # call make inside the destination directory
    $(MAKE) -C $(DESTINATION_DIRABS) -f $(ROOTDIR)/Makefile ROOTDIR='$(ROOTDIR)'
endif

%.o: %.c
    @echo "$@ --- $<"

(在这个小例子中未经测试,但在我更大的Makefile中工作)

所以最后它按预期正在运行。非常感谢您对MichaelGrünewald,MadScientist和Beta的评论。

<强>更新

最后我重试了$(DESTINATION_DIR)/%。o:$(SOURCE_DIR)/%。c方法,故障只是$(DESTINATION_DIR)已经包含了我的完整makefile中的斜杠。

对不起,请再次感谢。对于因为遇到类似问题而阅读此内容的任何人:检查斜杠两次!