打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
基于CMake,交叉编译C、C++

嵌入式开发,尤其SOA(Service Oriented Architecture,面向服务架构)的工程开发中,会碰到这样一种的场景:一部分业务功能使用C开发,且比较成熟,想直接复用。但是,业务层获取的底层服务是C++编写,如果要将两者放到一个进程里,需要将C、C++对应的源码交叉编译生成可执行文件。本文,针对C和C++交叉编译展开聊聊。

1、C与C++区别

首先,我们知道:C是面向过程(Procedure Oriented,简称PO)的编程语言,而C++是面向对象(Object Oriented ,简称OO)的编程语言。C++可以看作C的超集,C++包含了更多的特性。

(一)PO与OO的区别

  • PO优势:效率更高,因为PO语言(eg:C语言)不用实例化对象,消耗的资源更少;

  • PO不足:移植性差,维护成本高。

  • OO优势:复用性高,维护成本低;

  • OO不足:效率低,使用之前,需要先实例化一个对象(Object)。

2、编译原理

不管是C还是C++,这些易于人类阅读的高级语言,终究要进行编译,最终转换成机器可识别的二进制语言

编译一般分为四个步骤预处理->编译->汇编->链接
(一)预处理

预处理由预处理器(Preprocessor)处理,删除注释,引入头文件或者包,将宏定义内容在源文件(*.c、*.cpp等)中进行替换。

(二)编译

汇编阶段,编译器(Compiler)将经过预处理的高级语言翻译成机器可识别的汇编语言。

(三)汇编

由汇编器(Assembler),将汇编语言转换成机器语言(二进制文件),并进行重定位(Relocatable)。再由加载器(Loader)将重定向后的指令数据放到内存指定位置

(四)链接

最终,由链接器(Linker)将多个可重定位的机器代码文件(包括库文件)连接到一起形成可执行文件。

编译过程,如下所示:

3、基于CMake,进行C、C++交叉编译

说明:主函数(main.cpp)使用C++编写,并在main()中调用C编写的add()接口。文件结构如下所示:

提示:Windows下,获取某个文件夹下的文件结构,可以使用命令:Get-ChildItem . -recurse
(一)文件内容
1、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
如上,为了实现C和C++的混合编程,需要在头文件中,使用extern "C"。extern “C”是C++提供的一个连接交换指定符号,用于告知编译器:这是C编写的函数。extern “C”后面声明的函数,不再使用C++编译的修饰符。因为C++编译后,函数名会增加额外的修饰符,而C语言生成的函数不含额外的修饰符,因此,两者对同一个函数编译后的名称不同,这样,就使得C++无法直接调用C函数。
2、Cal.c文件
#include "Cal.h"
int add(int x,int y){ return (x + y);}
与Cal.c相同文件夹(src)下的CMakeLists.txt文件内容如下所示:
# 查找当前目录下的所有源文件,并将名称保存到 CUR_DIR_SRCS 变量aux_source_directory(. CUR_DIR_SRCS)# 生成链接库add_library (Cal ${CUR_DIR_SRCS})
target_include_directories(Cal PUBLIC "../include/")
3、main.cpp文件
#include <iostream>#include "Cal.h"
int main(){
int result; calOpt optFunc = add;    /* 通过函数指针调用add函数 */ result = optFunc(0x10, 0x20);
std::cout << "result = " << result << std::endl; return 0;}
与main.cpp相同文件夹下的CMakeLists.txt文件内容如下所示:
# cmake最低版本要求cmake_minimum_required(VERSION 3.10)
# 设置项目名称和版本号project(CMake_Pro)
# 设置使用C++标准版本set(CMAKE_CXX_STANDARD 11)set(CMAKE_CXX_STANDARD_REQUIRED True)
set(ENV{myEnvVar} "80")
MESSAGE(STATUS "myEnvVar: $ENV{myEnvVar}")# 添加src子目录add_subdirectory(src)
# 编译源码生成目标add_executable(CMake_Pro main.cpp)# 包含头文件路径target_include_directories(CMake_Pro PUBLIC "./include/")# 添加链接库target_link_libraries(CMake_Pro Cal)
4、运行编译的批处理脚本(*.bat)
@echo off
set buildDir=build
@REM build的文件夹不存在则创建if not exist %buildDir% md %buildDir%
if exist %buildDir% cd %buildDir%echo "***************:Execute cmake ***************"cmake -G"Unix Makefiles" ../echo "***************:Execute make ***************"make
pause
(二)编译
运行CMake_Build.bat脚本,编译过程如下所示:

可以看出,如上编译过程中,先将Cal.c文件编译成静态库文件(libCal.a),最终在链接的时候,链接器将其链接成一个完整的可执行文件。这样处理的好处:保留了原有C文件的高效
运行结果:

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
make makefile cmake qmake都是什么,有什么区别
【AI白身境】只会用Python?g++,CMake和Makefile了解一下
C 语言的单元测试与代码覆盖率
PX4飞控学习与开发(六)-利用 VScode 修改源码_vscode编译px4
C老头和Java小子的硬盘夜话
gcc编译 .s文件和.S文件有什么区别
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服