一直以来总觉得NetBeans生活在Eclipse的阴影下,同样做为一款不错的基于Java开发的IDE却走着完全不同的发展道路。可能是由于之前我一直较多的使用Java的缘故,所以Eclipse一直是我最为常用的工具。偶尔我也会尝鲜一下NetBeans,但是总觉得使用习惯上有点别扭。不过由于工作的需要,开始更多的接触Linux C,Eclipse CDT就显得越来越苍白。毕竟Cygwin和真正的Linux还是有很大差异的,写一个简单的C程序Cygwin可以应付,但是对于一个较大的C程序且需要非常复杂的环境时,Cygwin就明显的力不从心了。于是乎就开始寻找其他的解决方案......。
在网上搜索了相关的技术类文章,说实话,90%的文章内容相仿,或是抄来抄去,或是浅尝即止。大部分内容均来自官网手册,而使用的例子也是“Hello World”型的,毫无实用价值。做为一名“骑自行车”的架构师,有责任写一篇系统的,图文并茂的总结性文章,给所有有类似需要的同学提供一个有价值的参考。
闲话少说,先来介绍一下我们的环境和此次演示的例程:
环境:
本机环境为windows7,NetBeans7.3.1,Java1.6(NetBeans运行需要Java环境)。
远程主机为RHEL5.8 64位,SSH,Oracle数据库11.2.0,Oracle客户端11.2.0,GCC4.1.2,安装了所有C/C++开发包,编译安装ocilib3.12.1。
演示例程:
本次我们演示的例程是开发一个访问Oracle数据库的C程序,它需要访问一个第三方的函数库(ocilib),并且依赖Oracle客户端。
之所以采用这个例程主要出于如下几个目的:
1. 了解C访问Oracle数据库的其他方式(之前我们一般都使用PRO*C的方式);
2. 了解如何在远程模式下compile源代码;
3. 了解如何在远程模式下linked第三方函数库;
4. 了解如何在远程模式下进行Debug;
以上几个知识点基本上涵盖了日常开发中所需掌握的大部分技能(我指的仅限于开发工具的使用技能,至于编程技能因人而异了)。
一. 配置NetBeans远程开发环境
这部分确实很乏味,因为官网上已经有很详细的介绍了(中英文版都有),且网上也有一群人在不停的复制拷贝把自己当成复印机,所以我实在没必要再拷贝一遍。这里我提供一个链接:https://netbeans.org/kb/docs/cnd/remotedev-tutorial_zh_CN.html,如果不知道如何配置的同学可以先去了解一下。
最后提供一下我自己本机上的配置结果截图,可做为一个参照系:
这里在唠叨几句,同学们可能看到那个图标是红色的,和上面的"localhost"的图标不一样,这是因为这个远程主机尚未连接,你可以通过在这个主机上单击右键,并选择“连接”命令来连接远程主机,如果连接成功图标就会变成绿色了。另外这里还会列出我远程主机上的工具链,有gcc, g++,make和gdb等,有了这些工具我们才能进行远程开发和调试。
NetBeans还提供了问题跟踪器(JIRA)和Hudson构建器服务,这 2个服务对我们日常的开发也大有帮助,至少我在Eclipse上没有发现这些有用的工具(可能是我孤陋寡闻)。
二. 准备远程主机开发环境
远程主机上需要安装Oracle数据库,当然还有Oracle数据库客户端(需要oci.h头文件和libclntsh.so动态库以及TNS的配置),这些环境的安装和配置如果要写又是上W字,估计写了你也不会去看,所以如果您对此还不甚了解,那就去google一下吧,相关的文章多的是(判断一个Oracle客户端是否安装成功,只要执行一下sqlplus命令并且可以连接Oracle数据库且可执行select语句即可)。
我这里想介绍一下ocilib函数库的编译安装。这个函数库是对OCI的一个封装,提供了非常友好的API接口,如果你熟悉JDBC,那你会觉得它很亲切。从http://sourceforge.net/projects/orclib上下载最新的版本,并解压缩到远程主机上。网上有些文章写的有点问题,编译参数不太一样,我的编译参数如下:
[plain] view plaincopyprint?
./configure --prefix=/usr/local/ocilib --with-oracle-lib-path=/u01/app/oracle/product/11.2.0/db_1/lib --with-oracle-headers-path=/u01/app/oracle/product/11.2.0/db_1/rdbms/public
make && make install
./configure --prefix=/usr/local/ocilib --with-oracle-lib-path=/u01/app/oracle/product/11.2.0/db_1/lib --with-oracle-headers-path=/u01/app/oracle/product/11.2.0/db_1/rdbms/public
make && make install
我是将其安装在/usr/local/ocilib目录中,并且一定要指定oracle的lib目录和头文件所在的目录,否则编译不通过。
当编译完成之后,会产生ocilib的头文件和相关的链接库,如下所示:
头文件目录及头文件。
动态库和静态库文件。
至此,我们的第三方函数库编译安装完成,接下去可以在本机上开发源代码了。
三. 在本机上编写源代码
最让人兴奋的环节到来了,终于可以写代码了。在NetBeans中新建一项目,选择项目类别为“C/C++应用程序”,然后点击下一步,如下图所示:
在第二个对话框中输入项目名称,项目位置,构建主机等信息,如下图所示:
最新点击完成,新建项目完成。如下图所示:
我们打开main.c文件,开始编写代码,如下所示:
[cpp] view plaincopyprint?
/*
* File: main.c
* Author: Administrator
*
* Created on 2013年7月5日, 下午5:32
*/
#include <stdio.h>
#include <stdlib.h>
#include <ocilib.h>
/*
*
*/
int main(int argc, char** argv) {
OCI_Connection *cn;
OCI_Statement *st;
OCI_Resultset *rs;
//init instance
if (!OCI_Initialize(NULL, NULL, OCI_ENV_DEFAULT | OCI_ENV_CONTEXT)) {
printf("OCI_Initialize failure! ");
return EXIT_FAILURE;
}
cn = OCI_ConnectionCreate("STOREVM", "username", "password",
OCI_SESSION_DEFAULT);
if (!cn) {
printf("OCI_ConnectionCreate failure! ");
return EXIT_FAILURE;
}
st = OCI_StatementCreate(cn);
if (!st) {
printf("OCI_StatementCreate failure! ");
return EXIT_FAILURE;
}
OCI_ExecuteStmt(st, "select * from test t");
rs = OCI_GetResultset(st);
while (OCI_FetchNext(rs))
printf("table.name: %s, PK.name %s ", OCI_GetString(rs, 1),
OCI_GetString(rs, 2));
printf(" %d row(s) fetched ", OCI_GetRowCount(rs));
OCI_Cleanup();
return EXIT_SUCCESS;
}
/*
* File: main.c
* Author: Administrator
*
* Created on 2013年7月5日, 下午5:32
*/
#include <stdio.h>
#include <stdlib.h>
#include <ocilib.h>
/*
*
*/
int main(int argc, char** argv) {
OCI_Connection *cn;
OCI_Statement *st;
OCI_Resultset *rs;
//init instance
if (!OCI_Initialize(NULL, NULL, OCI_ENV_DEFAULT | OCI_ENV_CONTEXT)) {
printf("OCI_Initialize failure! ");
return EXIT_FAILURE;
}
cn = OCI_ConnectionCreate("STOREVM", "username", "password",
OCI_SESSION_DEFAULT);
if (!cn) {
printf("OCI_ConnectionCreate failure! ");
return EXIT_FAILURE;
}
st = OCI_StatementCreate(cn);
if (!st) {
printf("OCI_StatementCreate failure! ");
return EXIT_FAILURE;
}
OCI_ExecuteStmt(st, "select * from test t");
rs = OCI_GetResultset(st);
while (OCI_FetchNext(rs))
printf("table.name: %s, PK.name %s ", OCI_GetString(rs, 1),
OCI_GetString(rs, 2));
printf(" %d row(s) fetched ", OCI_GetRowCount(rs));
OCI_Cleanup();
return EXIT_SUCCESS;
}
可能IDE会提示找不到ocilib.h文件,因为没有把ocilib的include路径包含进来。我们可以点击“工具”菜单并选择“选项”菜单项,在弹出的对话框中选择“C/C++”选项卡,如下图所示:
在“代码帮助”选项卡中,首先在“工具集合”下拉框中选择我们定义的远程主机,然后再“C 编译器”选项卡中点击“添加”按钮,这时会显示远程主机的目录结构,接着选择ocilib的include路径,比如我远程主机上的路径是“/usr/local/ocilib/inculde”,完成之后点击确定按钮。这时就不会再提示找不到ocilib.h头文件了。我们也可以通过此方法将其他函数库的头文件引进来(这个方法解决了在本地IDE中引入远程主机上头文件的问题)。
四. 编译及链接
代码写好了,开始编译代码,点击工具栏上“构建项目”按钮,如下图所示:
悲剧!编译失败了,提示找不到ocilib.h文件。如下图所示:
之前我们不是已经将ocilib.h头文件引入进来吗?这么还说没找到呢?其实这是两个概念,之前引入的只是代码帮助的功能,此功能提供了我们可以在IDE中浏览头文件的内容,而现在是在远程主机上编译源代码,说白了,就是我们遗漏了GCC编译参数。好吧,让我们继续。
在项目中点击右键,在上下文菜单中选择“属性”,会弹出一个项目属性对话框,如下图所示:
在构建下我们选择“C编译器”,然后在 右边的“包含目录”项中填写远程主机上ocilib的include路径(如果是多个目录,每个目录之间用分号隔开)。最后点击确定按钮。当然此处还有其他一些GCC的编译参数可供选择,按照自己的实际情况加以选择即可。这里建议把“警告级别”替换成“更多警告”或“将警告替换成错误”选项。
好了,我们再次点击工具栏上的“构建项目”按钮。这次编译总算过了,但是在连接ocilib动态库的时候报错了,如下图所示:
这是明显的未连接到动态库的错误,好吧,继续打开项目属性对话框,如下图所示:
在构建的下面我们选择“链接器”,然后在右面的“其他库目录”中填写远程主机上的ocilib的lib目录路径(如果有多个目录,每个目录之间用分号隔开)。接着我们在“库”这项中点击右边的按钮,会弹出一个库对话框,如下图所示:
由于我们要选择远程的函数库,所以只能选择“添加选项”按钮,在弹出的对话框中,选择“其他选项”并填写指定库的参数,如上图中所示。通过这种方法,我们就可以解决gcc编译链接远程主机上任意函数库的问题。我们不再需要在本机上安装gcc的仿真linux环境了,比如:Cygwin等。
完成之后点击一连串的确定按钮,再次的点击工具栏上的“构建项目”按钮,这次编译链接都成功完成了,如下图所示:
从上图中,我们还能发现,远程主机上同时生成了可执行文件的路径:/root/.netbeans/remote/www.storevm.org/zgc-20130102uwx-Windows-x86/D/CPRO/ocilib_test。你可以到远程主机上去检查一下,看看是否存在这个文件(至于这是通过什么工作机制实现的,请参考官网介绍,我这里就不再赘述了)。
五. 代码运行与调试
编译链接都OK了,可以执行程序了,我们先创建一张表,表名为test,表中有2个字段,都是varchar2类型的,最后在insert一些测试数据。点击工具栏上的“运行项目”按钮,在IDE的输出控制台输出了表中的3行记录,程序执行成功,如下图所示:
以下是我们实际表中的记录(通过PL/SQL):
程序执行的结果和SQL执行的结果完全相同。
至此,所有开发全部完成。接下去我们来玩玩远程主机的调试,其实NetBeans的远程主机调试和在本地调试的操作步骤完全一样。打上断点,然后点击“调试项目”按钮,最后按F6键进行单步调试。如下图所示:
可通过调试工具栏上的按钮进行单步,步入,步出等Debug操作。感觉上和在本地调试程序完全一样。有一点要注意,就是不要在项目路径中包含中文字符,否则无法启动远程调试程序。
我想讲述的内容就这些了,写到这里,突然有些感想,记得十几年前,在那IDE匮乏的年代,基本上都是靠记事本或是vim等工具来编写C代码,然后再FTP到Linux下编译运行调试。有时为了调试一个很难发现的bug不得不在代码中加上一大堆的printf函数。或许直至今日你仍然看不起那些用IDE写代码的人,或许那些刚入公司的80,90后正在用崇拜的眼光看着你飞速的在记事本上敲入代码而让你沾沾自喜,又或许你会用100种理由在论坛上大谈徒手代码的优势。的确,你很牛逼,我也由衷的崇拜你这种毅力。不过做为技术人员我们应该拥抱变化,接受变化。应该始终的站在技术的前沿阵地。技术人员只能向前看,不能原地看,更不能回头看,那只会制约我们的发展。中国人墨守成规是上千年来的积习,但是搞技术的人不能墨守,否则我们永远都只会模仿,山寨!那些仍然还在记事本上写代码人们,希望我的这篇文章或许给你一点微不足道的启示!