GNU MAKE:缺少分离器。停止'源代码文件的含义?

发布于 2025-02-09 23:50:58 字数 2397 浏览 1 评论 0原文

我是Makefiles的新手,我正在尝试使用GCC为C项目创建一个。

我熟悉错误makefile:< col>:***缺少分离器。停止。它在我使用空格而不是标签以先于makefile中的规则之前弹出。我只是尝试为这个特定项目编写一个makefile(确保使用选项卡字符而不是空格),当我运行make命令时,我会遇到一个非常不明智的错误,我不明白如何修复: src/main.c:7:***缺少分离器。 stop

我的目录结构看起来像这样:

- projectfolder/
    - Makefile
    - bin/
    - build/
    - inc/
    - src/
        - main.c
- otherfolder/
    - inc/
        - common.h
        - io.h
    - src/
        - io.c

main.c,其中包括main函数,具有以下导入:

#include <stdio.h>
#include <stdlib.h>
#include "common.h"
#include "io.h"

我的目标是制作一堆<<代码> .o 和.d来自src/inc/目录的文件中的文件> projectFolder/build/,以便可以使用ProjectFolder/bin/code>在projectfolder/bin/code>中使最终

# Compiler and linker
CC          :=  gcc

# Target binary
TARGET      :=  the-program

# File extensions
SRCEXT      :=  c

# Directories
TARGETDIR   :=  bin
BUILDDIR    :=  build
SRCDIRS     :=  src /home/myusername/otherfolder/src
INCDIRS     :=  inc /home/myusername/otherfolder/inc

# gcc options
CCFLAGS     :=  -Wall -Wextra -O3

#---------------------------------------------------------------------------------
#DO NOT EDIT BELOW THIS LINE
#---------------------------------------------------------------------------------
vpath   %.$(SRCEXT) $(SRCDIRS)
vpath   %.h         $(INCDIRS)
CCFLAGS +=  $(addprefix -I,$(INCDIRS)) -MMD -MP

SRC     :=  $(shell find $(SRCDIRS) -name *.$(SRCEXT))
OBJ     :=  $(SRC:$(SRCDIRS)/%.$(SRCEXT)=$(BUILDDIR)/%.o)
DEP     :=  $(OBJ:.o=.d)
TARGET  :=  $(TARGETDIR)/$(TARGET)

# RULE: Default make
all: makedirs $(TARGET) clean

# RULE: Remake
remake: fullclean all

# RULE: Clean
clean:
    rm -rf $(BUILDDIR)

# RULE: Full clean (objects and binaries)
fullclean: clean
    rm -rf $(TARGETDIR)

# RULE: Make dirs
makedirs:
    mkdir -p $(BUILDDIR)
    mkdir -p $(TARGETDIR)

# RULE: Link
$(TARGET): $(OBJ)
    $(CC) $(OBJ) -o $@

# RULE: Compile
$(OBJ): $(SRC)
    $(CC) $(CCFLAGS) -c $< -o $@

# RULE: Non-file targets
.PHONY: all remake clean fullclean makedirs

# include dependencies
-include $(DEP)

执行 会导致所述错误吗?我假设它与makefile本身有关,而不是src/main.c实际上包含的C代码,因为这似乎不是汇编错误,但是如果我错了,请让我知道,我可以更改帖子。

I'm fairly new to Makefiles, and I am trying to create one for a C project I am building using gcc.

I am familiar with the error Makefile:<col>: *** missing separator. Stop. It has popped up before when I used spaces instead of tabs to precede rules in the Makefile. I just tried writing a Makefile for this particular project (being sure to use TAB character instead of spaces) and when I run the make command, I get a very nondescript error I do not understand how to fix: src/main.c:7: *** missing separator. Stop

My directory structure looks like this:

- projectfolder/
    - Makefile
    - bin/
    - build/
    - inc/
    - src/
        - main.c
- otherfolder/
    - inc/
        - common.h
        - io.h
    - src/
        - io.c

main.c, which includes the main function, has the following imports:

#include <stdio.h>
#include <stdlib.h>
#include "common.h"
#include "io.h"

My goal is to make a bunch of .o and .d files from the files in both src/ and inc/ directories and put those into projectfolder/build/, so that they can then be used to make the final executable in projectfolder/bin/

Finally, here is the Makefile that is causing the issue:

# Compiler and linker
CC          :=  gcc

# Target binary
TARGET      :=  the-program

# File extensions
SRCEXT      :=  c

# Directories
TARGETDIR   :=  bin
BUILDDIR    :=  build
SRCDIRS     :=  src /home/myusername/otherfolder/src
INCDIRS     :=  inc /home/myusername/otherfolder/inc

# gcc options
CCFLAGS     :=  -Wall -Wextra -O3

#---------------------------------------------------------------------------------
#DO NOT EDIT BELOW THIS LINE
#---------------------------------------------------------------------------------
vpath   %.$(SRCEXT) $(SRCDIRS)
vpath   %.h         $(INCDIRS)
CCFLAGS +=  $(addprefix -I,$(INCDIRS)) -MMD -MP

SRC     :=  $(shell find $(SRCDIRS) -name *.$(SRCEXT))
OBJ     :=  $(SRC:$(SRCDIRS)/%.$(SRCEXT)=$(BUILDDIR)/%.o)
DEP     :=  $(OBJ:.o=.d)
TARGET  :=  $(TARGETDIR)/$(TARGET)

# RULE: Default make
all: makedirs $(TARGET) clean

# RULE: Remake
remake: fullclean all

# RULE: Clean
clean:
    rm -rf $(BUILDDIR)

# RULE: Full clean (objects and binaries)
fullclean: clean
    rm -rf $(TARGETDIR)

# RULE: Make dirs
makedirs:
    mkdir -p $(BUILDDIR)
    mkdir -p $(TARGETDIR)

# RULE: Link
$(TARGET): $(OBJ)
    $(CC) $(OBJ) -o $@

# RULE: Compile
$(OBJ): $(SRC)
    $(CC) $(CCFLAGS) -c 
lt; -o $@

# RULE: Non-file targets
.PHONY: all remake clean fullclean makedirs

# include dependencies
-include $(DEP)

What about this file would cause the described error? I am assuming that it is related to the Makefile itself rather than the C code actually contained in src/main.c since this does not appear to be a compilation error, but if I am wrong, let me know and I can change the post.

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

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

发布评论

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

评论(2

小红帽 2025-02-16 23:50:58

此错误:

src/main.c:7: *** missing separator. Stop

显然是由Make打印。由于我们知道这些消息的格式是&lt; makefile&gt;:&lt; linenumber&gt;:&lt; error&gt;,我们可以看到这是试图解析文件src/main.c.c.c.c.c作为makefile,显然这是行不通的。

如何做这样的事情?显而易见的罪魁祸首是:

-include $(DEP)

如果变量dep包含文件src/main.c,那么Make将尝试将其包括在内并解析。那么dep如何设置?

DEP     :=  $(OBJ:.o=.d)

这将以obj.o结尾的所有单词更改为.d结束。至关重要的是,应该注意的是,这没有任何更改 .o结尾的单词。因此,如果objs包含src/main.c,则将其通过未修改的deps

那么obj如何设置?以下是相关变量:

SRCDIRS     :=  src /home/myusername/otherfolder/src

SRC     :=  $(shell find $(SRCDIRS) -name *.$(SRCEXT))
OBJ     :=  $(SRC:$(SRCDIRS)/%.$(SRCEXT)=$(BUILDDIR)/%.o)

让我们扩展以下内容:src变量运行

find src /home/myusername/otherfolder/src -name *.c

: )。

现在我们要说SRC获得了值:

SRC := src/main.c /home/myusername/otherfolder/src/other.c

现在obj包含什么?

OBJ     :=  $(SRC:src /home/myusername/otherfolder/src/%.$(SRCEXT)=build/%.o)

这显然无法使用:您不能将多个目录放入srcdirs中,但随后将其视为仅包含一个单词。

This error:

src/main.c:7: *** missing separator. Stop

is clearly being printed by make. Since we know the format of these messages is <makefile>:<linenumber>: <error>, we can see that make is trying to parse the file src/main.c as a makefile and obviously this cannot work.

How could make be doing such a thing? The obvious culprit is this line:

-include $(DEP)

If the variable DEP contains the file src/main.c, then make would try to include that as a makefile and parse it. So how is DEP set?

DEP     :=  $(OBJ:.o=.d)

This changes all words in OBJ that end with .o to end with .d. Crucially, it should be noted that this makes no changes to words that do not end in .o. So, if OBJS contained src/main.c, this would pass it through unmodified to DEPS.

So how is OBJ set? Here are the relevant variables:

SRCDIRS     :=  src /home/myusername/otherfolder/src

SRC     :=  $(shell find $(SRCDIRS) -name *.$(SRCEXT))
OBJ     :=  $(SRC:$(SRCDIRS)/%.$(SRCEXT)=$(BUILDDIR)/%.o)

Let's expand this: the SRC variable runs:

find src /home/myusername/otherfolder/src -name *.c

(you really should escape the *, either with backslash or quotes: it's very dangerous how you have this).

Now we'll say that SRC gets the value:

SRC := src/main.c /home/myusername/otherfolder/src/other.c

Now what does OBJ contain?

OBJ     :=  $(SRC:src /home/myusername/otherfolder/src/%.$(SRCEXT)=build/%.o)

This clearly cannot work: you can't put multiple directories into SRCDIRS, but then treat it as if it contained only one word.

你丑哭了我 2025-02-16 23:50:58

问题是在线中,

OBJ     :=  $(SRC:$(SRCDIRS)/%.$(SRCEXT)=$(BUILDDIR)/%.o)

模式替代起作用 ,其中模式匹配,而则使所有其他字符串单独

作为一个简单的演示,请参阅此makefile(没有规则,只有变量分配):

x := foo bar baz
y := $(x:ba%=gu%)
$(info $(x))
$(info $(y))

输出:

foo bar baz
foo gur guz

您可以看到,foo仍然存在,尽管它与模式ba%<不匹配,但仍未改变/代码>。

在您的情况下,您将无法替代模式,$(srcdirs)的内容是两个单词:src/home/myusername/myusername/shotherfolder/src to替代调用,因此main.c - 是src/main.c/home/myusername/myusername/otherfolder/src/src/main.c保持在您的列表中保持不变,无意间冲入$(dep)中,最终作为文本包含在您的最后一行incclude $(dep)

作为建议,我想向您指出vather(请参阅手册,此处: https://www.cmcrossroads.com/article/basics-vath-and-vath ),这是指示源位置到make

The problem is in the line

OBJ     :=  $(SRC:$(SRCDIRS)/%.$(SRCEXT)=$(BUILDDIR)/%.o)

The pattern substitution works only where the pattern matches and leaves all other strings alone.

As a simple demonstration see this makefile (no rules, just variable assignments):

x := foo bar baz
y := $(x:ba%=gu%)
$(info $(x))
$(info $(y))

Output:

foo bar baz
foo gur guz

As you can see, foo still is there, unchanged although it didn't match the pattern ba%.

In your case you are passing an impossible to substitute pattern, the content of $(SRCDIRS), which is the two words: src /home/myusername/otherfolder/src to the substitution call, therefore main.c - which is either src/main.c or /home/myusername/otherfolder/src/main.c remains unchanged in your list, gets inadvertently flushed further into $(DEP) and is finally included as text with your last line -include $(DEP).

As a recommendation I want to point you to VPATH (see manual and here: https://www.cmcrossroads.com/article/basics-vpath-and-vpath), which is the better alternative to indicate the location of your sources to make.

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