关于GNU makefile的一些问题

时间:2011-01-20 07:46:50

标签: makefile gnu

我想知道是否有人有时间回答有关GNU makefile的一些问题......

  1. 如果目录不存在(“./obj”)用于输出,如何创建目录?
  2. 我有一个makefile,但我有2个构建方法“Debug”和“Release”,我可以同时拥有1个makefile以及如何告诉它要构建哪个?
  3. 我一直在使用Code :: Blocks,它只构建已更改的文件,但我的makefile每次调用make命令时都会构建它们,而不会触及任何文件。我怎样才能让它只构建更改的文件?
  4. 这是我当前的makefile

    OBJPATH=./obj
    COMPILER=gcc
    
    Output: main.o Base64.o
     $(COMPILER) -o Output.exe $(OBJPATH)/main.o $(OBJPATH)/Base64.o
     strip Output.exe
    
    main.o: main.c main.h
     $(COMPILER) -c main.c -o $(OBJPATH)/main.o
    
    Base64.o: Base64.c Base64.h
     $(COMPILER) -c Base64.c -o $(OBJPATH)/Base64.o
    

    感谢。

3 个答案:

答案 0 :(得分:2)

对于第一个问题,你可以在其他任何一个之前放置一个假目标,如下所示:

preamble:
    -mkdir obj

main.o: preamble main.c
    blah blah blah

在构建其他任何内容之前,它将自动执行前导码中的所有内容(您必须使其成为每个规则中的第一个依赖项)。 -开头的mkdir会忽略失败,例如,如果目录已经存在。

对于第二个问题,您可以提供类似的内容:

all: debug release

debug: blah blah blah

release: blah blah blah

实际上将调试和发布代码放在单独的子目录中。这样,您可以使用make releasemake debug进行构建,并使用make all构建两者

第三个问题:你的makefile每次都会构建,因为规则告诉它。例如,Output: main.o Base64.o将始终尝试构建,因为Output永远不存在(正确的目标似乎是Output.exe)。

同样,您的目标文件规则将始终执行,因为main.oBase64.o都不会被其语句更新(它们会更新obj目录中的文件)。

你可以通过制作目标$(OBJPATH)/main.o来解决这个问题,但说实话,我通常不担心将对象和可执行文件分成不同的目录。我倾向于将它们全部放在一个目录中,让make -clean清理它们。


所以我开始的makefile将是:

COMPILER=gcc

# Meta rules

all: release debug

release: Output.exe

debug: Output-d.exe

# Release stuff

Output.exe: main.o Base64.o
    $(COMPILER) -o Output.exe main.o Base64.o
    strip Output.exe

main.o: main.c main.h
    $(COMPILER) -c main.c -o main.o

Base64.o: Base64.c Base64.h
    $(COMPILER) -c Base64.c -o Base64.o

# Debug stuff

Output-d.exe: main-d.o Base64-d.o
    $(COMPILER) -g -o Output-d.exe main-d.o Base64-d.o

main-d.o: main.c main.h
    $(COMPILER) -g -DDEBUG -c main.c -o main-d.o

Base64-d.o: Base64.c Base64.h
    $(COMPILER) -g -DDEBUG -c Base64.c -o Base64-d.o

回应您的评论问题:

  

无论如何我可以根据目标选择重新设置变量吗?例如,如果选择了调试OBJPATH =“。/ obj / Debug”,如果选择的版本OBJPATH将是“./obj/Release”?

GNU Make可能比我习惯的更强大,但你可以通过设置环境变量然后重新运行make来实现这一点:

all: release debug

release:
        ( export zzvar=release ; $(MAKE) zz_Output.exe )

debug:
        ( export zzvar=debug ; $(MAKE) zz_Output-d.exe )

zz_Output.exe:
        echo $(zzvar)
        touch zz_Output.exe

zz_Output-d.exe: zz_main-d.o zz_Base64-d.o
        echo $(zzvar)
        touch zz_Output-d.exe

输出:

( export zzvar=release ; make zz_Output.exe )
make[1]: Entering directory '/home/pax'
echo release
release                                             <==
touch zz_Output.exe
make[1]: Leaving directory '/home/pax'

( export zzvar=debug ; make zz_Output-d.exe )
make[1]: Entering directory '/home/pax'
echo debug
debug                                               <==
touch zz_Output-d.exe
make[1]: Leaving directory '/home/pax'

您可以看到上面标有<==的两个独立变量。

正如我所说,使用GNU Make可能有一种更简单的方法,但这会让你开始。

答案 1 :(得分:1)

  

如果目录不存在(“./obj”)用于输出,如何创建目录?

rm -Rf ./obj && mkdir ./obj
  

我有一个makefile,但我有2个构建方法“Debug”和“Release”,我可以同时拥有1个makefile以及如何告诉它构建哪个?

您可以拥有多个顶级构建目标。 makefile中的Output是顶级目标。做两个。一个叫做“Debug”,另一个叫“Release”。然后,您可以为调试版本说make Debug,为发布版本说make Release

  

我一直在使用Code :: Blocks,它只构建已更改的文件,但我的makefile每次调用make命令时都会构建它们,而不会触及任何文件。我怎样才能让它只构建更改的文件?

我没有使用Code::Blocks(我不知道它是什么)但是如果你的Makefile正确编写(即正确指定了依赖项),它只会重建所需的目标。

答案 2 :(得分:0)

回应您的评论问题:

  

无论如何我可以根据目标选择重新设置变量吗?   例如,如果选择的释放OBJPATH将是“./obj/Release”   选择调试OBJPATH =“./ obj / Debug”?

以下是没有递归的方法:

COMPILER=gcc

release: OBJPATH = obj
release: Output.exe

debug: OBJPATH = obj-dbg
debug: Outputd.exe

Output%.exe: main.o Base64.o
 $(COMPILER) -o $@ $(OBJPATH)/main.o $(OBJPATH)/Base64.o
 strip $@

main.o: main.c main.h
 $(COMPILER) -c main.c -o $(OBJPATH)/main.o

Base64.o: Base64.c Base64.h
 $(COMPILER) -c Base64.c -o $(OBJPATH)/Base64.o