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 进行未定义的引用的主要内容,如果未能解决你的问题,请参考以下文章