
基于Makefile的C、C++混编
工程开发中,集成是至关重要的一环,很多公司会安排专人做集成工作。一个项目,需要众多开发人员协作,大家各自负责一部分模块,最终将各自模块merge到主线,由集成工程师将所有源码进行集成编译,并释放节点版本。整个集成过程中,可能遇到各种各样的编译问题,这需要集成工程师对编译有一定的了解。本文,基于makefile,讨论如下几个问题:
1. 如何基于makefile混合编译C、C++
2. 如何生成静态链接库(*.a)
3. 如何使用静态链接库。
1、如何基于makefile混合编译C、C++
工程中,有的工程师负责算法,有的工程师负责底层软件,有的工程师负责MCAL...大家负责的模块不同,可能使用的开发语言也不同。比如:算法工程师使用C++开发算法,底层工程师使用C生成底层模块代码。如此,就需要解决一个问题,即:C、C++的混合编译。
(一)示例
本文在Cal.c中定义一个加法运算,在Cal.h文件中声明加法运算。在Sub.cpp中定义一个减法运算,在Sub.hpp中声明减法运算。并将加法和减法函数打包到静态库libmyFun.a中,在main.cpp中调用加法和减法函数。同时,在源文件夹下各自编写Makefile文件,文件结构如下所示(使用 tree /F 命令):
Cal.h文件内容如下所示:
#ifndef _CAL_H_
#define _CAL_H_
typedef int(*calOpt)(int, int);
#ifdef __cplusplus
extern "C"
{
#endif
extern int add(int x,int y);
#ifdef __cplusplus
}
#endif
#endif
Sub.hpp文件内容如下所示:
#ifndef _SUB_HPP_
#define _SUB_HPP_
extern int sub(int x,int y);
#endif
Cal.c文件内容如下所示:
#include "../inc/Cal.h"
int add(int x,int y)
{
return (x + y);
}
Sub.cpp文件内容如下所示:
#include "../inc/Sub.hpp"
int sub(int x,int y)
{
if( x >= y)
{
return (x - y);
}
else
{
return (y - x);
}
}
src文件夹下的Makefile文件内容如下所示:
#指定编译器路径
CROSS_COMPILE = D:/App/Work/Mingw64/mingw64/bin/
#汇编器
AS = $(CROSS_COMPILE)as
#链接器
LD = $(CROSS_COMPILE)ld
CXX = $(CROSS_COMPILE)g++
CC = $(CROSS_COMPILE)gcc
#用于创建,修改和提取档案的实用程序
AR = $(CROSS_COMPILE)ar
#列出目标文件中的符号
NM = $(CROSS_COMPILE)nm
#丢弃的符号
STRIP = $(CROSS_COMPILE)strip
#复制并转换目标文件
OBJCOPY = $(CROSS_COMPILE)objcopy
#显示目标文件中的信息
OBJDUMP = $(CROSS_COMPILE)objdump
export AS LD CXX CC AR NM
export STRIP OBJCOPY OBJDUMP
CFLAGS +=-I. -g -O0 -Wall -fpermissive
#头文件搜索路径
INCLUDE := \
-I ../ \
-I ../inc/
#查找当前路径下所有后缀为.c的文件,保存到SRC_C变量中
SRC_C=$(wildcard *.c)
#查找当前路径下所有后缀为.cpp的文件,保存到SRC_CPP变量中
SRC_CPP=$(wildcard *.cpp)
#将SRC_C变量中.c替换为.o并保存到APP_C_OBJS变量中
APP_C_OBJS=$(SRC_C:.c=.o)
APP_CPP_OBJS=$(SRC_CPP:.cpp=.o)
#生成静态库libmyFun.a需要依赖中间产物APP_C_OBJS和APP_CPP_OBJS
libmyFun.a:$(APP_C_OBJS) $(APP_CPP_OBJS)
$(AR) rcs $@ $^
%.o:%.c
@$(CC) $(INCLUDE) -fPIC -c $< -o $@ $(CFLAGS)
%.o:%.cpp
@$(CXX) $(INCLUDE) -fPIC -c $< -o $@ $(CPPFLAGS)
clean:
rm -rf *.o *.a
main.cpp文件内容如下所示:
#include <iostream>
#include "inc/Cal.h"
#include "inc/Sub.hpp"
int main(){
int result;
calOpt optFunc = add;
/* 通过函数指针调用add函数 */
result = optFunc(0x10, 0x20);
std::cout << "add result = " << result << std::endl;
/* 通过函数指针调用sub函数 */
optFunc = sub;
result = optFunc(0x10, 0x20);
std::cout << "sub result = " << result << std::endl;
return 0;
}
主目录下的Makefile内容如下所示:
#指定编译器路径
CROSS_COMPILE = D:/App/Work/Mingw64/mingw64/bin/
#汇编器
AS = $(CROSS_COMPILE)as
#链接器
LD = $(CROSS_COMPILE)ld
CXX = $(CROSS_COMPILE)g++
CC = $(CROSS_COMPILE)gcc
#用于创建,修改和提取档案的实用程序
AR = $(CROSS_COMPILE)ar
#列出目标文件中的符号
NM = $(CROSS_COMPILE)nm
#丢弃的符号
STRIP = $(CROSS_COMPILE)strip
#复制并转换目标文件
OBJCOPY = $(CROSS_COMPILE)objcopy
#显示目标文件中的信息
OBJDUMP = $(CROSS_COMPILE)objdump
export AS LD CXX CC AR NM
export STRIP OBJCOPY OBJDUMP
LIB_FLAGS += -L./src\
-l:libmyFun.a
#头文件搜索路径
INCLUDE := \
-I ./ \
-I ./inc/
#查找当前路径下所有后缀为.cpp的文件,保存到SRC_CPP变量中
SRC_CPP=$(wildcard *.cpp)
#将SRC_CPP变量中.cpp替换为.o并保存到APP_CPP_OBJS变量中
APP_CPP_OBJS=$(SRC_CPP:.cpp=.o)
TARGETS = main
all: $(TARGETS)
main: $(APP_CPP_OBJS)
$(CXX) $(LIB_FLAGS) $(CPPFLAGS) $(INCLUDE) -o $(TARGETS) -g $(APP_CPP_OBJS) -lmyFun
%.o:%.cpp
$(CXX) $(INCLUDE) -fPIC -c $< -o $@ $(CPPFLAGS)
clean:
rm -rf *.o $(TARGETS)
提示:每行命令之前使用TAB隔开,不是空格
2、如何生成静态链接库(*.a)
混编C、C++,生成libmyFun.a静态库。在src文件夹下执行make命令以后,生成中间产物(Cal.o、Sub.o)与libmyFun.a静态库,文件结构如下所示:
生成静态库,主要由以下语句实现:
#生成静态库libmyFun.a需要依赖中间产物APP_C_OBJS和APP_CPP_OBJS
libmyFun.a:$(APP_C_OBJS) $(APP_CPP_OBJS)
$(AR) rcs $@ $^
如上,生成静态库文件(*.a),需要依赖中间产物(*.o,本例:Sub.o和Cal.o)。
3、如何使用静态链接库
在主目录下执行make命令,如下所示:
这个过程中,链接上一步生成的libmyFun.a静态库,并最终生成可执行文件main.exe,文件结构如下所示:
运行可执行文件,执行结果如下所示:
文章转载自公众号:开心果 Need Car
