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

推荐订阅源

SecWiki News
SecWiki News
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
V
Visual Studio Blog
博客园 - 叶小钗
S
SegmentFault 最新的问题
IT之家
IT之家
大猫的无限游戏
大猫的无限游戏
博客园_首页
Apple Machine Learning Research
Apple Machine Learning Research
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
月光博客
月光博客
酷 壳 – CoolShell
酷 壳 – CoolShell
腾讯CDC
D
Darknet – Hacking Tools, Hacker News & Cyber Security
V
V2EX
阮一峰的网络日志
阮一峰的网络日志
L
Lohrmann on Cybersecurity
量子位
C
Cyber Attacks, Cyber Crime and Cyber Security
T
Tor Project blog
J
Java Code Geeks
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
博客园 - 三生石上(FineUI控件)
Attack and Defense Labs
Attack and Defense Labs
AI
AI
The Cloudflare Blog
T
Tailwind CSS Blog
S
Schneier on Security
爱范儿
爱范儿
PCI Perspectives
PCI Perspectives
Stack Overflow Blog
Stack Overflow Blog
S
Secure Thoughts
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
T
The Exploit Database - CXSecurity.com
博客园 - 【当耐特】
V2EX - 技术
V2EX - 技术
S
Securelist
P
Proofpoint News Feed
T
Threat Research - Cisco Blogs
Help Net Security
Help Net Security
C
Cisco Blogs
N
News and Events Feed by Topic
人人都是产品经理
人人都是产品经理
B
Blog RSS Feed
K
Kaspersky official blog
T
The Blog of Author Tim Ferriss
G
Google Developers Blog
S
Security Affairs
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Simon Willison's Weblog
Simon Willison's Weblog

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

【琐记】烟火与尘埃 【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,并指明哪一篇博客,我看到一定及时回复!