序言
-
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
发布版和调试版,调试版为/MDd/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:动态库
实现一个库函数
math.h
#ifdef MATH_H
#define MATH_H
extern int add(int, int);
#endif
math.cpp
#include "math.h"
int add(int p1, int p2){
return p1+p2;
}
编译成静态库
@rem 静态库的编译
@rem 编译
@cl /c /EHsc /MD /nologo /source-charset:utf-8 /execution-charset:utf-8 /Fo:math.obj math.cpp //输出文件名
@rem 静态库链接
lib /MACHINE:X64 /nologo /OUT:math.lib math.obj
代码的组织
-
使用shell脚本或者bat处理脚本,比较麻烦的是多个操作需要写成多个bat文件;实际引入一个专门的工程组织脚本Makefile;
-
工程组织的方式:
- 通用
- Makefile(一个环境开发)
- CMake(多个环境)
- QMake
- 个性化:
- Visual Studio
- Qt Creator
- QMake
- Eclipse C++
- C++ Builder
- 通用
-
Makefile脚本的语法:Makefile(强制的文件名)
- 定义变量
- 任务(Task)
- 依赖(任务依赖另外一任务)
- 指令
-
Makfile例子
makefile的命令行前为tab,而不是空格;
下面\(退格符)的后面不能有空格
CL_FLAGS = /c \
/EHsc \
/MD \
/nologo \
/source-charset:utf-8 \
/execution-charset:utf-8
LINK_FLAGS = /MACHINE:X64 \
/nologo
OBJS = math.obj
SOURCES = math.cpp
TARGETS = math.lib
main:$(TARGETS) main.cpp
@ cl /nologo /MD /Fe:main.exe main.cpp $(TARGETS)
$(TARGETS):$(OBJS)
@lib $(LINK_FLAGS) /OUT:$(TARGETS) $(OBJS)
$(OBJS): math.h math.cpp
@cl $(CL_FLAGS) /Fo:$(OBJS) $(SOURCES)
clean:
@del *.exe *.obj *.lib 2>/Nul
使用静态库
- 在链接的时候使用静态库
#include <stdio.h>
#include "math.h"
//
int main(int argc, char **argv, char **arge){
printf("C++程序编程!静态库调用结果:%d\n", add(45,55));
return 0;
}
关于int main(int argc, char **argv)
**argc是参数个数,定义为int
argv是字符串数组,存的是参数,定义为char***或者char argv[]
比如编译好的程序为my.exe
命令行下运行可执行文件的一般形式为:可执行文件名 参数 参数……,在命令行执行my.exe 1 2 3
那argc就是4,argv[0]是"my.exe",argv[1]是"1",argv[2]是"2",argv[3]是"3"
main函数可以带参数,这个参数可以认为是 main函数的形式参数。
C语言规定main函数的参数只能有两个, 习惯上这两个参数写为argc和argv。
规定argc(第一个形参)必须是整型变量,argv( 第二个形参)必须是指向字符串的指针数组。
由于main函数不能被其它函数调用, 因此不可能在程序内部取得实际值。那么,在何处把实参值赋予main函数的形参呢? 实际上,main函数的参数值是从操作系统命令行上获得的。当我们要运行一个可执行文件时,在命令行键入文件名,再输入实际参数即可把这些实参传送到main的形参中去。
- 编译脚本
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 "math.h"
#pragma comment(lib, "math.lib")
int main(int argc, char **argv, char **arge){
printf("C++程序编程!静态库调用结果:%d\n", 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开始)
- 伪任务目标:
- 文件不存在
- 任务目标:依赖
- 开发工具
动态库
实现代码
- math.h文件
#ifdef MATH_H//宏
#define MATH_H
extern int myadd(int, int);
#endif
- math.cpp文件
#include "math.h"
int 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输出名字
-
编译脚本 makefile
#编译选项设置一个变量
CL_FLAGS = /EHsc /MD /source-charset:utf-8 /execution-charset:utf-8 /nologo
#链接选项设置一个变量
LINK_FLAGS = /MACHINE:X64 /NOLOGO /DLL
#文件设置成变量
SOURCES = math.cpp
OBJS = math.obj #目标文件
OUTLIBS = math.lib #输出
OUTDLLS = math.dll
$(OUTDLLS):$(SOURCES)
@cl /c $(CL_FLAGS) /Fo:$(OBJS) math.cpp
@link /MACHINE:X64 /NOLOGO /DLL /OUT:$(OUTDLLS) /IMPLIB:$(OUTLIBS) /EXPORT:myadd $(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("math.dll");
if (h == NULL){
printf("加载失败!\n");
return -1;
}
printf("加载成功!");
// 查找函数
FARPROC f = GetProcAddress(h, "myadd"); // ?myadd@@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 : 指定头文件的路径
@cl /c /utf-8 /nologo /MD /Fo:call_manual_dll.obj call_manual_dll.cpp
@link /NOLOGO /OUT:main.exe /DYNAMICBASE Kernel32.lib call_manual_dll.obj
动态库的调用方式2
- 在编译的时候调用函数(根本不需要dll,只需要lib,但是运行的时候需要dll,不需要lib)较为简洁
#include <stdio.h>
#include "math.h"
#pragma comment(lib, "math.lib") // 强调,不推荐使用
int main(int argc, const char*argv[]){
printf("调用结果:%d\n", myadd(55,55));
return 0;
}
Qt编译环境设置
-
掌握的重点:
- GUI (Qt应用 + QtWidgets(QDialog))
-
Qt程序qmain.cpp
#include <iostream>
#include <QtWidgets/QApplication>
#include <QtWidgets/QDialog>
//QtGUI模块:QtWidgets
//Qt底层模块:QtCore
//Qt图形的绘制模块QtGui
int main(int argc, char**argv){
//构建qt应用:
QApplication app(argc, argv);
//窗体创建QDialog
QDialog dlg;
//窗体的属性(函数对
dlg.setWindowTitle("Qt开发");
dlg.resize(640,480);
dlg.move(200,200);
dlg.show();
//消息循环处理
int status = app.exec();//block函数 消息循环
//退出程序,返回状态码给系统0-255(-1=255)
return status;
}
- Qt编译
INCLUDES = /I "D:\Qt\5.13.0\msvc2017_64\include"
LIBS = /LIBPATH:"D:\Qt\5.13.0\msvc2017_64\lib" \
/DYNAMICBASE \
"Qt5Widgetsd.lib" \
"Qt5Guid.lib" \
"Qt5Cored.lib"
CL_ARGS = /EHsc\
/MDd \
/source-charset:utf-8 \
/execution-charset:utf-8 \
/nologo
LINK_ARGS = /MACHINE:X64 /NOLOGO
main:qmain.cpp
@cl /c $(CL_ARGS) /Fo:main.obj $(INCLUDES) qmain.cpp
@link $(LINK_ARGS) $(LIBS) /OUT:main.exe main.obj
clean:
@del *.exe *.obj *exp 2>/Nul
OpenCV的环境
-
cmake configure
-
generate
-
VS2019 打开:BUILD_ALL / INSTAL 重新生成
作业
-
写Qt程序,并编译链接成执行文件,且能执行成功;
- 动态的使用
- 编译器/连接器
-
作业
#include <iostream>
#include <QtWidgets/QApplication>
#include <QtWidgets/QDialog>
int main(int argc, char**argv){
//构建qt应用:
QApplication app(argc, argv);
//窗体创建QDialog
QDialog dlg;
//窗体的属性(函数对
dlg.setWindowTitle("Qt开发");
dlg.resize(640,480);
dlg.move(200,200);
dlg.show();
//消息循环处理
int status = app.exec();//block函数 消息循环
//退出程序,返回状态码给系统0-255(-1=255)
return status;
}
INCLUDES = /I "D:\Qt\5.13.0\msvc2017_64\include"
LIBS = /LIBPATH:"D:\Qt\5.13.0\msvc2017_64\lib" \
/DYNAMICBASE \
"Qt5Widgetsd.lib" \
"Qt5Guid.lib" \
"Qt5Cored.lib"
CL_ARGS = /EHsc\
/MDd \
/source-charset:utf-8 \
/execution-charset:utf-8 \
/nologo
LINK_ARGS = /MACHINE:X64 /NOLOGO
main:qmain.cpp
@cl /c $(CL_ARGS) /Fo:main.obj $(INCLUDES) qmain.cpp
@link $(LINK_ARGS) $(LIBS) /OUT:main.exe main.obj
clean:
@del *.exe *.obj *exp 2>/Nul
如果出现 qt.qpa.plugin: Could not find the Qt platform plugin “windows” in""
解决:windeployqt main.exe