说明:(1)转载请注明出处:http://www.cnblogs.com/opangle/p/4298155.htmlhtml
(2)如下以VS2013为例,并假设VC安装路径为%VC_INSTALL_PATH%(本人的安装目录为D:\Program Files (x86)\Microsoft Visual Studio 12.0)。linux
1、环境配置windows
■ 方法一:使用MS提供的Developer Command Prompt快捷方式函数
“开始” => “Visual Studio 2013” => “Visual Studio Tools” => “Developer Command Prompt for VS2013”。工具
■ 方法二:使用MS提供的vcvarsall.bat脚本测试
在命令行窗口中进入%VC_INSTALL_PATH%目录,执行“vcvarsall.bat”脚本。ui
■ 方法三:手动配置环境变量spa
手动配置环境变量,至少要设置一下三个环境变量:操作系统
※ PATH:默认状况下cl命令(微软编译器)是不可使用的,须要将cl.exe文件所在的路径(即%VC_INSTALL_PATH%\bin目录)添加到PATH环境变量中。命令行
※ INCLUDE:默认状况下cl命令不知道从何处查找系统头文件的,该环境变量告诉cl命令从何处查找系统头文件。
※ LIB:与INCLUDE环境变量相似,LIB环境变量用来告诉连接器:从何处查找库文件、目标文件等。
本人试过的最小配置以下:
环境变量 |
配置说明(多个路径之间用分号分隔) |
PATH |
将如下路径加入PATH环境变量中: %VC_INSTALL_PATH%\bin |
INCLUDE |
将如下路径加入INCLUDE环境变量中: %VC_INSTALL_PATH%\include C:\Program Files (x86)\Windows Kits\8.1\include\shared C:\Program Files (x86)\Windows Kits\8.1\include\um |
LIB |
将如下路径加入到LIB环境变量中: %VC_INSTALL_PATH%\lib C:\Program Files (x86)\Windows Kits\8.1\lib\winv6.3\um\x86 |
注:最完整的配置方式能够参考“方法一”、“方法二”中的环境变量配置方式。
■ 测试环境配置
写一个简单的“Hello World”程序(假设为hello.cpp),在命令行下执行:cl hello.cpp,若是能成功生成hello.exe可执行文件,即说明配置成功!
2、经常使用的命令行选项
下表列出了一些经常使用的命令行选项,并同时列出了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环境变量:连接器会自动将该环境变量中的内容加入到连接命令中。
3、静态库的建立与使用
■ 建立静态库
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; }
4、动态库的建立与使用
与静态库的建立相比,动态库的建立相对复杂。为了更容易理解,这里先介绍一些关于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()\n"); } // bar.cpp #include <stdio.h> extern "C" void bar() { printf("bar()\n"); } // 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()\n"); } // bar.cpp __declspec(dllexport) void __stdcall bar() { printf("foo()\n"); }
编译生成动态库:
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。
5、关于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 /?”。
6、参考文档
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.aspxImporting and Exporting https://msdn.microsoft.com/en-us/library/9h658af8.aspxExporting 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