首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在C++文件中使用C外部函数:与Makefile的链接问题

在C++文件中使用C外部函数:与Makefile的链接问题
EN

Stack Overflow用户
提问于 2010-09-16 13:05:26
回答 2查看 3.2K关注 0票数 1

我有个问题。我在C文件read-line.c中定义了一个函数print,如下所示:

代码语言:javascript
复制
void history_print(void)
{
    /* some stuff */
}

在一个名为command.cc的C++文件中,我有以下内容:

代码语言:javascript
复制
extern "C" void history_print(void);

然后我简单地调用history_print()。

代码语言:javascript
复制
#Use GNU compiler
cc = gcc -g
CC = g++ -g   

all: shell

tty-raw-mode.o: tty-raw-mode.c
    gcc -c tty-raw-mode.c

read-line.o: read-line.c
    gcc -c read-line.c

lex.yy.o: shell.l
    lex shell.l
    $(cc) -c lex.yy.c

y.tab.o: shell.y
    yacc -d shell.y
    $(CC) -c y.tab.c

command.o: command.cc
    $(CC) -c command.cc

shell: y.tab.o lex.yy.o tty-raw-mode.o read-line.o command.o
    $(CC) -o shell lex.yy.o y.tab.o tty-raw-mode.o read-line.o command.o -ll -lgen

当我在Makefile中链接规则输出时,我遇到了一个问题:

代码语言:javascript
复制
Undefined                       first referenced
 symbol                             in file
history_print                       command.o
ld: fatal: Symbol referencing errors. No output written to shell
collect2: ld returned 1 exit status
*** Error code 1
make: Fatal error: Command failed for target `shell'

make的-v选项标志的输出:

代码语言:javascript
复制
yacc -d shell.y
g++ -g -v -c y.tab.c
Reading specs from /opt/csw/gcc3/lib/gcc/sparc-sun-solaris2.8/3.4.6/specs
Configured with: ../sources/gcc-3.4.6/configure --prefix=/opt/csw/gcc3 --with-local-    prefix=/opt/csw --without-gnu-as --with-as=/usr/ccs/bin/as --without-gnu-ld     --with-ld=/usr/ccs/bin/ld --enable-threads=posix --enable-shared --enable-multilib     --enable-nls --with-included-gettext --with-libiconv-prefix=/opt/csw --with-x --enable-    java-awt=xlib --enable-languages=all
Thread model: posix
gcc version 3.4.6
 /opt/csw/gcc3/libexec/gcc/sparc-sun-solaris2.8/3.4.6/cc1plus -quiet -v y.tab.c -quiet     -dumpbase y.tab.c -mcpu=v7 -auxbase y.tab -g -version -o /var/tmp//ccCi8vXj.s
ignoring nonexistent directory "/opt/csw/gcc3/lib/gcc/sparc-sun-solaris2.8/3.4.6/../..    /../../sparc-sun-solaris2.8/include"
#include "..." search starts here:
#include <...> search starts here:
 /opt/csw/gcc3/lib/gcc/sparc-sun-solaris2.8/3.4.6/../../../../include/c++/3.4.6
 /opt/csw/gcc3/lib/gcc/sparc-sun-solaris2.8/3.4.6/../../../../include/c++/3.4.6/sparc-    sun-solaris2.8
 /opt/csw/gcc3/lib/gcc/sparc-sun-solaris2.8/3.4.6/../../../../include/c++/3.4.6/backward
 /opt/csw/include
 /opt/csw/gcc3/include
 /opt/csw/gcc3/lib/gcc/sparc-sun-solaris2.8/3.4.6/include
 /usr/include
End of search list.
GNU C++ version 3.4.6 (sparc-sun-solaris2.8)
        compiled by GNU C version 3.4.6.
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
 /usr/ccs/bin/as -V -Qy -s -xarch=v8 -o y.tab.o /var/tmp//ccCi8vXj.s
/usr/ccs/bin/as: SunOS 5.10 118683-05 Patch 04/30/2010
lex shell.l
gcc -g -c lex.yy.c
gcc -c tty-raw-mode.c
gcc -c read-line.c
g++ -g -v -c command.cc
Reading specs from /opt/csw/gcc3/lib/gcc/sparc-sun-solaris2.8/3.4.6/specs
Configured with: ../sources/gcc-3.4.6/configure --prefix=/opt/csw/gcc3 --with-local-    prefix=/opt/csw --without-gnu-as --with-as=/usr/ccs/bin/as --without-gnu-ld --with-ld=/usr/ccs/bin/ld --enable-threads=posix --enable-shared --enable-multilib --enable-nls --with-included-gettext --with-libiconv-prefix=/opt/csw --with-x --enable-    java-awt=xlib --enable-languages=all
Thread model: posix
gcc version 3.4.6
 /opt/csw/gcc3/libexec/gcc/sparc-sun-solaris2.8/3.4.6/cc1plus -quiet -v command.cc -quiet -dumpbase command.cc -mcpu=v7 -auxbase command -g -version -o /var/tmp//cckVWlC7.s
ignoring nonexistent directory "/opt/csw/gcc3/lib/gcc/sparc-sun-solaris2.8/3.4.6/../../../../sparc-sun-solaris2.8/include"
#include "..." search starts here:
#include <...> search starts here:
 /opt/csw/gcc3/lib/gcc/sparc-sun-solaris2.8/3.4.6/../../../../include/c++/3.4.6
 /opt/csw/gcc3/lib/gcc/sparc-sun-solaris2.8/3.4.6/../../../../include/c++/3.4.6/sparc-sun-solaris2.8
 /opt/csw/gcc3/lib/gcc/sparc-sun-solaris2.8/3.4.6/../../../../include/c++/3.4.6/backward
 /opt/csw/include
 /opt/csw/gcc3/include
 /opt/csw/gcc3/lib/gcc/sparc-sun-solaris2.8/3.4.6/include
 /usr/include
End of search list.
GNU C++ version 3.4.6 (sparc-sun-solaris2.8)
        compiled by GNU C version 3.4.6.
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
 /usr/ccs/bin/as -V -Qy -s -xarch=v8 -o command.o /var/tmp//cckVWlC7.s
/usr/ccs/bin/as: SunOS 5.10 118683-05 Patch 04/30/2010
g++ -g -v -o shell lex.yy.o y.tab.o tty-raw-mode.o read-line.o command.o -ll -lgen
Reading specs from /opt/csw/gcc3/lib/gcc/sparc-sun-solaris2.8/3.4.6/specs
Configured with: ../sources/gcc-3.4.6/configure --prefix=/opt/csw/gcc3 --with-local-    prefix=/opt/csw --without-gnu-as --with-as=/usr/ccs/bin/as --without-gnu-ld --with-ld=/usr/ccs/bin/ld --enable-threads=posix --enable-shared --enable-multilib --enable-nls --with-included-gettext --with-libiconv-prefix=/opt/csw --with-x --enable-    java-awt=xlib --enable-languages=all
Thread model: posix
gcc version 3.4.6
 /opt/csw/gcc3/libexec/gcc/sparc-sun-solaris2.8/3.4.6/collect2 -V -R /opt/csw/lib -Y P,/opt/csw/lib:/usr/ccs/lib:/usr/lib -Qy -o shell /opt/csw/gcc3/lib/gcc/sparc-sun-solaris2.8/3.4.6/crt1.o /opt/csw/gcc3/lib/gcc/sparc-sun-solaris2.8/3.4.6/crti.o     /usr/ccs/lib/values-Xa.o /opt/csw/gcc3/lib/gcc/sparc-sun-solaris2.8/3.4.6/crtbegin.o -L/opt    /csw/gcc3/lib/gcc/sparc-sun-solaris2.8/3.4.6 -L/usr/ccs/bin -L/usr/ccs/lib -L/opt/csw/gcc3/lib/gcc/sparc-sun-solaris2.8/3.4.6/../../.. lex.yy.o y.tab.o tty-raw-mode.o read-line.o command.o -ll -lgen -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc -lc /opt/csw/gcc3/lib/gcc/sparc-sun-solaris2.8/3.4.6/crtend.o /opt/csw/gcc3/lib/gcc/sparc-sun-solaris2.8/3.4.6/crtn.o
ld: Software Generation Utilities - Solaris Link Editors: 5.10-1.497
Undefined                       first referenced
 symbol                             in file
history_print                       command.o
ld: fatal: Symbol referencing errors. No output written to shell
collect2: ld returned 1 exit status
*** Error code 1
make: Fatal error: Command failed for target `shell'

我猜这个问题是由于链接造成的,它与Makefile有关,但我不确定如何修复。有谁能帮帮我吗?

非常感谢,我真的很感谢你的帮助。

加里

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2010-09-16 13:11:41

makefile需要一个链接规则,而不是单独的编译规则:

代码语言:javascript
复制
CC  = gcc -g
CPP = g++ -g

program: a.o b.o
    ${CPP} -o $@ a.o b.o

Make已经知道如何将源文件转换为目标文件-您不需要重新训练它。

票数 1
EN

Stack Overflow用户

发布于 2010-09-16 13:08:33

这是因为您正在使用g++重新编译a.c文件,而函数定义周围没有extern C包装器。因此,该名称将经历C++损坏,并且在a.o对象文件中将不会有print

但是,b.cc会认为print是一个C名称(因为它有extern C),所以它会去寻找未损坏的版本。

要么将extern C放在a.c中的定义周围(这可能使常规C编译器无法使用,所以请记住这一点),或者将您的g++命令更改为使用a.o (由于它是用C编译器完成的,因此具有完整的名称)而不是a.c

实际上,这是行不通的,因为您没有在g++命令中调用链接器。我甚至不确定您为什么要在b.o中包含a.o。最好的时机可能是在链接时创建一个ab可执行文件,而不是编译时,例如:

代码语言:javascript
复制
CC = g++ -g

a.o: a.c
    gcc -o a.o -c a.c

b.o: b.cc
    $(CC) -o b.o -c b.cc

ab: a.o b.o
    $(CC) -o ab a.o b.o

更新:把它分解成最简单的测试用例,这样你就能明白我的意思了:

代码语言:javascript
复制
a.c:
    #include <stdio.h>
    void print(void) {
        printf ("7\n");
    }

b.cc:
    extern "C" void print(void);
    int main(void) {
        print();
        return 0;
    }

Makefile:
    output: a.o b.o Makefile
        g++ -o output a.o b.o

    a.o: a.c Makefile
        gcc -o a.o -c a.c

    b.o: b.cc Makefile
        g++ -o b.o -c b.cc

然后运行make和程序:

代码语言:javascript
复制
pax> make
gcc -o a.o -c a.c
g++ -o b.o -c b.cc
g++ -o output a.o b.o

pax> ./output
7

如果您将a.c的编译更改为使用g++,则会在无法找到print的位置生成原始错误

代码语言:javascript
复制
pax> make
g++ -o a.o -c a.c
g++ -o b.o -c b.cc
g++ -o output a.o b.o
b.o:b.cc:(.text+0x2b): undefined reference to `_print'
collect2: ld returned 1 exit status
make: *** [output] Error 1

现在看来,您最终的Makefile是正确的。它使用C编译器编译a.c,这样就不会发生名称损坏。我的建议是清除所有内容(删除所有*.o文件),然后再次运行make,然后将输出发布到问题的底部。

这可能是一些文件是旧的,这就是为什么您应该在运行make之前删除所有目标文件。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3723863

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档