Returns the list of files matching the given pattern in the
    specified directory.  Both directories and patterns are
    supplied as portable paths. Each pattern should be non-absolute
    path, and can't contain '.' or '..' elements. Each slash separated
    element of pattern can contain the following special characters:
    -  '?', which match any character
    -  '*', which matches arbitrary number of characters.
    A file $(d)/e1/e2/e3 (where 'd' is in $(dirs)) matches pattern p1/p2/p3
    if and only if e1 matches p1, e2 matches p2 and so on.
    For example:
        [ glob . : *.cpp ]
        [ glob . : */build/Jamfile ]

def glob(dirs, patterns, exclude_patterns=None):
    """Returns the list of files matching the given pattern in the
    specified directory.  Both directories and patterns are
    supplied as portable paths. Each pattern should be non-absolute
    path, and can't contain '.' or '..' elements. Each slash separated
    element of pattern can contain the following special characters:
    -  '?', which match any character
    -  '*', which matches arbitrary number of characters.
    A file $(d)/e1/e2/e3 (where 'd' is in $(dirs)) matches pattern p1/p2/p3
    if and only if e1 matches p1, e2 matches p2 and so on.
    For example:
        [ glob . : *.cpp ]
        [ glob . : */build/Jamfile ]
    """

    assert(isinstance(patterns, list))
    assert(isinstance(dirs, list))

    if not exclude_patterns:
        exclude_patterns = []
    else:
       assert(isinstance(exclude_patterns, list))

    real_patterns = [os.path.join(d, p) for p in patterns for d in dirs]
    real_exclude_patterns = [os.path.join(d, p) for p in exclude_patterns
                             for d in dirs]

    inc = [os.path.normpath(name) for p in real_patterns
           for name in builtin_glob(p)]
    exc = [os.path.normpath(name) for p in real_exclude_patterns
           for name in builtin_glob(p)]
    return [x for x in inc if x not in exc]