I am LAZY bones ? all linux

分类: '编程相关' 的归档

跟我一起写 Makefile (PDF)

以前有人在论坛里发过: http://forum.ubuntu.org.cn/viewtopic.php?t=61841
原文在这里: http://blog.csdn.net/haoel/archive/2004/02/24/2886.aspx
作者: 陈皓

我整理成了PDF,并修改少量错字.
给有需要的人,估计受众不会很大,嘿嘿.

这里不能上传文件附件,可以到 这里 或者这里 下载.

链接期的”undefined reference to”问题又一解

今天拿到公司的一个程序,在本机(ubuntu8.04)编译了一下,编译起见是一堆的警告:” 警告: 不建议使用从字符串常量到‘char*’的转换”,可以跳过去,但是到了链接期间,就又是可恶的 “undefined reference to”问题了,网上查了一些资料说是因为找不到 *.a/*.o 之类的库文件,或者是库文件里面没有相关的符号导致,但是我这程序原样复制到服务器里面,借给是可以编译的,而且提示错误的那个 .a 文件也是从服务器复制的,可以保证是一模一样的,但为什么本机编译就是不行呢?后来想到服务器是RHEL4,
gcc –version 的输出是: gcc (GCC) 3.4.6 20060404 (Red Hat 3.4.6-8)
g++ –version 的输出是: g++ (GCC) 3.2.3 20030502 (Red Hat Linux 3.2.3-47.3)
而我本机的 gcc和g++确都是 4.2.3 的新版本,会不会是编译器的版本不兼容呢?看makefile里面用的是 g++ ,所以我先安装了 g++-3.4 ,然后把makefile里面的 PUBCC = g++ 改为 PUBCC = g++-3.4 ,再编译的时候发现编译期间的警告没了,但是链接还是照样报错;于是又卸载了 g++-3.4,换成了 g++-3.3,再编译的时候,居然是一切正常,和服务器上的表现一样了….
最后: 虽然是找到了 链接期的”undefined reference to”问题 的又一个答案,但个人对编译器的不兼容问题表示忧虑.

修改了下lunar-applet的源代码

lunar-applet是一个可以显示农历的软件,我一直是用这个代替原来的时钟的。最近把panel改成透明的了,而且壁纸的颜色比较深,这样一来,黑色的时钟文字在深色背景下看起来就有点累了.刚好,TX兄发现了修改applet时钟颜色的方法,可以自己写HTML定义颜色等.但是那个是针对原版的applet的,在lunar-applet上实验了下,居然无效,有点郁闷了.
好在linux下,一切都是自由的,居然原来无效,那就自己加上这功能吧,于是找来源码,自己修改了一些,嘿嘿,实现了想要的功能:

gconftool-2 --set --type string /apps/panel/applets/applet_2/prefs/format "custom"
gconftool-2 --set --type string /apps/panel/applets/applet_2/prefs/custom_format '<span color="#ee1111">%Y-%m-%d %A <b>%H:%M:%S</b></span>'

效果:
lunar-applet
如果有需要,可以放出修改后的源码或者deb包. (其实是因为本人至今都不知道怎么用patch和打deb包…)

[转]用gettext实现shell脚本国际化.

$ cat test.sh
#!/bin/bash
export TEXTDOMAINDIR=/usr/share/locale
export TEXTDOMAIN=test.sh
echo “$(gettext -s hello)”

编辑一个po文件:
$ cat test.sh.po
msgid “hello”
msgstr “你好!”

编译成mo文件:
$msgfmt -o test.sh.mo test.sh.po

复制到/usr/share/locale/zh_CN/LC_MESSAGES/
$sudo cp test.sh.mo /usr/share/locale/zh_CN/LC_MESSAGES/

中文:
$ export LANG=zh_CN.UTF-8
$ ./test.sh
你好!

英文:
$ export LANG=en_US.UTF-8
$ ./test.sh
hello

这里可以看到,gettext在locale是 zh_CN的时候,会去 TEXTDOMAINDIR 下面的 zh_CN/LC_MESSAGES 里面找mo文件,所以,TEXTDOMAINDIR也可以放在当前目录,只要里面有zh_CN这目录,并且里面的内容是正确的,这样就可以避免放文件到 /usr/share/local 时候所需的root权限.
参考: http://forum.ubuntu.org.cn/viewtopic.php?t=105507

C语言中的uname示例

呵呵,其实很简单,man页上都有写了,还是发上来,高手莫笑.

#include<stdio.h>
#include<sys/utsname.h>
 
int main(){
        struct utsname buf;
        if(0!=uname( &buf )){
                printf("ERROR");
                return -1;
        }else{
                printf("sysname=\t%s\n",buf.sysname);
                printf("nodename=\t%s\n",buf.nodename);
                printf("release=\t%s\n",buf.release);
                printf("version=\t%s\n",buf.version);
                printf("machine=\t%s\n",buf.machine);
                #ifdef _GNU_SOURCE
                printf("domainname=\t%s\n",buf.domainname);
                #endif
        }
        return 0;
}

执行结果:

  1. $ ./a.out
  2. sysname=        Linux
  3. nodename=       LLY
  4. release=        2.6.22-14-generic
  5. version=        #1 SMP Tue Dec 18 08:02:57 UTC 2007
  6. machine=        i686

一个关于time的有意思的问题

原帖: http://forum.ubuntu.org.cn/viewtopic.php?p=591866
问:
目的:用time命令来获得一个程序p执行的时间。

方法一:如果在终端命令符$下直接输入 $time p 2>foo.tmp
则可得到下面的foo.tmp内容
real 0m1.017s
user 0m0.916s
sys 0m0.056s

方法二:现在想用下面这个shell代码来执行这个命令
#!/bin/sh
。。。
。。。
time p 2>foo.tmp
。。。

但是执行完这个shell代码后查看foo.tmp的内容,却是这样的:
0.81user 0.06system 0:01.01elapsed 86%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (0major+723minor)pagefaults 0swaps

问题:我想知道为什么这两种方法得到的结果(foo.tmp文件)会不同?

谢谢!

答:
又是ubuntu的bash和dash的差异引起的问题,呵呵.

首先,time关键字是bash或者dash的保留字,就是说每个shell有不同的表现属于正常现象.
其次,ubuntu默认的用户打开终端以后用的是bash,所以这个时候输出是
real 0m1.017s
user 0m0.916s
sys 0m0.056s
这样的.但是ubuntu的 /bin/sh 指向的确是dash,这点可以通过 ls -l /bin/sh 来确认.就是系统是调用dash来执行你的脚本的,所以有了另一种形式的输出.

知道原因以后,如果你想在脚本里面也得到之前的那种输出,可以用以下两种方法:
1.把/bin/sh指向bash
2.脚本开头写成 #!/bin/bash

C中调用shell命令的方法 popen演示

以下是 popen.c

#include <stdio.h>
int main(){
        FILE * fp;
        char str[1024];
        if(NULL==(fp=popen("pwd","r"))){
                return -1;
        }else{
                printf("%s",fgets(str,1023,fp));
                pclose(fp);
        }
        return 0;
}

编译运行的结果:

lily@LLY:~/test$ gcc popen.c
lily@LLY:~/test$ ./a.out
/home/lily/test
lily@LLY:~/test$

另如果只是要执行shell命令,而不管输出的话,有可以用system函数:
man system这么说:

NAME
       system - execute a shell command
 
SYNOPSIS
       #include <stdlib.h>
 
       int system(const char *command);
 
DESCRIPTION
       system() executes a command specified in command by calling /bin/sh -c command, and returns after the command has been completed.  During execution of the
       command, SIGCHLD will be blocked, and SIGINT and SIGQUIT will be ignored.

(++i)+(++i)+(++i)+(++i)

今天,看到一个面试题,居然无聊到这种地步,看这代码:

下载: test.c
  1. #include&lt;stdio.h&gt;
  2. main()
  3. {
  4. int i=1,j;
  5. j=(++i)+(++i)+(++i)+(++i);
  6. printf("%d\n",j);
  7. }

问输出的j是多少。。。虽然知道这个很无聊,但是反正闲着也是闲着嘛,就研究了下,执行

lly@LLY:~/test$ gcc test.c
lly@LLY:~/test$ ./a.out
15

这我就不懂了。。。再看看objdump的结果:

lly@LLY:~/test$ objdump -d a.out
...省略若干
8048385: c7 45 f4 01 00 00 00 movl $0x1,0xfffffff4(%ebp)
804838c: 83 45 f4 01 addl $0x1,0xfffffff4(%ebp)
8048390: 83 45 f4 01 addl $0x1,0xfffffff4(%ebp)
8048394: 8b 45 f4 mov 0xfffffff4(%ebp),%eax
8048397: 03 45 f4 add 0xfffffff4(%ebp),%eax
804839a: 83 45 f4 01 addl $0x1,0xfffffff4(%ebp)
804839e: 03 45 f4 add 0xfffffff4(%ebp),%eax
80483a1: 83 45 f4 01 addl $0x1,0xfffffff4(%ebp)
80483a5: 03 45 f4 add 0xfffffff4(%ebp),%eax
80483a8: 89 45 f8 mov %eax,0xfffffff8(%ebp)
...省略若干

里面的0xfffffff4 是变量i,0xfffffff8是j,可以看出现在是先把i自加2次,再取出两个i的值相加(这时候两个i的值都是3),再执行后面的,也就是 3+3+4+5 = 15。不解,于是用了另一个编译器(小型的tcc)编译,执行,结果就不一样了:

lily@LLY:~/test$ tcc test.c
lily@LLY:~/test$ ./a.out
14

也看看关键的汇编代码:

....
80481ed: b8 01 00 00 00 mov $0x1,%eax
80481f2: 89 45 fc mov %eax,-0x4(%ebp)
80481f5: 8b 45 fc mov -0x4(%ebp),%eax
80481f8: 83 c0 01 add $0x1,%eax
80481fb: 89 45 fc mov %eax,-0x4(%ebp)
80481fe: 8b 4d fc mov -0x4(%ebp),%ecx
8048201: 83 c1 01 add $0x1,%ecx
8048204: 89 4d fc mov %ecx,-0x4(%ebp)
8048207: 01 c8 add %ecx,%eax
8048209: 8b 4d fc mov -0x4(%ebp),%ecx
804820c: 83 c1 01 add $0x1,%ecx
804820f: 89 4d fc mov %ecx,-0x4(%ebp)
8048212: 01 c8 add %ecx,%eax
8048214: 8b 4d fc mov -0x4(%ebp),%ecx
8048217: 83 c1 01 add $0x1,%ecx
804821a: 89 4d fc mov %ecx,-0x4(%ebp)
804821d: 01 c8 add %ecx,%eax
804821f: 89 45 f8 mov %eax,-0x8(%ebp)
...

可以看到这里面的-0×4(%ebp) 是i,而 -0×8(%ebp)是j。而之前的两次自加操作分别是在 %eax 和 %ecx 上执行的,第一次相加操作就是直接把这两个寄存器里面的值加在一起了。所以最终的效果相对于 2+3+4+5 = 14 。
这样的结果说明了同样的C代码,在不同的编译器下,会产生完全不同的可执行文件,当然如果你的源代码写得不好,完全有可能产生不同的执行结果。另外也再一次说明了这样一个面试题的无聊性,作为反面教材还差不多,嘿嘿。

BTW: 有兴趣的朋友还可以自行研究一下 (++i)+(++i)+(i++)+(i++)+(++i) 的执行结果。

Shell脚本转化成二进制文件

工具名称: shc
安装方法: sudo apt-get install shc
使用方法: shc -f xx.sh ,就会生成一个 xx.sh.x 的二进制可执行文件,执行这个可执行文件的效果和执行原shell脚本的效果一样,另外还会生成一个 xx.sh.x.c 的C源文件,自己编译这个源文件成二进制文件也是可以的.
另外这个工具好像还可以设置过期时间,到了这个预设的时间后,再执行二进制文件的话,就会输出一行已过期的信息(当然这个信息也可以自定义),不过我想这个功能一般用不着吧 :)

调整Eclipse中树状列表的显示密度(转)

发了点牢骚,结果有人给推荐了这篇文章,不错,转一下.不过我喜欢Verdana字体,所以把字体改了,哈哈.

如果你在Windows和Linux两个平台下都使用过Eclipse,那么你一定注意到Windows下Eclipse项目列表的显示要比Linux下 紧凑许多。对于做开发的朋友来讲,在屏幕上同时看到的信息总是希望尽可能多,尽可能全,在这一点上目前的GNOME并不能让我们十分满意,它的GTK+控 件本身和控件之间的间隙占掉了不少本来就很有限的屏幕空间,尤其当屏幕分辨率不是特别高的时候。

Linux版的Eclipse默认使用GTK+2.0的控件,所以在默认的情况下,会和其他GTK应用程序(如OpenOffice.org)一样给人一 种不够密实的感觉。当然,这和GNOME的设计哲学不无关系,不过这不是本文主旨,就不深入讨论了,进入正题讲讲如何调整Eclipse树状列表的显示密 度。

基于GTK+2.0的程序在启动时会到用户的home目录找GTK+2.0的配置文件,即~/.gtkrc-2.0,Ubuntu下默认没有这个文件,需要我们自己创建。打开你习惯的编辑器,加入如下代码:

下载: .gtkrc-2.0
  1. style "eclipse" {
  2. font_name="Verdana 8"
  3. GtkTreeView::vertical-separator=0
  4. GtkTreeView::horizontal-separator=0
  5. }
  6. class "GtkTreeView" style "eclipse"

重启Eclipse应该就能看到效果了。如果你想做得更彻底,对所有常用的GTK+2.0控件都开刀的话,可以这样写:

下载: .gtkrc-2.0
  1. style "gtkcompact" {
  2. font_name="Verdana 8"
  3. GtkButton::default_border={0,0,0,0}
  4. GtkButton::default_outside_border={0,0,0,0}
  5. GtkButtonBox::child_min_width=0
  6. GtkButtonBox::child_min_heigth=0
  7. GtkButtonBox::child_internal_pad_x=0
  8. GtkButtonBox::child_internal_pad_y=0
  9. GtkMenu::vertical-padding=1
  10. GtkMenuBar::internal_padding=0
  11. GtkMenuItem::horizontal_padding=4
  12. GtkOptionMenu::indicator_size=0
  13. GtkOptionMenu::indicator_spacing=0
  14. GtkPaned::handle_size=4
  15. GtkRange::trough_border=0
  16. GtkRange::stepper_spacing=0
  17. GtkScale::value_spacing=0
  18. GtkScrolledWindow::scrollbar_spacing=0
  19. GtkExpander::expander_size=10
  20. GtkExpander::expander_spacing=0
  21. GtkTreeView::vertical-separator=0
  22. GtkTreeView::horizontal-separator=0
  23. GtkTreeView::expander-size=8
  24. GtkTreeView::fixed-height-mode=TRUE
  25. GtkWidget::focus_padding=0
  26. }
  27. class "GtkWidget" style "gtkcompact"