Windows、Linux下“交叉”编译环境的搭建和测试。
来源:互联网 发布:mac u盘 10. 编辑:程序博客网 时间:2024/05/16 07:25
开源给了我们极大的便利,使得我们能够有众多优秀的工具可以使用。
作为Windows(R)下的程序开发者,经典的开发环境Microsoft Visual Studio一直是众多开发环境中及其流行的产品,——且不讨论大家使用的是否是真正经过微软授权的正版开发环境,我们无法否认VS的普及程度。
而进行过Linux开发的程序员必定会对gcc的强大功能所震撼,——在Linux下的经典开发环境不是所谓的IDE,尽管IDE环境也数不胜数,但是使用commandline上的VI(VIM)/Emacs + gcc + GNUmake + gdb (+ autotools)的搭配却无可辩驳的成为Linux下产出最多的开发环境,感谢GNU项目等。
开源社区正因为这些强有力的工具,成就了众多使得我们目瞪口呆的优秀作品。
cygwin便是其中相当出众的一个项目。
cygwin是在Windows下模拟Linux开发的及其成功的一个项目。首先我们可以想当然的认为,只要gcc等可以被移植到Windows下,那么几乎所有GNU工具就都可以移植到Windows下,——我们确实有对应的Windows版本的gcc,可是,仍然有些东西是不能直接移植到Windows下的,因为毕竟Linux不同于Windows,系统核心不同,底层细节不同,甚至没有多少相同或者类似的实现,尽管KDE3.5酷似XP,KDE4也像极了Vista。
但是,cygwin使得这都变得不再重要,——将Linux的底层用Windows的底层实现,封装了众多DLL,从而将这种貌似不可能的事情变得及其简单,甚至源码包可以同在Linux下一样,./configure, make, make install,只要念三个咒,程序就装在cygwin下了。——这时候,我们得到的是“准”Windows应用程序,标准的、带有Windows经典PE文件头,可以在cmd下执行,可以通过鼠标双击运行……只是它的执行必须依赖于cygwin的一系列DLL而已。
目前看来,这似乎是尽管可能不是唯一却一定是最流行的在Windows下进行Linux程序开发的途径,——只要在cygwin下可以make成功,那么,在所有兼容POSIX标准的UNIX上,不论BSD,Mac X,Sun Solaris,还是日渐流行的各种发行版的Linux,包括LinuxLiveCD,几乎都可以保证编译通过。
这样,尽管我们还没有从Windows下直接生成可以在Linux下执行的可执行二进制文件,但是一般来说得到没有问题的源码已经可以了……
上面讨论的是Windows下进行Linux开发,虽然有些不太靠谱,但是事实是,似乎就只是这样了;下面我们讨论我写这个东东的主要目的,——在Linux下进行Windows应用程序开发。
使用虚拟机的方案已经被大家抛弃了,——如果只是这么简单,我似乎也没有写这个东东的必要了,而且,虚拟机毕竟达不到很快的,除非您的机器配置相当不错,比如流畅跑个虚拟的盗版Vista。
但是不用怕,不用虚拟机照样可以做Windows应用程序开发,因为我们用的是开源的Linux,开源的GNU工具,因为我们有无所不能的巨牛的gcc。
直接使用gcc的方式,不好意思,我还没试,所以就不乱说了……那么我们能用什么呢?
Linux用户应该都知道有这么一个东东,号称可以将大多数Windows的二进制应用程序直接“移植到”Linux下使用,——对,这就是大名鼎鼎的wine。作为一个开发者,光知道有个wine可以用还是不够的,你要知道,我们还有个将gcc进行相关包装的winegcc。
winegcc的目标号称是将Windows下的程序源码尽量保持兼容的在Linux下编译通过,并生成可以在wine下执行的应用程序,——这个目标是基本可以实现的,至少我的测试是,使用Windows API的应用程序完全可以编译通过,而且生成的应用程序和Windows下的程序看上去没有什么大的差别,——当然,我的测试仅针对C程序,C++和MFC的程序没有进行测试,所以不知道是什么效果。
这就很清楚了。winegcc可以编译Windows程序,但是由于使用的是winegcc相关的库,所以生成的程序尽管可以在wine中正常使用,但是将其直接搬到Windows下,将生成的.exe.so二进制文件改名为.exe后,仍然无法正常执行,——毕竟程序需要的环境已经变了。在WindowsNT的cmd下,装入程序时提示:Program too big to fit in memory,可见程序实际上已经是Windows应用程序了(虽然看上去是16位程序的文件头),只是,不算是完全的Windows应用程序。
到目前这个阶段,我们已经基本达到了同Windows下使用cygwin时相似的效果,——在Linux下可以得到基本上能够移植到Windows下的程序的源码,尽管没有直接得到应用程序。这样的效果也还是可以接受的,毕竟Windows下进行“准”Linux应用程序开发时也遇到了类似的情况。
当然,我们不会满足于这中源码的交叉移植,毕竟Linux环境下这么多巨牛的软件,以及Linux下"Nothing's impossible"的大众想法,我们一定可以得到直接可以运行在Windows下的程序,从Linux中编译。——因为我们有wine,以及更重要的,Linux下可以有很多使我们的工作简化的优秀工具,比如VIM(当然也有Windows版), GNUmake, sed, awk, grep...等等,不一而足。
下面是我实现的环境:操作系统:Knoppix5.3 LiveCD/DVD(这是开销最小的解决方案,毕竟我没有权限给别人的机器装一个他不会用到的系统),该Live Linux自带KDE3.5,wine0.9等工具,一般的开发基本没有问题(这是一款仅提供Live服务的Linux发行版,德国制造,基本没有汉语环境,提供各种工具,号称DVD版提供多达10G以上应用程序,常见的流行程序几乎全面囊括,如gcc, gdb, GNUmake, GVIM, Emacs, Octave, LaTeX, kate, Eclipse, Kdevelop, ...其丰富程度我已经不知道应该怎么说了)。
我要做的是将Windows下的经典开发环境MS VS加入Linux系统,当然使用wine。考虑到本人使用的是LiveCD,内存已划出一部分作为虚拟磁盘,所以在启动wine之后,可能已经没有太多的内存可供使用,所以没有试图将整个VS全部装到wine中,而是采用了经典迷你方案,——仅将与即将进行的测试相关的VS的组件整合一下“装”到wine中,也就是所谓的迷你VC,从命令行或者shell中进行相关工作,类似gcc的命令行开发。
有关于迷你VC的相关信息,本人不再啰嗦,具体细节我会在另外的日志或其他博客比如CSDN上详述,而且鉴于一般没有使用命令行进行Windows应用程序开发的,所以建议“好事者”还是尽量将整个VCwine出来看看,如果有兴趣,当然,为了使用比如VIM,GNUmake等工具,我个人觉得,迷你VC已经足够了。——大体上的实现是这样的,将下述若干文件拷贝到相关目录,并进行一些设置就搞定。下面是我的一个例子:
版本VC6.0withSP6,下述文件:$VSCOMMON/msdev98/bin下的mspdb60.dll,如果想进行资源编辑还有rc.exe,rcdll.dll等,$VSHOME/VC98/bin下的cl.exe, c1.dll, c2.dll, 如果想编译C++文件还有c1xx.dll; link.exe, 为方便项目管理还有nmake.exe,其他是不是还需要什么我记不太清了,好像就这些,拷贝到wine的C盘根目录下usr/bin目录(新建),将$VSHOME/VC98/include目录拷贝成~/.wine/drive_c/usr/include目录,$VSHOME/VC98/lib目录拷贝成~/.wine/drive_c/usr/lib目录,如果想使用MFC等,在将其他一些东西拷贝到相应目录。当然,这里目录取什么样的目录无所谓,只要后面设置时对应起来就可以。说明,前面的$VSCOMMON, $VSHOME变量没有必要存在,这只是为了说明方便而取的,代表相应的位置而已,相信搞过Windows、Linux开发的人们可以看懂。
好的,迷你VC已经就位,下面是开发环境的搭建。为了方便进行命令行开发,我们需要设置wine的环境变量,从终端中输入wine regedit,打开wine的注册表编辑器,展开到HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Session Manager/Environment下,修改环境变量path,加入刚刚拷贝cl.exe等的目录在wine中的路径,比如上例是:C:/usr/bin,别忘了分号;再添加环境变量include值为C:/usr/include,lib值为C:/usr/lib,至此,迷你VC开发环境搭建成功。当然,前面的环境变量也可以直接用VI打开wine的注册表信息文件修改,——只要您觉得自己足够牛,不怕把wine搞死。不过这也算不上怎么高级,只是在文件中加几行就行。
下面是Linux下进行Windows应用程序开发的例子:
例一:控制台应用程序echoall,功能:显示命令行参数,显示环境变量。下面是源码:
说明:由于文本框对跳格字符不怎么支持,所以下面的源码和makefile看上去相当混乱,敬请各位原谅!另:下述文件为了方便“观赏”,使用的是VIM对于对应文件语法高亮之后的显示样式,外加我本人对于有些标识符的“语法高亮”。
[code=C/C++]
/* Simple ANSI C file for echo the arguments */
#include<stdio.h>
int main(int argc, char * argv[], char * envp[]){
/* */
int i;
printf("/t%s: Echo all arguments and environment variables./n/n", argv[0]);
if(argc > 1){
printf("/t%s: The commandline arguments are as followed:/n", argv[0]);
for(i = 1; i < argc; i++){
printf("%s>>>: %s/n", argv[0], argv[i]);
} /* For all commandline arguments */
}
else{
printf("/t%s: No commandline arguments specified!/n/n", argv[0]);
}
printf("/n/t%s: Echo all environment variables./n/n", argv[0]);
for(i = 0; envp[i]; i++){
printf("%s>>>: %s/n", argv[0], envp[i]);
} /* For all environment variables */
printf("/n/t%s: Task finished! Exiting.../n", argv[0]);
return 0;
}
使用nmake的makefile:
# This is a simple makefile for microsoft nmake
# That is quit not a good makefile, but it just works, and I think that's enough...
CC = cl
RM = del
DBG = /Zi
CFLAGS = /W4 $(DBG)
OBJS = echoall.obj
SRCS = $(OBJS:.obj=.c)
DBGTMP = *.ilk *.pdb
TARGET = echoall.exe
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) $(OBJS) -Fe$@
$(OBJS): $(SRCS)
$(CC) $(CFLAGS) -c $(SRCS) -Fo$@
.PHONY: clean exec
clean:
-$(RM) $(TARGET) $(OBJS) $(DBGTMP)
exec: $(TARGET)
$(TARGET)
!EOF(End Of File)
上述文件的使用:在shell中键入wine nmake,或者wine cmd(也可能是wcmd)后,进入wine的cmd下,直接使用nmake。但是后者因为一直在wine的cmd下,所以像VIM等工具就不能使用了。
使用GNUmake的makefile:
# This is a simple makefile for GNUmake
# That is not a good makefile too, but still it works...
CC = wine cl
RM = rm -f
DBG = /Zi
CFLAGS = /W4 $(DBG)
OBJS = echoall.obj
SRCS = $(OBJS:.obj=.c)
DBGTMP = *.ilk *.pdb
TARGET = echoall.exe
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) $^ -Fe$@
$(OBJS): $(SRCS)
$(CC) $(CFLAGS) -c $< -Fo$@
.PHONY: clean exec
clean:
-$(RM) $(TARGET) $(OBJS) $(DBGTMP)
exec: $(TARGET)
wine $(TARGET)
!EOF(End Of File)
上述文件的使用方式,直接在shell中键入make,可以使用GNUmake的特性,可以使用GNU的各种优秀的工具等等。
例二:窗口应用程序drawlines,功能:使用鼠标在窗口中画线,可改变画笔大小和颜色。下面是源码:
[/code=C/C++]
/*
* DrawLines, use the mouse to draw lines on the screen
* Built buy suxpert, using cl of Visual C++, part of the Visual Studio of MS.
*
* Windows SDK, Win32 API ,Pure C, (Not C++ or MFC !!)
* Suxpert at gmail dot com, 2008/11
* */
#define WIN32_LEAN_AND_MEAN
#define _WIN32_WINNT 0x0400
#include<windows.h>
#include<stdio.h>
#define MAGIC_COLOR 0x010305
LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM );
int APIENTRY WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpszCmdLine,
int nCmdShow )
{
/* The Entry for windows program, just like main() in dos */
WNDCLASS wc;
HWND hwnd;
MSG msg;
wc.style = CS_HREDRAW | CS_VREDRAW; // Class style
wc.lpfnWndProc = (WNDPROC)WndProc; // Window procedure address
wc.cbClsExtra = 0; // Class extra bytes
wc.cbWndExtra = 0; // Window extra bytes
wc.hInstance = hInstance; // Instance handle
wc.hIcon = LoadIcon( NULL, IDI_WINLOGO ); // Icon handle
wc.hCursor = LoadCursor( NULL, IDC_ARROW ); // Cursor handle
wc.hbrBackground = (HBRUSH)( COLOR_WINDOW + 1 );// Background color
wc.lpszMenuName = NULL; // Menu name
wc.lpszClassName = "DrawLines"; // WNDCLASS name
RegisterClass( &wc );
hwnd = CreateWindow(
"DrawLines", // WNDCLASS name
"DrawLines", // Window title
WS_OVERLAPPEDWINDOW, // Window style
CW_USEDEFAULT, // Horizontal position
CW_USEDEFAULT, // Vertical position
CW_USEDEFAULT, // Initial width
CW_USEDEFAULT, // Initial height
HWND_DESKTOP, // Handle of parent window
NULL, // Menu handle
hInstance, // Application's instance handle
NULL // Window-creation data
);
ShowWindow( hwnd, nCmdShow );
UpdateWindow( hwnd );
while( GetMessage(&msg, NULL, 0, 0) ){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
} // WinMain
LRESULT CALLBACK WndProc( HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam )
{
/* Windows will call this function anytime... */
PAINTSTRUCT ps;
HDC hdc;
RECT rt;
HFONT textFont, OldFont;
int centx, centy;
int x, y;
static int xx, yy;
static COLORREF pen_color = 0x000000;
static int pen_size = 3;
char info[64];
HPEN pen, oldpen;
textFont=CreateFont(16,10,0,0,0,0,0,0,0,0,0,0,0,"Courier New");
switch(message){
case WM_KEYDOWN:
switch(wParam){
case VK_ESCAPE:
PostQuitMessage(0);
break;
}// switch wParam
break; // case WM_KEYDOWN
case WM_LBUTTONDOWN:
/* Store the position of the mouse */
xx = LOWORD(lParam);
yy = HIWORD(lParam);
/* Hidden the cursor */
ShowCursor(FALSE);
break; // case WM_LBUTTONDOWN
case WM_LBUTTONUP:
/* Show the cursor */
ShowCursor(TRUE);
break; // case WM_LBUTTONUP
case WM_MOUSEWHEEL:
/* Change the pen_color */
hdc = GetDC(hwnd);
OldFont = SelectObject(hdc, textFont);
SetTextColor(hdc, pen_color);
switch( LOWORD(wParam) ){
case MK_RBUTTON:
if( (int)wParam > 0 && pen_size < 64){
pen_size++;
}
else if(pen_size > 1){
pen_size--;
}
sprintf(info, "Current Pen Size: %8d ", pen_size);
TextOut( hdc, 0, 0, info, strlen(info) );
break;
default: //case MK_LBUTTON:
if( (int)wParam > 0 ){
if( pen_color < 0xFFFFFF - MAGIC_COLOR)
pen_color += MAGIC_COLOR;
else
pen_color = 0;
}
else{
if(pen_color >= MAGIC_COLOR)
pen_color -= MAGIC_COLOR;
else
pen_color = 0xFFFFFF;
}
sprintf(info, "Current Pen Color: %0#8X ", pen_color);
TextOut( hdc, 0, 0, info, strlen(info) );
break;
}
SelectObject(hdc, OldFont);
ReleaseDC(hwnd, hdc);
break; // case WM_MOUSEWHEEL
case WM_MOUSEMOVE:
hdc = GetDC(hwnd);
OldFont = SelectObject(hdc, textFont);
SetTextColor(hdc, pen_color);
/* Get the position of the mouse */
x = LOWORD(lParam);
y = HIWORD(lParam);
switch(wParam){
case MK_LBUTTON:
sprintf(info, "Drawing. Mouse: %5d, %5d ", x, y);
TextOut( hdc, 0, 0, info, strlen(info) );
pen = CreatePen(PS_SOLID, pen_size, pen_color);
oldpen = SelectObject(hdc, pen);
MoveToEx(hdc, xx, yy, NULL);
LineTo(hdc, x, y);
xx = x;
yy = y;
SelectObject(hdc, oldpen);
DeleteObject(pen);
break; // left button was down
}
SelectObject(hdc, OldFont);
ReleaseDC(hwnd, hdc);
break; // case WM_MOUSEMOVE
case WM_PAINT:
hdc = BeginPaint( hwnd, &ps );
GetClientRect(hwnd, &rt);
centx = (rt.left + rt.right)/2;
centy = (rt.top + rt.bottom)/2;
pen = CreatePen(PS_SOLID, pen_size, pen_color);
oldpen = SelectObject(hdc, pen);
Ellipse( hdc, rt.left, rt.top, rt.right, rt.bottom );
// Here we Draw an ellipse in the window of our program
SelectObject(hdc, oldpen);
DeleteObject(pen);
EndPaint( hwnd, &ps );
break; // case WM_PAINT
case WM_DESTROY:
PostQuitMessage(0);
break; // case WM_DESTROY
default:
return DefWindowProc( hwnd, message, wParam, lParam );
}
DeleteObject(textFont);
return 0;
}
[/code]
使用nmake的makefile:
# Makefile for DrawLines: using NMAKE & cl
#
CC = cl
RM = del
OBJS = DrawLines.obj
LIBS = kernel32.lib user32.lib gdi32.lib
CFLAGS = /W4 /GA /Zi
SRCS = DrawLines.c
TARGET = DrawLines.exe
DBGINF = *.pdb *.ilk
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) $(OBJS) $(LIBS) /Fe$@
$(OBJS): $(SRCS)
$(CC) $(CFLAGS) -c $(SRCS) /Fo$@
.PHONY: clean exec cleanall eraseback
clean:
-$(RM) $(TARGET) $(OBJS) $(DBGINF)
eraseback:
-$(RM) *~
cleanall: clean eraseback
@echo Clean all back files(*~) and build out files!
@echo Only source files are left!
exec: $(TARGET)
$(TARGET)
!EOF(End Of File)
上述文件的使用同前例相同。
使用GNUmake的makefile:
# Makefile for DrawLines: using GNUmake, wine & cl
#
CC = wine cl
RM = rm -f
OBJS = DrawLines.obj
LIBS = kernel32.lib user32.lib gdi32.lib
CFLAGS = /W4 /GA /Zi
SRCS = DrawLines.c
TARGET = DrawLines.exe
DBGINF = *.pdb *.ilk
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) $^ $(LIBS) /Fe$@
$(OBJS): $(SRCS)
$(CC) $(CFLAGS) -c $< /Fo$@
.PHONY: clean exec cleanall eraseback
clean:
-$(RM) $(TARGET) $(OBJS) $(DBGINF)
eraseback:
-$(RM) *~
cleanall: clean eraseback
@echo Clean all back files(*~) and build out files!
@echo Only source files are left!
exec: $(TARGET)
wine $(TARGET)
!EOF(End Of File)
由于使用的是GNUmake,同上所述,可以使用GNUmake的特性。
经测试,上述工程在knoppix&wine环境下进行开发,可以得到直接在Windows下可以执行的二进制文件.exe,测试成功!
- Windows、Linux下“交叉”编译环境的搭建和测试。
- eclipse在windows下的arm交叉编译环境搭建
- Windows下Cocos2dx-3.10的Android交叉编译环境搭建
- Windows下Cocos2dx-3.10的Android交叉编译环境搭建
- Windows下Cocos2dx-3.10的Android交叉编译环境搭建
- Linux下搭建arm交叉编译环境
- Linux下搭建嵌入式交叉编译环境
- Ubuntu下Arm-Linux-GCC交叉编译环境的搭建
- 利用虚拟机搭建linux下的交叉编译环境
- Ubuntu下Arm-Linux-GCC交叉编译环境的搭建
- Linux下搭建ARM交叉编译环境的步骤
- Ubuntu下交叉编译环境的搭建
- arm-linux交叉编译环境的搭建
- Linux嵌入式交叉编译环境 的搭建
- Linux嵌入式交叉编译环境 的搭建
- ARM-LINUX交叉编译环境的搭建
- Linux嵌入式交叉编译环境 的搭建
- linux 交叉编译环境的搭建
- 社交网站LinkedIn的Java架构技术
- as3 中的函数参数
- 通过ClassLoader说明容器热部署实现机制
- 分析RSSOwl如何做到只运行一个实例,并且可以激活
- 绕过Java开发瓶颈:解析EJB
- Windows、Linux下“交叉”编译环境的搭建和测试。
- Eclipse RCP 性能问题与解决方案
- Java远程通讯的6种可选技术及原理
- 爆笑
- 基于EXT JS 的可重用的无限级联下拉框
- 超越XML和JSON:YAML
- 网站如何提高访问量
- 优秀Java程序员必须了解的GC工作原理
- JSP页面的contentType和pageEncoding的差异