Category: 程序设计

1.什么是库
在windows平台和linux平台下都大量存在着库。
本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。
由于windows和linux的本质不同,因此二者库的二进制是不兼容的。
本文仅限于介绍linux下的库。

2.库的种类
linux下的库有两种:静态库和共享库(动态库)。
二者的不同点在于代码被载入的时刻不同。
静态库的代码在编译过程中已经被载入可执行程序,因此体积较大。
共享库的代码是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,因此代码体积较小。

3.库存在的意义
库是别人写好的现有的,成熟的,可以复用的代码,你可以使用但要记得遵守许可协议。
现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常。
共享库的好处是,不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例。

4.库文件是如何产生的在linux下
静态库的后缀是.a,它的产生分两步
Step 1.由源文件编译生成一堆.o,每个.o里都包含这个编译单元的符号表
Step 2.ar命令将很多.o转换成.a,成文静态库
动态库的后缀是.so,它由gcc加特定参数编译产生。
例如:
$ gcc -fPIC -c *.c $ gcc -shared -Wl,-soname, libfoo.so.1 -o libfoo.so.1.0 *.

5.库文件是如何命名的,有没有什么规范
在linux下,库文件一般放在/usr/lib /lib下,
静态库的名字一般为libxxxx.a,其中xxxx是该lib的名称
动态库的名字一般为libxxxx.so.major.minor,xxxx是该lib的名称,major是主版本号, minor是副版本号

6.如何知道一个可执行程序依赖哪些库
ldd命令可以查看一个可执行程序依赖的共享库,
例如# ldd /bin/lnlibc.so.6
=> /lib/libc.so.6 (0×40021000)/lib/ld-linux.so.2
=> /lib/ld- linux.so.2 (0×40000000)
可以看到ln命令依赖于libc库和ld-linux库

7.可执行程序在执行的时候如何定位共享库文件
当系统加载可执行代码时候,能够知道其所依赖的库的名字,但是还需要知道绝对路径
此时就需要系统动态载入器(dynamic linker/loader)
对于elf格式的可执行程序,是由ld-linux.so*来完成的,它先后搜索elf文件的 DT_RPATH段—环境变量LD_LIBRARY_PATH—/etc/ld.so.cache文件列表—/lib/,/usr/lib目录找到库文件后将其载入内存

8.在新安装一个库之后如何让系统能够找到他
如果安装在/lib或者/usr/lib下,那么ld默认能够找到,无需其他操作。
如果安装在其他目录,需要将其添加到/etc/ld.so.cache文件中,步骤如下
1.编辑/etc/ld.so.conf文件,加入库文件所在目录的路径
2.运行ldconfig,该命令会重建/etc/ld.so.cache文件

聊天记录

杨博在QQ上问我wxWidgets,下面是我的回答,乱七八糟的。整理一下。

Linux平台下的GUI开发,可以选择的图形库我知道的有gtk,gtkmm,wxWidgets,QT。
wxWidgets是我喜欢的图形库,看过gtk,看过gtkmm,最后发现我比较喜欢wxWidgets。gtk是最原生的,学习使用方法比较麻烦(个人感觉);gtkmm是对gtk的面向对象封装,按照通常的命名方法,一般应该叫做gtk++ (gtk plus plus),但是开发人员觉得叫plus plus的东西太多了,于是他们就叫gtk minus minus,所以就缩写成为gtkmm了;wxWidgets是开源的面向对象的跨平台图形库,已经有10多年的历史了,比较成熟,文档也不错(中文的几乎没有),最大的优势是跨平台,而且由于封装得不错,对各个控件的学习都还好掌握,没必要全部会,使用的时候查manual就可以了。据说wxWidgets比较像MFC,我不会MFC,尝试去学习过,但是发现学不进去,最后我觉得wxWidgets比较好懂好学。

wxWidgets有很多图形工具(GUI designer),例如wxFormbuilder,wxSmith,wxDev,wxGlade等等,各有千秋。没有必要全部掌握,选择一种学精了是不错的方法。

wxWidgets 由于层层封装,所以传说它的性能不好,这个问题我没有切身体会,但是总体的来说,wxWidgets编写的程序编译链接后的二进制文件都比原生图形库(gtk\MFC)写的程序的大。 wxWidgets在我个人看来是比较有潜力的,由于它良好的跨平台了,所以我选择它。
写一些简单的GUI,都可以用wxwidgets,很方便。当然更方便快捷的是wxPython,就是用wxwidgets的python库,国外比较火,我觉得因为他们用python的时间比较久了吧。这个东西我目前没见到过中文资料,我也不会python,所以不管他。
windows下的安装一点不难,网上有很多文章都介绍了,这里我就没必要重复了。一般问题google都能解决。另外,wxWidgets的问题就是中文参考比较少,所以最好多看英文资料。
学习wxWidgets,我的个人感觉,良好的C++基础是非常重要的。当然,只要能看懂C代码,学wxwidgets还是没问题。不过要学习透彻,要能够定制自己的控件,要理解其中的实现,都需要很好的C++知识。

跨平台的还有一个QT,我看到它的LOGO特别像镰刀帮的LOGO,所以我就没兴趣了。嘿嘿,这个是开玩笑,主要原因是wxWidgets先入为主,我就没关注QT了。但是这个东西在实际中应用是非常广的,远远超过开源的wxwidgets。QT的很多东西我不了解,不能乱说。

我是个wxWidgets菜鸟,边学边用。

实现一个虚拟设备“自增器”,该设备把写入的数据自增1。

ganquan@debian:~/Driver/01$ cat Add.h

#ifndef _MYDRIVER_H
#define _MYDRIVER_H

#include <linux/cdev.h>       /*cdev*/
#include <linux/types.h>    /*ssize_t*/

/*设备对象*/
struct Add
{
struct cdev MyChrDevice;    /*Char device structure*/
};

/*驱动程序要实现的函数*/
ssize_t Add_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos);
ssize_t Add_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos);

#endif    /*_MYDRIVER_H*/

ganquan@debian:~/Driver/01$ cat Add.c

#include <linux/init.h>			/*包含用于声明装载模块初始化和清除函数的宏*/
#include <linux/module.h>		/*包含装载模块需要的符号和函数定义*/
#include <linux/kernel.h>		/*printk()*/
#include <linux/fs.h>			/*申请设备号函数和数据结构,file_operation*/
#include <linux/types.h>		/*dev_t*/
#include <linux/kdev_t.h>		/*包含获取主设备号和次设备号的宏*/
#include <linux/slab.h>			/*kmalloc()*/
#include <linux/cdev.h>			/*cdev,cdev_init(),cdev_add()*/
#include <asm/uaccess.h>		/*copy_to_user(),copy_from_user()*/

#include "Add.h"

static int global_var = 0;
int Add_major = 0;	/*主设备号*/
int Add_minor = 0;	/*次设备号*/

struct Add *mydev;

struct file_operations Add_fops = {
	.owner = THIS_MODULE,
	.read = Add_read,
	.write = Add_write,
};

ssize_t Add_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
	if(copy_to_user(buf,&global_var,sizeof(int)))
	{
		return -EFAULT;
	}

	return sizeof(int);
}
ssize_t Add_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
	if(copy_from_user(&global_var,buf,sizeof(int)))
	{
		return -EFAULT;
	}
	if(global_var != 0)
		global_var++;

	return sizeof(int);
}

static int MyDriver_init(void)
{
	int ret;
	int devno;
	dev_t dev;

	/*申请设备号*/
	ret = alloc_chrdev_region(&dev,0,1,"Add");
	if(ret < 0)
	{
		printk(KERN_ALERT "Can not get dev_t\n");
	}
	else
	{
		Add_major = MAJOR(dev);		/*MAJOR in <linux/kdev_t.h>*/
		Add_minor = MINOR(dev);		/*MINOR in <linux/kdev_t.h>*/
	}
	/*申请设备号结束*/

	/*分配设备内存空间*/
	mydev = kmalloc(sizeof(struct Add),GFP_KERNEL);
	if(!mydev)
	{
		printk(KERN_ALERT "kmalloc error\n");
	}
	/*分配内存空间结束*/

	/*初始化内存空间*/
	memset(mydev,0,sizeof(struct Add));

	/*注册字符设备*/
	devno = MKDEV(Add_major,Add_minor);
	cdev_init(&mydev->MyChrDevice,&Add_fops);
	mydev->MyChrDevice.owner = THIS_MODULE;
	mydev->MyChrDevice.ops = &Add_fops;
	ret = cdev_add(&mydev->MyChrDevice,devno,1);
	if(ret)
		printk(KERN_ALERT "Error %d adding Add\n",ret);
	/*注册字符设备结束*/
	return 0;
}

static void MyDriver_exit(void)
{
	dev_t devno;

    devno = MKDEV(Add_major,Add_minor);
	cdev_del(&mydev->MyChrDevice);
	unregister_chrdev_region(devno,1);
	kfree(mydev);
}

module_init(MyDriver_init);	/*声明模块加载初始化函数*/
module_exit(MyDriver_exit);	/*声明模块卸载清除函数*/

MODULE_LICENSE("GPL");		/*驱动许可证协议*/
MODULE_AUTHOR("GanQuan");	/*作者*/
MODULE_VERSION("0.0.1");	/*版本号*/

不变的Makefile:
ganquan@debian:~/Driver/01$ cat Makefile

obj-m := Add.o
	KDIR ?= /lib/modules/$(shell uname -r)/build
	PWD := $(shell pwd)
all:
	    $(MAKE) -C $(KDIR) M=$(PWD)

.PHONY:clean
clean:
	    rm -f *.mod.c *.mod.o *.ko *.o *.tmp_versions

驱动加载脚本:
ganquan@debian:~/Driver/01$ cat addload

#!/bin/bash
#author ganqan
#	imganquan@gmail.com
#load a module

module="Add"
device="Add"
mode="777"

/sbin/insmod ./${module}.ko || exit 1

major=$(awk "\$2==\"$module\" {print \$1}" /proc/devices)

mknod /dev/${module} c $major 0
chmod $mode /dev/${device}

devinfo=`ls -l /dev/${device}`

echo "insmod	:$module.ko"
echo "major	:$major"
echo "devinfo	:$devinfo"

驱动卸载脚本:
ganquan@debian:~/Driver/01$ cat addunload

#!/bin/bash
#author ganquan
#	imganquan@gmail.com
#unload a module

module="Add"
device="Add"
/sbin/rmmod $module || exit 1
rm -f /dev/${device}

很简单的测试程序:
ganquan@debian:~/Driver/01$ cat test.c

#include <sys/stat.h>
#include <stdio.h>
#include <fcntl.h>
int main()
{
	int fd,num;
	fd = open("/dev/Add", O_RDWR, S_IRUSR | S_IWUSR);
	if (fd != -1)
	{
		read(fd, &num, sizeof(int));
		printf("The MyDevice is %d\n", num);

		printf("Please input the num written to MyDevice\n");
		scanf("%d", &num);
		write(fd, &num, sizeof(int));
		read(fd, &num, sizeof(int));
		printf("The MyDevice is %d\n", num);
		close(fd);
	}
	else
		printf("Device open failure\n");
		return 0;
}

测试结果:

ganquan@debian:~/Driver/01$ sudo ./addload
insmod	:Add.ko
major	:249
devinfo	:crwxrwxrwx 1 root root 249, 0 2009-06-09 22:55 /dev/Add
ganquan@debian:~/Driver/01$ ./test
The MyDevice is 0
Please input the num written to MyDevice
7
The MyDevice is 8
ganquan@debian:~/Driver/01$ sudo ./addunload

数字图像实验

把数字图像处理实验给做了。老师布置了两个任务,一个是直方图均衡化,另外一个是图像增强。第二个任务选择范围比较大,只要求任选一个,我选的是中值滤波去噪。

在Debian下完成,有时间了就继续做下去让这个程序变强大一点,完成其他的处理,其实可以用其他图像处理库这样就能轻松实现了。我觉得Linux下的GUI开发没有Windows下那么难,反正我很笨,学不会MFC,马上就要找工作的人了。。。唉

(1)原图

2009-05-25-174500_526x584_scrot

(2)直方图均衡化

2009-05-25-174616_526x584_scrot

(3)添加椒盐噪声

2009-05-25-174650_526x584_scrot

(4)3 x 3中值滤波

2009-05-25-174715_526x584_scrot