Wednesday, October 28, 2009

代码与API文档

从代码中直接提出API文档, 是一件令人高兴的事. 自己辛苦写的代码, 终于有了给人看得懂的文档了(虽然代码是ugly的)
python还方面的工具也很多的. epydoc就是送的一个小工具(我也不知道什么时候被安装入系统的).

从代码里取出API文档, 是原于一个叫documentation strings的东西. 在python里, 有这种东西的对象如下:
1. modules
2 functions
3 classes
4 methods

在哪里定义docstrings呢?
An object's docsting is defined by including a string constant as the first
statement in the object's definition.
看来, 第一个有效的语句, 并且是string型的, 就是叫docstring
function, classes, method比较好理解, 下面两个特殊一点的对象:
1. 在module中, 在py文件的除了"#"开始的行外, 第一个字符串语句
2. 在package中, docstring在于__init__.py文件中, 情况与module相同

docstring只是第一步. 需要进一步细分文档内容, 比如, 描述一个function的用途, 参数和返回情况. 这时需要在docstring中使用一种叫fields的东西, 如下URL:
* http://epydoc.sourceforge.net/manual-fields.html

如果想对docstring样式控制的话, 还有此功能的:
* http://epydoc.sourceforge.net/manual-epytext.html

BTW: docstring里样式控制就太花了. 加点缩进还是可以忍受的

Tuesday, October 27, 2009

django的ORM操作

不可否认, django的文档写的很好, 也很多文档.


对于本人还是那句话: 如果使用文字不能把一件事物清楚地描述出来的话, 那么你对这件事物还是不清晰 .  (^_^)


ORM类实例对象的创建

1. 使用类的__new__方法

2. 使用类Manager.create方法


两个类:

class Musician(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    instrument = models.CharField(max_length=100)

class Album(models.Model):
    artist = models.ForeignKey(Musician)
    name = models.CharField(max_length=100)
    release_date = models.DateField()
    num_stars = models.IntegerField()


创建对象:

1. 使用类的__new__方法:

In [6]: m = Musician(first_name='firename', last_name='lastname', instrument="something")
In [7]: m.id

这时, 新创建的对象是没有id的. 也就是还没有数据库的记录. 还需要使用方法把数据存在到数据库中:

In [8]: m.save()
In [9]: m.id
Out[9]: 2L

2. 使用类的Manager.creater方法:

In [4]: m = Musician.objects.create(first_name='firename', last_name='lastname', instrument="something")
In [5]: m.id
Out[5]: 3L

这时, 数据已经被添加到数据库表, 不用调用save方法


任何model类实例对象都有这两种方法创建.

ManyToOne Field添加引用实例

Album与Mussician的关系是"多对一", Album创建实例时多了一个条件: Album的__new__和Manager.create会检查artist参数是不是Musician的实例:

__new__方法:

In [12]: a = Album(artist=2, name='album name', release_date=datetime.datetime.now(), num_stars=10)

ValueError: Cannot assign "2": "Album.artist" must be a "Musician" instance.

Manager.create方法:

In [13]: a = Album.objects.create(artist=2, name='album name', release_date=datetime.datetime.now(), num_stars=10)
ValueError: Cannot assign "2": "Album.artist" must be a "Musician" instance.

* 传个与primary key相同的数字还是出错

需要在artist参数位置传入一个指定的实例:

步骤1: 使用Musician的__new__或者Manager.create创建Musician对象:

m = Musician(first_name='firename', last_name='lastname', instrument="something")

m.save() # 一定要被存在在数据库中才能被Album的创建方法正常使用, 则否出错.

a = Album(artist=m, name='album name', release_date=datetime.datetime.now(), num_stars=10)

a.save()


如果m不使用save()的情况:

In [27]: m = Musician(first_name='firename', last_name='lastname', instrument="something")
In [28]: a = Album(artist=m, name='album name', release_date=datetime.datetime.now(), num_stars=10)
In [29]: a.save()
IntegrityError: (1048, "Column 'artist_id' cannot be null")

出错. 说artist_id为null


使用对象:

有两个方向: 1. 从Foreign端; 2. 从被Foreign端

1. 从Foreign端

In [19]: a = Album.objects.get(pk=1)
In [20]: a.artist.id
Out[20]: 4L

In [22]: a.artist.first_name
Out[22]: u'firename'
这种引用方法很pythonic


2. 从被Foreign端


这时候被称为: The “other side” of a ForeignKey relation. 如果一个model类被其它类通过foreign key引用的话. 那么, 在被引用

的类和这个类的实例中, 会多一个属性:

In [61]: type Musician.album_set
-------> type(Musician.album_set )
Out[61]: <class 'django.db.models.fields.related.ForeignRelatedObjectsDescriptor'>
In [62]: m = Musician.objects.get(pk=1)
In [63]: type m.album_set
-------> type(m.album_set )
Out[63]: <class 'django.db.models.fields.related.RelatedManager'>
在django文档中有这样一句话:

Following relationships "backward"


If a model has a ForeignKey, instances of the foreign-key model will have
access to a Manager that returns all instances of the first model. By
default, this Manager is named FOO_set, where FOO is the source
model name, lowercased. This Manager returns QuerySets, which can be
filtered and manipulated as described in the "Retrieving objects"


作用就是能通过此方法找到一个对象都被哪些对象引用


# 下面是从album实例找到引用的musician实例

In [64]: a = Album.objects.get(pk=1)
In [65]: a.id
Out[65]: 1L

In [67]: a.artist.id
Out[67]: 4L

# 下面是从musician实例找到被哪个album实例引用了

In [68]: m = Musician.objects.get(pk=4)
In [70]: a_set = m.album_set.all()
In [71]: a_set.count()
Out[71]: 1
In [72]: a = a_set[0]
In [73]: a.id
Out[73]: 1L

蓝色的部分都是一样的, 表示是同一个album实例

ManyToMany Field添加引用实例

class Domain(models.Model):
    name = models.CharField(max_length=128)
    is_singular = models.IntegerField()
    description = models.CharField(max_length=32, default="")
    object = models.ManyToManyField("Object")

class Object(models.Model):
    name = models.CharField(max_length=128)
    description = models.CharField(max_length=32, default="")

ManyToMany字段是可以引用(foreign)多个实例的. 这通过ManyToMany Field的add方法实例:
 In [2]: domain = Domain(name = 'china', is_singular=1)
In [3]: domain.object.add
ValueError: 'Domain' instance needs to have a primary key value before a many-to-many relationship can be used.
In [5]: domain.object.add
Out[5]: <bound method ManyRelatedManager.add of <django.db.models.fields.related.ManyRelatedManager object at 0x9fa82ec>>
可以看出, ManyToMany Field的add方法是需要在save后才有的.

下面为ManyToMany Field增加引用实例:
In [6]: obj = Mod.Object(name="object1")
In [7]: domain.object.add(obj)
IntegrityError: (1048, "Column 'object_id' cannot be null")
* 与Foreign Field是一样的, 都是需要被引用的对象先存在于数据库表中!
In [8]: obj.save()
In [9]: domain.object.add(obj)
In [10]: domain.save()

* 调用obj.save后, 才成功添加引用实例!
还是可以引用多个实例的:
In [11]: obj = Object(name="object2")
In [12]: obj.save()
In [13]: domain.object.add(obj)
In [14]: domain.save()
* 这么多个save(), 是因为底层还是关系型数据库, 每一次save就对应着一次insert或者是update

通过through参数, 使用定制义的中间表, 此后, ManyToMany Field没有了add方法!

新的模型如下:
class Domain(models.Model):
    name = models.CharField(max_length=128)
    is_singular = models.IntegerField()
    description = models.CharField(max_length=32, default="")
    object = models.ManyToManyField("Object", through="DomainObject")

class Object(models.Model):
    name = models.CharField(max_length=128)
    description = models.CharField(max_length=32, default="")

class DomainObject(models.Model):
    domain = models.ForeignKey("Domain")
    object = models.ForeignKey("Object")

# 找一找ManyToMany Field的add方法:
In [2]: domain = Mod.Domain(name = 'china', is_singular=1)
In [3]: domain.save()
In [4]: domain.add
AttributeError: 'Domain' object has no attribute 'add'
* 被掩了!
为ManyToMany Field添加引用实例需要使用如下方法:
In [6]: domain
Out[6]: <Domain: Domain object>
In [7]: obj
Out[7]: <Object: Object object>
In [8]: domain_object = Mod.DomainObject.objects.create(domain=domain, object=obj)
* 这里的Manager.create方法可以类的__new__方法
这是显式使用了中间表对应的类来生成映射关系.

使用对象:

和上面的ManyToOne情况一样, 有两个方向: 1. 从Foreign端; 2. 从被Foreign端

1. 从Foreign端
In [23]: domain.object
Out[23]: <django.db.models.fields.related.ManyRelatedManager object at 0x9fa802c>
为一个Manager对象!
In [24]: objs = domain.object.all()
In [27]: for item in objs:
   ....:     print item.id
1
2
可见, 这时间是需要指定select条件才能取回自己想要的对象

2. 从被Foreign端
In [28]: obj = domain.object.all()[0]
In [29]: obj.id
Out[29]: 1L
In [30]: domain.id
Out[30]: 1L
可见, ID为1的domain引用了ID为1的object, 反过来找:
In [35]: obj = Object.objects.get(pk=1)
In [39]: domain = obj.domain_set.get(pk=1)
In [40]: domain.id
Out[40]: 1L

改变RelatedManager的名字

class Musician(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    instrument = models.CharField(max_length=100)

class Album(models.Model):
    artist = models.ForeignKey(Musician, related_name="Musician_set")
    name = models.CharField(max_length=100)
    release_date = models.DateField()
    num_stars = models.IntegerField()

多了红色代码, 然后:
In [7]: m = Musician(first_name='first_name', last_name='last_name', instrument='instrument')
In [8]: m.Musician_set
Out[8]: <django.db.models.fields.related.RelatedManager object at 0x8de220c>


映射与primary key, foreign key

一对多, 多对多, 多对一, 一对一. 这是什么?

这种是什么关系? 在初中数学中有一种叫: 映射 的概念.

定义:设A和B是两个非空集合,如果按照某种对应关系f,对于集合A中的任何一个元素,在集合B中都存在唯一的一个元素与之对应,那么,这样的对应(包括集合A,B,以及集合A到集合B的对应关系f)叫做集合A到集合B的映射(Mapping),记作f:A→B。

这个"对应关系f"又是一个忽悠级的概念. 又如, money与owner就是一种"对应关系". 那么girls与me有没有关系呢? 当然了! 当me为mine时就很明显了!

重要的几句话:
1. 映射,或者射影,在数学及相关的领域经常等同于函数
 * f就是这个函数. A的与B只不过是stdout与stdin罢了
2. 对应的唯一性:定义域中的一个元素只能与映射值域中的一个元素对应
 * 如图:
图1不是中的集合A到集合B不形成映射! 因为这不是唯一性!

那么为什么在数据库中常出现"一对多"的情况呢?
映射是有方向的, 上面的图(1)如果方向从B到A, 使用f = N^2这个法则的话. 就形成了集合B到集合A的映射. 就是说"一对多"的另一个方向是"多对一"

"多对多"是怎么解释?
从django的ORM实现ManyToMany关系类型就大概知道了:

左边的图是"多对多"的情况, 等价于右边的图. 增加一个中间集合, 关系被分成两个大圆上. 结果是: "一对多 => 多对一".

所以, 映射有二种:
1. 一对一
2. 一对多

primary key 和 foreign key又是何方神圣?

1. primary key就是一个集合中, 为每个元素分配一个唯一的序号. f(集合, pk)一定可以得到唯一的元素
2. foreign key就是当某一集合的元素的primary key序号在另一集合中作为元素值时对这个序号(数字)的称呼. 与上面一样, f(集合, pk)也是可以得到唯一的元素. 如果得到的元素又是另一个集合的primary key呢? 于是: f2(集合2, f1(集合, pk))也是有唯一的元素的. 这样就可以把N个集合的关系表达出来.

primary key应该放在哪个集合中?

1. 对于"一对一"的情况, 放在哪个集合都是可以形成映射的

2. 对于"一对多"的情况. primary key应该存在"多"的一端.

数据库技术中, 使用primary key 与 forgein key概念来完成了表与表的相引用, 也增加了一些约束, 使key(为某一数字)拥有更多功能. 例如django文档这样写的:
When Django deletes an object, it emulates the behavior of the SQL
constraint ON DELETE CASCADE -- in other words, any objects which
had foreign keys pointing at the object to be deleted will be deleted
along with it.

虽然foreign key也是一个数字, 但给以它更多的意义.




BTW: 找数学知识文档没有经难. 比较难找.
http://baike.baidu.com/view/21249.htm

Thursday, October 22, 2009

screen的同类产品

一个名为tmux的软件, 功能与screen类似, 号称是BSD协议的GNU screen

这里有介绍: http://niallohiggins.com/2009/06/04/tmux-a-bsd-alternative-to-gnu-screen/


随便找个地方记录一下自己的screen配置, 方便日后快速找回:

escape ^Ss
bind j focus down
bind k focus up
bind t focus top
bind b focus bottom
# 删除这几个
bind ^k
bind 'K'

django的session处理

I. cookie与session的关系

HTTP是无状态协议, 它区别请求是借且于HTTP中的cookie字段来实现.
服务器端发出带cookie字段的HTTP response大致如下:
Set-Cookie: name=newvalue; expires=date; path=/; domain=.example.org
客户端发出带cookie字段的HTTP request大致如下:
Cookie: name=newvalue; expires=date; path=/; domain=.example.org

HTTP协议中对cookie有约定的属性, 见: http://en.wikipedia.org/wiki/HTTP_cookie#Cookie_attributes

session是在cookie的机制的基础上, 增加一个可以被WEB服务使用的token. 此token对应于服务器端的一个些具体的, 不希望在HTTP中传输的数据.

这就是{key:vaule}的关系

II. django里的cookie与session

在django的request对象中, 有两个与会话相关的对象:
request.COOKIES: 一个dict实例
request.session. 一个SessionStore类的实例. 在SessionMiddleware中被创建.

django在默认时, cookie被加入了一个叫sessionid的属性. 如下:
(Pdb) print request.COOKIES
{'sessionid': '40c340a947b41e4def92ed70c25affbe'}
* 可以通过settings.py修改

这个属性就是django里与session对应的token. 被称为session_key, 如:
(Pdb) print request.session.session_key
40c340a947b41e4def92ed70c25affbe

III. 服务器端返回set-cookie段

要把session对应的session_key放在HTTP的cookie段中, 是用到response.set_cookie方法. 一般情况下, 我们不需要直接调用它, 因为:
SessionMiddleware的process_response方法中调用了set_cookie方法.
需要被中间件调用se_cookie方法需要一个条件:
modified = request.session.modified
if modified or settings.SESSION_SAVE_EVERY_REQUEST:

要想request.session.modified == True, 有两种方法:
1. 生成一个新的session对象
2. 修改或者增加session的key对应的值
也就是说, request.session.modified为True. 这涉及到SessionStore类. 下面理理这个类.

SessionStore类

在看django代码时, 会扯到python的一种语法: descriptor. 具体见:
1. http://users.rcn.com/python/download/Descriptor.htm
2. http://www.ibm.com/developerworks/cn/linux/l-python-elegance-2.html

SessionStore类主要起到session管理的作用. 如生成新的session, 修改session中key的value. 检查session_key是否有对应的session对象等等

1. 产生Session对象

SessionStore产生新的session对象(就是新的session_key)有两种方法:
1. load()
2. create()
load是从数据库中对指定session_key对应的session对象, 如果没有就调用create, 所以看create方法:
    def create(self):
        while True:
            self.session_key = self._get_new_session_key() #其实就是产生一个唯一的key
            try:
                # Save immediately to ensure we have a unique entry in the
                # database.
                self.save(must_create=True) #应用了数据库的models对象
            except CreateError:
                # Key wasn't unique. Try again.
                continue
            self.modified = True
            self._session_cache = {}
            return

2. 修改Session实例

在SessionStore类中, 定义了N多对Session实例的操作, 但是这些操作都是引用self._session这个descriptor. 这个descriptor到底返回了什么呢?
   def _get_session(self, no_load=False):

        """
        Lazily loads session from storage (unless "no_load" is True, when only
        an empty dict is stored) and stores it in the current instance.
        """
        self.accessed = True
        try:
            return self._session_cache
        except AttributeError:
            if self._session_key is None or no_load:
                self._session_cache = {}
            else:
                self._session_cache = self.load()
        return self._session_cache

    _session = property(_get_session)

* 引用self._session 其实是引用了self.load(), 这就是descriptor用法!
* 上面的self._session_cache就是session实例的session_data对应的那个dict实例


SessionStore对session实例的一个修改方法:
    def setdefault(self, key, value):
        if key in self._session:
            return self._session[key]
        else:
            self.modified = True
            self._session[key] = value
            return value
* 其中的 self._session[key]其实等于 self.load()[key] = value, 结合self.load的代码后同于 self._session_cache[key] = value

session对应的字典的保存:
在SessionBase中定义了一方法:
    def encode(self, session_dict):
        "Returns the given session dictionary pickled and encoded as a string."
        pickled = pickle.dumps(session_dict, pickle.HIGHEST_PROTOCOL)
        pickled_md5 = md5_constructor(pickled + settings.SECRET_KEY).hexdigest()
        return base64.encodestring(pickled + pickled_md5)
可以看出, 字典是被pickled成一堆字符串了. 需要被使用时, 就使用SessionBase的decode方法


BTW:: 使用eclipse看代码真是他妈的爽!! 前段时间花了不少功夫在eclipse上面, 还是有回报的. 看来除了firefox外, 还有一个一定要是GUI的软件

Wednesday, October 21, 2009

django的auth与session

一直对网站的认证感兴趣. 看了一把django在这方面的实现方式:
认证有两部分, 一是session, 二是用户的信息(密码等).

django的contrib.auth是基于contrib.session的
django是怎么生成request.session和request.user的呢?

因为request.session和user都是在view被调用之前生成的. 所以使用到了中间件:
MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
)

django.contrib.sessions.middleware.SessionMiddleware的内容:
class SessionMiddleware(object):                                                                                  
    def process_request(self, request):                 
        engine = import_module(settings.SESSION_ENGINE)
        session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME, None)
        request.session = engine.SessionStore(session_key)    
django在默认情况下使用数据库存放session, 它还实现了方式存放session的方法. 可以通过SESSION_ENGINE来配置
初始化SessionStore时需要一个参数, 如果没有显式给出就是None, 代码:
class SessionBase(object):
    """
    Base class for all Session classes.
    """
    TEST_COOKIE_NAME = 'testcookie'
    TEST_COOKIE_VALUE = 'worked'

    def __init__(self, session_key=None):
        self._session_key = session_key
        self.accessed = False
        self.modified = False
SessionStore可以使用的方法在SessionStore和SessionBase两个类中可以找到

对于request.user的情况:
django.contrib.auth.middleware.AuthenticationMiddleware的内容
class LazyUser(object):
    def __get__(self, request, obj_type=None):
        if not hasattr(request, '_cached_user'):
            from django.contrib.auth import get_user
            request._cached_user = get_user(request)
        return request._cached_user

class AuthenticationMiddleware(object):
    def process_request(self, request):
        assert hasattr(request, 'session'), "The Django authentication middleware requires session middleware to be installed. Edit your MIDDLEWARE_CLASSES setting to insert 'django.contrib.sessions.middleware.SessionMiddleware'."
        request.__class__.user = LazyUser()
        return None

很短,就一个构造函数! 但是python的__get__有意思! AuthenticationMiddleware中只是实现了request.user的引用. 平时django应用使用request.user的方式:
1. request.user.name
2. request.user.is_authenticated()
上面的request.usr不只是一个LazyUser的实例吗? 怎么与django.contrib.auth.models.User关联在一起?

重点在于LazyUser的__get__方法. 关于这种用法, 下次认真做记录

Monday, October 12, 2009

linux代码浏览好去处

在看人家的blog文章时, 发现一个很好的网站: http://lxr.linux.no

此网站对linux内核代码索引. 方便交叉引用.

Linux的代码比森林还要复杂. 本人觉得, 最好不急着看linux代码, 这步之前应该把linux内核的功能与之结构搞明白. 然后才走这一步. 否则很痛苦.

比如:
多看点这样的图片: http://iamanush.com/wp-content/uploads/2008/06/linux_kernel_map_img_3.png

多看点这样的文章: http://docs.huihoo.com/linux/kernel/a2/index.html


哈, 本人想像中的走法. 别人有别人的路. 如果有好的, 推介一把吧.

Saturday, October 10, 2009

ebuild依赖死循环

使用gentoo其实也不是很久. 但是起码几个月了. 呃.... 对portage还是很陌生. 看来只能慢慢来了.

今天碰到这个问题:

[nomerge      ] dev-python/pycairo-1.8.8 [1.8.2] USE="doc%* -svg%"
[nomerge      ]  dev-python/sphinx-0.6.1-r1  USE="doc -test"
[ebuild  N    ]   dev-python/jinja2-2.1.1-r1  USE="doc -examples -i18n -test"
[ebuild  N    ]    dev-python/sphinx-0.6.1-r1  USE="doc -test"

 * Error: circular dependencies:

('ebuild', '/', 'dev-python/sphinx-0.6.1-r1', 'merge') depends on
  ('ebuild', '/', 'dev-python/jinja2-2.1.1-r1', 'merge') (buildtime)
('ebuild', '/', 'dev-python/jinja2-2.1.1-r1', 'merge') depends on
  ('ebuild', '/', 'dev-python/sphinx-0.6.1-r1', 'merge') (buildtime)

 * Note that circular dependencies can often be avoided by temporarily
 * disabling USE flags that trigger optional dependencies.

看来是一个死循环, 不过, emerge做得很好, 知道了! 也给出了建议: 临时去掉一(些)USE可以解决这种optional dependencies

在/etc/portage/package.use加入dev-python/pycairo -doc 果真好了.

另:

emerge的用法中:
emerge [options] [action] [ebuild | tbz2file | file | set | atom]....

有一个叫atom的东西, 指定它是可以使用如: >, >=, <之类的符号的. 也就是说, 在/etc/portage/package.use配置文件中:
dev-python/pycairo -doc

=dev-python/pycairo-1.8.8 -doc

是不同的!!

emerge的输出提示

在console和terminal下的命令行有两种提示方式:
1. 颜色
2. 额外的字符

I. 颜色

颜色在视觉上给人一定的提示. 不论是terminal下还是console下, 本人严重依赖于颜色! 如果两者的输出没有颜色是非常难看, 很容易看少, 看漏信息

使用得最多的就是ls命令的颜色了, 如:
jessinio@niolaptop ~ $ type ls
ls is aliased to `ls --color=auto'

平时使用有颜色的ls也是使用的参数去控制的.

还好, gentoo的emerge在这方面做得不错, 来两幅例子, 下面两幅输出文字相同, 只是颜色的区别:

看一幅没有color的输出:

下面是有color的输出:

颜色还是很鲜明的, 特别是在一堆文字中强调一小部分文字, 比如画中的-idn


II. 额外的字符

还是与ls命令为例:
jessinio@niolaptop ~ $ ls --color=none -F
结果为:
输出的文件名后有额外的字符: "/", "*"
这些额外的字符其实是表示不同的强调含义!
       -F, --classify
              append indicator (one of */=>@|) to entries

III. 两种方式的比较

颜色只要是给人类看到的. 对于computer是对颜色没有兴趣的. 反而它对额外的字符比较感兴趣. 用一个grep就可以方便处理带有"*"的文件名, 多方便!

IV. emerge的输出

今天update world, 感受emerge的提示帮助本人大大提高了升级的便利. 随便做做笔记. 方便日后回顾

emerge的输出同时有两种提示, 从上面emerge的输出图片都可以看得出.
1. 颜色由--color参数指定(默认是打开的)
2. 额外的symbols是由-v(--verbose)打开. 如下:
              Symbol   Location    Meaning
              ──────────────────────────────────────────────────────────────
              -        prefix      not enabled (either disabled or removed)
              *        suffix      transition to or from the enabled state
              %        suffix      newly added or removed
              ()       circumfix   forced, masked, or removed

从实例中, 本人注意到:
-前缀的都是这种颜色的!
*后缀的USE都是这种颜色的!
有%的USE都是这种颜色的!

下面翻译一下symbol的意思:
-前缀: 被禁止的USE.
*后缀: 有两层意思:
1. 与USE的默认值不同. 即被人为enabled了;
2. 与已安装的包的USE不同. 这又有两种情况:
1. 与已安装的包相比, USE被修改
2. 正在使用的USE在新的版本中被remove了. 这时与%同时存在
%后缀: 被增加或者是被移除了.

这些symbol本身不难, 难在它们之间可以同时存在! 上面对*后缀描述得详细, 因为它很敏感. 它的存在表示:
* 此USE被修改或者被enable了!
* transition to or from the enabled state 这句话其在太有难度了!

所以, 应该留言!

其它:
man 5 color.map就可以看到: color.map - custom color settings for Portage
用户是可以自定义颜色的. 当然也有默认的颜色信息在这个man手册里了!

Wednesday, October 7, 2009

麦克风与music

最近玩起skype了. 说到skype, 我就被折腾得.... 呃!!!
搞alsa就扯到一堆与声音, 音乐相关的术语. 现在还没有搞清楚
不过最后使用了一个旧版本的skype才完成了语音通话

在保持通话连接的情况下有时需要来一段music, 想到了软件关掉microphone:

#!/bin/bash                                                                  
# shutdown microphone, otherwise no un-pause music 
amixer -c 0 set Capture nocap && mocp -U                   

当对方有话来时, 停掉music, 打开microphone:
#!/bin/bash                                                                                                         
# an error will raise if mocp server no running, but this is no-importance                
# example: You can stop microphone but no play music if mocp server no running 
mocp -P                                                                                                               
amixer -c 0 set Capture cap                                                                                  

把上面的两段代码绑定到两个hotkey上, 结果.... 就像DJ 一样, 想说话就说话, 想来music也行. 哈

Monday, October 5, 2009

动态链接库

多人使用的发行版本就是方便. 下个bin就可以使用. 比如chromium有deb包的.
今天懒了, 想下载个bin版本的mysql-gui-tools用. 结果给我报了个Error:
jessinio@niolaptop /tmp/mysql-gui-tools-5.0 $ ./mysql-administrator-bin
./mysql-administrator-bin: error while loading shared libraries: libpcre.so.3: cannot open shared object file: No such file or directory    

这其实就是dynamic share library的问题. 因为下载的binary文件中包括了需要使用的动态链接库的绝对路径. 三个问题:
1. 我的gentoo的动态链接库放在哪里呢?
2. 我的gentoo有没有安装这个library呢?
3. 怎么得知这个二进制文件中需要使用的动态链接库的绝对路径呢?

还有一个是不希望出现的问题: 动态链接库的版本问题. 出这个问题还不如干脆自己emerge一个.

对于第一个问题: 哪里放library文件的呢?
linux下没有强制, 只有约定! 一般放在下面的文件夹中:
1. /lib
2. /usr/lib
3. /usr/local/lib

随便看到两个比较有意思的文夹:
1. /usr/local/libexec
2. /usr/libexec
* 文档是这样描述这两个文件夹的用法的: Note that if your library calls programs that can only be called via
libraries, you should place those programs in /usr/local/libexec
这两个文件夹下的文件说白了就是可运行的程序! 只不是我们说常用的CLI. 而是只为了给API调用的程序

第二个问题: 我的gentoo有没有安装这个library呢?
在上面的基础上:
jessinio@niolaptop ~$ find /lib/ /usr/lib /usr/local/lib -name "*pcre*"

可以轻松出来:
/lib/libpcre.so.0
/lib/libpcre.so.0.0.1

可知道没有名叫: libpcre.so.3 的文件, 应该为找到的/lib/libpcre.so.0创建一个link文件(这其实是so文件的命名方式). 问题是这个link文件应该放在哪里才会被运行的程序使用呢? 这就来了第三个问题: 怎么得知这个二进制文件中需要使用的动态链接库的绝对路径呢?

jessinio@niolaptop /tmp/mysql-gui-tools-5.0 $ ldd mysql-administrator-bin |grep pcre
        libpcre.so.3 => /lib/libpcre.so.3 (0xb7261000)
这就被强大的ldd命令挖出来了, 创建一个link文件:
jessinio@niolaptop /tmp/mysql-gui-tools-5.0 $ sudo ln -s /lib/libpcre.so.0.0.1 /lib/libpcre.so.3

这就解决了下载的binrary文件在gentoo下的运行问题. 当然, 不是万能的! 要根据实际问题找解决方法. gentoo下有时间还是emerge(至少make)一个binrary!

于关dynamic share library的文档: http://www.linux.org/docs/ldp/howto/Program-Library-HOWTO/shared-libraries.html