Windows/Unix文本格式转换导致“/usr/bin/env: No such file or directory”

今天在用同事写的一个python脚本,一运行就出现了以下错误:

/usr/bin/env: No such file or directory

用ls命令查看了一下,“/usr/bin/env”明明存在:

bash-3.2# ls -lt /usr/bin/env
-r-xr-xr-x 1 root bin 5780 Jan 23  2005 /usr/bin/env

用vi打开这个python脚本,第一行显示:

#!/usr/bin/env python^M

又是一个Windows/Unix文本格式转换问题。用dos2unix转换好以后,运行OK!

P.S. 请参考stakoverflow这个问题:http://stackoverflow.com/questions/3598592/invoking-perl-scripts

我心目中理想的软件开发过程

我心目中理想的软件开发过程是这样的:

(1)RD(程序员)写完一段代码后,会review两遍,这样很多基本的问题就都能被发现。在完成整块代码功能后,通过使用gdb等工具,改变程序的执行流程,以保证每个分支,每条语句都能执行一遍。在这个过程中,要检查变量的值和代码逻辑,看看是否和预期的一样。最后写测试用例,执行集成测试,确保不会出现很低级的bug;执行稳定性测试,确保程序可以长时间运行不出问题。在这一过程结束后,提交代码库,准备code review。

(2)QA(测试人员)在RD将代码提交到版本库后,开始review code,记下问题。然后在code review会议上,和RD讨论,把需要修改的地方记下来。接下来,设计测试用例,测试用例除了包含基本的功能测试和稳定性测试外,还要包含通过仔细阅读代码,找到可能出错的地方。最后进入测试阶段。

关于“error: conflicting types for ‘function’”编译错误的分析

在使用gcc编译C程序时,有时会碰到“error: conflicting types for ‘function’”的编译错误。从字面意义上理解,是说函数的定义和声明不一致。在这篇文章里,我就对这个错误做个简单的分析(使用的gcc版本是4.9.0)。

(一)首先我们看一个函数的定义和声明不一致的例子:

#include <stdio.h>
 
int func(int a);
 
int func(void) {
	return 0;
}
 
int main(void) {
 
	func();
 
	return 0;
}

编译程序:

gcc -g -o a a.c
a.c:5:5: error: conflicting types for ‘func’
 int func(void) {
     ^
a.c:3:5: note: previous declaration of ‘func’ was here
 int func(int a);

可以看到由于“func”的声明和定义不一致(一个有参数,一个没有),所以编译时出现了这个错误。

(二)最近我在把一个老程序从Solaris移植到Linux,编译时也出现了这个错误。但是我发现函数在头文件里的声明和函数定义是完全一样的,这就令我很奇怪。查了将近一天时间,最后得到结论是函数参数类型在函数声明后定义了。简化的代码如下:

#include <stdio.h>

void func(struct A *A);

struct A {
        int a;
};

void func(struct A *A)
{
        printf("%d", A->a);
}

int main(void) {
        // your code goes here
        struct A a = {4};
        func(&a);
        return 0;
}

其中“structure A”的定义放在“func”函数声明之后了,而func函数的参数是“structure A*”类型。编译结果如下:

gcc -g -o a a.c
a.c:3:18: warning: ‘struct A’ declared inside parameter list
 void func(struct A *A);
                  ^
a.c:3:18: warning: its scope is only this definition or declaration, which is probably not what you want
a.c:9:6: error: conflicting types for ‘func’
 void func(struct A *A)
      ^
a.c:3:6: note: previous declaration of ‘func’ was here
 void func(struct A *A);
      ^

可以看到也输出了error: conflicting types for ‘func’”的编译错误,也许编译警告可以给一点提示吧。

我检查了一下程序的Makefile,所有编译警告都关掉了,也许是编译警告太多了吧。

为什么gcc在64位Solaris上编译出来的程序默认是32位的?

最近发现一个问题,gcc在64位Solaris上编译出来的程序默认是32位的,而在64位Linux上编译出来的程序默认就是64位的,觉得有点奇怪,就在stackoverflow上问了一下(http://stackoverflow.com/questions/25560539/how-does-gcc-determine-if-to-generate-a-32-bit-or-64-bit-executable-file-by-defa)。其中一个回答给出了一个链接(https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58833),原来这是Solaris有意而为之。总结一下,有以下几点:

(1)64位的gcc或程序不一定比32位运行快;

(2)Studio程序默认是32位的,gcc最好和它行为保持一致;

(3)从用户体验出发,以前都是默认生成32位程序,现在一下变成64位,用户可能需要改很多配置;

(4)64位Solaris位的gcc可以既编译32位,又编译64位,看用户自己的选择了。

使用SonarQube的一点经验

这两天在折腾SonarQube(也就是Sonar,以下简称为“Sonar”),有一点心得体会在这里记录下来(网上能找到的这里就不写了):

(一)使用“./sonar.sh console”命令

如果不确定Sonar是否配置成功,可以先使用这个命令。成功的启动输出如下:


确定能启动成功后,再使用“./sonar.sh start”命令。

(二)查看sonar log

有时,启动sonar不成功而且提示信息也不够时(像下面这样),


可以通过查看sonar的log,来定位问题。Log文件位置配置在conf目录下单wrapper.conf。

比方说从下面的log就可以定位到问题是缺少java插件:


(三) 导入plugin的license

有些plugin是收费的,需要license。导入license的方法如下:

a)以administrator身份登录;

b)进入Settings->General Settings->Licenses,粘贴license即可。

参考这个链接

(四) 保存和导入quality profile

有的时候,我们想保存修改过的quality profile,然后在其它的SonarQube上使用。

保存profile:Quality Profiles->backup;

导入profile:Quality Profiles->Restore Profile。

参考这个链接

liteIDE写Golang程序引用外面的package不能自动补全的问题

在使用liteIDE开发Golang程序时,会出现Golang自带的package可以自动补全,而引用外面的package则不能自动补全。今天终于在stackoverflow(http://stackoverflow.com/questions/19876902/liteide-no-autocomplete)找到了答案:在使用外面的package时,应该把package安装成功(使用go get, go install命令),才可以使用自动补全。

第一次南下之旅

由于个人原因,2014年8月6日,我开启了人生的第一次南下之旅。

8月6日中午,我坐上G133次北京开往上海的列车,一路顺利,下午六点,到达昆山南车站,见到了多年不见的兄弟臣。想想上次见面还是4年前,而上次一起吃饭还要追溯到9年前,不禁觉得时间过得真快。我们找了一家台湾火锅店(由于昆山台企较多,所以台湾人也多),这家火锅店是那种大锅,味道也还可以,但是始终觉得这种大锅不如“呷哺呷哺”那种小锅味道好。吃完饭,到了臣的家里。他家是那种复式结构,上下两层,装修一般,但是很温馨。由于第二天各自都有事,所以就早早休息了。

第二天一早,臣带我去吃昆山奥灶面,味道也还行,没什么不适应。然后他把我送到车站,自己去上班。我坐车来到上海张江园区,见到了韦总。韦总和7年前没有任何变化,身材也没走样,不像我已经开始有了肚腩。韦总带我吃了上海菜,然后我们又逛了东方明珠,南京路,城隍庙。总体感觉一般,其实我也对旅游没什么兴趣,所以就走马观花看了看。然后就坐车回了昆山。

第三天中午,我见到了张总,和毕业时也没什么变化。张总现在事业家庭都很如意,很是幸福。赶巧杨总回到上海,晚上我,韦总,杨总又吃了一顿。韦总和杨总毕业后再未见过,这次要不是我来,他们也未必能见面。我们三人谈了这些年的经历,很是感慨“岁月催人老”啊!

第四天是周六,我和臣去了周庄,我第一次看到了江南水乡。我印象最深的就是周庄里到处卖“万三蹄”,不知沈万三泉下有知,会作何感想。晚上回来,我买了些土特产,准备回家。

8月10日,我告别臣,返回北京。第一次南下之旅到此结束。

监控redis的内存使用情况

redis可以配置使用内存的最大值,配置项是maxmemory。如果不设置的话,64位程序默认内存没有限制,而32位程序的默认值为3G。相关代码如下:

    if (server.arch_bits == 32 && server.maxmemory == 0) {
        redisLog(REDIS_WARNING,"Warning: 32 bit instance detected but no memory limit set. Setting 3 GB maxmemory limit with 'noeviction' policy now.");
        server.maxmemory = 3072LL*(1024*1024); /* 3 GB */
        server.maxmemory_policy = REDIS_MAXMEMORY_NO_EVICTION;
    }

 

redis使用zmalloc去做内存的分配和释放工作,这样便于统计当前redis进程消耗了多少内存。

 

通过“info”命令,我们可以得到当前redis已使用的内存值:used_memory字段;通过“config get maxmemory”命令可以得到redis可使用内存的最大值。这样一旦监控程序发现redis使用的内存超过一个百分比(例如:80%),就可以通知我们,进而让我们采取相应的措施。

参考资料:

(1)When would one use malloc over zmalloc?

(2)Why redis need zmalloc? 

 

关于知乎话题“程序员有哪些借口可以让自己写出低质量的代码?”的一点想法

以下是知乎上一个有趣话题:“程序员有哪些借口可以让自己写出低质量的代码?”得票最多的回答(原帖请参考这里:http://www.zhihu.com/question/24665029):


关于这件事,网上有很多讨论,感兴趣的同学可以搜一下。我感兴趣的一点是:“离职之前老板大夸我厚道,最后一个月还给公司做了这么多的事情,别人走都是删代码,我居然还毫无保留的为公司做出贡献。”。我理解这个公司离职的员工删代码应该不是一个正常的代码维护,而是为了报复公司去删除有用的代码,否则老板也不会这样说。我好奇这个公司的员工为什么离职都会有报复公司的举动,我也经历了几家公司,但从来没有听说过这种行为。我没在这家公司工作过,所以不知道具体原因是什么。是不是所有经历过这家公司的人都应该反思一下,为什么会出现这种情况呢?也许答案并不简单。

编译gdb注意事项:一定要用一个干净的build文件夹

上周收到gdb的通知邮件,说gdb 7.8已经release了。作为gdb的忠实用户,自然是体验一下了。我赶紧下了一个版本,然后build了一下,结果在最后link阶段,出了错误:

gcc: unrecognized option `-rdynamic’
ld: warning: file /usr/local/lib/libiconv.so: attempted multiple inclusion of file
Undefined                       first referenced
 symbol                             in file
observer_attach_exited              cli-interp.o
observer_notify_signal_exited       infrun.o
observer_attach_sync_execution_done cli-interp.o
observer_attach_command_error       cli-interp.o
observer_notify_signal_received     infrun.o
observer_attach_end_stepping_range  cli-interp.o
observer_attach_no_history          cli-interp.o
ptid_match                          remote.o
observer_notify_end_stepping_range  infrun.o
observer_notify_exited              infrun.o
observer_notify_no_history          infrun.o
observer_attach_signal_exited       cli-interp.o
observer_notify_command_error       event-loop.o
observer_notify_sync_execution_done infrun.o
observer_attach_signal_received     cli-interp.o
ld: fatal: symbol referencing errors. No output written to gdb
collect2: ld returned 1 exit status
Makefile:1334: recipe for target ‘gdb’ failed
make[2]: *** [gdb] Error 1
make[2]: Leaving directory ‘/export/home/nan/build_gdb/gdb’
Makefile:8667: recipe for target ‘all-gdb’ failed
make[1]: *** [all-gdb] Error 2
make[1]: Leaving directory ‘/export/home/nan/build_gdb’
Makefile:831: recipe for target ‘all’ failed
make: *** [all] Error 2

gdb的编译过程一向是最简单的,link错误我还是第一次碰到。我先是在gdb的IRC里讨论,接着又自己debug,检查代码文件和脚本,结果最后得到的结论是:因为我所用的build目录之前是编译7.7.1版本的,我因为偷懒,没有清空,导致现在编译7.8版本时会有问题,原因应该是link的还是7.7.1的目标文件。

最后得到的经验是:在编译gdb(或是其它软件)时,一定要准备一个干净的build文件夹,否则可能会有你意想不到的问题,像我碰到的在link阶段出问题还好办,如果在执行阶段出了问题,可就更难查了。

注:build文件夹是为了保持源码的干净,通常在源代码文件夹外,新建一个build文件夹,然后所有的configure,make操作等都在这个build文件夹下进行。例如:

mkdir build_gdb;
cd build_gdb;
../gdb-7.8/configure
make
make install