CMake进行C/C++与汇编混合编程
1. 前提
这篇文章记录一下怎么用CMake进行项目管理, 并用C/C++和汇编进行混合编程, 为了使用这项技术, 必须在VS的环境中安装好cmake组件

由于大部分人不会使用C/C++与汇编进行混合编程的情况。所以这篇文章并不适用于绝大部分人不会对其中具体细节进行过多叙述。只是做一些简单的记录
2. 配置
创建一个cmake工程

VS是支持多个工程在一个解决方案中的, 目前使用的是单工程。这是我习惯的目录树:
解释一下其中含义:
- include: 所有头文件都将放在这个目录下
- src: 所有源文件都将放在这个目录下
- out/build: 构建项目所生产的中间文件
- install: 最终工程所生产的可执行文件以及库文件, 和必须的文件, 这是最终使用部分可以直接打包
- scripts: 辅助编译链接的脚本
下面我将先用cmake脚本配置一个cpp项目:
首先看一下目录树:
CMakeLists.txt编写:
# cmake的最低版本要求是3.8
cmake_minimum_required (VERSION 3.8)# 项目名称
project (TestJoke)# 设置默认安装路径
if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)set(CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}/install" CACHE PATH "默认安装路径" FORCE)
endif()# 生成可执行文件, 并使用main.cpp和arthmetic.cpp
add_executable(TestJoke main.cpp src/calc/arthmetic.cpp)# 将include/calc包含进头文件目录内
target_include_directories(TestJoke PRIVATE "${CMAKE_SOURCE_DIR}/include/calc")# 生成的目标放到install/bin目录下
install(TARGETS TestJoke DESTINATION bin)# 执行命令TestJoke, 依赖是TestJoke生成, 也就是说TestJoke生成后立马执行TestJoke
add_custom_command(TARGET TestJokeCOMMAND TestJoke DEPENDS TestJoke
)
arthmetic.h编写:
#pragma once #ifdef __cplusplus
extern "C" {
#endif int add(int iNum1, int iNum2);int sub(int iNum1, int iNum2);int div1(int iNum1, int iNum2);int mul(int iNum1, int iNum2);#ifdef __cplusplus
}
#endif
arthmetic.h编写:
#include "arthmetic.h"int add(int iNum1, int iNum2)
{return(iNum1 + iNum2);
}int sub(int iNum1, int iNum2)
{return(iNum1 - iNum2);
}int div1(int iNum1, int iNum2)
{return(iNum1 / iNum2);
}int mul(int iNum1, int iNum2)
{return(iNum1 * iNum2);
}
main.cpp编写:
#include <windows.h>
#include <cstdio>
#include <cstdlib>
#include "arthmetic.h"int main()
{printf("%d", add(12, 8));system("pause");return(0);
}
build.bat脚本编写:
@echo off:: 保存原本的环境变量
setlocal:: 进入out/build构建目录
set BUILD_PATH=%~dp0../out/build/
pushd "%BUILD_PATH%":: 以x86 Debug方式构建项目
cmake ../.. -DCMAKE_BUILD_TYPE=Debug -G "Visual Studio 17 2022" -A Win32
cmake --build . --config Debug
:: 将生成内容安装
cmake --install . --config Debug :: 回到原来目录
popd
:: 恢复原本的环境变量
endlocal
完成之后进入scripts目录执行build.bat脚本就可以发现执行成功了

执行成功后, 可执行文件被安装到了install/bin/目录下, 构建文件在out/build/目录下生成

下面将进行汇编语言的配置, 首先去masm32下载对应的sdk: 下载masm32 sdk
添加汇编代码后的目录树:

stupid.asm内容:
.586
.model flat, C
option casemap:noneinclude windows.inc
include kernel32.inc
include user32.inc
includelib kernel32.lib
includelib user32.lib.data
szCap SBYTE '测试', 0
szMsg SBYTE '这是一个测试', 0.code
MsgBox PROC pszMsg:PTR SBYTE, pszCap:PTR SBYTEpush MB_OKpush pszCappush pszMsg push NULLcall MessageBoxret
MsgBox ENDP
END
完成之后就可以对cmake进行配置
主要是将masm32 SDK的库文件和头文件加入cmake环境变量中
CMakeLists.txt修改后:
# cmakee的最低版本要求是3.8
cmake_minimum_required (VERSION 3.8)# 项目名称
project (TestJoke)# 允许基于masm的Intel汇编
enable_language(ASM_MASM)# 设置默认安装路径
if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)set(CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}/install" CACHE PATH "默认安装路径" FORCE)
endif()# 包含masm32 sdk的头文件目录
include_directories(D:/masm32/include)
# 包含masm32 sdk的库文件目录
link_directories(D:/masm32/lib)# 生成可执行文件, 并使用main.cpp和arthmetic.cpp
add_executable(TestJoke main.cpp src/calc/arthmetic.cpp src/asm/stupid.asm)# 将include/calc包含进头文件目录内
target_include_directories(TestJoke PRIVATE "${CMAKE_SOURCE_DIR}/include/calc")# 生成的目标放到install/bin目录下
install(TARGETS TestJoke DESTINATION bin)# 执行命令TestJoke, 依赖是TestJoke生成, 也就是说TestJoke生成后立马执行TestJoke
add_custom_command(TARGET TestJokeCOMMAND TestJoke DEPENDS TestJoke
)
再次运行构建脚本后发现这个错误, 这是studid.asm出的错, 因为汇编代码无法使用SafeSEH特性, 这里给关掉

在CMakeLists.txt中加入链接选项以此来关闭SafeSEH:
再次运行build.bat后发现如下错误:

由于masm32 sdk开发包中是含有自己的编译器和链接器的。而当我使用VS编写cmake项目的时候使用的是VS自带的编译器和链接器, 这里是VS自带的编译器版本可以看到是14.x
而masm32 SDK开发套件的编译器版本是6.x

不同的编译器对汇编语法可能有细微的不同, 对语法的严格程度也不一样, 为了能适应VS自带版本编译器, 这里我选择修改masm32 sdk的头文件:
首先找到windows.inc并定位到出错行:

这里我选择将其改成宏, 这样可以规避这个问题:

代码如下:
COMP_ELEM_ALL MACROLOCAL temptemp = (COMP_ELEM_TYPE+COMP_ELEM_CHECKED+COMP_ELEM_DIRTY+COMP_ELEM_NOSCROLL)temp = temp + (COMP_ELEM_POS_LEFT+COMP_ELEM_SIZE_WIDTH+COMP_ELEM_SIZE_HEIGHT)temp = temp + (COMP_ELEM_POS_ZINDEX+COMP_ELEM_SOURCE+COMP_ELEM_FRIENDLYNAME)EXITM <temp>
ENDM
接着定位到winextra.inc, 并定位到出错的位置:

将方括号改成圆括号即可:

完成之后发现成功了:

3. 总结与注意点
- 要非常注意名称粉碎的问题, 函数在C++编译后的名称, 与C编译后的名称是完全不同的, 为了确保能够找到对应的名称, 如果你要使用C++特性必须加上extern "C"让C++函数以C的名称粉碎的方式进行
- 汇编语言和C的名称粉碎结果是一样的, 但是调用约定会影响名称粉碎的结果。默认情况下C/C++都用的是C调用约定, 所以你的汇编代码也要用C调用约定, 这也是为啥我用的是.model flat, C了
(完)
相关文章:
CMake进行C/C++与汇编混合编程
1. 前提 这篇文章记录一下怎么用CMake进行项目管理, 并用C/C和汇编进行混合编程, 为了使用这项技术, 必须在VS的环境中安装好cmake组件 由于大部分人不会使用C/C与汇编进行混合编程的情况。所以这篇文章并不适用于绝大部分人不会对其中具体细节进行过多叙述。只是做一些简单的…...
缓存预热!真香
预热一般指缓存预热,一般用在高并发系统中,为了提升系统在高并发情况下的稳定性的一种手段。 缓存预热是指在系统启动之前或系统达到高峰期之前,通过预先将常用数据加载到缓存中,以提高缓存命中率和系统性能的过程。缓存预热的目…...
VS中设置#define _CRT_SECURE_NO_WARNINGS的原因和设置方式
原因: 在编译老的用C语言的开源项目的时候,可能因为一些老的.c文件使用了strcpy,scanf等不安全的函数,而报警告和错误,而导致无法编译通过。 解决方案: 我们有两种解决方案: 1、在指定的源文件的开头定…...
【网站项目】155在线考试与学习交流网页平台
🙊作者简介:拥有多年开发工作经验,分享技术代码帮助学生学习,独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。🌹赠送计算机毕业设计600个选题excel文件,帮助大学选题。赠送开题报告模板ÿ…...
解决IDEA的Project无法正常显示的问题
一、问题描述 打开IDEA,结果发现项目结构显示有问题: 二、解决办法 File -> Project Structure… -> Project Settings (选Modules),然后导入Module 结果: 补充: IDEA提示“The imported module settings a…...
CDF和PDF的比较
以下内容来自ChatGPT,科技改变生活 Cumulative Distribution Function (CDF)(累积分布函数)和 Probability Density Function (PDF)(概率密度函数)是统计学和概率论中两个重要的概念,用于描述随机变量的性…...
编译基本过程 预处理器
编译基本过程 源代码(main.c)->预处理器(cpp)->编译器(gcc/clang/msvc)->汇编器(as)->链接器(ld)->可执行文件(main.exe) 预处理器 C语言中预处理器:执行预处理命令(文件包含、宏替换、条件编译)处理注释(将所有注释替换为空格)处理续行符(将所有…...
模拟算法.
1.什么是模拟 在信息奥赛中,有一类问题是模拟一个游戏的对弈过程或者模拟一项任务的操作过程.比如乒乓球在比赛中模拟统计记分最终判断输赢的过程等等,这些问题通常很难通过建立数学模型用特定的算法来解决因为它没有一种固定的解法,需要深刻理解出题者对过程的解释一般只能采…...
ClickHouse--10--临时表、视图、向表中导入导出数据
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 1.临时表1.1 特征1.2 创建一个临时表 2.视图2.1 普通视图2.2 物化视图 3.向表中导入导出数据3.1 案例 1.临时表 1.1 特征 ClickHouse 支持临时表,临时表…...
Python一些可能用的到的函数系列124 GlobalFunc
说明 GlobalFunc是算网的下一代核心数据处理基础。 算网是一个分布式网络,为了能够实现真的分布式计算(加快大规模任务执行效率),以及能够在很长的时间内维护不同版本的计算方法,需要这样一个对象/服务来支撑。Globa…...
python中线程/线程池,进程/进程池的创建
创建子线程 # 创建子线程t1 threading.Thread(targetjob,args(1,))# 执行子线程t1.start()# 等待子线程执行print("waiting threading")t1.join()print("threading done")创建子进程 # 创建子进程p1 multiprocessing.Process(targetjob,args(1,),name&qu…...
【c++】vector的增删查改
1.先定义一个类对象vector 为了防止和库里面发生冲突,定义一个命名空间,将类对象放在命名空间 里面 #include<iostream> using namespace std; namespace zjw {class vector {public:private:}; }2.定义变量,需要一个迭代器ÿ…...
【研究生复试】计算机软件工程人工智能研究生复试——资料整理(速记版)——JAVA
1、JAVA 2、计算机网络 3、计算机体系结构 4、数据库 5、计算机租场原理 6、软件工程 7、大数据 8、英文 自我介绍 1. Java 1. 和 equals的区别 比较基本数据类型是比较的值,引用数据类型是比较两个是不是同一个对象,也就是引用是否指向同 一个对象&…...
JVM-JVM中对象的生命周期
申明:文章内容是本人学习极客时间课程所写,文字和图片基本来源于课程资料,在某些地方会插入一点自己的理解,未用于商业用途,侵删。 原资料地址:课程资料 对象的创建 常量池检查:检查new指令是否能在常量池…...
RegExp正则表达式左限定右限定左右限定,预查询,预查寻,断言 : (?<= , (?= , (?<! , (?!
RegExp正则表达式左限定右限定左右限定,预查询,预查寻,断言 : (?< , (? , (?<! , (?! 有好多种称呼 (?< , (? , (?<! , (?! 有好多种称呼 , 我称为: 左限定, 右限定, 左否定, 右否定 (?<左限定) (?右限定)(?<!左否定) (?!右限定) 再…...
相机图像质量研究(30)常见问题总结:图像处理对成像的影响--重影
系列文章目录 相机图像质量研究(1)Camera成像流程介绍 相机图像质量研究(2)ISP专用平台调优介绍 相机图像质量研究(3)图像质量测试介绍 相机图像质量研究(4)常见问题总结:光学结构对成像的影响--焦距 相机图像质量研究(5)常见问题总结:光学结构对成…...
问题记录——c++ sort 函数 和 严格弱序比较
引出 看下面这段cmp函数的定义 //按照vector第一个元素升序排序 static bool cmp(const vector<int>& a, const vector<int>& b){return a[0] < b[0]; }int eraseOverlapIntervals(vector<vector<int>>& intervals) {//按区间左端排序…...
《Go 简易速速上手小册》第9章:数据库交互(2024 最新版)
文章目录 9.1 连接数据库 - Go 语言的海底宝藏之门9.1.1 基础知识讲解安装数据库驱动数据库连接 9.1.2 重点案例:用户信息管理系统准备数据库Go 代码实现连接数据库添加新用户查询用户信息用户登录验证主函数 9.1.3 拓展案例 1:批量添加用户准备数据库Go…...
redis的hash数据结构底层简记
hash:k和v都是string的hash表。 HSET(设置集合数据,4.0之前只能设置1个,之后可以设置多个),HSETNX(若k不存在则设置对应v),HDEL(删除指定kv,可以一次删除多个)…...
清除Django的管理员admin站点中“Recent Actions“最近活动面板上的所有信息
清除Django的管理员admin站点中"Recent Actions"最近活动面板上的所有信息 本文主要介绍了如何清除Django的管理员admin站点中"Recent Actions"最近活动面板上的所有信息 操作步骤如下 进入Django项目目录中运行代python manage.py shell进入Django shell…...
Qwen3-ASR-1.7B与QT集成:开发跨平台语音识别桌面应用
Qwen3-ASR-1.7B与QT集成:开发跨平台语音识别桌面应用 1. 引言 想象一下,你正在开发一个需要语音输入功能的桌面应用。传统的语音识别方案要么需要联网调用云端API,要么识别准确率不够理想。现在,有了Qwen3-ASR-1.7B这个强大的开…...
SmolVLA长序列建模效果剖析:对比LSTM在时序预测任务中的表现
SmolVLA长序列建模效果剖析:对比LSTM在时序预测任务中的表现 最近在时间序列预测这个老生常谈的领域里,总有人问我:现在各种基于Transformer的新模型层出不穷,它们真的比LSTM这种“老将”强很多吗?尤其是在处理长序列…...
RVC效果对比实测:原声vs克隆声,你能听出区别吗?
RVC效果对比实测:原声vs克隆声,你能听出区别吗? 1. 引言:AI语音克隆技术的新突破 想象一下,你最喜欢的歌手正在用你的声音唱歌,或者你的播客节目突然有了专业播音员的音色。这不再是科幻场景,…...
Alpamayo-R1-10B保姆级教程:Windows WSL2环境下通过NVIDIA Container Toolkit部署
Alpamayo-R1-10B保姆级教程:Windows WSL2环境下通过NVIDIA Container Toolkit部署 1. 引言:为什么要在Windows上部署自动驾驶AI模型? 如果你对自动驾驶技术感兴趣,或者正在从事相关的研究开发工作,那么Alpamayo-R1-1…...
【Spring 面试突击 · 03】大厂高频面试题:从IoC容器底层原理到Spring Boot自动配置解析
目录 一、Spring Boot如何启动Tomcat? 二、Spring Boot配置文件加载顺序 三、MyBatis的优缺点 四、Hibernate与MyBatis的区别 五、Spring Context模块的理解 六、什么是Spring依赖注入? 七、什么是Spring Bean? 八、Spring AOP与Aspec…...
技术深度:Windows任务栏透明化引擎TranslucentTB架构原理与高级配置指南
技术深度:Windows任务栏透明化引擎TranslucentTB架构原理与高级配置指南 【免费下载链接】TranslucentTB A lightweight utility that makes the Windows taskbar translucent/transparent. 项目地址: https://gitcode.com/gh_mirrors/tr/TranslucentTB Tran…...
OpenClaw多模型混搭方案:百川2-13B-4bits与Qwen在自动化流程中的协同调用
OpenClaw多模型混搭方案:百川2-13B-4bits与Qwen在自动化流程中的协同调用 1. 为什么需要多模型混搭 去年冬天,当我第一次尝试用OpenClaw自动化处理周报时,发现一个尴尬的问题:用同一个模型处理文本润色和代码生成,效…...
给ESP32-S3智能音箱选个好麦克风:从灵敏度到阵列布局的实战避坑指南
给ESP32-S3智能音箱选个好麦克风:从灵敏度到阵列布局的实战避坑指南 在智能家居设备井喷式发展的今天,语音交互已成为人机交互的核心方式之一。作为语音入口的关键部件,麦克风的选择与设计直接决定了用户体验的优劣。本文将深入探讨如何为ESP…...
Zotero-GPT:智能文献处理的技术实现与应用指南
Zotero-GPT:智能文献处理的技术实现与应用指南 【免费下载链接】zotero-gpt GPT Meet Zotero. 项目地址: https://gitcode.com/gh_mirrors/zo/zotero-gpt 一、价值定位:重新定义文献管理的智能化范式 1.1 技术架构的革新突破 Zotero-GPT作为Zot…...
Linux内存管理:malloc与free实现原理详解
Linux内存管理:malloc和free的实现原理深度解析1. 动态内存分配基础1.1 malloc和free函数原型void* malloc(size_t size); void free(void* ptr);malloc函数分配指定字节数的内存空间,返回指向该空间的void指针。由于返回的是通用指针,使用时…...
