这一小结包含的内容有:
- Winemaker
- 编译资源文件:wrc
- Spec文件
- 链接
(一):Winemaker
1:对Visual C++项目的支持
Winemaker支持Visual C++项目文件。支持的文件类型位.dsp,.dsw,.vcproj和.sln。他检测要被使用的定义,这些自定义包括路径,要被链接的库和构建一个特定目标的源码文件。
如果可以的话,对一个项目文件推荐使用Winemaker。如果你必须在.dsp和.vcproj文件中选择的话,你应该使用.dsp,因为他提供了更多的信息。
用法是非常简单的,仅仅讲项目文件的路径来替换源码文件夹的路径。
$ winemaker --lower-uppercase myproject.vcproj
$ make
2:Winemaker源码分析
即使没有Windows makefile文件或者是Visual Studio文件开始,Winemaker也能够工作(它并不知道对windows makefile文件做什么工作)。这牵扯到需要做许多可能错误的猜测。这一小结主要是解释一下winemaker工作的细节,让你能够更好的理解和修改他。
在内核中,winemaker对你的源码树做了一个递归遍历来寻找目标和源码文件。我们从目标开始。
第一个就是可执行程序和DLL库。每一次他在一个目录中找到一个,winemaker将他添加到构建的列表中并且在每一个目录中生成一个Makefile文件。注意,Winemaker也知道Release和Debug目录,所以,他将会把在这个目录下找到的可执行程序和库放到他的父目录中。当他找到一个可执行文件和一个DLL的时候,winemaker是开心的,因为这会比下面的情况给他更多的信息。
如果他找不到任何可执行程序或者是DLL文件,winemaker将会寻找扩展名为.mak的文件。如果他们不是伪装的Visual C++项目,winemaker将会假设在这个目录中那个名称的目标文件将会被构建。但是他并不知道这个目标是不是一个可执行文件或者是一个库。所以他将会假设这个是默认的类型之一,例如一个图形应用,你可以通过使用
--cuiexe
和
--dll
选项来替代。
最后,winemaker将会检查是否都存在一个名称为makefile的文件。如果存在,他就会假设这个目录存在一个要被构建的目标文件。但是他并不知道这个目标的名称或者是类型。对于类型,他将会按照上面的方式去处理。对于名称,他将会使用目录的名称替代。事实上,如果目录以src开始,winemaker将会尝试使用他的父目录的名称替代。
一旦这个目录的目标被建立了,他就会检查他是否包含一个混合的可执行文件和目录。如果是这样的话,他将会把这个目录中所有的库链接在一起来构建他。
如果上面的两步不能产生期望的结果的话,你应该设置winemaker到交互式模式。这会允许你为每一个目录指定目标列表。
在每一个目录中,winemaker也会寻找源码文件:C,C++或者是资源文件。如果在这个目录中他发现了构建的目标,他将会基于这些目标的名称尝试去分配每一个源码文件到这些目标之一。不与任何一个目标相匹配的源码文件将会放到这个目录的全局列表中,查看在Makefile文件中的EXTRA_xxx变量,与每一个目标相链接。这里的假设是这些源码文件包含了所有的目标共享的公共代码。如果在这些文件所在的目录中找不到任何目标,他们将被分配到父目录中。所以如果在父目录中找到了一个目标文件,他也会“继承”在他子目录中找到的源码文件。
最后,winemaker也会寻找一些其他文件例如.h头文件,包含inline函数的.inl文件和其他文件。既然他们并不被直接编译,他们就不会被放在普通的源码文件列表中。但是他会依然记着他们以便在需要修改源码文件的时候处理他们。
一旦递归遍历目录完成,就会修改源码文件。这个步骤中的两个主要的任务就是修复CRLF问题和验证include语句的问题。winemaker会对每一个源码文件做一个备份(以符号链接被保留的方式),然后随着他的进行读取他修复CRLF问题和其他问题。一旦他完成了对这个文件的工作,他就会检查是否完成了那些非CRLF相关工作的修改,如果没有删除的话,就会删除备份文件。
检查include语句的问题(或者是被源码文件引用的文件),是在源码文件项目的上下文中完成的。这样的话winemaker就能使用正确的包含路径了。如果winemaker所包含的路径的目录中没有找到相应的文件,他将会把所有的文件都会重新命名成小写。(这个可以使用–nolower-include来重写).
最后winemaker生成Makefile文件。从上面的描述中,你可能会猜测到在有些方面可能会出错:宏定义,包含路径,DLL路径,引用的DLL,库路径,链接的库。你可以使用winemaker的
-D,-P,-i,-I,-L,和-l
选项来解决这些问题。你也可以使用winemaker的交互模式,你可以为每一个项目/目标指定不同的设置。
举个例子,你很有可能遇到的一个问题就是STRICT宏。如果STRICT没有打开的话一些程序将不会被编译;如果他启用的话,其他一些文件将不会被编译。
幸运的是给定的源码树的所有的文件都是使用相同的设置,所以你需要做的就是在winemaker命令行中或者是在Makefile文件中添加一个-DSTRICT选项。
最后,丢失或者是重复符号可能的原因有:
- 目标没有引入正确的DLL集合,或者是没有被正确的库所链接。你可以使用winemaker的
-P,-i,-L和-l
选项或者是将这些dll和库添加到Makefile文件中来解决这个问题。
- 在一个目录中可能有多个目标,当winemaker尝试将源码文件和目标匹配的时候猜测错了。解决这个问题的唯一办法就是手动的编辑Makefile文件
- Winemaker假设你已经组织了你的源码文件结构。如果一个目标使用在姊妹目录中的源码文件,例如你使用../hello/world.o来链接,你将会丢失链接。唯一的解决办法就是手动编辑Makefile文件。
3:交互模式
当winemaker分析你的代码的时候,交互模式将会询问你确认或者是改变选项。当编译MFC或者是每一个项目/目标有不同的设置的时候这可能是非常有用的。你应该考虑使用下列的方式来增加更多的选项。
$ winemaker --interactive .
$ make
4:Makefile文件
Makefile就是你的makefile文件。如果你想定制的话,你就需要修改这个文件。下面是对他内容的详细解释:
SRCDIR = .
SUBDIRS =
DLLS =
LIBS =
EXES = hello.exe
这里列出了这个目录的目标在哪里。名称就自我解释的很清楚了。SUBDIRS通常仅仅是位于顶层的makefile文件。对于库和可执行文件,指定全名称,包括.dll,.a,或者是.exe扩展名。注意这些名称一定要都是小写。
DEFINES = -DSTRICT
INCLUDE_PATH =
DLL_PATH =
DLL_IMPORTS =
LIBRARY_PATH =
LIBRARIES =
这一小节包含了全局编译设置:在这个makefile文件中他们应用到所有的目标中。LIBRARIES变量允许你指定被链接的Unix库。注意你不能在这里指定Winelib库。为了链接一个Winelib库,应该使用DLL_IMPORTS。对于C++库会出现异常,当前你没有别的选择只能在Unix上链接他们。你很可能找到的一个库就是mfc。
其他的变量的名称应该是自我解释的很清楚了。也存在CEXTRA,CXXEXTRA和RCEXTRA允许你指定其他的标志,分别为C编译器,C++编译器和资源编译器。最后要注意所有的这些变量都包含选项的名称。
然后对于每一个目标都有一个节点,每一个描述了目标组成的变量组件。
hello_exe_C_SRCS = hello.c
hello_exe_CXX_SRCS =
hello_exe_RC_SRCS =
上面的变量列出了用于生成目标的源码。每一个节点都以表示目标名称的评论开始。然后有一系列一目标名称位前缀的变量。注意,前缀的名称可能和目标有点不同,因为变量名称的限制。
hello_exe_DLL_PATH =
hello_exe_DLLS =
hello_exe_LIBRARY_PATH =
hello_exe_LIBRARIES =
上面的变量指定了如何去链接目标。注意,他将他们添加到这个文件开始的全局设置中。
DLLS域是你枚举可执行程序引入的DLL列表的地方。他应该包含DLL的全名称,而不是-l选项。
hello_exe_OBJS = $(hello_exe_C_SRCS:.c=.o)
$(hello_exe_CXX_SRCS:.cpp=.o)
$(hello_exe_RC_SRCS:.rc=.res)
上面仅仅是构建除了与目标相对应的对象文件。这个列表后来被用于链接指令。
C_SRCS = $(hello_exe_C_SRCS)
CXX_SRCS = $(hello_exe_CXX_SRCS)
RC_SRCS = $(hello_exe_RC_SRCS)
这一小节构建了源文件的“总结”列表。
all: $(SUBDIRS) $(DLLS:%=%.so) $(LIBS) $(EXES)
上面首先定义了这个makefile文件的默认的目标。这里他尝试去构建所有的目标。
### 目标指定构建规则
然后进入附加目录来链接可执行程序和目录。这个是相当标准的并且你不必去做修改。
注:
CRLF问题解释