欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

C 语言项目调用 C++ 库的解决方案 - B:用 Cmake 编译和运行

最编程 2024-04-22 16:53:40
...

在工程根目录,将CMakeList.txt内容替换为

# CMakeList.txt
cmake_minimum_required (VERSION 3.5)
project (demo)
include_directories (${PROJECT_SOURCE_DIR}/include)  # 指定头文件目录
find_library(Hello_LIB hello HINTS ${PROJECT_SOURCE_DIR}/bin) # 引入libhello.a静态库
set (hello_List ${PROJECT_SOURCE_DIR}/src/main.c)
add_executable (Hello ${hello_List})  # 默认gcc 编译 main.c
target_link_libraries (Hello ${Hello_LIB} stdc++)

命令行运行:

cd build
cmake ..
make
./Hello

A B 两种方式均输出结果: 至此C语言工程能够成功调用C++库

以上A B两种方式中均出现 stdc++ ,一般以libstdc++.so的方式存在,是C++标准库。

可以看下图 “G++ and GCC”

“G++ and GCC”

GCC在编译时不会自动链接 C++ 标准库, 因此hello.cpp用到的 类似 "iostream"等C++标准库需要手动链接,否则会出现以下错误:

二、C++库为第三方库,无法编辑的情况

在《一、C++库可以编辑的情况》 中提到 【①需要注意的是 “ 将C++标准库放在该cpp文件中”】 是因为 GCC编译不仅找不到C++标准库 stdc++ ,也找不到C++标准库的头文件。如果在hello.h中引用“iostream", 那么用GCC编译C语言工程时,会报找不到头文件错误。

// hello.h
#include "stdio.h"  
#include "iostream"  // 这里出现了C++标准库
void sayHello();

但是当我们想用的C++库为第三方库,而它在头文件里引用了大量C++标准库的情况下,该如何处理呢?

再看图 “G++ and GCC”,里面指明G++编译器能够编译C和C++文件,且能够自动链接C++标准库。所以在这种情况下,只需要在编译C语言工程的时候,指定G++为编译器(编译C文件默认使用的是GCC编译器)就可以了。

下面是与《一、C++库可以编辑的情况》相似的总体流程(有修改的地方会有注释):

// hello.cpp
#include "hello.h"  // C++ 标准库头文件转移到 hello.h 中
using namespace std;
void sayHello(){
    cout<< " # iostream: i am saying hello !" << endl;
    printf(" # c: i am saying hello !\n");
}

创建 hello.cpp 文件,实现 sayHello() 功能,分别用C++标准库和C标准库的输入输出功能打印 hello!

// hello.h
#include "stdio.h" 
#include "iostream"  // C++ 标准库出现在这里
void sayHello();

 创建头文件 hello.h

以上 hello.h 和 hello.cpp 模拟了C++库。为了使C语言工程能够调用该库,需要增加一个中间层:

// helloWapper.cpp
#include "helloWapper.h"
void Wapper_sayHello(){
        sayHello();
}

 创建中间层 helloWapper.cpp , 对想要使用的C++库函数进行封装,即: 通过 Wapper_sayHello() 调用 sayHello()

// helloWapper.h
#include "hello.h"
#ifdef __cplusplus
extern "C"{
#endif
    void Wapper_sayHello();
#ifdef __cplusplus
}
#endif

创建中间层头文件 helloWapper.h,暴露 Wapper_sayHello() 接口。中间出现的 extern "C" {} 是告诉G++编译器,对中间的函数按照C语言的方式进行编译。

然后将上述两个CPP文件编译成 静态库 ,使用的 CMakeLists.txt 文件如下:        

cmake_minimum_required (VERSION 3.5)
project (demo)
include_directories (${PROJECT_SOURCE_DIR}/include ) # 指定头文件位置
set (test_call_LIST ${PROJECT_SOURCE_DIR}/src/hello.cpp
                    ${PROJECT_SOURCE_DIR}/src/helloWapper.cpp)  # 指定需要编译的CPP文件
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) # 指定库输出路径
add_library(hello STATIC ${test_call_LIST}) # 编译

所有文件结构如下:

在工程根目录输入:

mkdir build & cd build
cmake .. 
make 

bin文件夹下就会出现 封装好的库 libhello.a

创建mian.c来模拟C语言工程:

#include "stdio.h"
#include "helloWapper.h"  // 调用C++库接口
int main(){
    Wapper_sayHello();
    return 0;
}

推荐阅读