在VS2013中引用freeglut,glew和lua源码编译为DLL

2014-08-01 21:13:00

这篇文章作为博客搬家到VPS的新的开始, 同时也标志着我要慢慢习惯把工作中遇到的一些技术问题用文字的形式保存下来. 某种形式下预示着我在慢慢老去了.

受云风的影响, 我迷上了Lua. 可能也有一些原因是之前尝试了N次要学习OpenGL, 却一直耽搁和放弃了. 这次一定要坚持下去.

今天重构项目代码之余, 看了一点Lua的基础知识. 为了调节一下情绪, 下午开始搭建自己的项目. 基于freeglut,glewlua. 期间碰到了很多问题, 最终一一解决了, 现在记录下来, 以免下次忘记.

由于我之前没有系统的学习过C++, 接触的Linux编译环境也很少. 所以这篇文章更适合C++新手阅读.

首先从官网下载源码:

  1. Lua 5.2.3官网链接
  2. freeglut 2.8.1SourceForge链接
  3. glew 1.10.0SourceForge链接

在VS2013中新建解决方案, 新建三个子项目, 分别引入头文件和C文件.

这里需要注意:

  1. Lua不需要lua.cluac.c文件, 这两个分别是Lua的交互环境和编译环境的实现.
  2. glew不需要glewinfo.cvisualinfo.c.

项目属性->配置属性->常规->默认类型处选择动态库(.dll).

如果这时候点击"项目->生成解决方案"会发现有以下几个警告和错误:

    path\to\freeglut\freeglut_window.c(1542): warning C4273: glutCreateWindow: dll 链接不一致
    path\to\freeglut\freeglut_joystick.c(1020): warning C4996: '_snprintf': This function or variable may be unsafe. Consider using _snprintf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.

Google了几个关键字发现是因为编译成dll需要配置几个宏:

  1. FREEGLUT_EXPORTS
  2. GLEW_BUILD
  3. LUA_BUILD_AS_DLL (可选)
  4. _CRT_SECURE_NO_WARNINGS (可选)

这些宏的配置路径都在相对应项目的项目属性->C/C++->预处理器->预处理器定义. 第一个宏是freeglut的宏, 能解决warning C4273: “glutCreateWindow”: dll 链接不一致的错误. 在freeglut_std.h中有下面一段代码:

/*
 * Under windows, we have to differentiate between static and dynamic libraries
 */
#ifdef _WIN32
/* #pragma may not be supported by some compilers.
 * Discussion by FreeGLUT developers suggests that
 * Visual C++ specific code involving pragmas may
 * need to move to a separate header.  24th Dec 2003
 */

/* Define FREEGLUT_LIB_PRAGMAS to 1 to include library
 * pragmas or to 0 to exclude library pragmas.
 * The default behavior depends on the compiler/platform.
 */
#   ifndef FREEGLUT_LIB_PRAGMAS
#       if ( defined(_MSC_VER) || defined(__WATCOMC__) ) && !defined(_WIN32_WCE)
#           define FREEGLUT_LIB_PRAGMAS 1
#       else
#           define FREEGLUT_LIB_PRAGMAS 0
#       endif
#   endif

#  ifndef WIN32_LEAN_AND_MEAN
#    define WIN32_LEAN_AND_MEAN 1
#  endif
#  ifndef NOMINMAX
#    define NOMINMAX
#  endif
#   include <windows.h>

/* Windows static library */
#   ifdef FREEGLUT_STATIC

#       define FGAPI
#       define FGAPIENTRY

        /* Link with Win32 static freeglut lib */
#       if FREEGLUT_LIB_PRAGMAS
#           pragma comment (lib, "freeglut_static.lib")
#       endif

/* Windows shared library (DLL) */
#   else

#       define FGAPIENTRY __stdcall
#       if defined(FREEGLUT_EXPORTS)
#           define FGAPI __declspec(dllexport)
#       else
#           define FGAPI __declspec(dllimport)

            /* Link with Win32 shared freeglut lib */
#           if FREEGLUT_LIB_PRAGMAS
#               pragma comment (lib, "freeglut.lib")
#           endif

#       endif

#   endif

/* Drag in other Windows libraries as required by FreeGLUT */
#   if FREEGLUT_LIB_PRAGMAS
#       pragma comment (lib, "glu32.lib")    /* link OpenGL Utility lib     */
#       pragma comment (lib, "opengl32.lib") /* link Microsoft OpenGL lib   */
#       pragma comment (lib, "gdi32.lib")    /* link Windows GDI lib        */
#       pragma comment (lib, "winmm.lib")    /* link Windows MultiMedia lib */
#       pragma comment (lib, "user32.lib")   /* link Windows user lib       */
#   endif

#else

/* Non-Windows definition of FGAPI and FGAPIENTRY  */
#        define FGAPI
#        define FGAPIENTRY

#endif    

宏控制的是这一段

#       if defined(FREEGLUT_EXPORTS)
#           define FGAPI __declspec(dllexport)
#       else
#           define FGAPI __declspec(dllimport)

Google之后发现是这样的:

__declspec用于指定所给定类型的实例的与Microsoft相关的存储方式。其它的有关存储方式的修饰符如staticextern等是C和C++语言的ANSI规范,而__declspec是一种扩展属性的定义。扩展属性语法简化并标准化了C和C++语言关于Microsoft的扩展。

有兴趣的同学可以继续Google.

同理GLEW_BUILD也是为了解决这个报错

_CRT_SECURE_NO_WARNINGS是为了解决开启了SDL检查之后提示_snprintf这个函数不推荐使用的问题.

总结

其实是很简单的两个报错, 但是有时候隔行如隔山, 如果静不下心来配置, 可能就放弃了. 就像之前好几次我都因为不习惯Visual Studio的项目属性配置. 转而寻找eclipse之类的IDE, 最后折磨到被迫放弃治疗.

End

2014-08-02更新

今天继续折腾

先推荐一个OpenGL的[教程]"http://opengl.leafnsand.com/", 顺便吐槽一下红宝书, 还在用已经废弃了的GLUT. 推荐的这个教程虽然只有英文, 但很简洁, 并且作者也说了, 用什么库(SFML, SDL, freeglut, glfw)来做跨平台都不重要, 只要能新建窗口, 初始化OpenGL上下文就可以.

好了, 回到环境配置上. 昨天晚上回去在Mac上折腾了好久, 最后还是没有编译成功, 貌似最后是卡在ARC的一个报错上. 简直蛋疼.

今天继续折腾VS2013. 并且决定不用freeglut了, 先用glfw. 等到有一天真的在跨平台上需要考虑的时候, 再去折腾. 现在换成glfw主要是因为api看起来稍微舒服点. 但是glfw的编译宏更多:

    _GLFW_BUILD_DLL
    _GLFW_WGL
    _GLFW_WIN32
    _GLFW_USE_OPENGL

其实只要稍微阅读以下glfw3.h的头文件就知道为什么需要这么定义了. 另外因为我用到了glew, 而glfw中包含了一个deps文件夹, 里面有tinythread和GL/glext.h以及GL/wglext.h在win32下需要用到. 观察发现跟glew的头文件有重复貌似可以用glew替代,于是修改了一下glfw相关的c文件直接引用了glew的头文件.