如何在GNU Make中更改当前目录

时间:2016-05-26 17:57:45

标签: makefile gnu-make guile

我想将目录中的源与目录分开。似乎从Makefile更改当前工作目录应该是最简单的解决方案。

由于以下缺点,目标的显式路径是不够的:

  1. Makefile中的冗余代码,因为每次引用目标都应该以变量为前缀。
  2. 构建特定中间目标的更复杂的命令行(更糟糕的是用于调试)。
  3. 另见Pauls's rule #3

      

    如果目标是在当前工作中构建的,那么生命是最简单的   。目录

    Regarding VPATH - 我也同意要求开发人员“在运行make之前更改到目标目录是一件痛苦的事”。

4 个答案:

答案 0 :(得分:4)

在单独的目录中构建目标是一种常见的make做法 GNU make可以方便地支持而无需更改目录或 调用辅助工具。这是一个例行说明:

<强>生成文件

srcs := main.c foo.c
blddir := bld
objs := $(addprefix $(blddir)/,$(srcs:.c=.o))
exe := $(blddir)/prog

.PHONY: all clean

all: $(exe)

$(blddir):
    mkdir -p $@

$(blddir)/%.o: %.c | $(blddir)
    $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<

$(exe) : $(objs)
    $(CC) -o $@ $^ $(LDFLAGS) $(LDLIBS)

clean:
    rm -fr $(blddir)

的运行方式如下:

$ make
mkdir -p bld
cc   -c -o bld/main.o main.c
cc   -c -o bld/foo.o foo.c
cc -o bld/prog bld/main.o bld/foo.o

婴儿床: -

可能有强大的理由让make更改其工作目录,但是 仅仅将构建产品放在一个单独的目录中就不是一个。

答案 1 :(得分:2)

已知方法概述

保罗·D·史密斯在“Multi-Architecture Builds”论文中对各种方法如何分离源目录和目标目录进行了出色的研究。描述了以下方法(有其缺点):

  • 源副本
  • 显式路径(对每个目标的引用以路径名为前缀)
  • VPATH(从目标目录调用构建)
  • 高级VPATH(自动递归调用)

又一种方法

但是我找到了更简单的解决方案 - 使用更小的样板并且没有make的递归调用。对于使用Guile support的GNU Make,我们可以使用Guile chdir function来更改Makefile中的当前工作目录。 我们也可以在此之前通过mkdir创建目录。

data ?= ./data/

# Create $(data) directory if it is not exist (just for example)
$(guile (if (not (access? "$(data)" F_OK)) (mkdir "$(data)") ))

# Set the new correct value of CURDIR (before changing directory)
CURDIR := $(abspath $(data))

# Change the current directory to $(data)
$(guile (chdir "$(data)"))

# Another way of updating CURDIR
#  — via sub-shell call after changing directory
# CURDIR := $(shell pwd)


# Don't try to recreate Makefile file
# that is disappeared now from the current directory
Makefile : ;

$(info     CURDIR = $(CURDIR)     )
$(info        PWD = $(shell pwd)  )

更改当前目录的最终样板

假设:data变量在上下文中可用,$(data)目录的父目录是可访问的,路径可以是相对的。

srcdir := $(realpath $(dir $(lastword $(MAKEFILE_LIST))))
ifeq (,$(filter guile,$(.FEATURES)))
  $(warning Guile is required to change the current directory.)
  $(error Your Make version $(MAKE_VERSION) is not built with support for Guile)
endif
$(MAKEFILE_LIST): ;
$(guile (if (not (file-exists? "$(data)")) (mkdir "$(data)") ))
ORIGCURDIR  := $(CURDIR)
CURDIR      := $(realpath $(data))
$(guile (chdir "$(data)"))
ifneq ($(CURDIR),$(realpath .))
  $(error Cannot change the current directory)
endif
$(warning CURDIR is changed to "$(data)")

请记住,include指令中的相对路径默认是从当前目录计算的,因此它取决于位置 - 是在此样板之前还是之后使用。

NB $(data)不应在规则中使用; $(srcdir)可用于指定相对于此Makefile文件位置的文件。

发现问题

此方法在GNU Make 4.0和4.2.1中进行了测试

观察到一个小问题。更改当前目录后,abspath函数无法正常工作 - 它会根据旧CURDIR继续解析相对路径; realpath工作正常。

此方法也可能有其他未知的缺点。

答案 2 :(得分:1)

正确的方法是打开一个手册页:

man make

并通过输入 -C 并按一次 Enter 搜索 /-C 。你会发现这样的东西:

   -C dir, --directory=dir
        Change  to  directory dir before reading the makefiles or doing
        anything else.  If multiple -C options are specified,  each  is
        interpreted relative to the previous one: -C / -C etc is equiv‐
        alent to -C /etc.  This is typically used with recursive  invo‐
        cations of make.

所以你可以使用它:

make -C <desired directory> ...

答案 3 :(得分:0)

在GNU Make程序中,我使用的是mingw64(Windows)专用程序,

  

GNU Make 4.2.1专为x86_64-w64-mingw32构建

我可以通过此命令使用该目标,

debug:
    cd $(PREFIX) && $(GDB) kiwigb.exe

结果是目录更改是暂时的,但是可以正常工作。