c/c++在windows下编译:使用visual studio从0构建项目
梳理了一下构建visual studio项目的全过程,其中包括了大部分编译的常规操作。
文章目录
前言
梳理了一下构建visual studio项目的全过程,其中包括了大部分编译的常规操作。
一、项目简介
项目由一个主函数,一个静态库和动态库组成。
main文件夹:main.cpp
#include"add.h"
#include"multi.h"
#include<stdio.h>
int main()
{
int a=5;
int b=2;
int num1=add(a,b);
int num2=sub(a,b);
int num3=multi(a,b);
int num4=mod_a(a,b);
#ifdef DEBUG
printf("a+b=%d a-b=%d a*b=%d a%%b=%d\n",num1,num2,num3,num4);
#endif
}
shared文件夹下:add.h add.cpp print_add.h print_add.cpp
add.h
#ifndef _ADD_H_
#define _ADD_H_
#ifdef EXPORTS
#define WIN_API __declspec(dllexport)
#else
#ifdef WIN32
#define WIN_API __declspec(dllimport)
#else
#define WIN_API
#endif
#endif
int WIN_API add(int a,int b);
int WIN_API sub(int a,int b);
#endif
print_add.h
#ifndef _PRINT_ADD_H_
#define _PRINT_ADD_H_
void print_add(int a);
void print_sub(int a);
#endif
add.cpp
#include "add.h"
#include"print_add.h"
int add(int a,int b)
{
int result = a+b;
print_add(result);
return result;
}
int sub(int a,int b)
{
int result = a-b;
print_sub(result);
return result;
}
print_add.cpp
#include "print_add.h"
#include <stdio.h>
void print_add(int a)
{
printf("add result is:%d\n",a);
}
void print_sub(int a)
{
printf("sub result is:%d\n",a);
}
static文件夹下:multi.h print_multi.h multi.cpp print_multi.cpp
multi.h
#ifndef _MULTI_H_
#define _MULTI_H_
int multi(int a,int b);
int mod_a(int a,int b);
#endif
print_multi.h
#ifndef _PRINT_MULTI_H
#define _PRINT_MULTI_H_
void print_multi(int a);
void print_mod(int a);
#endif
multi.cpp
#include"multi.h"
#include"print_multi.h"
int multi(int a,int b)
{
int result=a*b;
print_multi(result);
return result;
}
int mod_a(int a,int b)
{
int result=a%b;
print_mod(result);
return result;
}
print_multi.cpp
#include"print_multi.h"
#include<stdio.h>
void print_multi(int a)
{
printf("multi result is:%d\n",a);
}
void print_mod(int a)
{
printf("mod result is:%d\n",a);
}
二、使用visual studio进行编译
1.从0构建项目
创建空项目
打开visual studio—》创建新项目–》空项目–》项目名称
选择模式:release/debug 平台:x86/x64
创建shared动态库
右击解决方案–》添加–》新建项目–》空项目–》项目名称
右击头文件和源文件–》添加新建项或现有项
配置属性:右击shared工程—》属性
1)配置属性–》常规–》设置输出目录/配置类型/选择平台
注意: 输出目录仅是dll生成的目录。
2)c/c+±-》常规–》附加包含目录
添加dll所需的所有头文件,在工程中的头文件添加了,这里可以不添加
c/c+±->预处理器–》预处理器定义
添加导出.lib需要的宏 EXPORTS
3)链接器–》高级–》导入库
生成.lib时存放的路径
创建static静态库
1)配置属性–》常规
2)c/c++ --》常规–》附加包含目录(设置头文件)
创建exe
- 配置属性–》常规
注意: visual studio的版本要大于等于编译静态库和动态库的版本。
2)c/c++ --》附加包含目录(添加头文件,相当于g++ -I)
c/c++ -》预处理器(添加宏DEBUG,相当于g++ -D)
3)链接器–》常规–》附加库目录(生成静态库和动态库lib的目录,相当于g++ -L)
链接器–》输入–》附加依赖项(添加依赖库shared.lib static.lib 相当于g++ -l)
运行工程
右击main函数工程–》设为启动项
右击main函数工程–》生成依赖项–》项目依赖项–》勾选依赖的动态库和静态库
点击生成,可生成exe 静态库.lib和动态库.lib .dll
运行bin 需将.dll拷贝到bin目录下或者将.dll的目录添加环境变量
visual studio工程中生成的文件*.sln *.vcxproj *.filters *.user
*.sln: visual studio的解决方案文件,整个项目中生成一个,其中包含了每一个工程的工程文件。
*.vcxproj: 工程文件,描述了工程中的各项属性(通过右击工程配置的各项属性),每一个工程当中都会生成一个,修改该文件工程会重新编译。
*.filters: 视图文件,定义了工程打开后的目录结构,包括源文件和头文件的路径,修改该文件工程不会重新编译。
*.user: 是本地化用户配置,允许多个用户使用自己喜好的方式配置这个项目(例如打开项目时候窗体位置等与项目内容无关的配置)。
2.编译动态库的注意事项
关于lib和dll的区别
编译动态库时会同时生成.lib和.dll,.lib是链接动态库使用,.dll是运行程序时使用的,.lib中是一些索引信息,记录dll中函数的入口和位置,dll中是函数的具体内容;
编译静态库时只会生成.lib,其中索引和实现都在.lib当中,编译时直接将它编译到程序中,运行时可直接运行。
__declspec(dllexport),__declspec(dllimport)的作用
__declspec 是visual c++提供的在visual studio 编程环境的关键字:
dllexport的作用:生成动态库所用关键字,一个动态库对外提供的函数接口加上他,.dll会导出该函数的符号表,生成导出库.lib;如果没有它则不会导出.lib只会生成.dll,而且生成的.dll中没有符号表。
dllimport的作用:调用动态库中的函数所用关键字,会优化编译的代码,能够链接类中的静态变量。多数情况没有它也能正常工作。
下面是跨平台的宏定义:
#ifdef EXPORTS //导出动态库需要添加的关键字
#define WIN_API __declspec(dllexport) //导出动态库使用的关键字
#else
#ifdef WIN32
#define WIN_API __declspec(dllimport) //如果是windows平台,使用动态库的关键字
#else
#define WIN_API //如果是linux平台则不需要使用该关键字,以空格替换
#endif
#endif
.def文件的作用
导出动态库的方法有两种,一种时在导出函数前面加上__declspec(dllexport),另一种就是将导出函数定义到.def文件当中。
.def文件的格式:
LIBRARY shared_dll //动态库的名称,shared.dll写成shared_dll
EXPORTS //需要导出的函数
add //函数的先后顺序与导出符号表的先后顺序是一致的
sub
将.def文件加载到动态库的属性当中
右击动态库工程–>属性–>链接器–>模块定义文件
加上后也能生成带符号表的动态库.dll和导出库.lib。
3.查看函数符号表的命令
dumpbin.exe 是微软二进制文件转储器。显示有关通用对象文件格式的二进制文件的信息。通过vs的开发工具能够直接使用
dumpbin /dependents *.dll *.exe 查看依赖的动态库
dumpbin /exports *.dll *.lib 查看动态库函数表
dumpbin /symbols *.lib 查看静态库函数表
可以看到静态库的很多信息,很杂,需要找找才能找到自定义函数的符号表
dumpbin /LINKERMEMBER *.lib 看动态库和静态库的符号表
dumpbin /LINKERMEMBER static.lib
dumpbin /LINKERMEMBER shared.lib
这些命令除了查看函数表还有很多其他用途,目前没有仔细研究。
完整的选项可移步至MSDN文档查看
https://docs.microsoft.com/en-us/cpp/build/reference/dumpbin-options?view=vs-2017
4.使用MSBuild来编译项目
构建好了一个visual studio工程项目后,我们能够打开这个项目工程来在界面当中进行编译,也能用MSBuild通过脚本来进行编译:
以visual studio2019为例 MSBuild所在路径:C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\MSBuild.exe 后面跟着.sln则进行整个项目的编译,如果后面跟*.vcxproj则编译单个工程如单独编译静态库,或动态库。
通过 /p选项可以配置编译的一些属性:
/t:Rebuild 表示每次都重建,不使用增量编译,不使用则文件有修改才会编译
/p:Configuration=Debug表示编译 Debug版本
/p:Platform=x86 指定平台
set build_project="C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\MSBuild.exe" %cd%\gcc_testv.sln /p:Configuration=Debug;Platform=x86
%build_project%
总结
visual studio提供了windows编程的全套解决方案,在windows环境中进行编译非常方便。
更多推荐
所有评论(0)