序言
-
IDE工具
- VSCode
- 语法检测:头文件(include头文件) + 编译内置的语法
- 添加头文件检测:ctrl + shift + p->C++配置编辑,添加头文件所在目录;
- VSCode
-
控制终端
- 命令
- 环境变量
- PATH: echo %PATH%
- set指令显示所有环境变量
- PATH:window执行程序的搜索的路径;每个路径使用
;
分号分隔 - 有可视化的设置的
-
VisualStudio 开发环境的设置
- 使用脚本的文件来设置,脚本是vcvars64.bat
- 设置vcvars64.bat的目录到PATH环境变量;
PATH=C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build
- 使用可视化设置环境变量,需要重启终端;
-
开发工具
- cl 编译器
- link 连接器 (PE格式)
- lib 库归档工具(静态库:目标文件的归档)
- dumpbin PE与目标文件格式分析工具
工程组织与编译器
-
编译器
cl 源代码
编译/链接为执行文件/EHsc
/MD
/utf-8
/source-charset:utf-8
/execution-charset:utf-8
- 头文件目录
-
说明:
- 第一次你输出,汉字可能是乱码
- 使用chcp命令改变终端的代码页。utf-8的code page= 65001
chcp 65001
- 在区域/语言中直接设置编码(整个系统设置为utf-8)
- opencv不识别中文目录;(系统设置编码)
- 使用chcp命令改变终端的代码页。utf-8的code page= 65001
- 第一次你输出,汉字可能是乱码
-
链接器
- link
- cl负责编译 : 检测语法,生成目标文件
- link负责链接:负责生成PE格式文件,需要信息动态库信息
- link 选项 目标文件s
/out
/MACHINE:X64
- 第三方的库的库目录
- 第三方的库名
- link
静态库
- 前提:lib/dll这两个文件解释清楚;
- lib:静态库
- dll:动态库
实现一个库函数
gk_math.h
#ifndef GK_MATH_H
#define GK_MATH_H
extern int gk_add(int, int);
#endif
gk_math.cpp
#include "gk_math.h"
int gk_add(int p1, int p2){
return p1 + p2;
}
编译成静态库
@rem 静态库的编译
@rem 编译
@cl /c /EHsc /MD /nologo /source-charset:utf-8 /execution-charset:utf-8 /Fo:gkmath.obj gk_math.cpp
@rem 静态库链接
lib /MACHINE:X64 /nologo /OUT:gkmath.lib gkmath.obj
代码的组织
-
使用shell脚本或者bat处理脚本,比较麻烦的是多个操作需要写成多个bat文件;实际引入一个专门的工程组织脚本Makefile;
-
工程组织的方式:
- 通用
- Makefile
- CMake
- QMake
- 个性化:
- Visual Studio
- Qt Creator
- QMake
- Eclipse C++
- C++ Builder
- 通用
-
Makefile脚本的语法:Makefile
- 定义变量
- 任务(Task)
- 依赖(任务依赖另外一任务)
- 指令
-
Makfile例子
CL_FLAGS = /c \
/EHsc \
/MD \
/nologo \
/source-charset:utf-8 \
/execution-charset:utf-8
LINK_FLAGS = /MACHINE:X64 \
/nologo
OBJS = gkmath.obj
SOURCES = gk_math.cpp
TARGETS = gkmath.lib
main:$(TARGETS) main.cpp
@ cl /nologo /MD /Fe:main.exe main.cpp $(TARGETS)
$(TARGETS):$(OBJS)
@lib $(LINK_FLAGS) /OUT:$(TARGETS) $(OBJS)
$(OBJS): gk_math.h gk_math.cpp
@cl $(CL_FLAGS) /Fo:$(OBJS) $(SOURCES)
clean:
@del *.exe *.obj *.lib 2>/Nul
使用静态库
- 在链接的时候使用静态库
#include <stdio.h>
#include "gk_math.h"
int main(int argc, char **argv, char **arge){
printf("C++程序编程!静态库调用结果:%d\n", gk_add(45, 55));
return 0;
}
- 编译脚本
CL_FLAGS = /c \
/EHsc \
/MD \
/nologo \
/source-charset:utf-8 \
/execution-charset:utf-8
LINK_FLAGS = /MACHINE:X64 \
/nologo
OBJS = gkmath.obj
SOURCES = gk_math.cpp
TARGETS = gkmath.lib
main:$(TARGETS) main.cpp
@ cl /nologo /MD /Fe:main.exe main.cpp $(TARGETS)
$(TARGETS):$(OBJS)
@lib $(LINK_FLAGS) /OUT:$(TARGETS) $(OBJS)
$(OBJS): gk_math.h gk_math.cpp
@cl $(CL_FLAGS) /Fo:$(OBJS) $(SOURCES)
clean:
@del *.exe *.obj *.lib 2>/Nul
- 在代码中使用静态库
#include <stdio.h>
#include "gk_math.h"
#pragma comment(lib, "gkmath.lib")
int main(int argc, char **argv, char **arge){
printf("C++程序编程!静态库调用结果:%d\n", gk_add(45, 55));
return 0;
}
// cl /nologo /MD /Fe:main.exe main_lib.cpp
- 编译命令:
cl /nologo /MD /Fe:main.exe main_lib.cpp
- 回顾
- 开发工具
-
cl编译器 (mac:clang/g++,posix:gnu g++,hp:acc: intel:cc, sun:cc)
- 默认是调用link默认链接
- /link 后面直接包含link选项
- 默认是调用link默认链接
-
link连接器(posix:ld)
- link步骤很多编译器中默认自动调用
-
lib(ar)
- 静态库
-
dumpbin(nm)
- 分析目标文件与PE执行文件
-
nmake(make)
- nmake task
- nmake task -f makefile文件
-
- vcvars64.bat / vcvars32.bat (mac/linux不需要单独的设置,默认在系统设置)
- 空格转义: “C:\Program Files (x86)\Microsoft Visual Studio”
- makefile的语法
- 任务目标:依赖
- 指令(使用tab开始)
- 伪任务目标:
- 文件不存在
- 任务目标:依赖
- 开发工具
动态库
实现代码
- gkmath.h文件
#ifndef GK_MATH_H
#define GK_MATH_H
extern int gk_add(int, int);
#endif
- gkmath.cpp文件
#include "gkmath.h"
int gk_add(int p1, int p2){
return p1 + p2;
}
编译动态库
-
准备:link选项
- /DLL:不需要main入口
- /IMPLIB : 指定链接的时候产生导入的符号,使用lib静态库的方式存放;
- /EXPORT : 指定哪些函数可以被别人调用
= /DEF:DEF导出函数的描述文件
- /MACHINE:指定CPU结构X64/X86/ARM/ARM64/EBC
- /OUT:指定输出文件名,dll输出名字
-
编译脚本
# 编译选项设置一个变量
CL_ARGS=/EHsc /MD /source-charset:utf-8 /execution-charset:utf-8 /nologo
# 链接选项设置一个变量
LINK_ARGS=/MACHINE:X64 /NOLOGO /DLL
# 文件设置成变量
SOURCES = gkmath.cpp
OBJS = gkmath.obj
OUTLIBS = gkmath.lib
OUTDLLS = gkmath.dll
# 目标指令实现
$(OUTDLLS):$(SOURCES)
@cl /c $(CL_ARGS) /Fo:$(OBJS) gkmath.cpp
@link /MACHINE:X64 /NOLOGO /DLL /OUT:$(OUTDLLS) /IMPLIB:$(OUTLIBS) /EXPORT:gk_add $(OBJS)
clean:
@del *.obj *.lib *.dll *.ilk *.exe *.exp 2>/Nul
动态库的调用方式1
-
直接使用dll调用函数(lib根本不需要,只需要dll) 【不推荐】
-
准备技术:
- HMODULE = LoadLibraryA(LPCSTR dllfilename): 加载动态库到内存
- FARPROC = GetProcAddress(HMODULE hModule, LPCSTR functioname)
- 函数类型转换
- 调用
- 释放dll空间:BOOL FreeLibraray(HMODULE)
-
代码实现
#include <stdio.h>
#include <windows.h>
// typedef int(*type_f)(int,int);
int main(int argc, const char**argv){
// 加载dll模块
HMODULE h = LoadLibraryA("gkmath.dll");
if (h == NULL){
printf("加载失败!\n");
return -1;
}
printf("加载成功!");
// 查找函数
FARPROC f = GetProcAddress(h, "gk_add"); // ?gk_add@@YAHHH@Z
printf("%p\n", f);
// 类型转换
// type_f myfunc = (type_f)f;
int (*myfunc)(int, int) = (int(*)(int, int))f;
// 调用
printf("结果:%d\n", myfunc(45,55));
// 释放模块
FreeLibrary(h);
}
-
编译
-
/I : 指定头文件的路径
动态库的调用方式2
- 在编译的时候调用函数(根本不需要dll,只需要lib,但是运行的时候需要dll,不需要lib)
#include <stdio.h>
#include "gkmath.h"
#pragma comment(lib, "gkmath.lib") // 强调,不推荐使用
int main(int argc, const char*argv[]){
printf("调用结果:%d\n", gk_add(55,55));
return 0;
}