zoukankan      html  css  js  c++  java
  • 转 命令行下玩VC

    说明:(1)转载请注明出处:http://www.cnblogs.com/opangle/p/4298155.html

    (2)以下以VS2013为例,并假设VC安装路径为%VC_INSTALL_PATH%(本人的安装目录为D:Program Files (x86)Microsoft Visual Studio 12.0)。

     

    一、环境配置

     

    ■ 方法一:使用MS提供的Developer Command Prompt快捷方式

     

    “开始” => “Visual Studio 2013” => “Visual Studio Tools” => “Developer Command Prompt for VS2013”。

     

    ■  方法二:使用MS提供的vcvarsall.bat脚本

     

    在命令行窗口中进入%VC_INSTALL_PATH%目录,执行“vcvarsall.bat”脚本。

     

    ■  方法三:手动配置环境变量

     

    手动配置环境变量,至少要设置一下三个环境变量:

    ※  PATH:默认情况下cl命令(微软编译器)是不可以使用的,需要将cl.exe文件所在的路径(即%VC_INSTALL_PATH%in目录)添加到PATH环境变量中。

    ※  INCLUDE:默认情况下cl命令不知道从何处查找系统头文件的,该环境变量告诉cl命令从何处查找系统头文件。

    ※  LIB:与INCLUDE环境变量类似,LIB环境变量用来告诉链接器:从何处查找库文件、目标文件等。

     

    本人试过的最小配置如下:

    环境变量

    配置说明(多个路径之间用分号分隔)

    PATH

    将以下路径加入PATH环境变量中:

    %VC_INSTALL_PATH%in

    INCLUDE

    将以下路径加入INCLUDE环境变量中:

    %VC_INSTALL_PATH%include

    C:Program Files (x86)Windows Kits8.1includeshared

    C:Program Files (x86)Windows Kits8.1includeum

    LIB

    将以下路径加入到LIB环境变量中:

    %VC_INSTALL_PATH%lib

    C:Program Files (x86)Windows Kits8.1libwinv6.3umx86

    注:最完整的配置方式可以参考“方法一”、“方法二”中的环境变量配置方式。

     

    ■  测试环境配置

     

    写一个简单的“Hello World”程序(假设为hello.cpp),在命令行下执行:cl hello.cpp,如果能成功生成hello.exe可执行文件,即说明配置成功!

     

    二、常用的命令行选项

     

    下表列出了一些常用的命令行选项,并同时列出了gcc中相对应的选项,熟悉gcc的朋友可以不用看“说明”应该也能明白各选项的含义和作用。

    MSVC

    gcc

    说明

    /E

    -E

    输出预处理结果

    /Dname

    /Dname=value

    -Dname

    -Dname=value

    定义一个宏

    /Idirecotry

    -Idirecotry

    指定头文件搜索路径

    /c

    -c

    编译、汇编生成目标文件

    /libpath:direcotry

    -Ldirecotry

    指定库文件搜索路径(MSVC的/libpath属于链接选项,第一个链接选项之前要指定/link选项,用来告诉编译器驱动,后续选项传给链接器使用)

     

    另外,如果觉得每次编译都要使用同样的选项,敲太长的命令实在是一件累人的事,微软同样为大家提供了省事的方式:仍然是设置环境变量。详细说明如下:

    ※  CL环境变量:其中可以指定多个常用的选项,cl命令会自动将该环境变量的内容加入编译命令。

    ※  LINK环境变量:链接器会自动将该环境变量中的内容加入到链接命令中。

     

    三、静态库的创建与使用

     

    ■  创建静态库

     

    linux下创建静态库(*.a)通常需要借助ar命令,例如:“ar -r mylib.a foo.o bar.o”。微软也提供了类似的命令——lib命令,该命令的详细使用方法可参考其帮助文档“lib /?”,下面仅给出一个简单的示例:

    cl /c foo.cpp
    cl /c bar.cpp
    lib foo.obj bar.obj /out:mylib.lib

    注:其中“/out选项”用于指定生成的静态库文件名。

     

    ■ 使用静态库

     

    测试目录结构如下:

    .
    +-- lib
    |    +-- mylib.lib
    |    +-- mylib.h
    +-- test
         +-- test.cpp

    测试代码如下:

    复制代码
    // mylib.h
    extern "C" void foo();
    
    // test.cpp
    #include <mylib.h>
    int main() {
        foo();
        return 0;
    }
    复制代码

    在test目录下编译test.cpp文件:

            cl /I..lib test.cpp /link /libpath:..lib mylib.lib

    其中/link选项用于告诉cl命令:后续选项为链接选项,请从..lib目录查找mylib.lib库文件!

     

    除了使用命令行选项告诉链接器应该链接的库、从何处查找库,还可以使用“#pragma comment”指令。

    例1(编译命令cl /I..lib test.cpp /link /libpath:..lib):

    #include <mylib.h>
    #pragma comment(lib, "mylib.lib") // 此处包含库名信息,因此命令行选项中不需指定库名
    int main() {
        foo();
        return 0;
    }

    例2(编译命令cl /I..lib test.cpp):

    #include <mylib.h>
    #pragma comment(lib, "..\lib\mylib.lib") // 此处包含库名及路径信息,注意转义符用“\”
    int main() {
        foo();
        return 0;
    }

     

    四、动态库的创建与使用

     

    与静态库的创建相比,动态库的创建相对复杂。为了更容易理解,这里先介绍一些关于windows动态链接库(DLL)基本概念,然后再介绍动态库的创建和使用方法。

     

    ■ 基本概念一:动态库的分类

     

    微软将动态库分为四类:

    ※ 非MFC动态链接库(Non-MFC DLL)

    ※ 静态链接MFC的正规DLL(Regular DLLs statically linked to MFC)

    ※ 动态链接MFC的正规DLL(Regular DLLs dynamically linked to MFC)

    ※ 扩展DLL(Extension DLLs)

    其中只有第一种动态库不需要链接微软的MFC,后三种都需要链接MFC(不管你是否使用MFC),个人感觉微软这样做,似乎有点将自己的产品强加于人的感觉,当然,这纯属本人的个人想法,也许有人真的需要MFC吧。这里需要特别说明的是:下文中所提到的“动态库”,特指上述第一种动态库,而不再赘述成“非MFC动态链接库(Non-MFC DLL)”了。

     

    ■ 基本概念二:符号的导出与导入

     

    符号的导出与导入的分两个方向:

    ※ 从动态库导出符号:生成导出符号表;

    ※ 向应用程序导入符号:告知链接器——我需要的符号来自某个动态库。

    下面首先介绍符号的导出,再介绍符号的导入。

     

    windows下的动态库文件(.dll)与可执行文件(.exe)在文件的组织结构上最大的区别在于:动态库文件中包含一个导出符号表。只有存在于该导出符号表中的符号(名字)才可以被其它程序直接访问,我们可以使用dumpbin命令来查看一个动态库的导出符号表,例如:

            dumpbin /exports mylib.dll

     

    在动态库中导出符号有两种方式:

    (1) 创建模块定义文件(.def)(Exporting a symbol from DLL by ordinal):

         优点:可以减小导出符号表的大小;

         缺点:当导出C++函数时,需要使用名字修饰后的符号名。

    (2) 使用__declspec(dllexport)关键字(Exporting a symbol from DLL by name)。

         优点:不用考虑名字修饰的问题;

         缺点:将符号名存储在导出符号表中,当导出内容较多时,会导致符号表变得非常庞大。

     

    ■ 创建动态库

     

    示例1:创建模块定义文件来导出函数

    复制代码
    // foo.cpp
    #include <stdio.h>
    extern "C" void foo() { printf("foo()
    "); }
    
    // bar.cpp
    #include <stdio.h>
    extern "C" void bar() { printf("bar()
    "); }
    
    // mylib.def
    LIBRARY   mylib
    EXPORTS
       foo   @1
       bar   @2
    复制代码

    编译生成动态库:

            cl foo.cpp bar.cpp /link /dll /def:mylib.def /out:mylib.dll

     

    示例2:使用__declspec(dllexport)关键字来导出函数

    // foo.cpp
    __declspec(dllexport) void foo() { printf("foo()
    "); }
    
    // bar.cpp
    __declspec(dllexport) void __stdcall bar() { printf("foo()
    "); }

    编译生成动态库:

            cl foo.cpp bar.cpp /link /dll /out:mylib.dll

     

    注:上述两个示例中,无论使用哪种方式来导出符号,最终都会生成以下三个文件:

    ※  mylib.dll:动态链接库;

    ※  mylib.lib:导入库,后面“使用动态库”一节中“使用加载时动态链接”的示例中会用到。

    ※  mylib.exp:暂未知。

     

    ■ 使用动态库

     

    示例1:加载时动态链接(Using Load-Time Dynamic Linking)

    复制代码
    extern "C" __declspec(dllimport) void foo();
    extern "C" void bar(); // __declspec(dllimport)并不是必须的
    int main() {
        foo();
        bar();
        return 0;
    }
    复制代码

    编译链接上述代码时需要链接导入库mylib.lib,例如:

            cl test.cpp /link /libpath:..lib mylib.lib

     

    示例2:运行时动态链接(Using Run-Time Dynamic Linking)

    复制代码
    #include <windows.h>
    typedef void (FunType)(void);
    int main() {
        FunType* pfoo, *pbar;
        HINSTANCE dll = LoadLibrary(TEXT("mylib.dll"));
        pfoo = (FunType*)GetProcAddress(dll, "foo");
        pbar = (FunType*)GetProcAddress(dll, "bar");
        pfoo();
        pbar();
        FreeLibrary(dll);
        return 0;
    }
    复制代码

    编译链接上述代码时需要链接导入库mylib.lib,例如:

            cl test.cpp

     

    注:在运行上述两个示例中生成的test.exe可执行文件时,都需要拷贝一份mylib.dll到test目录下,或者将mylib.dll所在的路径加入PATH环境变量中,否则操作系统不知道从何处查找mylib.dll。

     

    五、关于nmake和Makefile

     

    与GNU make类似,VC安装目录下还自带了nmake工具,Makefile的书写形式也与linux下类似。下面给出一个简单的示例(示例文件名为Makefile):

    复制代码
    CXX     = cl.exe
    LD      = link.exe
    default: mylib.dll
    mylib.dll: foo.obj bar.obj
        $(LD) foo.obj bar.obj /dll /out:mylib.dll
    foo.obj: foo.cpp
        $(CXX) /c foo.cpp
    bar.obj: bar.cpp
        $(CXX) /c bar.cpp
    复制代码

    执行:  nmake,即可编译生成mylib.dll动态库文件。关于nmake的更多说明可参考:“nmake /?”。

     

    六、参考文档

    Setting the Path and Environment Variables for Command-Line Builds
        https://msdn.microsoft.com/en-us/library/f2ccy3wt.aspx
        
    CL Environment Variables
        https://msdn.microsoft.com/en-us/library/kezkeayy.aspx
        
    LINK Environment Variables
        https://msdn.microsoft.com/en-us/library/6y6t9esh.aspx
        
    Compiler Options Listed by Category
        https://msdn.microsoft.com/en-us/library/19z1t1wy.aspx
        
    Kinds of DLLs
        https://msdn.microsoft.com/en-us/library/9se914de.aspx

    Importing and Exporting
        https://msdn.microsoft.com/en-us/library/9h658af8.aspx

    Exporting from a DLL
        https://msdn.microsoft.com/en-us/library/z4zxe9k8.aspx
        
    Importing into an Application
        https://msdn.microsoft.com/en-us/library/kh1zw7z7.aspx
        
    Using Load-Time Dynamic Linking
        https://msdn.microsoft.com/en-us/library/ms686923.aspx
        
    Using Run-Time Dynamic Linking
        https://msdn.microsoft.com/en-us/library/ms686944.aspx
        
    NMAKE Reference
        https://msdn.microsoft.com/en-us/library/dd9y37ha.aspx 

  • 相关阅读:
    Python全栈开发之路 【第十八篇】:Ajax技术
    Python全栈开发之路 【第十七篇】:jQuery的位置属性、事件及案例
    Python全栈开发之路 【第十六篇】:jQuey的动画效果、属性操作、文档操作、input的value
    Burp Suite安装&环境配置&启动&浏览器设置代理
    git个人使用总结
    Windows下创建.gitgnore文件
    git个人使用总结(界面版)
    测试左移之代码评审
    Java自动内存管理机制
    【海盗派测试分析MFQ&PPDCS】读书笔记
  • 原文地址:https://www.cnblogs.com/weinyzhou/p/4983308.html
Copyright © 2011-2022 走看看