前言

梳理了一下构建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

  1. 配置属性–》常规
    在这里插入图片描述注意: 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环境中进行编译非常方便。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐