Linux C++ 对 main 进行未定义的引用

Posted

技术标签:

【中文标题】Linux C++ 对 main 进行未定义的引用【英文标题】:Linux C++ make undefined reference to main 【发布时间】:2015-09-18 09:20:11 【问题描述】:

我正在开发一个 C++ 项目,以使自己对这门语言有所了解,但在使用 make 构建时遇到了一个(对我而言)相当奇怪的问题。

我的项目设置如下:

 bin/
 include/
 src/
 Makefile
 build.sh

src 我目前有 2 个文件,loggerConfig.cpp 和 proxy.cpp。主要方法在proxy.cpp 中。我的 Makefile 包含以下内容,取自 this post:

CC := g++
SRCDIR := src
BUILDDIR := build
TARGET := bin/proxy

SRCEXT := cpp
SOURCES := $(shell find $(SRCDIR) -type f -iname *.$(SRCEXT))
OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.o))

LINKFLAGS = -pthread -std=c++11
CFLAGS := -g -Wall -pedantic -std=c++11 -pthread
LIB := -lconfig++
INC := -I include


$(TARGET): $(OBJECTS)
    @echo " Linking..."
    @echo " $(CC) $^ -o $(TARGET) $(LIB)"; $(CC) $^ -o $(TARGET) $(LIB) $(LINKFLAGS)

$(BUILDDIR)/%.o: $(SRCDIR)/%.$(SRCEXT)
    @echo " Building..."
    @mkdir -p $(BUILDDIR)
    @echo " $(CC) $(CFLAGS) $(INC) -c -o $@ $<"; $(CC) $(CFLAGS) $(INC) -c -o $@ $<

clean:
    @echo " Cleaning..."; 
    @echo " $(RM) -r $(BUILDDIR) $(TARGET)"; $(RM) -r $(BUILDDIR) $(TARGET)

..PHONY: clean

除非我在 Makefile 所在的目录中有一个 .cpp 文件,否则一切正常。因为我目前正在玩,所以在我将一些东西放入我的项目之前,我将在 test.cpp 文件中制作一个小型独立应用程序。当我这样做并切换回使用 make 时,我会收到以下错误:

$ make clean ; make
 Cleaning...
 rm -f -r build bin/proxy
 Linking...
 g++  -o bin/proxy -lconfig++
/usr/lib/gcc/x86_64-redhat-linux/4.8.3/../../../../lib64/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status
make: *** [bin/proxy] Error 1

只需将test.cpp 文件上移一个目录即可解决问题并编译。谁能解释为什么?我对make 的理解相当简单,所以我不知道谷歌是为了什么......

[编辑]

直接在 shell 中为 SOURCES 列表运行 find 命令后,我发现当存在 test.cpp 文件时它没有返回任何结果。

$ ls
bin  build.sh  include  log  Makefile  src  test.cpp
$ find src -type f -iname *.cpp
$ mv test.cpp ../
$ find src -type f -iname *.cpp
src/proxy.cpp
src/loggerConfig.cpp

【问题讨论】:

正如你在这里看到的g++ -o bin/proxy -lconfig++ 它没有找到任何要编译的源文件。因此,要么您的 src 文件夹中没有任何源文件,要么 find 命令不正确。我建议直接在你的 Shell 上运行所有这些 find 命令,看看是否真的找到了你的源文件。 啊,好吧,当test.cpp 文件在目录中时,由于某种原因find 命令没有正确返回。原来它需要围绕源扩展名的语音标记。虽然当文件不在目录中时它为什么工作我不知道 如果你解决了问题,你应该把它作为答案发布 【参考方案1】:

这是一个非常漂亮的 Makefile,你可能会因为过于复杂而给自己带来麻烦。

我会这样写:

TARGET=bin/proxy
SOURCES=loggerConfig proxy

$(TARGET): $(SOURCES:%=build/%.o)
    @echo " Linking..."
    $(CC) $^ -o $(TARGET) $(LIB) $(LINKFLAGS)

build/%.o: src/%.cpp
    @echo " Building..."
    test -d build || mkdir -p build
    $(CC) $(CFLAGS) $(INC) -c -o $@ $<

也许我有点老派,但是玩带有花哨的变量替换的游戏很有趣,直到有人受伤,当我在那里屈服于诱惑时,我通常最终会后悔,并简化了 Makefile .

特别是,这里有两个进一步的观察。

这组源似乎不太可能非常动态地生成SOURCES 变量。添加文件时,无需将名称添加到 Makefile 中,如果不添加,程序将无法构建,因此不会有忘记的危险。

@echo foo bar; foo bar 模式肯定是在自找麻烦!在某些时候,您必须调整foo bar 部分之一而不调整另一个部分,您会非常感到困惑。 Make 回显它执行的行,除非你用 @ 前缀停止它,所以你似乎是通过迂回路线合成默认行为。

【讨论】:

感谢您的回答,虽然我的回答解释了我遇到问题的原因,但我会接受这个问题,因为我认为这最终可能是一个更清洁的解决方案。我不知道 make 回显它默认执行的行;所以我删除了这些并简化了 make 文件。 我很高兴它有帮助。您发现的问题很好地说明了花哨的替换可能导致的一般问题。【参考方案2】:

问题是由于查找命令find $(SRCDIR) -type f -iname *.$(SRCEXT)) 导致make 文件中的$SOURCES 列表为空。

要解决此问题,需要将行更新为:

SOURCES := $(shell find $(SRCDIR) -type f -iname '*.$(SRCEXT)')

根据this answer 的说法,原因是外壳中断*.cpp 作为全局模式并在传递查找之前将其扩展为匹配任何文件。所以实际上正在运行的find 命令是find src -type f -iname test.cpp,它现在正在返回结果。

【讨论】:

以上是关于Linux C++ 对 main 进行未定义的引用的主要内容,如果未能解决你的问题,请参考以下文章

对 `JNI_CreateJavaVM' linux 的未定义引用

c++中对静态变量的未定义引用

当 main 存在时,未定义对 `main' 的引用

我的编译器对main的未定义引用错误

C++ 错误,未定义的引用类

C++ MySQL++ 未定义对 dlclose 的引用