惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
The Exploit Database - CXSecurity.com
F
Fortinet All Blogs
U
Unit 42
F
Full Disclosure
雷峰网
雷峰网
博客园 - 司徒正美
云风的 BLOG
云风的 BLOG
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
Tailwind CSS Blog
The Cloudflare Blog
Last Week in AI
Last Week in AI
罗磊的独立博客
D
DataBreaches.Net
C
Check Point Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
O
OpenAI News
C
CXSECURITY Database RSS Feed - CXSecurity.com
aimingoo的专栏
aimingoo的专栏
S
Security @ Cisco Blogs
大猫的无限游戏
大猫的无限游戏
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
S
SegmentFault 最新的问题
NISL@THU
NISL@THU
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The Hacker News
The Hacker News
Webroot Blog
Webroot Blog
Security Latest
Security Latest
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Google DeepMind News
Google DeepMind News
酷 壳 – CoolShell
酷 壳 – CoolShell
N
News | PayPal Newsroom
P
Proofpoint News Feed
B
Blog RSS Feed
MongoDB | Blog
MongoDB | Blog
C
Cybersecurity and Infrastructure Security Agency CISA
N
News and Events Feed by Topic
Google Online Security Blog
Google Online Security Blog
H
Help Net Security
Spread Privacy
Spread Privacy
T
Threat Research - Cisco Blogs
GbyAI
GbyAI
I
Intezer
Application and Cybersecurity Blog
Application and Cybersecurity Blog
M
MIT News - Artificial intelligence
Vercel News
Vercel News
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
IT之家
IT之家
MyScale Blog
MyScale Blog
腾讯CDC

Пусть этот камень будет более крепким, чем человек

【琐记】烟火与尘埃 【Triton】Triton实现矩阵乘 【LLM推理加速】FlashAttention 【LLM推理加速】PagedAttention 【LLM推理加速】Online Softmax LLM基础知识【1】 Transformer模型 【AI编译】LayerGroup Tiling Tile的疑惑和思考 【AI编译】深度优先的Tile调度,万事大吉? 【AI编译】多级流水线Tile调度策略 【CUDA C++】GPU内存使用【3】 【AI编译】Cache缓存地址映射 【CUDA C++】GPU存储【2】 【CUDA C++】GPU基本介绍【1】 【00】0序章-不受欢迎的来客 【转载】我来了——持续低熵 【Halide】调度优化【2】 【感想】写作进度报告5 【Halide】调度优化【1】 【转载】北大中文男足战报2 【BYOC】TVM切分子图 【转载】北大中文男足战报1 【AI编译】张量生命周期管理 SystemC 用寄存器同步建模方法 【脉动阵列】脉动阵列类型 【im2col】AScend conv accelerate 【感想】写作进度报告4 【BYOC】TVM添加自定义编译器 ccompiler 【感想】写作进度报告3 【Tengine】推理流程脑图【2】 【Tengine】推理流程脑图【1】 【NCNN】学习ncnn模型转换 【编译器】使用llvm编译自定义语言【3】编译 object 【编译器】使用llvm编译自定义语言【2】转llvm IR 【编译器】使用llvm编译自定义语言【1】构建AST 【AI编译】如何进行内存分配 【感想】写作进度报告2 【AI编译】layer-group之后如何tiling 【AI编译】如何进行layer-group 【量化】连续卷积层首尾量化的可行性 【Gemm】内存对齐 【gemm】Gemm计算加速 【TVM】通过代码学习编译流程【5】FuseOps 【TVM】通过代码学习编译流程【6】CodeGen 【TVM】通过代码学习类【3.5】Pass 【TVM】通过代码学习编译流程【4】BuildRelay 【AI编译】Tiling操作能优化什么时间 【TVM】通过代码学习编译流程【3】模型编译 【TVM】通过代码学习编译流程【2】模型转换 【TVM】通过代码学习编译流程【1】必要知识 【感想】写作进度报告1 【Winograd】卷积加速算法原理及实现 SystemC 等待异步事件解决方案 【TVM】Python脚本实现模型编译和保存 【推理引擎】常见AI推理框架 【3D建模】T110E3卡迪夫蓝调皮肤模型 【TVM】C++部署运行TVM 【推理引擎】NCNN和Tengine量化推理逻辑对比 【3D建模】IS-7攻城锤流纹岩皮肤展示 【TVM】根据例子走通代码库 博客汇总目录 【Im2Col】卷积加速算法【2】NHWC 【Im2Col】卷积加速算法【1】 NCHW openBlas库的安装与简单使用 foo Hello World
C语言工程调用Cpp库解决方案
Post author: XianMu@Пусть этот камень будет более крепким, чем ч · 2024-05-14 · via Пусть этот камень будет более крепким, чем человек

本文为 C 语言工程调用 C++ 库的解决方案。

应用场景: 需要 C++ 程序编译成的库提供函数接口,来解决 C 语言工程的需求。

想要快速解决问题,直接看 三、通用解决方法

人的出场顺序真的很重要,很多人如果换一个时间认识,换一个时间共处,一切都将是不一样的场景,不一样的结局。所以,人生有无限种可能,我的人生,是现在这一种。感谢大家恰到好处的出现,组成我最好的一种可能。
------ 大家好啊 我是 暮冬 Z 羡慕

C++ 库由自己编写,可以决定头文件书写的位置

#include "hello.h"
#include "iostream" 
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!

①需要注意的是 “将 C++ 标准库放在该 cpp 文件中”,原因后续指出。

#include "stdio.h"  
void sayHello();

创建头文件 hello.h 这里可以添加 C 语言标准库,但是不要把 C++ 标准库放在这里。

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

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

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

#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)  
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"  
int main(){
    Wapper_sayHello();
    return 0;
}

A:通过命令行进行编译运行

回到工程根目录,编译 main.c , 运行:

cd ..
gcc -o Hello ./src/main.c -I./include -L./bin -lhello -lstdc++
./Hello

B:通过 Cmake 编译运行

在工程根目录,将 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) 
set (hello_List ${PROJECT_SOURCE_DIR}/src/main.c)
add_executable (Hello ${hello_List})  
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 库可以编辑的情况》 中提到 【①需要注意的是 “ 将 C 标准库放在该 cpp 文件中”】 是因为 GCC 编译不仅找不到 C 标准库 stdc ,也找不到 C++ 标准库的头文件。如果在 hello.h 中引用 “iostream", 那么用 GCC 编译 C 语言工程时,会报找不到头文件错误。

#include "stdio.h"  
#include "iostream"  
void sayHello();

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

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

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

#include "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!

#include "stdio.h" 
#include "iostream"  
void sayHello();

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

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

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

#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)  
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"  
int main(){
    Wapper_sayHello();
    return 0;
}

A:通过命令行进行编译运行
回到工程根目录,编译 main.c , 运行:
编译器使用了 g++ ,可以自动搜索 C 标准库路径及链接 C 标准库,因此不需要再加 “-lstdc++”。

cd ..
g++ -o Hello ./src/main.c -I./include -L./bin -lhello
./Hello

B:通过 Cmake 编译运行
在工程根目录,将 CMakeList.txt 内容替换为:

cmake_minimum_required (VERSION 3.5)
project (demo)
SET(CMAKE_C_COMPILER "g++")  
include_directories (${PROJECT_SOURCE_DIR}/include)  
find_library(Hello_LIB hello HINTS ${PROJECT_SOURCE_DIR}/bin) 
set (hello_List ${PROJECT_SOURCE_DIR}/src/main.c)
add_executable (Hello ${hello_List})
target_link_libraries (Hello ${Hello_LIB})

编译、执行:

cd build && cmake ..
make
./Hello

# 通用方法

可以忽略方法一和二。方法三可以采用 GCC 编译调用了 C 库的 C 语言工程。
解决的方法是: 在 中间层 helloWapper.cpp 中引用 C
库头文件 #include "hello.h", 而不是在 helloWapper.h 中引用

例子:
创建 C++ 库源文件

#include "hello.h"  
using namespace std;
void sayHello(){
    cout<< " # iostream: i am saying hello !" << endl;
    printf(" # c: i am saying hello !\n");
}

创建头文件 hello.h

#include "stdio.h" 
#include "iostream" 
void sayHello();

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

其中注意:一定要将 C 库的头文件 "hello.h" 加在 中间层的.cpp 文件中, 而不是放在中间层.h 文件中。这种情况下能够将 "hello.h" 等所有 C 库头文件编译到库当中,防止最后采用 GCC 编译时找不到 g++ 标准库的头文件。

#include "hello.h"  
#include "helloWapper.h"
void Wapper_sayHello(){
        sayHello();
}
#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)  
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"  
int main(){
    Wapper_sayHello();
    return 0;
}

A:通过命令行进行编译运行
回到工程根目录,编译 main.c , 运行:
编译器使用了 gcc ,需要添加 C 标准库 “ -lstdc”(标准库的头文件已经在 C++ 库中了)。

cd ..
gcc -o Hello ./src/main.c -I./include -L./bin -lhello -lstdc++
./Hello

B:通过 Cmake 编译运行
在工程根目录,将 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) 
set (hello_List ${PROJECT_SOURCE_DIR}/src/main.c)
add_executable (Hello ${hello_List})
target_link_libraries (Hello ${Hello_LIB} stdc++)

编译、执行:

cd build && cmake ..
make
./Hello

方法三是最通用的解决方法,不仅仍然可以使用 GCC 编译,而且想要在其他地方调用 C++ 库时,需要的头文件只有 “helloWapper.h” 一个。

# 后记

本博客目前以及可预期的将来都不会支持评论功能。各位大侠如若有指教和问题,可以在我的 github 项目 或随便一个项目下提出 issue,并指明哪一篇博客,我看到一定及时回复!