转换到OS X Mavericks和XCode 5.0.1后,我再也无法优雅地将已编译的C文件(从gcc输出)链接到C ++项目(从g ++输出)。
我的makefile生成的令人讨厌的命令对是:
gcc `pkg-config --cflags glib-2.0` -g -Wall -O3 `pkg-config --cflags flann` -c -o vec.o vec.c
g++ `pkg-config --cflags glib-2.0` -g -Wall -O3 -stdlib=libstdc++ -lstdc++ layoutquality.cpp vec.o `pkg-config --libs glib-2.0` -L/usr/local/Cellar/flann/1.8.4/lib -lflann -o layoutquality
链接器抱怨:
架构x86_64的未定义符号: “load_dmat(char const *)”,引自: _main in layoutquality-I8HOqy.o ld:找不到架构x86_64的符号
其中load_dmat
只是文件vec.c中的一个函数。如果我在第一行中将gcc
替换为g++
,那么所有内容都会编译并链接正常,但clang说:
clang:警告:在C ++模式下将'c'输入视为'c ++',不推荐这种行为
是否有一种无害的,不推荐的编译和链接方式?在升级到OS X Mavericks和新的命令行工具之前,将g++
与来自gcc
的目标文件链接起来工作正常。任何有关改变和如何前进的见解都会很棒,谢谢。
答案 0 :(得分:18)
在“vec.c”之前添加“-x c”(不带引号)应修复它。
如果在同一行中编译多个.c / .cpp文件,则可以在每个C或C ++文件名列表之前使用“-x c”或“-x c ++”来适当地切换上下文。例如:
g++ -x c alpha.c beta.c -x c++ gamma.cpp
答案 1 :(得分:5)
这是一个示例Makefile
,它允许我们在C++
程序中使用C
代码/函数。
CC=clang
CXX=clang++
CFLAGS=-Wall -g
CXXFLAGS=-Wall -g -std=c++11 -I.
DEPS=CPP.h
OBJ=main.o CPP.o
RM=rm -f
# compile only, C source
%.o: %.c
$(CC) -c -o $@ $< $(CFLAGS)
# compile only, C++ source
%.o: %.cpp $(DEPS)
$(CXX) -c -o $@ $< $(CXXFLAGS)
# link
main: $(OBJ)
$(CXX) -o $@ $^ $(CXXFLAGS)
clean:
$(RM) $(OBJ)
如您所见,我们在对编译器的两次单独调用中使用CXXFLAGS
和CFLAGS
分别生成对象。在使用Xcode的clang的Mac环境中,clang(CC
)和clang ++(CXX
)实际上是相同的。只有不同的旗帜很重要。在上面的例子CC
中陈述CXX
和Makefile
的定义,我只是在迂腐。
生成目标文件后,我们可以将它们链接在一起。
但请注意,您必须执行一个额外步骤才能使C++
代码可供C程序使用。
在此示例的CPP.h
中,您必须明确使用extern "C"
来指定C++
代码的链接,以供C
使用。
例如,像这样:
#ifdef __cplusplus
extern "C" {
#endif
double timesTwo(double number);
#ifdef __cplusplus
}
#endif
预处理器宏#ifdef __cplusplus
和#endif
是为了确保我们的头文件不会导致C模式编译错误,并且只在C ++模式编译期间生效。
这个完整的例子只包含4个文件。
上面解释了Makefile
来源和CPP.h
。
为了完整理解,我在此处也包括main.c
和CPP.cpp
。
main.c
:
#include <stdio.h>
#include "CPP.h"
int main()
{
printf("Running main.c\n");
double ans = timesTwo(3.0);
printf("The answer from our C++ timesTwo function, when given 3.0, is %f\n", ans);
return 0;
}
CPP.cpp
:
#include "CPP.h"
double timesTwo(double number)
{
return 2 * number;
}
我相信这个解释和示例阐明了我们如何设置Makefile
,指定#ifdef __cplusplus
预处理器宏和extern "C"
链接声明以允许C ++ - to-C互操作,以及当我们跑步时没有错误的铿锵警告。
答案 2 :(得分:1)
很可能你是Name mangling的受害者。要避免在C ++中进行名称修改,请在声明周围使用extern "C"
,例如:
#ifdef __cplusplus
extern "C" {
#endif
void load_dmat(char const*);
#ifdef __cplusplus
}
#endif