关于 GNU makefile 的一些问题

发布于 2024-10-12 22:48:45 字数 624 浏览 5 评论 0原文

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

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

这是我当前的 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

谢谢。

i was wondering if anyone have sometime to answer some questions about GNU makefiles...

  1. how to create a directory if it doesn't exists ("./obj") for output?
  2. i have one makefile, but i got 2 build methods "Debug" and "Release", can i have both in 1 makefile and how to tell it which one to build?
  3. ive been using Code::Blocks which builds only changed files, but my makefile builds them everytime i call make command, without touching any files. how can i make it build changed files only?

here is my current 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

thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

梦幻之岛 2024-10-19 22:48:45

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

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/Release”,如果选择的调试 OBJPATH =“./obj/Debug”?

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 可能有一种更简单的方法,但这将帮助您入门。

For the first question, you can put a fake target before any of the others, along the lines of:

preamble:
    -mkdir obj

main.o: preamble main.c
    blah blah blah

That will automatically execute everything in the preamble (you have to make it the first dependency in every rule) before it builds anything else. The - at the start of the mkdir ignores failures if, for example, the directory already exists.

For the second question, you can provide something like:

all: debug release

debug: blah blah blah

release: blah blah blah

and actually put the debug and release code in separate subdirectories. That way, you can build either with make release or make debug and build them both with make all.

Third question: Your makefile builds every time because the rules tell it to. For example, Output: main.o Base64.o will always try to build since Output never exists (the correct target seems to be Output.exe).

Similarly your object file rules will always execute since neither main.o nor Base64.o are updated by their statements (they update the files in the obj directory instead).

You may be able to fix that case by making the target $(OBJPATH)/main.o but, to be honest, I don't usually worry about separating objects and executables into separate directories. I tend to just lump them all into one directory and let make -clean clean them up.


So the makefile I would start with would be:

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

In response to your comment question:

Is there anyway I can re-set a variable based on the Target Selected? for example if selected release OBJPATH will be "./obj/Release" if selected debug OBJPATH = "./obj/Debug"?

GNU Make may be more powerful than the ones I'm used to but you can do that by setting an environment variable then re-running make as per the following:

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

which outputs:

( 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'

You can see the two separate variables marked with <== above.

As I said, there's probably an easier way to do it with GNU Make but that'll get you started.

白鸥掠海 2024-10-19 22:48:45

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

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

我有一个 makefile,但我有 2 个构建方法“调试”和“发布”,我可以在 1 个 makefile 中同时拥有这两个方法吗?如何告诉它构建哪一个?

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

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

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

how to create a directory if it doesn't exists ("./obj") for output?

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

i have one makefile, but i got 2 build methods "Debug" and "Release", can i have both in 1 makefile and how to tell it which one to build?

You can have multiple top level build targets. Output in your makefile is a top level target. Make two. One called "Debug" and the other "Release". You can then say make Debug for the debug build and make Release for the release build.

ive been using Code::Blocks which builds only changed files, but my makefile builds them everytime i call make command, without touching any files. how can i make it build changed files only?

I haven't used Code::Blocks (I don't know what it is) but if your Makefiles are written properly (i.e. with dependencies properly specified), it will only rebuild the required targets.

遇到 2024-10-19 22:48:45

回复您的评论问题:

我是否可以根据所选目标重新设置变量?
例如,如果选定的版本 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

In response to your comment question:

Is there anyway I can re-set a variable based on the Target Selected?
for example if selected release OBJPATH will be "./obj/Release" if
selected debug OBJPATH = "./obj/Debug"?

Here is how you do it without recursion:

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文