C和CPP混合编译遇到的问题
一个工程中需要用.c和.cpp文件连接生成一个可执行文件。在项目实践中,经常遇到C和C++混合编程的情况。
一、C和CPP混合编译的Makefile文件编写
将C和C++文件混合在一起编译成可执行文件,makefile文件如下:
.PHONY: all clean
SOURCE := $(shell find ./ -name "*.c") #当前目录下.c文件
SOURCE += $(shell find ../common -name "*c") #共享目录下.c文件
SOURCECPP := $(shell find ./ -name "*.cpp") #当前目录下.cpp文件
OBJS3 := $(SOURCE:%.c=%) #由于需要使用三个不同版本的库,所以生成三个.O
OBJS4 := $(SOURCE:%.c=%)
OBJSN4 := $(SOURCE:%.c=%)
OBJSCPP3 := $(SOURCECPP:%.cpp=%)
OBJSCPP4 := $(SOURCECPP:%.cpp=%)
OBJSCPPN4 := $(SOURCECPP:%.cpp=%)
#DEPS := $(shell find ./ -name "*.h")
BUILD_BIN := ../../bin
#target you can change test to what you want
TARGET3 := $(BUILD_BIN)/v2xcenter3 #目标文件
TARGET4 := $(BUILD_BIN)/v2xcenter4
TARGETN4 := $(BUILD_BIN)/v2xcentern4
#compile and lib parameter
CC := /home/ubuntu/SDK_REPO/prebuilt/toolchain/gcc-4.9-2016.02-x86_64_arm-linux-gnueabi/bin/arm-linux-gnueabi-gcc
CPP := /home/ubuntu/SDK_REPO/prebuilt/toolchain/gcc-4.9-2016.02-x86_64_arm-linux-gnueabi/bin/arm-linux-gnueabi-g++
LIBS := -L../../lib -lpthread -lssl -lcrypto -lmosquitto -lubox -lubus -ljson-c -luci -lzlog -lpcap -ljsonxml #库
LDFLAGS :=
DEFINES :=
INCLUDE := -I./ -I../../include/libubox/ -I../../include/libubus/ -I../../include/json-c/ -I../../include/libuci/ -I../../include/pcap -I../../include -I../common
-I../../include/jsonxml/ #头文件
#不同版本的库文件
LIBS3 := $(LIBS) -lasncodecv3
LIBS4 := $(LIBS) -lasncodec
LIBSN4 := $(LIBS) -lasncodecv4_new
INCLUDE3 := $(INCLUDE) -I../../include/asn1codecv3
INCLUDE4 := $(INCLUDE) -I../../include/asn1codec
INCLUDEN4 := $(INCLUDE) -I../../include/asn1codecv4_new
#编译参数
CFLAGS3 := -g -Wall $(DEFINES) $(INCLUDE3)
CFLAGS3CPP := -g -Wall -std=gnu++11 -fpermissive $(DEFINES) $(INCLUDE3)
CFLAGS4 := -g -Wall $(DEFINES) $(INCLUDE4)
CFLAGS4CPP := -g -Wall -std=gnu++11 -fpermissive $(DEFINES) $(INCLUDE4)
CFLAGSN4 := -g -Wall $(DEFINES) $(INCLUDEN4)
CFLAGSN4CPP := -g -Wall -std=gnu++11 -fpermissive $(DEFINES) $(INCLUDEN4)
CFLAGS := -g -Wall $(DEFINES) $(INCLUDE)
CFLAGSCPP := -g -Wall -std=gnu++11 -fpermissive $(DEFINES) $(INCLUDE)
all: $(TARGET3) $(TARGET4) $(TARGETN4) $(VS_TARGET3) $(VS_TARGET4) $(VS_TARGETN4) $(VC_TARGET)
$(TARGET3) : $(OBJS3) $(OBJSCPP3)
$(CPP) $(CFLAGS3CPP) -o $(TARGET3) $(OBJS3) $(OBJSCPP3) $(LDFLAGS) $(LIBS3)
$(TARGET4) : $(OBJS4) $(OBJSCPP4)
$(CPP) $(CFLAGS4CPP) -o $(TARGET4) $(OBJS4) $(OBJSCPP4) $(LDFLAGS) $(LIBS4)
$(TARGETN4) : $(OBJSN4) $(OBJSCPPN4)
$(CPP) $(CFLAGSN4CPP) -o $(TARGETN4) $(OBJSN4) $(OBJSCPPN4) $(LDFLAGS) $(LIBSN4)
%.o : %.c $(DEPS)
$(CC) $(CFLAGS) -c $< -o $@
% : %.c $(DEPS)
$(CC) $(CFLAGS3) -c $< -o $@ -D VERSION3
% : %.c $(DEPS)
$(CC) $(CFLAGS4) -c $< -o $@ -D VERSION4
% : %.c $(DEPS)
$(CC) $(CFLAGSN4) -c $< -o $@ -D VERSIONN4
%.o : %.cpp $(DEPS)
$(CPP) $(CFLAGSCPP) -c $< -o $@
% : %.cpp $(DEPS)
$(CPP) $(CFLAGS3CPP) -c $< -o $@ -D VERSION3
% : %.cpp $(DEPS)
$(CPP) $(CFLAGS4CPP) -c $< -o $@ -D VERSION4
% : %.cpp $(DEPS)
$(CPP) $(CFLAGSN4CPP) -c $< -o $@ -D VERSIONN4
clean:
rm -f $(OBJS) $(OBJS3) $(OBJS4) $(OBJSN4) $(VS_OBJS3) $(VS_OBJS4) $(VS_OBJSN4) $(TARGET3) $(TARGET4) $(TARGETN4) $(VS_TARGET3) $(VS_TARGET4) $(VS_TARGETN4) $(VC_TARGET) $(OBJSCPP4) $(OBJSCPPN4) $(OBJSCPP3)
二、解决C和CPP混合编译出现undefined reference to的问题
相对简单的混合编译头文件如上,其中编译链接的时候可能会出现undefined reference to的问题,这是因为cpp编译器和c编译本身不是同一个编译器,C和CPP采用不同的编译器,C++编译器在编译.cpp文件时生成的函数名与C编译器在编译.c文件时生成的函数名是不一样的,导致C++代码无法直接调用C的代码,两者混用是会产生不兼容的情况。
解决办法如下:
1、确保C和C++采用的是同类型的编译器,比如C用的是GCC,而CPP采用的是G++;
2、在C的头文件中将C++需要调用的所有函数声明添加extern "C"即可解决;如果反过来在CPP的头文件中将C需要调用的所有函数声明添加extern "C"也可解决。
#ifndef AAAA_H
#define AAAA_H
#ifdef __cplusplus
extern "C" {
#endif
#include<>
void fun();//混合调用的函数
#ifdef __cplusplus
}
#endif/* End of the 'extern "C"' block */
#endif